mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Reject RSA DNSKEYs with degenerate modulus at parse time
The wire-format RSA DNSKEY parser used the residual rdata length after the exponent as the modulus length, with no positive lower bound. A crafted DNSKEY whose declared exponent length consumed the whole buffer produced n = 0; the BN_bin2bn(_, 0, _) returned a non-NULL BIGNUM, the NULL-check passed, and dnssec-importkey -f wrote out a "valid" key with no key material. RSASHA1 also bypassed the algorithm-specific lower bound in opensslrsa_createctx (which only checks an upper bound for the SHA1 algorithms), so the degenerate key reached the verify path with whatever behaviour the linked OpenSSL exhibits for n = 0. Add OPENSSLRSA_MIN_MODULUS_BITS = 512 (the lowest legitimate modulus across the RSA DNSSEC algorithms per RFC 5702) and reject smaller moduli at parse time in opensslrsa_fromdns, opensslrsa_parse, and opensslrsa_fromlabel — the same three load paths where the existing exponent upper-bound check lives. Assisted-by: Claude:claude-opus-4-7
This commit is contained in:
parent
62ced63e22
commit
045d5d0455
2 changed files with 49 additions and 0 deletions
|
|
@ -34,6 +34,7 @@
|
|||
#include "openssl_shim.h"
|
||||
|
||||
#define OPENSSLRSA_MAX_MODULUS_BITS 4096
|
||||
#define OPENSSLRSA_MIN_MODULUS_BITS 512
|
||||
|
||||
/* length byte + 1.2.840.113549.1.1.11 BER encoded RFC 4055 */
|
||||
static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
||||
|
|
@ -465,6 +466,9 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
|
|||
if (BN_num_bits(c.e) > RSA_MAX_PUBEXP_BITS) {
|
||||
CLEANUP(ISC_R_RANGE);
|
||||
}
|
||||
if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS) {
|
||||
CLEANUP(ISC_R_RANGE);
|
||||
}
|
||||
isc_buffer_forward(data, length);
|
||||
|
||||
key->key_size = BN_num_bits(c.n);
|
||||
|
|
@ -699,6 +703,9 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
|
|||
if (c.n == NULL || c.e == NULL) {
|
||||
CLEANUP(DST_R_INVALIDPRIVATEKEY);
|
||||
}
|
||||
if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS) {
|
||||
CLEANUP(ISC_R_RANGE);
|
||||
}
|
||||
if (BN_num_bits(c.e) > RSA_MAX_PUBEXP_BITS) {
|
||||
CLEANUP(ISC_R_RANGE);
|
||||
}
|
||||
|
|
@ -740,6 +747,9 @@ opensslrsa_fromlabel(dst_key_t *key, const char *label, const char *pin) {
|
|||
if (!isc_ossl_wrap_rsa_key_bits_leq(pubpkey, RSA_MAX_PUBEXP_BITS)) {
|
||||
CLEANUP(ISC_R_RANGE);
|
||||
}
|
||||
if (EVP_PKEY_bits(pubpkey) < OPENSSLRSA_MIN_MODULUS_BITS) {
|
||||
CLEANUP(ISC_R_RANGE);
|
||||
}
|
||||
|
||||
key->label = isc_mem_strdup(key->mctx, label);
|
||||
key->key_size = EVP_PKEY_bits(privpkey);
|
||||
|
|
|
|||
|
|
@ -250,9 +250,48 @@ ISC_RUN_TEST_IMPL(isc_rsa_fromdns_oversized_exponent) {
|
|||
assert_null(key);
|
||||
}
|
||||
|
||||
/* dst_key_fromdns rejects RSA DNSKEYs with a degenerate modulus */
|
||||
ISC_RUN_TEST_IMPL(isc_rsa_fromdns_short_modulus) {
|
||||
isc_result_t result;
|
||||
dns_fixedname_t fname;
|
||||
dns_name_t *name;
|
||||
dst_key_t *key = NULL;
|
||||
isc_buffer_t buf;
|
||||
unsigned char rdata[8];
|
||||
size_t i = 0;
|
||||
|
||||
UNUSED(state);
|
||||
|
||||
name = dns_fixedname_initname(&fname);
|
||||
isc_buffer_constinit(&buf, "rsa.", 4);
|
||||
isc_buffer_add(&buf, 4);
|
||||
result = dns_name_fromtext(name, &buf, NULL, 0);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* DNSKEY rdata: flags(2) + proto(1) + alg(1) + RSA wire pubkey
|
||||
* 'AQM=' (0x01 0x03): e_bytes=1, exponent=0x03, modulus tail empty.
|
||||
*/
|
||||
rdata[i++] = 0x01;
|
||||
rdata[i++] = 0x00;
|
||||
rdata[i++] = 0x03;
|
||||
rdata[i++] = DST_ALG_RSASHA256;
|
||||
rdata[i++] = 0x01;
|
||||
rdata[i++] = 0x03;
|
||||
|
||||
isc_buffer_init(&buf, rdata, i);
|
||||
isc_buffer_add(&buf, i);
|
||||
|
||||
result = dst_key_fromdns(name, dns_rdataclass_in, &buf, isc_g_mctx,
|
||||
&key);
|
||||
assert_int_equal(result, ISC_R_RANGE);
|
||||
assert_null(key);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY(isc_rsa_verify)
|
||||
ISC_TEST_ENTRY(isc_rsa_fromdns_oversized_exponent)
|
||||
ISC_TEST_ENTRY(isc_rsa_fromdns_short_modulus)
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
ISC_TEST_MAIN
|
||||
|
|
|
|||
Loading…
Reference in a new issue