5fe83d
From df11c6cb80238fb43c4a5994161cc2e70521ffb4 Mon Sep 17 00:00:00 2001
5fe83d
From: Petr Mensik <pemensik@redhat.com>
5fe83d
Date: Tue, 18 Aug 2020 10:54:39 +0200
5fe83d
Subject: [PATCH] Fix CVE-2020-8623
5fe83d
5fe83d
5480.	[security]	When BIND 9 was compiled with native PKCS#11 support, it
5fe83d
			was possible to trigger an assertion failure in code
5fe83d
			determining the number of bits in the PKCS#11 RSA public
5fe83d
			key with a specially crafted packet. (CVE-2020-8623)
5fe83d
			[GL #2037]
5fe83d
---
5fe83d
 lib/dns/pkcs11dh_link.c         | 15 ++++++-
5fe83d
 lib/dns/pkcs11dsa_link.c        |  8 +++-
5fe83d
 lib/dns/pkcs11rsa_link.c        | 79 +++++++++++++++++++++++++--------
5fe83d
 lib/isc/include/pk11/internal.h |  3 +-
5fe83d
 lib/isc/pk11.c                  | 60 ++++++++++++++++---------
5fe83d
 5 files changed, 121 insertions(+), 44 deletions(-)
5fe83d
5fe83d
diff --git a/lib/dns/pkcs11dh_link.c b/lib/dns/pkcs11dh_link.c
5fe83d
index c192b53..49ff58d 100644
5fe83d
--- a/lib/dns/pkcs11dh_link.c
5fe83d
+++ b/lib/dns/pkcs11dh_link.c
5fe83d
@@ -747,6 +747,7 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) {
5fe83d
 	CK_BYTE *prime = NULL, *base = NULL, *pub = NULL;
5fe83d
 	CK_ATTRIBUTE *attr;
5fe83d
 	int special = 0;
5fe83d
+	unsigned int bits;
5fe83d
 	isc_result_t result;
5fe83d
 
5fe83d
 	isc_buffer_remainingregion(data, &r);
5fe83d
@@ -851,7 +852,11 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) {
5fe83d
 	pub = r.base;
5fe83d
 	isc_region_consume(&r, publen);
5fe83d
 
5fe83d
-	key->key_size = pk11_numbits(prime, plen_);
5fe83d
+	result = pk11_numbits(prime, plen_, &bits);
5fe83d
+	if (result != ISC_R_SUCCESS) {
5fe83d
+		goto cleanup;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
5fe83d
 	if (dh->repr == NULL)
5fe83d
@@ -1011,6 +1016,7 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
5fe83d
 	dst_private_t priv;
5fe83d
 	isc_result_t ret;
5fe83d
 	int i;
5fe83d
+	unsigned int bits;
5fe83d
 	pk11_object_t *dh = NULL;
5fe83d
 	CK_ATTRIBUTE *attr;
5fe83d
 	isc_mem_t *mctx;
5fe83d
@@ -1081,7 +1087,12 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(dh, CKA_PRIME);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
5fe83d
+
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	return (ISC_R_SUCCESS);
5fe83d
 
5fe83d
diff --git a/lib/dns/pkcs11dsa_link.c b/lib/dns/pkcs11dsa_link.c
5fe83d
index 8d0fc62..3a8a0bb 100644
5fe83d
--- a/lib/dns/pkcs11dsa_link.c
5fe83d
+++ b/lib/dns/pkcs11dsa_link.c
5fe83d
@@ -982,6 +982,7 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
5fe83d
 	dst_private_t priv;
5fe83d
 	isc_result_t ret;
5fe83d
 	int i;
5fe83d
+	unsigned int bits;
5fe83d
 	pk11_object_t *dsa = NULL;
5fe83d
 	CK_ATTRIBUTE *attr;
5fe83d
 	isc_mem_t *mctx = key->mctx;
5fe83d
@@ -1071,7 +1072,12 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(dsa, CKA_PRIME);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
5fe83d
+
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	return (ISC_R_SUCCESS);
5fe83d
 
5fe83d
diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c
5fe83d
index af6008d..9a736dd 100644
5fe83d
--- a/lib/dns/pkcs11rsa_link.c
5fe83d
+++ b/lib/dns/pkcs11rsa_link.c
5fe83d
@@ -333,6 +333,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
5fe83d
 		key->key_alg == DST_ALG_RSASHA256 ||
5fe83d
 		key->key_alg == DST_ALG_RSASHA512);
5fe83d
 #endif
5fe83d
+	REQUIRE(maxbits <= RSA_MAX_PUBEXP_BITS);
5fe83d
 
5fe83d
 	/*
5fe83d
 	 * Reject incorrect RSA key lengths.
5fe83d
@@ -376,6 +377,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
5fe83d
 	for (attr = pk11_attribute_first(rsa);
5fe83d
 	     attr != NULL;
5fe83d
 	     attr = pk11_attribute_next(rsa, attr))
5fe83d
+	{
5fe83d
 		switch (attr->type) {
5fe83d
 		case CKA_MODULUS:
5fe83d
 			INSIST(keyTemplate[5].type == attr->type);
5fe83d
@@ -396,12 +398,16 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
5fe83d
 			memmove(keyTemplate[6].pValue, attr->pValue,
5fe83d
 				attr->ulValueLen);
5fe83d
 			keyTemplate[6].ulValueLen = attr->ulValueLen;
5fe83d
-			if (pk11_numbits(attr->pValue,
5fe83d
-					 attr->ulValueLen) > maxbits &&
5fe83d
-			    maxbits != 0)
5fe83d
+			unsigned int bits;
5fe83d
+			ret = pk11_numbits(attr->pValue, attr->ulValueLen,
5fe83d
+					   &bits);
5fe83d
+			if (ret != ISC_R_SUCCESS ||
5fe83d
+			    (bits > maxbits && maxbits != 0)) {
5fe83d
 				DST_RET(DST_R_VERIFYFAILURE);
5fe83d
+			}
5fe83d
 			break;
5fe83d
 		}
5fe83d
+	}
5fe83d
 	pk11_ctx->object = CK_INVALID_HANDLE;
5fe83d
 	pk11_ctx->ontoken = ISC_FALSE;
5fe83d
 	PK11_RET(pkcs_C_CreateObject,
5fe83d
@@ -1075,6 +1081,7 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
5fe83d
 			keyTemplate[5].ulValueLen = attr->ulValueLen;
5fe83d
 			break;
5fe83d
 		case CKA_PUBLIC_EXPONENT:
5fe83d
+			unsigned int bits;
5fe83d
 			INSIST(keyTemplate[6].type == attr->type);
5fe83d
 			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
5fe83d
 							    attr->ulValueLen);
5fe83d
@@ -1083,10 +1090,12 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
5fe83d
 			memmove(keyTemplate[6].pValue, attr->pValue,
5fe83d
 				attr->ulValueLen);
5fe83d
 			keyTemplate[6].ulValueLen = attr->ulValueLen;
5fe83d
-			if (pk11_numbits(attr->pValue,
5fe83d
-					 attr->ulValueLen)
5fe83d
-				> RSA_MAX_PUBEXP_BITS)
5fe83d
+			ret = pk11_numbits(attr->pValue, attr->ulValueLen,
5fe83d
+					   &bits);
5fe83d
+			if (ret != ISC_R_SUCCESS || bits > RSA_MAX_PUBEXP_BITS)
5fe83d
+			{
5fe83d
 				DST_RET(DST_R_VERIFYFAILURE);
5fe83d
+			}
5fe83d
 			break;
5fe83d
 		}
5fe83d
 	pk11_ctx->object = CK_INVALID_HANDLE;
5fe83d
@@ -1463,6 +1472,8 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
5fe83d
 	CK_BYTE *exponent = NULL, *modulus = NULL;
5fe83d
 	CK_ATTRIBUTE *attr;
5fe83d
 	unsigned int length;
5fe83d
+	unsigned int bits;
5fe83d
+	isc_result_t ret = ISC_R_SUCCESS;
5fe83d
 
5fe83d
 	isc_buffer_remainingregion(data, &r);
5fe83d
 	if (r.length == 0)
5fe83d
@@ -1480,9 +1491,7 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
5fe83d
 
5fe83d
 	if (e_bytes == 0) {
5fe83d
 		if (r.length < 2) {
5fe83d
-			isc_safe_memwipe(rsa, sizeof(*rsa));
5fe83d
-			isc_mem_put(key->mctx, rsa, sizeof(*rsa));
5fe83d
-			return (DST_R_INVALIDPUBLICKEY);
5fe83d
+			DST_RET(DST_R_INVALIDPUBLICKEY);
5fe83d
 		}
5fe83d
 		e_bytes = (*r.base) << 8;
5fe83d
 		isc_region_consume(&r, 1);
5fe83d
@@ -1491,16 +1500,18 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
5fe83d
 	}
5fe83d
 
5fe83d
 	if (r.length < e_bytes) {
5fe83d
-		isc_safe_memwipe(rsa, sizeof(*rsa));
5fe83d
-		isc_mem_put(key->mctx, rsa, sizeof(*rsa));
5fe83d
-		return (DST_R_INVALIDPUBLICKEY);
5fe83d
+		DST_RET(DST_R_INVALIDPUBLICKEY);
5fe83d
 	}
5fe83d
 	exponent = r.base;
5fe83d
 	isc_region_consume(&r, e_bytes);
5fe83d
 	modulus = r.base;
5fe83d
 	mod_bytes = r.length;
5fe83d
 
5fe83d
-	key->key_size = pk11_numbits(modulus, mod_bytes);
5fe83d
+	ret = pk11_numbits(modulus, mod_bytes, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	isc_buffer_forward(data, length);
5fe83d
 
5fe83d
@@ -1550,9 +1561,12 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
5fe83d
 			    rsa->repr,
5fe83d
 			    rsa->attrcnt * sizeof(*attr));
5fe83d
 	}
5fe83d
+	ret = ISC_R_NOMEMORY;
5fe83d
+
5fe83d
+    err:
5fe83d
 	isc_safe_memwipe(rsa, sizeof(*rsa));
5fe83d
 	isc_mem_put(key->mctx, rsa, sizeof(*rsa));
5fe83d
-	return (ISC_R_NOMEMORY);
5fe83d
+	return (ret);
5fe83d
 }
5fe83d
 
5fe83d
 static isc_result_t
5fe83d
@@ -1731,6 +1745,7 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
5fe83d
 	pk11_object_t *pubrsa;
5fe83d
 	pk11_context_t *pk11_ctx = NULL;
5fe83d
 	isc_result_t ret;
5fe83d
+	unsigned int bits;
5fe83d
 
5fe83d
 	if (label == NULL)
5fe83d
 		return (DST_R_NOENGINE);
5fe83d
@@ -1815,7 +1830,11 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	return (ISC_R_SUCCESS);
5fe83d
 
5fe83d
@@ -1901,6 +1920,7 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
5fe83d
 	CK_ATTRIBUTE *attr;
5fe83d
 	isc_mem_t *mctx = key->mctx;
5fe83d
 	const char *engine = NULL, *label = NULL;
5fe83d
+	unsigned int bits;
5fe83d
 
5fe83d
 	/* read private key file */
5fe83d
 	ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv;;
5fe83d
@@ -2044,12 +2064,22 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
5fe83d
+
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	if (bits > RSA_MAX_PUBEXP_BITS) {
5fe83d
 		DST_RET(ISC_R_RANGE);
5fe83d
+	}
5fe83d
 
5fe83d
 	dst__privstruct_free(&priv, mctx);
5fe83d
 	isc_safe_memwipe(&priv, sizeof(priv));
5fe83d
@@ -2084,6 +2114,7 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
5fe83d
 	pk11_context_t *pk11_ctx = NULL;
5fe83d
 	isc_result_t ret;
5fe83d
 	unsigned int i;
5fe83d
+	unsigned int bits;
5fe83d
 
5fe83d
 	UNUSED(pin);
5fe83d
 
5fe83d
@@ -2178,12 +2209,22 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
5fe83d
+
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	if (bits > RSA_MAX_PUBEXP_BITS) {
5fe83d
 		DST_RET(ISC_R_RANGE);
5fe83d
+	}
5fe83d
 
5fe83d
 	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
5fe83d
 	INSIST(attr != NULL);
5fe83d
-	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
5fe83d
+	ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
5fe83d
+	if (ret != ISC_R_SUCCESS) {
5fe83d
+		goto err;
5fe83d
+	}
5fe83d
+	key->key_size = bits;
5fe83d
 
5fe83d
 	pk11_return_session(pk11_ctx);
5fe83d
 	isc_safe_memwipe(pk11_ctx, sizeof(*pk11_ctx));
5fe83d
diff --git a/lib/isc/include/pk11/internal.h b/lib/isc/include/pk11/internal.h
5fe83d
index 603712a..b9680bc 100644
5fe83d
--- a/lib/isc/include/pk11/internal.h
5fe83d
+++ b/lib/isc/include/pk11/internal.h
5fe83d
@@ -27,7 +27,8 @@ void pk11_mem_put(void *ptr, size_t size);
5fe83d
 
5fe83d
 CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype);
5fe83d
 
5fe83d
-unsigned int pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt);
5fe83d
+isc_result_t
5fe83d
+pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits);
5fe83d
 
5fe83d
 CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj);
5fe83d
 
5fe83d
diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
5fe83d
index 48e1031..792b2e3 100644
5fe83d
--- a/lib/isc/pk11.c
5fe83d
+++ b/lib/isc/pk11.c
5fe83d
@@ -985,13 +985,15 @@ pk11_get_best_token(pk11_optype_t optype) {
5fe83d
 	return (token->slotid);
5fe83d
 }
5fe83d
 
5fe83d
-unsigned int
5fe83d
-pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
5fe83d
+isc_result_t
5fe83d
+pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits) {
5fe83d
 	unsigned int bitcnt, i;
5fe83d
 	CK_BYTE top;
5fe83d
 
5fe83d
-	if (bytecnt == 0)
5fe83d
-		return (0);
5fe83d
+	if (bytecnt == 0) {
5fe83d
+		*bits = 0;
5fe83d
+		return (ISC_R_SUCCESS);
5fe83d
+	}
5fe83d
 	bitcnt = bytecnt * 8;
5fe83d
 	for (i = 0; i < bytecnt; i++) {
5fe83d
 		top = data[i];
5fe83d
@@ -999,25 +1001,41 @@ pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
5fe83d
 			bitcnt -= 8;
5fe83d
 			continue;
5fe83d
 		}
5fe83d
-		if (top & 0x80)
5fe83d
-			return (bitcnt);
5fe83d
-		if (top & 0x40)
5fe83d
-			return (bitcnt - 1);
5fe83d
-		if (top & 0x20)
5fe83d
-			return (bitcnt - 2);
5fe83d
-		if (top & 0x10)
5fe83d
-			return (bitcnt - 3);
5fe83d
-		if (top & 0x08)
5fe83d
-			return (bitcnt - 4);
5fe83d
-		if (top & 0x04)
5fe83d
-			return (bitcnt - 5);
5fe83d
-		if (top & 0x02)
5fe83d
-			return (bitcnt - 6);
5fe83d
-		if (top & 0x01)
5fe83d
-			return (bitcnt - 7);
5fe83d
+		if (top & 0x80) {
5fe83d
+			*bits = bitcnt;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x40) {
5fe83d
+			*bits = bitcnt - 1;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x20) {
5fe83d
+			*bits = bitcnt - 2;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x10) {
5fe83d
+			*bits = bitcnt - 3;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x08) {
5fe83d
+			*bits = bitcnt - 4;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x04) {
5fe83d
+			*bits = bitcnt - 5;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x02) {
5fe83d
+			*bits = bitcnt - 6;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
+		if (top & 0x01) {
5fe83d
+			*bits = bitcnt - 7;
5fe83d
+			return (ISC_R_SUCCESS);
5fe83d
+		}
5fe83d
 		break;
5fe83d
 	}
5fe83d
-	INSIST(0);
5fe83d
+	return (ISC_R_RANGE);
5fe83d
 }
5fe83d
 
5fe83d
 CK_ATTRIBUTE *
5fe83d
-- 
5fe83d
2.26.2
5fe83d