void
dst__lib_shutdown(void) {
+ dst__opensslrsa_shutdown();
+
isc_mem_detach(&dst__mctx);
}
void
dst__opensslrsa_init(struct dst_func **funcp, unsigned short algorithm);
void
+dst__opensslrsa_shutdown(void);
+void
dst__opensslecdsa_init(struct dst_func **funcp);
void
dst__openssleddsa_init(struct dst_func **funcp, unsigned char algorithm);
#include <openssl/opensslv.h>
#include <openssl/rsa.h>
-/*
- * Limit the size of public exponents.
- */
-#ifndef RSA_MAX_PUBEXP_BITS
-#define RSA_MAX_PUBEXP_BITS 35
-#endif /* ifndef RSA_MAX_PUBEXP_BITS */
-
#if !HAVE_EVP_PKEY_EQ
#define EVP_PKEY_eq EVP_PKEY_cmp
#endif
#define OPENSSLRSA_MAX_MODULUS_BITS 4096
#define OPENSSLRSA_MIN_MODULUS_BITS 512
+static BIGNUM *rsa_exponent_min = NULL;
+static BIGNUM *rsa_exponent_max = NULL;
+
+/*
+ * Accept odd public exponents in [3, 2^32 + 1]. That covers every Fermat
+ * prime up to F5 and the odd intermediate values seen on the wire.
+ */
+static bool
+rsa_exponent_in_range(const BIGNUM *e) {
+ if (!BN_is_odd(e)) {
+ return false;
+ }
+
+ if (BN_cmp(e, rsa_exponent_min) < 0) {
+ return false;
+ }
+
+ if (BN_cmp(e, rsa_exponent_max) > 0) {
+ return false;
+ }
+
+ return true;
+}
+
/* length byte + 1.2.840.113549.1.1.11 BER encoded RFC 4055 */
static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b };
evp_md_ctx = dctx->ctxdata.evp_md_ctx;
pkey = key->keydata.pkeypair.pub;
- if (!isc_ossl_wrap_rsa_key_bits_leq(pkey, OPENSSLRSA_MAX_MODULUS_BITS))
+ if (!isc_ossl_wrap_rsa_modulus_bits_in_range(
+ pkey, OPENSSLRSA_MIN_MODULUS_BITS,
+ OPENSSLRSA_MAX_MODULUS_BITS) ||
+ !isc_ossl_wrap_rsa_exponent_is_allowed(pkey))
{
return DST_R_VERIFYFAILURE;
}
if (c.e == NULL || c.n == NULL) {
CLEANUP(ISC_R_NOMEMORY);
}
- if (BN_num_bits(c.e) > RSA_MAX_PUBEXP_BITS) {
+ if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS ||
+ BN_num_bits(c.n) > OPENSSLRSA_MAX_MODULUS_BITS)
+ {
CLEANUP(ISC_R_RANGE);
}
- if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS) {
+ if (!rsa_exponent_in_range(c.e)) {
CLEANUP(ISC_R_RANGE);
}
isc_buffer_forward(data, length);
if (c.n == NULL || c.e == NULL) {
CLEANUP(DST_R_INVALIDPRIVATEKEY);
}
- if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS) {
+ if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS ||
+ BN_num_bits(c.n) > OPENSSLRSA_MAX_MODULUS_BITS)
+ {
CLEANUP(ISC_R_RANGE);
}
- if (BN_num_bits(c.e) > RSA_MAX_PUBEXP_BITS) {
+ if (!rsa_exponent_in_range(c.e)) {
CLEANUP(ISC_R_RANGE);
}
CHECK(dst__openssl_fromlabel(EVP_PKEY_RSA, label, pin, &pubpkey,
&privpkey));
- if (!isc_ossl_wrap_rsa_key_bits_leq(pubpkey, RSA_MAX_PUBEXP_BITS)) {
+ if (!isc_ossl_wrap_rsa_exponent_is_allowed(pubpkey)) {
CLEANUP(ISC_R_RANGE);
}
- if (EVP_PKEY_bits(pubpkey) < OPENSSLRSA_MIN_MODULUS_BITS) {
+ if (!isc_ossl_wrap_rsa_modulus_bits_in_range(
+ pubpkey, OPENSSLRSA_MIN_MODULUS_BITS,
+ OPENSSLRSA_MAX_MODULUS_BITS))
+ {
CLEANUP(ISC_R_RANGE);
}
*funcp = &opensslrsa_functions;
}
}
+
+ if (rsa_exponent_min == NULL) {
+ rsa_exponent_min = BN_new();
+ INSIST(rsa_exponent_min != NULL);
+
+ RUNTIME_CHECK(BN_set_word(rsa_exponent_min, 3) == 1);
+ }
+
+ if (rsa_exponent_max == NULL) {
+ rsa_exponent_max = BN_new();
+ INSIST(rsa_exponent_max != NULL);
+
+ RUNTIME_CHECK(BN_set_bit(rsa_exponent_max, 0) == 1);
+ RUNTIME_CHECK(BN_set_bit(rsa_exponent_max, 32) == 1);
+ }
+}
+
+void
+dst__opensslrsa_shutdown(void) {
+ REQUIRE(rsa_exponent_min != NULL);
+ REQUIRE(rsa_exponent_max != NULL);
+
+ BN_free(rsa_exponent_min);
+ BN_free(rsa_exponent_max);
}
*/
bool
-isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit);
+isc_ossl_wrap_rsa_exponent_is_allowed(EVP_PKEY *pkey);
+/*%
+ * Returns true if the RSA public exponent of `pkey` is odd and lies
+ * within the closed range [3, 2^32 + 1]. This covers every Fermat
+ * prime up to F5 plus all odd intermediate values seen in deployed
+ * DNSSEC keys. Returns false if the exponent cannot be retrieved or
+ * falls outside that range.
+ */
+
+bool
+isc_ossl_wrap_rsa_modulus_bits_in_range(EVP_PKEY *pkey, size_t min, size_t max);
+/*%
+ * Returns true if the RSA modulus bit length of `pkey` is between `min`
+ * and `max` inclusive. Returns false if the modulus bit length cannot
+ * be determined.
+ */
isc_result_t
isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey,
}
bool
-isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) {
+isc_ossl_wrap_rsa_exponent_is_allowed(EVP_PKEY *pkey) {
const RSA *rsa;
const BIGNUM *ce;
+ BIGNUM *emin = NULL;
+ BIGNUM *emax = NULL;
+ bool ok = false;
REQUIRE(pkey != NULL);
rsa = EVP_PKEY_get0_RSA(pkey);
- if (rsa != NULL) {
- ce = NULL;
- RSA_get0_key(rsa, NULL, &ce, NULL);
- if (ce != NULL) {
- int bits = BN_num_bits(ce);
+ if (rsa == NULL) {
+ return false;
+ }
+ ce = NULL;
+ RSA_get0_key(rsa, NULL, &ce, NULL);
+ if (ce == NULL) {
+ return false;
+ }
- return bits > 0 && (size_t)bits <= limit;
- }
+ emin = BN_new();
+ if (emin == NULL || !BN_set_word(emin, 3)) {
+ goto cleanup;
+ }
+ if (BN_hex2bn(&emax, "100000001") == 0) {
+ goto cleanup;
}
- return false;
+ ok = BN_is_odd(ce) && BN_cmp(ce, emin) >= 0 && BN_cmp(ce, emax) <= 0;
+
+cleanup:
+ BN_free(emin);
+ BN_free(emax);
+ return ok;
+}
+
+bool
+isc_ossl_wrap_rsa_modulus_bits_in_range(EVP_PKEY *pkey, size_t min,
+ size_t max) {
+ REQUIRE(pkey != NULL);
+
+ int bits = EVP_PKEY_bits(pkey);
+ return bits > 0 && (size_t)bits >= min && (size_t)bits <= max;
}
isc_result_t
}
bool
-isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) {
+isc_ossl_wrap_rsa_exponent_is_allowed(EVP_PKEY *pkey) {
BIGNUM *e = NULL;
- if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 1) {
- int bits = BN_num_bits(e);
- BN_free(e);
+ BIGNUM *emin = NULL;
+ BIGNUM *emax = NULL;
+ bool ok = false;
- return bits > 0 && (size_t)bits <= limit;
+ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) != 1) {
+ goto cleanup;
}
- return false;
+
+ emin = BN_new();
+ if (emin == NULL || !BN_set_word(emin, 3)) {
+ goto cleanup;
+ }
+ if (BN_hex2bn(&emax, "100000001") == 0) {
+ goto cleanup;
+ }
+
+ ok = BN_is_odd(e) && BN_cmp(e, emin) >= 0 && BN_cmp(e, emax) <= 0;
+
+cleanup:
+ BN_free(e);
+ BN_free(emin);
+ BN_free(emax);
+ return ok;
+}
+
+bool
+isc_ossl_wrap_rsa_modulus_bits_in_range(EVP_PKEY *pkey, size_t min,
+ size_t max) {
+ REQUIRE(pkey != NULL);
+
+ int bits = EVP_PKEY_bits(pkey);
+ return bits > 0 && (size_t)bits >= min && (size_t)bits <= max;
}
isc_result_t
rdata[i++] = 0x03; /* protocol */
rdata[i++] = DST_ALG_RSASHA256;
/* RSA wire key: e_bytes + e + n. Use a 6-byte (48-bit) e
- * with a non-zero leading byte so it exceeds the 35-bit cap. */
+ * with a non-zero leading byte; outside the allowlist. */
rdata[i++] = 6;
rdata[i++] = 0x01;
rdata[i++] = 0x02;
assert_null(key);
}
+/*
+ * dst_key_fromdns rejects RSA DNSKEYs whose public exponent is in the
+ * accepted numeric range but even (and therefore not a valid RSA exponent).
+ */
+ISC_RUN_TEST_IMPL(isc_rsa_fromdns_even_exponent) {
+ isc_result_t result;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ dst_key_t *key = NULL;
+ isc_buffer_t buf;
+ unsigned char rdata[300] = { 0 };
+ 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. */
+ rdata[i++] = 0x01; /* flags hi (KSK) */
+ rdata[i++] = 0x00; /* flags lo */
+ rdata[i++] = 0x03; /* protocol */
+ rdata[i++] = DST_ALG_RSASHA256;
+ /* e_bytes=1, exponent=0x04 (even, mathematically invalid). */
+ rdata[i++] = 1;
+ rdata[i++] = 0x04;
+ /* 256 bytes of arbitrary modulus (2048-bit). */
+ for (size_t j = 0; j < 256; j++) {
+ rdata[i++] = 0xAB;
+ }
+
+ 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);
+}
+
+/* dst_key_fromdns rejects RSA DNSKEYs whose modulus exceeds the cap */
+ISC_RUN_TEST_IMPL(isc_rsa_fromdns_oversized_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[1100] = { 0 };
+ 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. */
+ rdata[i++] = 0x01; /* flags hi (KSK) */
+ rdata[i++] = 0x00; /* flags lo */
+ rdata[i++] = 0x03; /* protocol */
+ rdata[i++] = DST_ALG_RSASHA256;
+ /*
+ * RSA wire key: e_bytes + e + n. 1-byte exponent (0x03) and a
+ * 1024-byte modulus (8192 bits, leading byte 0xAB so the high bit
+ * is set) — twice the 4096-bit maximum.
+ */
+ rdata[i++] = 1;
+ rdata[i++] = 0x03;
+ for (size_t j = 0; j < 1024; j++) {
+ rdata[i++] = 0xAB;
+ }
+
+ 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);
+}
+
/* dst_key_fromdns rejects RSA DNSKEYs with a degenerate modulus */
ISC_RUN_TEST_IMPL(isc_rsa_fromdns_short_modulus) {
isc_result_t result;
ISC_TEST_LIST_START
ISC_TEST_ENTRY(isc_rsa_verify)
ISC_TEST_ENTRY(isc_rsa_fromdns_oversized_exponent)
+ISC_TEST_ENTRY(isc_rsa_fromdns_even_exponent)
+ISC_TEST_ENTRY(isc_rsa_fromdns_oversized_modulus)
ISC_TEST_ENTRY(isc_rsa_fromdns_short_modulus)
ISC_TEST_LIST_END