Commit 0660b022 authored by Michał Kępień's avatar Michał Kępień
Browse files

Merge branch '2037-confidential-issue-v9_11' into 'security-v9_11'

[CVE-2020-8623]: Fix crash in pk11_numbits() with crafted packet when native-pkcs11 is used (v9.11)

See merge request isc-private/bind9!200
parents ae9af802 efe31ac2
5480. [security] When BIND 9 was compiled with native PKCS#11 support, it
was possible to trigger an assertion failure in code
determining the number of bits in the PKCS#11 RSA public
key with a specially crafted packet. (CVE-2020-8623)
[GL #2037]
5476. [security] It was possible to trigger an assertion failure when 5476. [security] It was possible to trigger an assertion failure when
verifying the response to a TSIG-signed request. verifying the response to a TSIG-signed request.
(CVE-2020-8622) [GL #2028] (CVE-2020-8622) [GL #2028]
......
...@@ -24,6 +24,18 @@ ...@@ -24,6 +24,18 @@
of Oracle for bringing this vulnerability to our attention. [GL #2028] of Oracle for bringing this vulnerability to our attention. [GL #2028]
</para> </para>
</listitem> </listitem>
<listitem>
<para>
When BIND 9 was compiled with native PKCS#11 support, it was possible
to trigger an assertion failure in code determining the number of bits
in the PKCS#11 RSA public key with a specially crafted packet. This
was disclosed in CVE-2020-8623.
</para>
<para>
ISC would like to thank Lyu Chiy for bringing this vulnerability to
our attention. [GL #2037]
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
......
...@@ -748,6 +748,7 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) { ...@@ -748,6 +748,7 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) {
CK_BYTE *prime = NULL, *base = NULL, *pub = NULL; CK_BYTE *prime = NULL, *base = NULL, *pub = NULL;
CK_ATTRIBUTE *attr; CK_ATTRIBUTE *attr;
int special = 0; int special = 0;
unsigned int bits;
isc_result_t result; isc_result_t result;
isc_buffer_remainingregion(data, &r); isc_buffer_remainingregion(data, &r);
...@@ -852,7 +853,11 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) { ...@@ -852,7 +853,11 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) {
pub = r.base; pub = r.base;
isc_region_consume(&r, publen); isc_region_consume(&r, publen);
key->key_size = pk11_numbits(prime, plen_); result = pk11_numbits(prime, plen_, &bits);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
key->key_size = bits;
dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3); dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
if (dh->repr == NULL) if (dh->repr == NULL)
...@@ -1012,6 +1017,7 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ...@@ -1012,6 +1017,7 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
dst_private_t priv; dst_private_t priv;
isc_result_t ret; isc_result_t ret;
int i; int i;
unsigned int bits;
pk11_object_t *dh = NULL; pk11_object_t *dh = NULL;
CK_ATTRIBUTE *attr; CK_ATTRIBUTE *attr;
isc_mem_t *mctx; isc_mem_t *mctx;
...@@ -1082,7 +1088,12 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ...@@ -1082,7 +1088,12 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
attr = pk11_attribute_bytype(dh, CKA_PRIME); attr = pk11_attribute_bytype(dh, CKA_PRIME);
INSIST(attr != NULL); INSIST(attr != NULL);
key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
key->key_size = bits;
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
......
...@@ -983,6 +983,7 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ...@@ -983,6 +983,7 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
dst_private_t priv; dst_private_t priv;
isc_result_t ret; isc_result_t ret;
int i; int i;
unsigned int bits;
pk11_object_t *dsa = NULL; pk11_object_t *dsa = NULL;
CK_ATTRIBUTE *attr; CK_ATTRIBUTE *attr;
isc_mem_t *mctx = key->mctx; isc_mem_t *mctx = key->mctx;
...@@ -1072,7 +1073,12 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ...@@ -1072,7 +1073,12 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
attr = pk11_attribute_bytype(dsa, CKA_PRIME); attr = pk11_attribute_bytype(dsa, CKA_PRIME);
INSIST(attr != NULL); INSIST(attr != NULL);
key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
key->key_size = bits;
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
......
...@@ -332,6 +332,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, ...@@ -332,6 +332,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
key->key_alg == DST_ALG_RSASHA256 || key->key_alg == DST_ALG_RSASHA256 ||
key->key_alg == DST_ALG_RSASHA512); key->key_alg == DST_ALG_RSASHA512);
#endif #endif
REQUIRE(maxbits <= RSA_MAX_PUBEXP_BITS);
/* /*
* Reject incorrect RSA key lengths. * Reject incorrect RSA key lengths.
...@@ -376,6 +377,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, ...@@ -376,6 +377,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
for (attr = pk11_attribute_first(rsa); for (attr = pk11_attribute_first(rsa);
attr != NULL; attr != NULL;
attr = pk11_attribute_next(rsa, attr)) attr = pk11_attribute_next(rsa, attr))
{
switch (attr->type) { switch (attr->type) {
case CKA_MODULUS: case CKA_MODULUS:
INSIST(keyTemplate[5].type == attr->type); INSIST(keyTemplate[5].type == attr->type);
...@@ -396,12 +398,16 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, ...@@ -396,12 +398,16 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
memmove(keyTemplate[6].pValue, attr->pValue, memmove(keyTemplate[6].pValue, attr->pValue,
attr->ulValueLen); attr->ulValueLen);
keyTemplate[6].ulValueLen = attr->ulValueLen; keyTemplate[6].ulValueLen = attr->ulValueLen;
if (pk11_numbits(attr->pValue, unsigned int bits;
attr->ulValueLen) > maxbits && ret = pk11_numbits(attr->pValue, attr->ulValueLen,
maxbits != 0) &bits);
if (ret != ISC_R_SUCCESS ||
(bits > maxbits && maxbits != 0)) {
DST_RET(DST_R_VERIFYFAILURE); DST_RET(DST_R_VERIFYFAILURE);
}
break; break;
} }
}
pk11_ctx->object = CK_INVALID_HANDLE; pk11_ctx->object = CK_INVALID_HANDLE;
pk11_ctx->ontoken = false; pk11_ctx->ontoken = false;
PK11_RET(pkcs_C_CreateObject, PK11_RET(pkcs_C_CreateObject,
...@@ -1072,6 +1078,7 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { ...@@ -1072,6 +1078,7 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
keyTemplate[5].ulValueLen = attr->ulValueLen; keyTemplate[5].ulValueLen = attr->ulValueLen;
break; break;
case CKA_PUBLIC_EXPONENT: case CKA_PUBLIC_EXPONENT:
unsigned int bits;
INSIST(keyTemplate[6].type == attr->type); INSIST(keyTemplate[6].type == attr->type);
keyTemplate[6].pValue = isc_mem_get(dctx->mctx, keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
attr->ulValueLen); attr->ulValueLen);
...@@ -1080,10 +1087,12 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { ...@@ -1080,10 +1087,12 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
memmove(keyTemplate[6].pValue, attr->pValue, memmove(keyTemplate[6].pValue, attr->pValue,
attr->ulValueLen); attr->ulValueLen);
keyTemplate[6].ulValueLen = attr->ulValueLen; keyTemplate[6].ulValueLen = attr->ulValueLen;
if (pk11_numbits(attr->pValue, ret = pk11_numbits(attr->pValue, attr->ulValueLen,
attr->ulValueLen) &bits);
> RSA_MAX_PUBEXP_BITS) if (ret != ISC_R_SUCCESS || bits > RSA_MAX_PUBEXP_BITS)
{
DST_RET(DST_R_VERIFYFAILURE); DST_RET(DST_R_VERIFYFAILURE);
}
break; break;
} }
pk11_ctx->object = CK_INVALID_HANDLE; pk11_ctx->object = CK_INVALID_HANDLE;
...@@ -1461,6 +1470,8 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ...@@ -1461,6 +1470,8 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
CK_BYTE *exponent = NULL, *modulus = NULL; CK_BYTE *exponent = NULL, *modulus = NULL;
CK_ATTRIBUTE *attr; CK_ATTRIBUTE *attr;
unsigned int length; unsigned int length;
unsigned int bits;
isc_result_t ret = ISC_R_SUCCESS;
isc_buffer_remainingregion(data, &r); isc_buffer_remainingregion(data, &r);
if (r.length == 0) if (r.length == 0)
...@@ -1478,9 +1489,7 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ...@@ -1478,9 +1489,7 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
if (e_bytes == 0) { if (e_bytes == 0) {
if (r.length < 2) { if (r.length < 2) {
isc_safe_memwipe(rsa, sizeof(*rsa)); DST_RET(DST_R_INVALIDPUBLICKEY);
isc_mem_put(key->mctx, rsa, sizeof(*rsa));
return (DST_R_INVALIDPUBLICKEY);
} }
e_bytes = (*r.base) << 8; e_bytes = (*r.base) << 8;
isc_region_consume(&r, 1); isc_region_consume(&r, 1);
...@@ -1489,16 +1498,18 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ...@@ -1489,16 +1498,18 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
} }
if (r.length < e_bytes) { if (r.length < e_bytes) {
isc_safe_memwipe(rsa, sizeof(*rsa)); DST_RET(DST_R_INVALIDPUBLICKEY);
isc_mem_put(key->mctx, rsa, sizeof(*rsa));
return (DST_R_INVALIDPUBLICKEY);
} }
exponent = r.base; exponent = r.base;
isc_region_consume(&r, e_bytes); isc_region_consume(&r, e_bytes);
modulus = r.base; modulus = r.base;
mod_bytes = r.length; mod_bytes = r.length;
key->key_size = pk11_numbits(modulus, mod_bytes); ret = pk11_numbits(modulus, mod_bytes, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
key->key_size = bits;
isc_buffer_forward(data, length); isc_buffer_forward(data, length);
...@@ -1548,9 +1559,12 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ...@@ -1548,9 +1559,12 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
rsa->repr, rsa->repr,
rsa->attrcnt * sizeof(*attr)); rsa->attrcnt * sizeof(*attr));
} }
ret = ISC_R_NOMEMORY;
err:
isc_safe_memwipe(rsa, sizeof(*rsa)); isc_safe_memwipe(rsa, sizeof(*rsa));
isc_mem_put(key->mctx, rsa, sizeof(*rsa)); isc_mem_put(key->mctx, rsa, sizeof(*rsa));
return (ISC_R_NOMEMORY); return (ret);
} }
static isc_result_t static isc_result_t
...@@ -1729,6 +1743,7 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label, ...@@ -1729,6 +1743,7 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
pk11_object_t *pubrsa; pk11_object_t *pubrsa;
pk11_context_t *pk11_ctx = NULL; pk11_context_t *pk11_ctx = NULL;
isc_result_t ret; isc_result_t ret;
unsigned int bits;
if (label == NULL) if (label == NULL)
return (DST_R_NOENGINE); return (DST_R_NOENGINE);
...@@ -1815,7 +1830,11 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label, ...@@ -1815,7 +1830,11 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
attr = pk11_attribute_bytype(rsa, CKA_MODULUS); attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
INSIST(attr != NULL); INSIST(attr != NULL);
key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
key->key_size = bits;
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
...@@ -1901,6 +1920,7 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ...@@ -1901,6 +1920,7 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
CK_ATTRIBUTE *attr; CK_ATTRIBUTE *attr;
isc_mem_t *mctx = key->mctx; isc_mem_t *mctx = key->mctx;
const char *engine = NULL, *label = NULL; const char *engine = NULL, *label = NULL;
unsigned int bits;
/* read private key file */ /* read private key file */
ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv);
...@@ -2044,12 +2064,22 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ...@@ -2044,12 +2064,22 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
attr = pk11_attribute_bytype(rsa, CKA_MODULUS); attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
INSIST(attr != NULL); INSIST(attr != NULL);
key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
key->key_size = bits;
attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
INSIST(attr != NULL); INSIST(attr != NULL);
if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
if (bits > RSA_MAX_PUBEXP_BITS) {
DST_RET(ISC_R_RANGE); DST_RET(ISC_R_RANGE);
}
dst__privstruct_free(&priv, mctx); dst__privstruct_free(&priv, mctx);
isc_safe_memwipe(&priv, sizeof(priv)); isc_safe_memwipe(&priv, sizeof(priv));
...@@ -2084,6 +2114,7 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ...@@ -2084,6 +2114,7 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
pk11_context_t *pk11_ctx = NULL; pk11_context_t *pk11_ctx = NULL;
isc_result_t ret; isc_result_t ret;
unsigned int i; unsigned int i;
unsigned int bits;
UNUSED(pin); UNUSED(pin);
...@@ -2178,12 +2209,22 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ...@@ -2178,12 +2209,22 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
INSIST(attr != NULL); INSIST(attr != NULL);
if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
if (bits > RSA_MAX_PUBEXP_BITS) {
DST_RET(ISC_R_RANGE); DST_RET(ISC_R_RANGE);
}
attr = pk11_attribute_bytype(rsa, CKA_MODULUS); attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
INSIST(attr != NULL); INSIST(attr != NULL);
key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits);
if (ret != ISC_R_SUCCESS) {
goto err;
}
key->key_size = bits;
pk11_return_session(pk11_ctx); pk11_return_session(pk11_ctx);
isc_safe_memwipe(pk11_ctx, sizeof(*pk11_ctx)); isc_safe_memwipe(pk11_ctx, sizeof(*pk11_ctx));
......
...@@ -25,7 +25,8 @@ void pk11_mem_put(void *ptr, size_t size); ...@@ -25,7 +25,8 @@ void pk11_mem_put(void *ptr, size_t size);
CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype); CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype);
unsigned int pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt); isc_result_t
pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits);
CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj); CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj);
......
...@@ -962,13 +962,15 @@ pk11_get_best_token(pk11_optype_t optype) { ...@@ -962,13 +962,15 @@ pk11_get_best_token(pk11_optype_t optype) {
return (token->slotid); return (token->slotid);
} }
unsigned int isc_result_t
pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) { pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits) {
unsigned int bitcnt, i; unsigned int bitcnt, i;
CK_BYTE top; CK_BYTE top;
if (bytecnt == 0) if (bytecnt == 0) {
return (0); *bits = 0;
return (ISC_R_SUCCESS);
}
bitcnt = bytecnt * 8; bitcnt = bytecnt * 8;
for (i = 0; i < bytecnt; i++) { for (i = 0; i < bytecnt; i++) {
top = data[i]; top = data[i];
...@@ -976,26 +978,41 @@ pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) { ...@@ -976,26 +978,41 @@ pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
bitcnt -= 8; bitcnt -= 8;
continue; continue;
} }
if (top & 0x80) if (top & 0x80) {
return (bitcnt); *bits = bitcnt;
if (top & 0x40) return (ISC_R_SUCCESS);
return (bitcnt - 1); }
if (top & 0x20) if (top & 0x40) {
return (bitcnt - 2); *bits = bitcnt - 1;
if (top & 0x10) return (ISC_R_SUCCESS);
return (bitcnt - 3); }
if (top & 0x08) if (top & 0x20) {
return (bitcnt - 4); *bits = bitcnt - 2;
if (top & 0x04) return (ISC_R_SUCCESS);
return (bitcnt - 5); }
if (top & 0x02) if (top & 0x10) {
return (bitcnt - 6); *bits = bitcnt - 3;
if (top & 0x01) return (ISC_R_SUCCESS);
return (bitcnt - 7); }
if (top & 0x08) {
*bits = bitcnt - 4;
return (ISC_R_SUCCESS);
}
if (top & 0x04) {
*bits = bitcnt - 5;
return (ISC_R_SUCCESS);
}
if (top & 0x02) {
*bits = bitcnt - 6;
return (ISC_R_SUCCESS);
}
if (top & 0x01) {
*bits = bitcnt - 7;
return (ISC_R_SUCCESS);
}
break; break;
} }
INSIST(0); return (ISC_R_RANGE);
ISC_UNREACHABLE();
} }
CK_ATTRIBUTE * CK_ATTRIBUTE *
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment