diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba30f9e402..11ec934207 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1389,15 +1389,13 @@ gcc:trixie:amd64cross32: <<: *debian_trixie_amd64cross32_image <<: *build_job -# Jobs for strict OpenSSL 3.x (no deprecated) GCC builds on Debian "trixie" (amd64) # Run with pkcs11-provider tests - gcc:ossl3:trixie:amd64: <<: *debian_trixie_amd64_image <<: *build_job variables: CC: gcc - CFLAGS: "${CFLAGS_COMMON} -DOPENSSL_NO_DEPRECATED=1 -DOPENSSL_API_COMPAT=30000" + CFLAGS: "${CFLAGS_COMMON}" # See https://gitlab.isc.org/isc-projects/bind9/-/issues/3444 EXTRA_CONFIGURE: "-Doptimization=3 -Djemalloc=disabled -Dleak-detection=disabled" RUN_MESON_INSTALL: 1 diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index b28171bf70..27c0845c77 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/bin/named/server.c b/bin/named/server.c index 381997626b..9b3f170025 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/dns/catz.c b/lib/dns/catz.c index 410e00f078..6e16621204 100644 --- a/lib/dns/catz.c +++ b/lib/dns/catz.c @@ -1859,7 +1859,7 @@ dns_catz_generate_masterfilename(dns_catz_zone_t *catz, dns_catz_entry_t *entry, isc_buffer_subtract(tbuf, 1); /* __catz__.db */ - rlen = (isc_md_type_get_size(ISC_MD_SHA256) * 2 + 1) + 12; + rlen = (ISC_SHA256_DIGESTLENGTH * 2 + 1) + 12; /* optionally prepend with / */ if (entry->opts.zonedir != NULL) { diff --git a/lib/dns/ds.c b/lib/dns/ds.c index e8c71a80c7..bc937c8eec 100644 --- a/lib/dns/ds.c +++ b/lib/dns/ds.c @@ -41,7 +41,7 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, unsigned int privatelen = 0; isc_region_t r; isc_md_t *md; - const isc_md_type_t *md_type = NULL; + isc_md_type_t md_type = ISC_MD_UNKNOWN; REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey || diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 2f4ebf9753..b8b673043b 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -1321,22 +1321,22 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) { *n = DNS_SIG_ED448SIZE; break; case DST_ALG_HMACMD5: - *n = isc_md_type_get_size(ISC_MD_MD5); + *n = ISC_MD5_DIGESTLENGTH; break; case DST_ALG_HMACSHA1: - *n = isc_md_type_get_size(ISC_MD_SHA1); + *n = ISC_SHA1_DIGESTLENGTH; break; case DST_ALG_HMACSHA224: - *n = isc_md_type_get_size(ISC_MD_SHA224); + *n = ISC_SHA224_DIGESTLENGTH; break; case DST_ALG_HMACSHA256: - *n = isc_md_type_get_size(ISC_MD_SHA256); + *n = ISC_SHA256_DIGESTLENGTH; break; case DST_ALG_HMACSHA384: - *n = isc_md_type_get_size(ISC_MD_SHA384); + *n = ISC_SHA384_DIGESTLENGTH; break; case DST_ALG_HMACSHA512: - *n = isc_md_type_get_size(ISC_MD_SHA512); + *n = ISC_SHA512_DIGESTLENGTH; break; case DST_ALG_GSSAPI: *n = 128; /*%< XXX */ diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 51f8cd5d26..bc48c9fec4 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -62,8 +62,6 @@ typedef struct dst_func dst_func_t; -typedef struct dst_hmac_key dst_hmac_key_t; - /*% * Indicate whether a DST context will be used for signing * or for verification @@ -93,7 +91,7 @@ struct dst_key { union { void *generic; dns_gss_ctx_id_t gssctx; - dst_hmac_key_t *hmac_key; + isc_hmac_key_t *hmac_key; struct { EVP_PKEY *pub; EVP_PKEY *priv; diff --git a/lib/dns/dst_openssl.h b/lib/dns/dst_openssl.h index 8d57211af2..55d42645c4 100644 --- a/lib/dns/dst_openssl.h +++ b/lib/dns/dst_openssl.h @@ -21,18 +21,20 @@ #include #include +#include #include -#include -#define dst__openssl_toresult(fallback) \ - isc__tlserr2result(ISC_LOGCATEGORY_INVALID, ISC_LOGMODULE_INVALID, \ - NULL, fallback, __FILE__, __LINE__) -#define dst__openssl_toresult2(funcname, fallback) \ - isc__tlserr2result(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CRYPTO, \ - funcname, fallback, __FILE__, __LINE__) -#define dst__openssl_toresult3(category, funcname, fallback) \ - isc__tlserr2result(category, DNS_LOGMODULE_CRYPTO, funcname, fallback, \ - __FILE__, __LINE__) +#define dst__openssl_toresult(fallback) \ + isc__ossl_wrap_logged_toresult(ISC_LOGCATEGORY_INVALID, \ + ISC_LOGMODULE_INVALID, NULL, fallback, \ + __FILE__, __LINE__) +#define dst__openssl_toresult2(funcname, fallback) \ + isc__ossl_wrap_logged_toresult(DNS_LOGCATEGORY_GENERAL, \ + DNS_LOGMODULE_CRYPTO, funcname, \ + fallback, __FILE__, __LINE__) +#define dst__openssl_toresult3(category, funcname, fallback) \ + isc__ossl_wrap_logged_toresult(category, DNS_LOGMODULE_CRYPTO, \ + funcname, fallback, __FILE__, __LINE__) isc_result_t dst__openssl_fromlabel(int key_base_id, const char *label, const char *pin, diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 320b8adb85..41913095f2 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -55,7 +55,7 @@ #define hmac_register_algorithm(alg) \ static isc_result_t hmac##alg##_createctx(dst_key_t *key, \ dst_context_t *dctx) { \ - return (hmac_createctx(ISC_MD_##alg, key, dctx)); \ + return (hmac_createctx(key, dctx)); \ } \ static void hmac##alg##_destroyctx(dst_context_t *dctx) { \ hmac_destroyctx(dctx); \ @@ -74,7 +74,7 @@ } \ static bool hmac##alg##_compare(const dst_key_t *key1, \ const dst_key_t *key2) { \ - return (hmac_compare(ISC_MD_##alg, key1, key2)); \ + return (hmac_compare(key1, key2)); \ } \ static isc_result_t hmac##alg##_generate( \ dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { \ @@ -130,22 +130,19 @@ void dst__hmac##alg##_init(dst_func_t **funcp) { \ REQUIRE(funcp != NULL); \ if (*funcp == NULL) { \ - isc_hmac_t *ctx = isc_hmac_new(); \ - if (isc_hmac_init(ctx, "test", 4, ISC_MD_##alg) == \ - ISC_R_SUCCESS) \ + uint8_t data[] = "data"; \ + uint8_t mac_buffer[ISC_MAX_MD_SIZE]; \ + unsigned int mac_len = sizeof(mac_buffer); \ + if (isc_hmac(ISC_MD_##alg, "test", 4, data, 4, \ + mac_buffer, &mac_len) == ISC_R_SUCCESS) \ { \ *funcp = &hmac##alg##_functions; \ } \ - isc_hmac_free(ctx); \ } \ } static isc_result_t -hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data); - -struct dst_hmac_key { - uint8_t key[ISC_MAX_BLOCK_SIZE]; -}; +hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data); static isc_result_t getkeybits(dst_key_t *key, struct dst_private_element *element) { @@ -161,14 +158,11 @@ getkeybits(dst_key_t *key, struct dst_private_element *element) { } static isc_result_t -hmac_createctx(const isc_md_type_t *type, const dst_key_t *key, - dst_context_t *dctx) { +hmac_createctx(const dst_key_t *key, dst_context_t *dctx) { isc_result_t result; - const dst_hmac_key_t *hkey = key->keydata.hmac_key; isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */ - result = isc_hmac_init(ctx, hkey->key, isc_md_type_get_block_size(type), - type); + result = isc_hmac_init(ctx, key->keydata.hmac_key); if (result != ISC_R_SUCCESS) { isc_hmac_free(ctx); return DST_R_UNSUPPORTEDALG; @@ -205,44 +199,27 @@ hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) { isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; + REQUIRE(ctx != NULL); - unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); - if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) { - return DST_R_OPENSSLFAILURE; - } - - if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) { - return DST_R_OPENSSLFAILURE; - } - - if (isc_buffer_availablelength(sig) < digestlen) { - return ISC_R_NOSPACE; - } - - isc_buffer_putmem(sig, digest, digestlen); - - return ISC_R_SUCCESS; + return isc_hmac_final(ctx, sig); } static isc_result_t hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) { isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); + isc_buffer_t hmac; REQUIRE(ctx != NULL); - if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) { + isc_buffer_init(&hmac, digest, sizeof(digest)); + + if (isc_hmac_final(ctx, &hmac) != ISC_R_SUCCESS) { return DST_R_OPENSSLFAILURE; } - if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) { - return DST_R_OPENSSLFAILURE; - } - - if (sig->length > digestlen) { + if (sig->length > isc_buffer_usedlength(&hmac)) { return DST_R_VERIFYFAILURE; } @@ -252,9 +229,8 @@ hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) { } static bool -hmac_compare(const isc_md_type_t *type, const dst_key_t *key1, - const dst_key_t *key2) { - dst_hmac_key_t *hkey1, *hkey2; +hmac_compare(const dst_key_t *key1, const dst_key_t *key2) { + isc_hmac_key_t *hkey1, *hkey2; hkey1 = key1->keydata.hmac_key; hkey2 = key2->keydata.hmac_key; @@ -265,12 +241,11 @@ hmac_compare(const isc_md_type_t *type, const dst_key_t *key1, return false; } - return isc_safe_memequal(hkey1->key, hkey2->key, - isc_md_type_get_block_size(type)); + return isc_hmac_key_equal(hkey1, hkey2); } static isc_result_t -hmac_generate(const isc_md_type_t *type, dst_key_t *key) { +hmac_generate(isc_md_type_t type, dst_key_t *key) { isc_buffer_t b; isc_result_t result; unsigned int bytes, len; @@ -305,31 +280,28 @@ hmac_isprivate(const dst_key_t *key) { static void hmac_destroy(dst_key_t *key) { - dst_hmac_key_t *hkey = key->keydata.hmac_key; - isc_safe_memwipe(hkey, sizeof(*hkey)); - isc_mem_put(key->mctx, hkey, sizeof(*hkey)); - key->keydata.hmac_key = NULL; + isc_hmac_key_destroy(&key->keydata.hmac_key); } static isc_result_t hmac_todns(const dst_key_t *key, isc_buffer_t *data) { - REQUIRE(key != NULL && key->keydata.hmac_key != NULL); - dst_hmac_key_t *hkey = key->keydata.hmac_key; - unsigned int bytes; + isc_region_t raw_key; - bytes = (key->key_size + 7) / 8; - if (isc_buffer_availablelength(data) < bytes) { + REQUIRE(key != NULL && key->keydata.hmac_key != NULL); + + raw_key = isc_hmac_key_expose(key->keydata.hmac_key); + + if (isc_buffer_availablelength(data) < raw_key.length) { return ISC_R_NOSPACE; } - isc_buffer_putmem(data, hkey->key, bytes); - return ISC_R_SUCCESS; + return isc_buffer_copyregion(data, &raw_key); } static isc_result_t -hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) { - dst_hmac_key_t *hkey; - unsigned int keylen; +hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) { + isc_hmac_key_t *hkey = NULL; + isc_result_t result; isc_region_t r; isc_buffer_remainingregion(data, &r); @@ -337,24 +309,12 @@ hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) { return ISC_R_SUCCESS; } - hkey = isc_mem_get(key->mctx, sizeof(dst_hmac_key_t)); - - memset(hkey->key, 0, sizeof(hkey->key)); - - /* Hash the key if the key is longer then chosen MD block size */ - if (r.length > (unsigned int)isc_md_type_get_block_size(type)) { - if (isc_md(type, r.base, r.length, hkey->key, &keylen) != - ISC_R_SUCCESS) - { - isc_mem_put(key->mctx, hkey, sizeof(dst_hmac_key_t)); - return DST_R_OPENSSLFAILURE; - } - } else { - memmove(hkey->key, r.base, r.length); - keylen = r.length; + result = isc_hmac_key_create(type, r.base, r.length, key->mctx, &hkey); + if (result != ISC_R_SUCCESS) { + return DST_R_OPENSSLFAILURE; } - key->key_size = keylen * 8; + key->key_size = isc_hmac_key_expose(hkey).length * 8; key->keydata.hmac_key = hkey; isc_buffer_forward(data, r.length); @@ -363,49 +323,49 @@ hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) { } static int -hmac__get_tag_key(const isc_md_type_t *type) { - if (type == ISC_MD_MD5) { +hmac__get_tag_key(isc_md_type_t type) { + switch (type) { + case ISC_MD_MD5: return TAG_HMACMD5_KEY; - } else if (type == ISC_MD_SHA1) { + case ISC_MD_SHA1: return TAG_HMACSHA1_KEY; - } else if (type == ISC_MD_SHA224) { + case ISC_MD_SHA224: return TAG_HMACSHA224_KEY; - } else if (type == ISC_MD_SHA256) { + case ISC_MD_SHA256: return TAG_HMACSHA256_KEY; - } else if (type == ISC_MD_SHA384) { + case ISC_MD_SHA384: return TAG_HMACSHA384_KEY; - } else if (type == ISC_MD_SHA512) { + case ISC_MD_SHA512: return TAG_HMACSHA512_KEY; - } else { + default: UNREACHABLE(); } } static int -hmac__get_tag_bits(const isc_md_type_t *type) { - if (type == ISC_MD_MD5) { +hmac__get_tag_bits(isc_md_type_t type) { + switch (type) { + case ISC_MD_MD5: return TAG_HMACMD5_BITS; - } else if (type == ISC_MD_SHA1) { + case ISC_MD_SHA1: return TAG_HMACSHA1_BITS; - } else if (type == ISC_MD_SHA224) { + case ISC_MD_SHA224: return TAG_HMACSHA224_BITS; - } else if (type == ISC_MD_SHA256) { + case ISC_MD_SHA256: return TAG_HMACSHA256_BITS; - } else if (type == ISC_MD_SHA384) { + case ISC_MD_SHA384: return TAG_HMACSHA384_BITS; - } else if (type == ISC_MD_SHA512) { + case ISC_MD_SHA512: return TAG_HMACSHA512_BITS; - } else { + default: UNREACHABLE(); } } static isc_result_t -hmac_tofile(const isc_md_type_t *type, const dst_key_t *key, - const char *directory) { - dst_hmac_key_t *hkey; +hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) { + isc_region_t raw_key; dst_private_t priv; - int bytes = (key->key_size + 7) / 8; uint16_t bits; if (key->keydata.hmac_key == NULL) { @@ -416,11 +376,11 @@ hmac_tofile(const isc_md_type_t *type, const dst_key_t *key, return DST_R_EXTERNALKEY; } - hkey = key->keydata.hmac_key; + raw_key = isc_hmac_key_expose(key->keydata.hmac_key); priv.elements[0].tag = hmac__get_tag_key(type); - priv.elements[0].length = bytes; - priv.elements[0].data = hkey->key; + priv.elements[0].length = raw_key.length; + priv.elements[0].data = raw_key.base; bits = htons(key->key_bits); @@ -434,7 +394,7 @@ hmac_tofile(const isc_md_type_t *type, const dst_key_t *key, } static int -hmac__to_dst_alg(const isc_md_type_t *type) { +hmac__to_dst_alg(isc_md_type_t type) { if (type == ISC_MD_MD5) { return DST_ALG_HMACMD5; } else if (type == ISC_MD_SHA1) { @@ -453,7 +413,7 @@ hmac__to_dst_alg(const isc_md_type_t *type) { } static isc_result_t -hmac_parse(const isc_md_type_t *type, dst_key_t *key, isc_lex_t *lexer, +hmac_parse(isc_md_type_t type, dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result = ISC_R_SUCCESS, tresult; diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index 54213d5cdf..2b7518c576 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -17,16 +17,13 @@ #include #include -#include #include #include -#include -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#include -#endif +#include +#include #include +#include #include #include #include @@ -50,37 +47,6 @@ #define MAX_PRIVKEY_SIZE (MAX_PUBKEY_SIZE / 2) -#if OPENSSL_VERSION_NUMBER >= 0x30200000L -static isc_result_t -opensslecdsa_set_deterministic(EVP_PKEY_CTX *pctx, unsigned int key_alg) { - unsigned int rfc6979 = 1; - const char *md = NULL; - OSSL_PARAM params[3]; - - switch (key_alg) { - case DST_ALG_ECDSA256: - md = "SHA256"; - break; - case DST_ALG_ECDSA384: - md = "SHA384"; - break; - default: - UNREACHABLE(); - } - - params[0] = OSSL_PARAM_construct_utf8_string("digest", UNCONST(md), 0); - params[1] = OSSL_PARAM_construct_uint("nonce-type", &rfc6979); - params[2] = OSSL_PARAM_construct_end(); - - if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { - return dst__openssl_toresult2("EVP_PKEY_CTX_set_params", - DST_R_OPENSSLFAILURE); - } - - return ISC_R_SUCCESS; -} -#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */ - static bool opensslecdsa_valid_key_alg(unsigned int key_alg) { switch (key_alg) { @@ -92,18 +58,6 @@ opensslecdsa_valid_key_alg(unsigned int key_alg) { } } -static int -opensslecdsa_key_alg_to_group_nid(unsigned int key_alg) { - switch (key_alg) { - case DST_ALG_ECDSA256: - return NID_X9_62_prime256v1; - case DST_ALG_ECDSA384: - return NID_secp384r1; - default: - UNREACHABLE(); - } -} - static size_t opensslecdsa_key_alg_to_publickey_size(unsigned int key_alg) { switch (key_alg) { @@ -116,23 +70,6 @@ opensslecdsa_key_alg_to_publickey_size(unsigned int key_alg) { } } -/* - * OpenSSL requires us to set the public key portion, but since our private key - * file format does not contain it directly, we generate it as needed. - */ -static EC_POINT * -opensslecdsa_generate_public_key(const EC_GROUP *group, const BIGNUM *privkey) { - EC_POINT *pubkey = EC_POINT_new(group); - if (pubkey == NULL) { - return NULL; - } - if (EC_POINT_mul(group, pubkey, privkey, NULL, NULL, NULL) != 1) { - EC_POINT_free(pubkey); - return NULL; - } - return pubkey; -} - static int BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { int bytes = size - BN_num_bytes(bn); @@ -146,534 +83,13 @@ BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { return size; } -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - -static const char * -opensslecdsa_key_alg_to_group_name(unsigned int key_alg) { - switch (key_alg) { - case DST_ALG_ECDSA256: - return "prime256v1"; - case DST_ALG_ECDSA384: - return "secp384r1"; - default: - UNREACHABLE(); - } -} - -static isc_result_t -opensslecdsa_create_pkey_params(unsigned int key_alg, bool private, - const unsigned char *key, size_t key_len, - EVP_PKEY **pkey) { - isc_result_t result; - int status; - int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - const char *groupname = opensslecdsa_key_alg_to_group_name(key_alg); - OSSL_PARAM_BLD *bld = NULL; - OSSL_PARAM *params = NULL; - EVP_PKEY_CTX *ctx = NULL; - EC_POINT *pubkey = NULL; - EC_GROUP *group = NULL; - BIGNUM *priv = NULL; - unsigned char buf[MAX_PUBKEY_SIZE + 1]; - - bld = OSSL_PARAM_BLD_new(); - if (bld == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_new", - DST_R_OPENSSLFAILURE)); - } - status = OSSL_PARAM_BLD_push_utf8_string( - bld, OSSL_PKEY_PARAM_GROUP_NAME, groupname, 0); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" - "utf8_string", - DST_R_OPENSSLFAILURE)); - } - - if (private) { - group = EC_GROUP_new_by_curve_name(group_nid); - if (group == NULL) { - CLEANUP(dst__openssl_toresult2("EC_GROUP_new_by_" - "curve_name", - DST_R_OPENSSLFAILURE)); - } - - priv = BN_bin2bn(key, key_len, NULL); - if (priv == NULL) { - CLEANUP(dst__openssl_toresult2("BN_bin2bn", - DST_R_OPENSSLFAILURE)); - } - - status = OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, - priv); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - - pubkey = opensslecdsa_generate_public_key(group, priv); - if (pubkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - key = buf; - key_len = EC_POINT_point2oct(group, pubkey, - POINT_CONVERSION_UNCOMPRESSED, buf, - sizeof(buf), NULL); - if (key_len == 0) { - CLEANUP(dst__openssl_toresult2("EC_POINT_point2oct", - DST_R_OPENSSLFAILURE)); - } - } else { - INSIST(key_len + 1 <= sizeof(buf)); - buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memmove(buf + 1, key, key_len); - key = buf; - key_len = key_len + 1; - } - - status = OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, - key, key_len); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" - "octet_string", - DST_R_OPENSSLFAILURE)); - } - - params = OSSL_PARAM_BLD_to_param(bld); - if (params == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param", - DST_R_OPENSSLFAILURE)); - } - ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_fromdata_init(ctx); - if (status != 1) { - /* This will fail if the default provider is an engine. - * Return ISC_R_FAILURE to retry using the legacy API. */ - CLEANUP(dst__openssl_toresult(ISC_R_FAILURE)); - } - status = EVP_PKEY_fromdata( - ctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, - params); - if (status != 1 || *pkey == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_fromdata", - DST_R_OPENSSLFAILURE)); - } - - result = ISC_R_SUCCESS; - -cleanup: - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(bld); - EVP_PKEY_CTX_free(ctx); - BN_clear_free(priv); - EC_POINT_free(pubkey); - EC_GROUP_free(group); - - return result; -} - -static bool -opensslecdsa_extract_public_key_params(const dst_key_t *key, unsigned char *dst, - size_t dstlen) { - EVP_PKEY *pkey = key->keydata.pkeypair.pub; - BIGNUM *x = NULL; - BIGNUM *y = NULL; - bool ret = false; - - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) == 1 && - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) == 1) - { - BN_bn2bin_fixed(x, &dst[0], dstlen / 2); - BN_bn2bin_fixed(y, &dst[dstlen / 2], dstlen / 2); - ret = true; - } - BN_clear_free(x); - BN_clear_free(y); - return ret; -} - -#endif - -#if OPENSSL_VERSION_NUMBER < 0x30000000L - -static isc_result_t -opensslecdsa_create_pkey_legacy(unsigned int key_alg, bool private, - const unsigned char *key, size_t key_len, - EVP_PKEY **retkey) { - isc_result_t result = ISC_R_SUCCESS; - EC_KEY *eckey = NULL; - EVP_PKEY *pkey = NULL; - BIGNUM *privkey = NULL; - EC_POINT *pubkey = NULL; - unsigned char buf[MAX_PUBKEY_SIZE + 1]; - int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - - eckey = EC_KEY_new_by_curve_name(group_nid); - if (eckey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (private) { - const EC_GROUP *group = EC_KEY_get0_group(eckey); - - privkey = BN_bin2bn(key, key_len, NULL); - if (privkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - if (!EC_KEY_set_private_key(eckey, privkey)) { - CLEANUP(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); - } - - pubkey = opensslecdsa_generate_public_key(group, privkey); - if (pubkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - if (EC_KEY_set_public_key(eckey, pubkey) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - } else { - const unsigned char *cp = buf; - INSIST(key_len + 1 <= sizeof(buf)); - buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memmove(buf + 1, key, key_len); - if (o2i_ECPublicKey(&eckey, &cp, key_len + 1) == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); - } - if (EC_KEY_check_key(eckey) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); - } - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); - } - if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { - CLEANUP(dst__openssl_toresult(ISC_R_FAILURE)); - } - - *retkey = pkey; - pkey = NULL; - -cleanup: - BN_clear_free(privkey); - EC_POINT_free(pubkey); - EC_KEY_free(eckey); - EVP_PKEY_free(pkey); - return result; -} - -static bool -opensslecdsa_extract_public_key_legacy(const dst_key_t *key, unsigned char *dst, - size_t dstlen) { - EVP_PKEY *pkey = key->keydata.pkeypair.pub; - const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); - const EC_GROUP *group = (eckey == NULL) ? NULL - : EC_KEY_get0_group(eckey); - const EC_POINT *pub = (eckey == NULL) ? NULL - : EC_KEY_get0_public_key(eckey); - unsigned char buf[MAX_PUBKEY_SIZE + 1]; - size_t len; - - if (group == NULL || pub == NULL) { - return false; - } - - len = EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED, buf, - sizeof(buf), NULL); - if (len == dstlen + 1) { - memmove(dst, buf + 1, dstlen); - return true; - } - return false; -} - -#endif - -static bool -opensslecdsa_extract_public_key(const dst_key_t *key, unsigned char *dst, - size_t dstlen) { -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - if (opensslecdsa_extract_public_key_params(key, dst, dstlen)) { - return true; - } -#else - if (opensslecdsa_extract_public_key_legacy(key, dst, dstlen)) { - return true; - } -#endif - return false; -} - -static isc_result_t -opensslecdsa_create_pkey(unsigned int key_alg, bool private, - const unsigned char *key, size_t key_len, - EVP_PKEY **retkey) { - isc_result_t result; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - result = opensslecdsa_create_pkey_params(key_alg, private, key, key_len, - retkey); - if (result != ISC_R_FAILURE) { - return result; - } -#else - result = opensslecdsa_create_pkey_legacy(key_alg, private, key, key_len, - retkey); - if (result == ISC_R_SUCCESS) { - return result; - } -#endif - return DST_R_OPENSSLFAILURE; -} - -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - -static isc_result_t -opensslecdsa_generate_pkey_with_uri(int group_nid, const char *label, - EVP_PKEY **retkey) { - int status; - isc_result_t result; - char *uri = UNCONST(label); - EVP_PKEY_CTX *ctx = NULL; - OSSL_PARAM params[3]; - - /* Generate the key's parameters. */ - params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); - params[1] = OSSL_PARAM_construct_utf8_string( - "pkcs11_key_usage", (char *)"digitalSignature", 0); - params[2] = OSSL_PARAM_construct_end(); - - ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11"); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_keygen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen_init", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_CTX_set_params(ctx, params); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_params", - DST_R_OPENSSLFAILURE)); - } - /* - * Setting the P-384 curve doesn't work correctly when using: - * OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0); - * - * Instead use the OpenSSL function to set the curve nid param. - */ - status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_" - "curve_nid", - DST_R_OPENSSLFAILURE)); - } - - /* Generate the key. */ - status = EVP_PKEY_generate(ctx, retkey); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_generate", - DST_R_OPENSSLFAILURE)); - } - - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, - EVP_PKEY **retkey) { - isc_result_t result; - EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *params_pkey = NULL; - int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - int status; - - if (label != NULL) { - return opensslecdsa_generate_pkey_with_uri(group_nid, label, - retkey); - } - - /* Generate the key's parameters. */ - ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_paramgen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_paramgen_init", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_" - "curve_nid", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_paramgen(ctx, ¶ms_pkey); - if (status != 1 || params_pkey == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_paramgen", - DST_R_OPENSSLFAILURE)); - } - EVP_PKEY_CTX_free(ctx); - - /* Generate the key. */ - ctx = EVP_PKEY_CTX_new(params_pkey, NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_keygen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen_init", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_keygen(ctx, retkey); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen", - DST_R_OPENSSLFAILURE)); - } - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_free(params_pkey); - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslecdsa_validate_pkey_group(unsigned int key_alg, EVP_PKEY *pkey) { - const char *groupname = opensslecdsa_key_alg_to_group_name(key_alg); - char gname[64]; - - if (EVP_PKEY_get_group_name(pkey, gname, sizeof(gname), NULL) != 1) { - return DST_R_INVALIDPRIVATEKEY; - } - if (strcmp(gname, groupname) != 0) { - return DST_R_INVALIDPRIVATEKEY; - } - return ISC_R_SUCCESS; -} - -static bool -opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf, - size_t buflen) { - EVP_PKEY *pkey = key->keydata.pkeypair.priv; - BIGNUM *priv = NULL; - - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) { - return false; - } - - BN_bn2bin_fixed(priv, buf, buflen); - BN_clear_free(priv); - return true; -} - -#else - -static isc_result_t -opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, - EVP_PKEY **retkey) { - isc_result_t result; - EC_KEY *eckey = NULL; - EVP_PKEY *pkey = NULL; - int group_nid; - - UNUSED(label); - - group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - - eckey = EC_KEY_new_by_curve_name(group_nid); - if (eckey == NULL) { - CLEANUP(dst__openssl_toresult2("EC_KEY_new_by_curve_name", - DST_R_OPENSSLFAILURE)); - } - - if (EC_KEY_generate_key(eckey) != 1) { - CLEANUP(dst__openssl_toresult2("EC_KEY_generate_key", - DST_R_OPENSSLFAILURE)); - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); - } - if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_set1_EC_KEY", - DST_R_OPENSSLFAILURE)); - } - *retkey = pkey; - pkey = NULL; - result = ISC_R_SUCCESS; - -cleanup: - EC_KEY_free(eckey); - EVP_PKEY_free(pkey); - return result; -} - -static isc_result_t -opensslecdsa_validate_pkey_group(unsigned int key_alg, EVP_PKEY *pkey) { - const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); - int group_nid; - - if (eckey == NULL) { - return dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY); - } - - group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); - - if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)) != group_nid) { - return DST_R_INVALIDPRIVATEKEY; - } - - return ISC_R_SUCCESS; -} - -static bool -opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf, - size_t buflen) { - const EC_KEY *eckey = NULL; - const BIGNUM *privkey = NULL; - - eckey = EVP_PKEY_get0_EC_KEY(key->keydata.pkeypair.priv); - if (eckey == NULL) { - ERR_clear_error(); - return false; - } - - privkey = EC_KEY_get0_private_key(eckey); - if (privkey == NULL) { - ERR_clear_error(); - return false; - } - - BN_bn2bin_fixed(privkey, buf, buflen); - return true; -} - -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - static isc_result_t opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { isc_result_t result = ISC_R_SUCCESS; EVP_MD_CTX *evp_md_ctx; EVP_PKEY_CTX *pctx = NULL; const EVP_MD *type = NULL; + const char *md = NULL; UNUSED(key); REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg)); @@ -684,9 +100,11 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); } if (dctx->key->key_alg == DST_ALG_ECDSA256) { - type = isc__crypto_sha256; + type = isc__crypto_md[ISC_MD_SHA256]; + md = "SHA256"; } else { - type = isc__crypto_sha384; + type = isc__crypto_md[ISC_MD_SHA384]; + md = "SHA384"; } if (dctx->use == DO_SIGN) { @@ -699,12 +117,15 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { ISC_R_FAILURE)); } -#if OPENSSL_VERSION_NUMBER >= 0x30200000L if (!isc_crypto_fips_mode()) { - CHECK(opensslecdsa_set_deterministic( - pctx, dctx->key->key_alg)); + result = isc_ossl_wrap_ecdsa_set_deterministic(pctx, + md); + if (result != ISC_R_SUCCESS && + result != ISC_R_NOTIMPLEMENTED) + { + CLEANUP(result); + } } -#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */ } else { if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL, @@ -718,6 +139,7 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { } dctx->ctxdata.evp_md_ctx = evp_md_ctx; + result = ISC_R_SUCCESS; cleanup: return result; @@ -916,7 +338,31 @@ opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { UNUSED(unused); UNUSED(callback); - RETERR(opensslecdsa_generate_pkey(key->key_alg, key->label, &pkey)); + if (key->label != NULL) { + switch (key->key_alg) { + case DST_ALG_ECDSA256: + RETERR(isc_ossl_wrap_generate_pkcs11_p256_key( + key->label, &pkey)); + break; + case DST_ALG_ECDSA384: + RETERR(isc_ossl_wrap_generate_pkcs11_p384_key( + key->label, &pkey)); + break; + default: + UNREACHABLE(); + } + } else { + switch (key->key_alg) { + case DST_ALG_ECDSA256: + RETERR(isc_ossl_wrap_generate_p256_key(&pkey)); + break; + case DST_ALG_ECDSA384: + RETERR(isc_ossl_wrap_generate_p384_key(&pkey)); + break; + default: + UNREACHABLE(); + } + } key->key_size = EVP_PKEY_bits(pkey); key->keydata.pkeypair.priv = pkey; @@ -928,6 +374,7 @@ static isc_result_t opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { isc_result_t result; isc_region_t r; + EVP_PKEY *pkey; size_t keysize; REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); @@ -938,8 +385,23 @@ opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { if (r.length < keysize) { CLEANUP(ISC_R_NOSPACE); } - if (!opensslecdsa_extract_public_key(key, r.base, keysize)) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + + pkey = key->keydata.pkeypair.pub; + switch (key->key_alg) { + case DST_ALG_ECDSA256: + if (isc_ossl_wrap_p256_public_region(pkey, r) != ISC_R_SUCCESS) + { + CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + break; + case DST_ALG_ECDSA384: + if (isc_ossl_wrap_p384_public_region(pkey, r) != ISC_R_SUCCESS) + { + CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + break; + default: + UNREACHABLE(); } isc_buffer_add(data, keysize); @@ -967,8 +429,16 @@ opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { CLEANUP(DST_R_INVALIDPUBLICKEY); } - CHECK(opensslecdsa_create_pkey(key->key_alg, false, r.base, len, - &pkey)); + switch (key->key_alg) { + case DST_ALG_ECDSA256: + CHECK(isc_ossl_wrap_load_p256_public_from_region(r, &pkey)); + break; + case DST_ALG_ECDSA384: + CHECK(isc_ossl_wrap_load_p384_public_from_region(r, &pkey)); + break; + default: + UNREACHABLE(); + } isc_buffer_forward(data, len); key->key_size = EVP_PKEY_bits(pkey); @@ -986,6 +456,7 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { unsigned char buf[MAX_PRIVKEY_SIZE]; size_t keylen = 0; unsigned short i; + EVP_PKEY *pkey; if (key->keydata.pkeypair.pub == NULL) { CLEANUP(DST_R_NULLKEY); @@ -1003,8 +474,23 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { keylen = opensslecdsa_key_alg_to_publickey_size(key->key_alg) / 2; INSIST(keylen <= sizeof(buf)); + pkey = key->keydata.pkeypair.priv; + i = 0; - if (opensslecdsa_extract_private_key(key, buf, keylen)) { + switch (key->key_alg) { + case DST_ALG_ECDSA256: + result = isc_ossl_wrap_p256_secret_region( + pkey, (isc_region_t){ buf, keylen }); + break; + case DST_ALG_ECDSA384: + result = isc_ossl_wrap_p384_secret_region( + pkey, (isc_region_t){ buf, keylen }); + break; + default: + UNREACHABLE(); + } + + if (result == ISC_R_SUCCESS) { priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY; priv.elements[i].length = keylen; priv.elements[i].data = buf; @@ -1034,6 +520,7 @@ static isc_result_t opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result; + isc_region_t r; EVP_PKEY *pkey = NULL; const char *label = NULL; int i, privkey_index = -1; @@ -1086,9 +573,21 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { CLEANUP(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); } - CHECK(opensslecdsa_create_pkey( - key->key_alg, true, priv.elements[privkey_index].data, - priv.elements[privkey_index].length, &pkey)); + r = (isc_region_t){ + .base = priv.elements[privkey_index].data, + .length = priv.elements[privkey_index].length, + }; + + switch (key->key_alg) { + case DST_ALG_ECDSA256: + CHECK(isc_ossl_wrap_load_p256_secret_from_region(r, &pkey)); + break; + case DST_ALG_ECDSA384: + CHECK(isc_ossl_wrap_load_p384_secret_from_region(r, &pkey)); + break; + default: + UNREACHABLE(); + } /* Check that the public component matches if given */ if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { @@ -1122,8 +621,18 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *label, const char *pin) { CHECK(dst__openssl_fromlabel(EVP_PKEY_EC, label, pin, &pubpkey, &privpkey)); - CHECK(opensslecdsa_validate_pkey_group(key->key_alg, privpkey)); - CHECK(opensslecdsa_validate_pkey_group(key->key_alg, pubpkey)); + switch (key->key_alg) { + case DST_ALG_ECDSA256: + CHECK(isc_ossl_wrap_validate_p256_pkey(privpkey)); + CHECK(isc_ossl_wrap_validate_p256_pkey(pubpkey)); + break; + case DST_ALG_ECDSA384: + CHECK(isc_ossl_wrap_validate_p384_pkey(privpkey)); + CHECK(isc_ossl_wrap_validate_p384_pkey(pubpkey)); + break; + default: + UNREACHABLE(); + } key->label = isc_mem_strdup(key->mctx, label); key->key_size = EVP_PKEY_bits(privpkey); diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index 7ef6e495c5..f9f1a0bdf0 100644 --- a/lib/dns/openssleddsa_link.c +++ b/lib/dns/openssleddsa_link.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 465e1f663d..6b322ff3b3 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -19,14 +19,10 @@ #include #include #include -#include #include -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#include -#endif #include +#include #include #include #include @@ -39,11 +35,6 @@ #define OPENSSLRSA_MAX_MODULUS_BITS 4096 -typedef struct rsa_components { - bool bnfree; - const BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; -} rsa_components_t; - /* 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 }; @@ -52,103 +43,6 @@ static unsigned char oid_rsasha256[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, static unsigned char oid_rsasha512[] = { 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d }; -static isc_result_t -opensslrsa_components_get(const dst_key_t *key, rsa_components_t *c, - bool private) { - REQUIRE(c->e == NULL && c->n == NULL && c->d == NULL && c->p == NULL && - c->q == NULL && c->dmp1 == NULL && c->dmq1 == NULL && - c->iqmp == NULL); - - EVP_PKEY *pub = key->keydata.pkeypair.pub; - EVP_PKEY *priv = key->keydata.pkeypair.priv; - - if (private && priv == NULL) { - return DST_R_INVALIDPRIVATEKEY; - } - /* - * NOTE: Errors regarding private compoments are ignored. - * - * OpenSSL allows omitting the parameters for CRT based calculations - * (factors, exponents, coefficients). Only the 'd' parameter is - * mandatory for software keys. - * - * However, for a label based keys, all private key component queries - * can fail if they key is e.g. on a hardware device. - */ -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - if (EVP_PKEY_get_bn_param(pub, OSSL_PKEY_PARAM_RSA_E, - (BIGNUM **)&c->e) != 1) - { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - - c->bnfree = true; - if (EVP_PKEY_get_bn_param(pub, OSSL_PKEY_PARAM_RSA_N, - (BIGNUM **)&c->n) != 1) - { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - if (!private) { - return ISC_R_SUCCESS; - } - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_D, - (BIGNUM **)&c->d); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_FACTOR1, - (BIGNUM **)&c->p); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_FACTOR2, - (BIGNUM **)&c->q); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_EXPONENT1, - (BIGNUM **)&c->dmp1); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_EXPONENT2, - (BIGNUM **)&c->dmq1); - (void)EVP_PKEY_get_bn_param(priv, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, - (BIGNUM **)&c->iqmp); - ERR_clear_error(); - return ISC_R_SUCCESS; -#else - const RSA *rsa = EVP_PKEY_get0_RSA(pub); - if (rsa == NULL) { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - RSA_get0_key(rsa, &c->n, &c->e, &c->d); - if (c->e == NULL || c->n == NULL) { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - if (!private) { - return ISC_R_SUCCESS; - } - rsa = EVP_PKEY_get0_RSA(priv); - if (rsa == NULL) { - return dst__openssl_toresult(DST_R_OPENSSLFAILURE); - } - RSA_get0_factors(rsa, &c->p, &c->q); - RSA_get0_crt_params(rsa, &c->dmp1, &c->dmq1, &c->iqmp); - return ISC_R_SUCCESS; -#endif -} - -static void -opensslrsa_components_free(rsa_components_t *c) { - if (!c->bnfree) { - return; - } - /* - * NOTE: BN_free() frees the components of the BIGNUM, and if it was - * created by BN_new(), also the structure itself. BN_clear_free() - * additionally overwrites the data before the memory is returned to the - * system. If a is NULL, nothing is done. - */ - BN_free((BIGNUM *)c->e); - BN_free((BIGNUM *)c->n); - BN_clear_free((BIGNUM *)c->d); - BN_clear_free((BIGNUM *)c->p); - BN_clear_free((BIGNUM *)c->q); - BN_clear_free((BIGNUM *)c->dmp1); - BN_clear_free((BIGNUM *)c->dmq1); - BN_clear_free((BIGNUM *)c->iqmp); - c->bnfree = false; -} - static bool opensslrsa_valid_key_alg(unsigned int key_alg) { switch (key_alg) { @@ -210,15 +104,15 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) { switch (dctx->key->key_alg) { case DST_ALG_RSASHA1: case DST_ALG_NSEC3RSASHA1: - type = isc__crypto_sha1; /* SHA1 + RSA */ + type = isc__crypto_md[ISC_MD_SHA1]; /* SHA1 + RSA */ break; case DST_ALG_RSASHA256: case DST_ALG_RSASHA256PRIVATEOID: - type = isc__crypto_sha256; /* SHA256 + RSA */ + type = isc__crypto_md[ISC_MD_SHA256]; /* SHA256 + RSA */ break; case DST_ALG_RSASHA512: case DST_ALG_RSASHA512PRIVATEOID: - type = isc__crypto_sha512; + type = isc__crypto_md[ISC_MD_SHA512]; break; default: UNREACHABLE(); @@ -322,29 +216,6 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { return ISC_R_SUCCESS; } -static bool -opensslrsa_check_exponent_bits(EVP_PKEY *pkey, int maxbits) { - /* Always use the new API first with OpenSSL 3.x. */ - int bits = INT_MAX; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - BIGNUM *e = NULL; - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 1) { - bits = BN_num_bits(e); - BN_free(e); - } -#else - const RSA *rsa = EVP_PKEY_get0_RSA(pkey); - if (rsa != NULL) { - const BIGNUM *ce = NULL; - RSA_get0_key(rsa, NULL, &ce, NULL); - if (ce != NULL) { - bits = BN_num_bits(ce); - } - } -#endif - return bits <= maxbits; -} - static isc_result_t opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { dst_key_t *key = NULL; @@ -361,7 +232,7 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { evp_md_ctx = dctx->ctxdata.evp_md_ctx; pkey = key->keydata.pkeypair.pub; - if (!opensslrsa_check_exponent_bits(pkey, OPENSSLRSA_MAX_MODULUS_BITS)) + if (!isc_ossl_wrap_rsa_key_bits_leq(pkey, OPENSSLRSA_MAX_MODULUS_BITS)) { return DST_R_VERIFYFAILURE; } @@ -402,344 +273,13 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { } } -#if OPENSSL_VERSION_NUMBER < 0x30000000L -static int -progress_cb(int p, int n, BN_GENCB *cb) { - void (*fptr)(int); - - UNUSED(n); - - fptr = BN_GENCB_get_arg(cb); - if (fptr != NULL) { - fptr(p); - } - return 1; -} - -static isc_result_t -opensslrsa_generate_pkey(unsigned int key_size, const char *label, BIGNUM *e, - void (*callback)(int), EVP_PKEY **retkey) { - RSA *rsa = NULL; - EVP_PKEY *pkey = NULL; - BN_GENCB *cb = NULL; - isc_result_t result; - - UNUSED(label); - - rsa = RSA_new(); - pkey = EVP_PKEY_new(); - if (rsa == NULL || pkey == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (callback != NULL) { - cb = BN_GENCB_new(); - if (cb == NULL) { - CLEANUP(dst__openssl_toresult(ISC_R_NOMEMORY)); - } - BN_GENCB_set(cb, progress_cb, (void *)callback); - } - - if (RSA_generate_key_ex(rsa, key_size, e, cb) != 1) { - CLEANUP(dst__openssl_toresult2("RSA_generate_key_ex", - DST_R_OPENSSLFAILURE)); - } - *retkey = pkey; - pkey = NULL; - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_free(pkey); - RSA_free(rsa); - BN_GENCB_free(cb); - return result; -} - -static isc_result_t -opensslrsa_build_pkey(bool private, rsa_components_t *c, EVP_PKEY **retpkey) { - isc_result_t result; - EVP_PKEY *pkey = NULL; - RSA *rsa = RSA_new(); - int status; - - REQUIRE(c->bnfree); - - if (c->n == NULL || c->e == NULL) { - if (private) { - CLEANUP(DST_R_INVALIDPRIVATEKEY); - } - CLEANUP(DST_R_INVALIDPUBLICKEY); - } - - if (rsa == NULL) { - CLEANUP(dst__openssl_toresult2("RSA_new", - DST_R_OPENSSLFAILURE)); - } - - if (RSA_set0_key(rsa, (BIGNUM *)c->n, (BIGNUM *)c->e, (BIGNUM *)c->d) != - 1) - { - CLEANUP(dst__openssl_toresult2("RSA_set0_key", - DST_R_OPENSSLFAILURE)); - } - c->n = NULL; - c->e = NULL; - c->d = NULL; - - if (c->p != NULL || c->q != NULL) { - if (RSA_set0_factors(rsa, (BIGNUM *)c->p, (BIGNUM *)c->q) != 1) - { - CLEANUP(dst__openssl_toresult2("RSA_set0_factors", - DST_R_OPENSSLFAILURE)); - } - c->p = NULL; - c->q = NULL; - } - - if (c->dmp1 != NULL || c->dmq1 != NULL || c->iqmp != NULL) { - if (RSA_set0_crt_params(rsa, (BIGNUM *)c->dmp1, - (BIGNUM *)c->dmq1, - (BIGNUM *)c->iqmp) == 0) - { - CLEANUP(dst__openssl_toresult2("RSA_set0_crt_params", - DST_R_OPENSSLFAILURE)); - } - c->dmp1 = NULL; - c->dmq1 = NULL; - c->iqmp = NULL; - } - - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_new", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_set1_RSA(pkey, rsa); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_set1_RSA", - DST_R_OPENSSLFAILURE)); - } - - *retpkey = pkey; - pkey = NULL; - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_free(pkey); - RSA_free(rsa); - opensslrsa_components_free(c); - return result; -} -#else -static int -progress_cb(EVP_PKEY_CTX *ctx) { - void (*fptr)(int); - - fptr = EVP_PKEY_CTX_get_app_data(ctx); - if (fptr != NULL) { - int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); - fptr(p); - } - return 1; -} - -static isc_result_t -opensslrsa_generate_pkey_with_uri(size_t key_size, const char *label, - EVP_PKEY **retkey) { - EVP_PKEY_CTX *ctx = NULL; - OSSL_PARAM params[4]; - char *uri = UNCONST(label); - isc_result_t result; - int status; - - params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); - params[1] = OSSL_PARAM_construct_utf8_string( - "pkcs11_key_usage", (char *)"digitalSignature", 0); - params[2] = OSSL_PARAM_construct_size_t("rsa_keygen_bits", &key_size); - params[3] = OSSL_PARAM_construct_end(); - - ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_keygen_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen_init", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_CTX_set_params(ctx, params); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_set_params", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_generate(ctx, retkey); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_generate", - DST_R_OPENSSLFAILURE)); - } - - result = ISC_R_SUCCESS; -cleanup: - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslrsa_generate_pkey(unsigned int key_size, const char *label, BIGNUM *e, - void (*callback)(int), EVP_PKEY **retkey) { - EVP_PKEY_CTX *ctx; - isc_result_t result; - - if (label != NULL) { - return opensslrsa_generate_pkey_with_uri(key_size, label, - retkey); - } - - ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_keygen_init(ctx) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)key_size) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) != 1) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - - if (callback != NULL) { - EVP_PKEY_CTX_set_app_data(ctx, (void *)callback); - EVP_PKEY_CTX_set_cb(ctx, progress_cb); - } - - if (EVP_PKEY_keygen(ctx, retkey) != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_keygen", - DST_R_OPENSSLFAILURE)); - } - result = ISC_R_SUCCESS; -cleanup: - EVP_PKEY_CTX_free(ctx); - return result; -} - -static isc_result_t -opensslrsa_build_pkey(bool private, rsa_components_t *c, EVP_PKEY **retpkey) { - isc_result_t result; - int status; - OSSL_PARAM_BLD *bld = NULL; - OSSL_PARAM *params = NULL; - EVP_PKEY_CTX *ctx = NULL; - - bld = OSSL_PARAM_BLD_new(); - if (bld == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_new", - DST_R_OPENSSLFAILURE)); - } - if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1 || - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - - if (c->d != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, c->d) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->p != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, c->p) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->q != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, c->q) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->dmp1 != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, - c->dmp1) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->dmq1 != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, - c->dmq1) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - if (c->iqmp != NULL && - OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, - c->iqmp) != 1) - { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", - DST_R_OPENSSLFAILURE)); - } - - params = OSSL_PARAM_BLD_to_param(bld); - if (params == NULL) { - CLEANUP(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param", - DST_R_OPENSSLFAILURE)); - } - ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - if (ctx == NULL) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", - DST_R_OPENSSLFAILURE)); - } - status = EVP_PKEY_fromdata_init(ctx); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_fromdata_init", - DST_R_OPENSSLFAILURE)); - } - - status = EVP_PKEY_fromdata( - ctx, retpkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, - params); - if (status != 1) { - CLEANUP(dst__openssl_toresult2("EVP_PKEY_fromdata", - DST_R_OPENSSLFAILURE)); - } - result = ISC_R_SUCCESS; - -cleanup: - EVP_PKEY_CTX_free(ctx); - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(bld); - return result; -} -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ - static isc_result_t opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { isc_result_t result; - BIGNUM *e = BN_new(); EVP_PKEY *pkey = NULL; UNUSED(unused); - if (e == NULL) { - CLEANUP(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - } - /* * Reject incorrect RSA key lengths. */ @@ -769,12 +309,13 @@ opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { UNREACHABLE(); } - /* e = 65537 (0x10001, F4) */ - BN_set_bit(e, 0); - BN_set_bit(e, 16); - - CHECK(opensslrsa_generate_pkey(key->key_size, key->label, e, callback, - &pkey)); + if (key->label != NULL) { + CHECK(isc_ossl_wrap_generate_pkcs11_rsa_key( + key->label, key->key_size, &pkey)); + } else { + CHECK(isc_ossl_wrap_generate_rsa_key(callback, key->key_size, + &pkey)); + } key->keydata.pkeypair.pub = pkey; key->keydata.pkeypair.priv = pkey; @@ -783,7 +324,6 @@ opensslrsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { cleanup: EVP_PKEY_free(pkey); - BN_free(e); return result; } @@ -793,7 +333,7 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { unsigned int e_bytes; unsigned int mod_bytes; isc_result_t result; - rsa_components_t c = { 0 }; + isc_ossl_wrap_rsa_components_t c = { 0 }; REQUIRE(key->keydata.pkeypair.pub != NULL); @@ -819,7 +359,8 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { break; } - CHECK(opensslrsa_components_get(key, &c, false)); + CHECK(isc_ossl_wrap_rsa_public_components(key->keydata.pkeypair.pub, + &c)); mod_bytes = BN_num_bytes(c.n); e_bytes = BN_num_bytes(c.e); @@ -850,9 +391,8 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { isc_buffer_add(data, e_bytes + mod_bytes); - result = ISC_R_SUCCESS; cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); return result; } @@ -862,7 +402,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_region_t r; unsigned int e_bytes; unsigned int length; - rsa_components_t c = { .bnfree = true }; + isc_ossl_wrap_rsa_components_t c = { .needs_cleanup = true }; REQUIRE(opensslrsa_valid_key_alg(key->key_alg)); @@ -925,10 +465,11 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_buffer_forward(data, length); key->key_size = BN_num_bits(c.n); - result = opensslrsa_build_pkey(false, &c, &key->keydata.pkeypair.pub); + result = isc_ossl_wrap_load_rsa_public_from_components( + &c, &key->keydata.pkeypair.pub); cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); return result; } @@ -938,13 +479,16 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { dst_private_t priv = { 0 }; unsigned char *bufs[8] = { NULL }; unsigned short i = 0; - rsa_components_t c = { 0 }; + isc_ossl_wrap_rsa_components_t c = { 0 }; if (key->external) { return dst__privstruct_writefile(key, &priv, directory); } - CHECK(opensslrsa_components_get(key, &c, true)); + CHECK(isc_ossl_wrap_rsa_public_components(key->keydata.pkeypair.pub, + &c)); + CHECK(isc_ossl_wrap_rsa_secret_components(key->keydata.pkeypair.priv, + &c)); priv.elements[i].tag = TAG_RSA_MODULUS; priv.elements[i].length = BN_num_bytes(c.n); @@ -1038,7 +582,7 @@ cleanup: priv.elements[i].length); } } - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); return result; } @@ -1054,7 +598,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { isc_mem_t *mctx = NULL; const char *label = NULL; EVP_PKEY *pkey = NULL; - rsa_components_t c = { .bnfree = true }; + isc_ossl_wrap_rsa_components_t c = { .needs_cleanup = true }; REQUIRE(key != NULL); REQUIRE(opensslrsa_valid_key_alg(key->key_alg)); @@ -1157,7 +701,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { } key->key_size = BN_num_bits(c.n); - CHECK(opensslrsa_build_pkey(true, &c, &pkey)); + + CHECK(isc_ossl_wrap_load_rsa_secret_from_components(&c, &pkey)); /* Check that the public component matches if given */ if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { @@ -1169,7 +714,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { pkey = NULL; cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); EVP_PKEY_free(pkey); if (result != ISC_R_SUCCESS) { key->keydata.generic = NULL; @@ -1189,7 +734,7 @@ opensslrsa_fromlabel(dst_key_t *key, const char *label, const char *pin) { CHECK(dst__openssl_fromlabel(EVP_PKEY_RSA, label, pin, &pubpkey, &privpkey)); - if (!opensslrsa_check_exponent_bits(pubpkey, RSA_MAX_PUBEXP_BITS)) { + if (!isc_ossl_wrap_rsa_key_bits_leq(pubpkey, RSA_MAX_PUBEXP_BITS)) { CLEANUP(ISC_R_RANGE); } @@ -1301,7 +846,7 @@ static const unsigned char sha512_sig[] = static isc_result_t check_algorithm(unsigned short algorithm) { - rsa_components_t c = { .bnfree = true }; + isc_ossl_wrap_rsa_components_t c = { .needs_cleanup = true }; EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create(); EVP_PKEY *pkey = NULL; const EVP_MD *type = NULL; @@ -1312,19 +857,19 @@ check_algorithm(unsigned short algorithm) { switch (algorithm) { case DST_ALG_RSASHA1: case DST_ALG_NSEC3RSASHA1: - type = isc__crypto_sha1; /* SHA1 + RSA */ + type = isc__crypto_md[ISC_MD_SHA1]; /* SHA1 + RSA */ sig = sha1_sig; len = sizeof(sha1_sig) - 1; break; case DST_ALG_RSASHA256: case DST_ALG_RSASHA256PRIVATEOID: - type = isc__crypto_sha256; /* SHA256 + RSA */ + type = isc__crypto_md[ISC_MD_SHA256]; /* SHA256 + RSA */ sig = sha256_sig; len = sizeof(sha256_sig) - 1; break; case DST_ALG_RSASHA512: case DST_ALG_RSASHA512PRIVATEOID: - type = isc__crypto_sha512; + type = isc__crypto_md[ISC_MD_SHA512]; sig = sha512_sig; len = sizeof(sha512_sig) - 1; break; @@ -1338,7 +883,7 @@ check_algorithm(unsigned short algorithm) { c.e = BN_bin2bn(e_bytes, sizeof(e_bytes) - 1, NULL); c.n = BN_bin2bn(n_bytes, sizeof(n_bytes) - 1, NULL); - result = opensslrsa_build_pkey(false, &c, &pkey); + result = isc_ossl_wrap_load_rsa_public_from_components(&c, &pkey); INSIST(result == ISC_R_SUCCESS); /* @@ -1352,7 +897,7 @@ check_algorithm(unsigned short algorithm) { } cleanup: - opensslrsa_components_free(&c); + isc_ossl_wrap_rsa_components_cleanup(&c); EVP_PKEY_free(pkey); EVP_MD_CTX_destroy(evp_md_ctx); ERR_clear_error(); diff --git a/lib/isc/crypto/meson.build b/lib/isc/crypto/meson.build new file mode 100644 index 0000000000..e610fbe817 --- /dev/null +++ b/lib/isc/crypto/meson.build @@ -0,0 +1,16 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +isc_srcset.add( + when: 'HAVE_OPENSSL_3', + if_true: files('ossl3.c', 'ossl_common.c'), + if_false: files('ossl1_1.c', 'ossl_common.c'), +) diff --git a/lib/isc/crypto.c b/lib/isc/crypto/ossl1_1.c similarity index 50% rename from lib/isc/crypto.c rename to lib/isc/crypto/ossl1_1.c index 9e4347794f..f672057095 100644 --- a/lib/isc/crypto.c +++ b/lib/isc/crypto/ossl1_1.c @@ -11,92 +11,232 @@ * information regarding copyright ownership. */ +#include + #include #include #include #include #include -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - +#include #include +#include #include +#include +#include #include -#include +#include +#include #include +#define HMAC_KEY_MAGIC ISC_MAGIC('H', 'M', 'A', 'C') + +struct isc_hmac_key { + uint32_t magic; + uint32_t len; + isc_mem_t *mctx; + EVP_MD *md; + uint8_t secret[]; +}; + static isc_mem_t *isc__crypto_mctx = NULL; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -static OSSL_PROVIDER *base = NULL, *fips = NULL; -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - -const EVP_MD *isc__crypto_md5 = NULL; -const EVP_MD *isc__crypto_sha1 = NULL; -const EVP_MD *isc__crypto_sha224 = NULL; -const EVP_MD *isc__crypto_sha256 = NULL; -const EVP_MD *isc__crypto_sha384 = NULL; -const EVP_MD *isc__crypto_sha512 = NULL; - -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#define md_register_algorithm(alg, algname) \ - { \ - REQUIRE(isc__crypto_##alg == NULL); \ - isc__crypto_##alg = EVP_MD_fetch(NULL, algname, NULL); \ - if (isc__crypto_##alg == NULL) { \ - ERR_clear_error(); \ - } \ +#define md_register_algorithm(alg, upperalg) \ + { \ + isc__crypto_md[ISC_MD_##upperalg] = UNCONST(EVP_##alg()); \ + if (isc__crypto_md[ISC_MD_##upperalg] == NULL) { \ + ERR_clear_error(); \ + } \ } -#define md_unregister_algorithm(alg) \ - { \ - if (isc__crypto_##alg != NULL) { \ - EVP_MD_free(UNCONST(isc__crypto_##alg)); \ - isc__crypto_##alg = NULL; \ - } \ - } -#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ -#define md_register_algorithm(alg, algname) \ - { \ - isc__crypto_##alg = EVP_##alg(); \ - if (isc__crypto_##alg == NULL) { \ - ERR_clear_error(); \ - } \ - } -#define md_unregister_algorithm(alg) -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - static isc_result_t register_algorithms(void) { if (!isc_crypto_fips_mode()) { - md_register_algorithm(md5, "MD5"); + md_register_algorithm(md5, MD5); } - md_register_algorithm(sha1, "SHA1"); - md_register_algorithm(sha224, "SHA224"); - md_register_algorithm(sha256, "SHA256"); - md_register_algorithm(sha384, "SHA384"); - md_register_algorithm(sha512, "SHA512"); + md_register_algorithm(sha1, SHA1); + md_register_algorithm(sha224, SHA224); + md_register_algorithm(sha256, SHA256); + md_register_algorithm(sha384, SHA384); + md_register_algorithm(sha512, SHA512); return ISC_R_SUCCESS; } -static void -unregister_algorithms(void) { - md_unregister_algorithm(sha512); - md_unregister_algorithm(sha384); - md_unregister_algorithm(sha256); - md_unregister_algorithm(sha224); - md_unregister_algorithm(sha1); - md_unregister_algorithm(md5); +#undef md_unregister_algorithm + +/* + * HMAC Notes + * + * For pre-3.0 libcrypto, we use HMAC_CTX instead of the EVP_PKEY API. + * + * EVP_PKEY will call HMAC_* functions internally so there is no need to add + * even more vtables. + */ + +isc_result_t +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, + const unsigned char *buf, const size_t len, unsigned char *digest, + unsigned int *digestlen) { + EVP_MD *md; + + REQUIRE(type < ISC_MD_MAX); + + md = isc__crypto_md[type]; + if (md == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + if (HMAC(md, key, keylen, buf, len, digest, digestlen) == NULL) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; } -#undef md_unregister_algorithm -#undef md_register_algorithm +isc_result_t +isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len, + isc_mem_t *mctx, isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + EVP_MD *md; -#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L + REQUIRE(keyp != NULL && *keyp == NULL); + REQUIRE(type < ISC_MD_MAX); + + md = isc__crypto_md[type]; + if (md == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + key = isc_mem_get(mctx, STRUCT_FLEX_SIZE(key, secret, len)); + *key = (isc_hmac_key_t){ + .magic = HMAC_KEY_MAGIC, + .len = len, + .md = md, + }; + memmove(key->secret, secret, len); + isc_mem_attach(mctx, &key->mctx); + + *keyp = key; + + return ISC_R_SUCCESS; +} + +void +isc_hmac_key_destroy(isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + + REQUIRE(keyp != NULL && *keyp != NULL); + REQUIRE((*keyp)->magic == HMAC_KEY_MAGIC); + + key = *keyp; + *keyp = NULL; + + key->magic = 0x00; + + isc_safe_memwipe(key->secret, sizeof(key->len)); + + isc_mem_putanddetach(&key->mctx, key, + STRUCT_FLEX_SIZE(key, secret, key->len)); +} + +isc_region_t +isc_hmac_key_expose(isc_hmac_key_t *key) { + REQUIRE(key != NULL && key->magic == HMAC_KEY_MAGIC); + + return (isc_region_t){ .base = key->secret, .length = key->len }; +} + +bool +isc_hmac_key_equal(isc_hmac_key_t *a, isc_hmac_key_t *b) { + REQUIRE(a != NULL && a->magic == HMAC_KEY_MAGIC); + REQUIRE(b != NULL && b->magic == HMAC_KEY_MAGIC); + + if (a->md != b->md) { + return false; + } + + if (a->len != b->len) { + return false; + } + + return isc_safe_memequal(a->secret, b->secret, a->len); +} + +isc_hmac_t * +isc_hmac_new(void) { + HMAC_CTX *ctx = HMAC_CTX_new(); + RUNTIME_CHECK(ctx != NULL); + return ctx; +} + +void +isc_hmac_free(isc_hmac_t *hmac) { + if (hmac != NULL) { + HMAC_CTX_free(hmac); + } +} + +isc_result_t +isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key) { + REQUIRE(hmac != NULL); + REQUIRE(key != NULL && key->magic == HMAC_KEY_MAGIC); + + if (HMAC_Init_ex(hmac, key->secret, key->len, key->md, NULL) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len) { + REQUIRE(hmac != NULL); + + if (buf == NULL || len == 0) { + return ISC_R_SUCCESS; + } + + if (HMAC_Update(hmac, buf, len) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out) { + unsigned int len; + + REQUIRE(hmac != NULL); + REQUIRE(out != NULL); + + /* + * LibreSSL changes HMAC_size's return from size_t to int but keeps the + * size_t signature in its manpage. + * + * Cast it instead of accepting LibreSSL's man(page)splaining. + */ + len = isc_buffer_availablelength(out); + if (len < (unsigned int)HMAC_size(hmac)) { + return ISC_R_NOSPACE; + } + + if (HMAC_Final(hmac, isc_buffer_used(out), &len) != 1) { + return ISC_R_CRYPTOFAILURE; + } + + isc_buffer_add(out, len); + + return ISC_R_SUCCESS; +} + +#ifndef LIBRESSL_VERSION_NUMBER /* * This was crippled with LibreSSL, so just skip it: * https://cvsweb.openbsd.org/src/lib/libcrypto/Attic/mem.c @@ -165,50 +305,9 @@ isc__crypto_free_ex(void *ptr, const char *file, int line) { #endif /* ISC_MEM_TRACKLINES */ -#endif /* !defined(LIBRESSL_VERSION_NUMBER) */ +#endif /* !LIBRESSL_VERSION_NUMBER */ -#if defined(HAVE_EVP_DEFAULT_PROPERTIES_ENABLE_FIPS) -bool -isc_crypto_fips_mode(void) { - return EVP_default_properties_is_fips_enabled(NULL) != 0; -} - -isc_result_t -isc_crypto_fips_enable(void) { - if (isc_crypto_fips_mode()) { - return ISC_R_SUCCESS; - } - - INSIST(fips == NULL); - fips = OSSL_PROVIDER_load(NULL, "fips"); - if (fips == NULL) { - return isc_tlserr2result( - ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, - "OSSL_PROVIDER_load", ISC_R_CRYPTOFAILURE); - } - - INSIST(base == NULL); - base = OSSL_PROVIDER_load(NULL, "base"); - if (base == NULL) { - OSSL_PROVIDER_unload(fips); - return isc_tlserr2result( - ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, - "OSS_PROVIDER_load", ISC_R_CRYPTOFAILURE); - } - - if (EVP_default_properties_enable_fips(NULL, 1) == 0) { - return isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, - ISC_LOGMODULE_CRYPTO, - "EVP_default_properties_enable_fips", - ISC_R_CRYPTOFAILURE); - } - - unregister_algorithms(); - register_algorithms(); - - return ISC_R_SUCCESS; -} -#elif defined(HAVE_FIPS_MODE) +#ifdef HAVE_FIPS_MODE bool isc_crypto_fips_mode(void) { return FIPS_mode() != 0; @@ -221,12 +320,11 @@ isc_crypto_fips_enable(void) { } if (FIPS_mode_set(1) == 0) { - return isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, - ISC_LOGMODULE_CRYPTO, "FIPS_mode_set", - ISC_R_CRYPTOFAILURE); + return isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "FIPS_mode_set", ISC_R_CRYPTOFAILURE); } - unregister_algorithms(); register_algorithms(); return ISC_R_SUCCESS; @@ -256,7 +354,7 @@ isc__crypto_initialize(void) { isc_mem_setdebugging(isc__crypto_mctx, 0); isc_mem_setdestroycheck(isc__crypto_mctx, false); -#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#ifndef LIBRESSL_VERSION_NUMBER /* * CRYPTO_set_mem_(_ex)_functions() returns 1 on success or 0 on * failure, which means OpenSSL already allocated some memory. There's @@ -265,8 +363,7 @@ isc__crypto_initialize(void) { (void)CRYPTO_set_mem_functions(isc__crypto_malloc_ex, isc__crypto_realloc_ex, isc__crypto_free_ex); -#endif /* !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \ - 0x30000000L */ +#endif /* !LIBRESSL_VERSION_NUMBER */ #if defined(OPENSSL_INIT_NO_ATEXIT) /* @@ -290,8 +387,9 @@ isc__crypto_initialize(void) { /* Protect ourselves against unseeded PRNG */ if (RAND_status() != 1) { - isc_tlserr2result(ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, - "RAND_status", ISC_R_CRYPTOFAILURE); + isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "RAND_status", ISC_R_CRYPTOFAILURE); FATAL_ERROR("OpenSSL pseudorandom number generator " "cannot be initialized (see the `PRNG not " "seeded' message in the OpenSSL FAQ)"); @@ -300,18 +398,6 @@ isc__crypto_initialize(void) { void isc__crypto_shutdown(void) { - unregister_algorithms(); - -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - if (base != NULL) { - OSSL_PROVIDER_unload(base); - } - - if (fips != NULL) { - OSSL_PROVIDER_unload(fips); - } -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - OPENSSL_cleanup(); isc_mem_detach(&isc__crypto_mctx); diff --git a/lib/isc/crypto/ossl3.c b/lib/isc/crypto/ossl3.c new file mode 100644 index 0000000000..1c2f3cab9d --- /dev/null +++ b/lib/isc/crypto/ossl3.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct isc_hmac_key { + uint32_t magic; + uint32_t len; + isc_mem_t *mctx; + const OSSL_PARAM *params; + uint8_t secret[]; +}; + +constexpr uint32_t hmac_key_magic = ISC_MAGIC('H', 'M', 'A', 'C'); + +static isc_mem_t *isc__crypto_mctx = NULL; + +static OSSL_PROVIDER *base = NULL, *fips = NULL; + +static EVP_MAC *evp_hmac = NULL; + +static OSSL_PARAM md_to_hmac_params[ISC_MD_MAX][2] = { + [ISC_MD_UNKNOWN] = { OSSL_PARAM_END }, + [ISC_MD_MD5] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("MD5"), sizeof("MD5") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA1] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA1"), sizeof("SHA1") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA224] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-224"), sizeof("SHA2-224") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA256] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-256"), sizeof("SHA2-256") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA384] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-384"), sizeof("SHA2-384") - 1), + OSSL_PARAM_END, + }, + [ISC_MD_SHA512] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-512"), sizeof("SHA2-512") - 1), + OSSL_PARAM_END, + }, +}; + +#define md_register_algorithm(alg) \ + { \ + REQUIRE(isc__crypto_md[ISC_MD_##alg] == NULL); \ + isc__crypto_md[ISC_MD_##alg] = EVP_MD_fetch(NULL, #alg, NULL); \ + if (isc__crypto_md[ISC_MD_##alg] == NULL) { \ + ERR_clear_error(); \ + } \ + } + +static isc_result_t +register_algorithms(void) { + if (!isc_crypto_fips_mode()) { + md_register_algorithm(MD5); + } + + md_register_algorithm(SHA1); + md_register_algorithm(SHA224); + md_register_algorithm(SHA256); + md_register_algorithm(SHA384); + md_register_algorithm(SHA512); + + /* We _must_ have HMAC */ + evp_hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (evp_hmac == NULL) { + ERR_clear_error(); + FATAL_ERROR("OpenSSL failed to find an HMAC implementation. " + "Please make sure the default provider has an " + "EVP_MAC-HMAC implementation"); + } + + return ISC_R_SUCCESS; +} + +static void +unregister_algorithms(void) { + for (size_t i = 0; i < ISC_MD_MAX; i++) { + if (isc__crypto_md[i] != NULL) { + EVP_MD_free(isc__crypto_md[i]); + isc__crypto_md[i] = NULL; + } + } + + INSIST(evp_hmac != NULL); + EVP_MAC_free(evp_hmac); + evp_hmac = NULL; +} + +#undef md_register_algorithm + +/* + * HMAC + */ + +/* + * Do not call EVP_Q_mac or HMAC (since it calls EVP_Q_mac internally) + * + * Each invocation of the EVP_Q_mac function causes an explicit fetch. + */ +isc_result_t +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, + const unsigned char *buf, const size_t len, unsigned char *digest, + unsigned int *digestlen) { + EVP_MAC_CTX *ctx; + size_t maclen; + + REQUIRE(type < ISC_MD_MAX); + + if (isc__crypto_md[type] == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + ctx = EVP_MAC_CTX_new(evp_hmac); + RUNTIME_CHECK(ctx != NULL); + + if (EVP_MAC_init(ctx, key, keylen, md_to_hmac_params[type]) != 1) { + goto fail; + } + + if (EVP_MAC_update(ctx, buf, len) != 1) { + goto fail; + } + + maclen = *digestlen; + if (EVP_MAC_final(ctx, digest, &maclen, maclen) != 1) { + goto fail; + } + + *digestlen = maclen; + + EVP_MAC_CTX_free(ctx); + return ISC_R_SUCCESS; + +fail: + ERR_clear_error(); + EVP_MAC_CTX_free(ctx); + return ISC_R_CRYPTOFAILURE; +} + +/* + * You do not need to process the key to fit the block size. + * + * https://github.com/openssl/openssl/blob/925e4fba1098036e8f8d22652cff6f64c5c7d571/crypto/hmac/hmac.c#L61-L80 + */ +isc_result_t +isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len, + isc_mem_t *mctx, isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + uint8_t digest[ISC_MAX_MD_SIZE]; + unsigned int digest_len = sizeof(digest); + size_t key_len; + + REQUIRE(keyp != NULL && *keyp == NULL); + REQUIRE(type < ISC_MD_MAX); + + if (isc__crypto_md[type] == NULL) { + return ISC_R_NOTIMPLEMENTED; + } + + if (len > (size_t)EVP_MD_block_size(isc__crypto_md[type])) { + RETERR(isc_md(type, secret, len, digest, &digest_len)); + secret = digest; + key_len = digest_len; + } else { + key_len = len; + } + + key = isc_mem_get(mctx, STRUCT_FLEX_SIZE(key, secret, key_len)); + *key = (isc_hmac_key_t){ + .magic = hmac_key_magic, + .len = key_len, + .params = md_to_hmac_params[type], + }; + memmove(key->secret, secret, key_len); + isc_mem_attach(mctx, &key->mctx); + + *keyp = key; + + return ISC_R_SUCCESS; +} + +void +isc_hmac_key_destroy(isc_hmac_key_t **keyp) { + isc_hmac_key_t *key; + + REQUIRE(keyp != NULL && *keyp != NULL); + REQUIRE((*keyp)->magic == hmac_key_magic); + + key = *keyp; + *keyp = NULL; + + key->magic = 0x00; + + isc_safe_memwipe(key->secret, key->len); + isc_mem_putanddetach(&key->mctx, key, + STRUCT_FLEX_SIZE(key, secret, key->len)); +} + +isc_region_t +isc_hmac_key_expose(isc_hmac_key_t *key) { + REQUIRE(key != NULL && key->magic == hmac_key_magic); + + return (isc_region_t){ .base = key->secret, .length = key->len }; +} + +bool +isc_hmac_key_equal(isc_hmac_key_t *a, isc_hmac_key_t *b) { + REQUIRE(a != NULL && a->magic == hmac_key_magic); + REQUIRE(b != NULL && b->magic == hmac_key_magic); + + if (a->params != b->params) { + return false; + } + + if (a->len != b->len) { + return false; + } + + return isc_safe_memequal(a->secret, b->secret, a->len); +} + +isc_hmac_t * +isc_hmac_new(void) { + EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(evp_hmac); + RUNTIME_CHECK(ctx != NULL); + return ctx; +} + +void +isc_hmac_free(isc_hmac_t *hmac) { + EVP_MAC_CTX_free(hmac); +} + +isc_result_t +isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key) { + REQUIRE(key != NULL && key->magic == hmac_key_magic); + REQUIRE(hmac != NULL); + + if (EVP_MAC_init(hmac, key->secret, key->len, key->params) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len) { + REQUIRE(hmac != NULL); + + if (buf == NULL || len == 0) { + return ISC_R_SUCCESS; + } + + if (EVP_MAC_update(hmac, buf, len) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out) { + size_t len; + + REQUIRE(hmac != NULL); + + len = isc_buffer_availablelength(out); + if (len < EVP_MAC_CTX_get_mac_size(hmac)) { + return ISC_R_NOSPACE; + } + + if (EVP_MAC_final(hmac, isc_buffer_used(out), &len, len) != 1) { + ERR_clear_error(); + return ISC_R_CRYPTOFAILURE; + } + + isc_buffer_add(out, len); + + return ISC_R_SUCCESS; +} + +#if ISC_MEM_TRACKLINES +/* + * We use the internal isc__mem API here, so we can pass the file and line + * arguments passed from OpenSSL >= 1.1.0 to our memory functions for better + * tracking of the OpenSSL allocations. Without this, we would always just see + * isc__crypto_{malloc,realloc,free} in the tracking output, but with this in + * place we get to see the places in the OpenSSL code where the allocations + * happen. + */ + +static void * +isc__crypto_malloc_ex(size_t size, const char *file, int line) { + return isc__mem_allocate(isc__crypto_mctx, size, 0, __func__, file, + (unsigned int)line); +} + +static void * +isc__crypto_realloc_ex(void *ptr, size_t size, const char *file, int line) { + return isc__mem_reallocate(isc__crypto_mctx, ptr, size, 0, __func__, + file, (unsigned int)line); +} + +static void +isc__crypto_free_ex(void *ptr, const char *file, int line) { + if (ptr == NULL) { + return; + } + if (isc__crypto_mctx != NULL) { + isc__mem_free(isc__crypto_mctx, ptr, 0, __func__, file, + (unsigned int)line); + } +} + +#else /* ISC_MEM_TRACKLINES */ + +static void * +isc__crypto_malloc_ex(size_t size, const char *file, int line) { + UNUSED(file); + UNUSED(line); + return isc_mem_allocate(isc__crypto_mctx, size); +} + +static void * +isc__crypto_realloc_ex(void *ptr, size_t size, const char *file, int line) { + UNUSED(file); + UNUSED(line); + return isc_mem_reallocate(isc__crypto_mctx, ptr, size); +} + +static void +isc__crypto_free_ex(void *ptr, const char *file, int line) { + UNUSED(file); + UNUSED(line); + if (ptr == NULL) { + return; + } + if (isc__crypto_mctx != NULL) { + isc__mem_free(isc__crypto_mctx, ptr, 0); + } +} + +#endif /* ISC_MEM_TRACKLINES */ + +bool +isc_crypto_fips_mode(void) { + return EVP_default_properties_is_fips_enabled(NULL) != 0; +} + +isc_result_t +isc_crypto_fips_enable(void) { + if (isc_crypto_fips_mode()) { + return ISC_R_SUCCESS; + } + + INSIST(fips == NULL); + fips = OSSL_PROVIDER_load(NULL, "fips"); + if (fips == NULL) { + return isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "OSSL_PROVIDER_load", ISC_R_CRYPTOFAILURE); + } + + INSIST(base == NULL); + base = OSSL_PROVIDER_load(NULL, "base"); + if (base == NULL) { + OSSL_PROVIDER_unload(fips); + return isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "OSS_PROVIDER_load", ISC_R_CRYPTOFAILURE); + } + + if (EVP_default_properties_enable_fips(NULL, 1) == 0) { + return isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "EVP_default_properties_enable_fips", + ISC_R_CRYPTOFAILURE); + } + + unregister_algorithms(); + register_algorithms(); + + return ISC_R_SUCCESS; +} + +void +isc__crypto_setdestroycheck(bool check) { + isc_mem_setdestroycheck(isc__crypto_mctx, check); +} + +void +isc__crypto_initialize(void) { + /* + * We call OPENSSL_cleanup() manually, in a correct order, thus disable + * the automatic atexit() handler. + */ + uint64_t opts = OPENSSL_INIT_LOAD_CONFIG | OPENSSL_INIT_NO_ATEXIT; + + isc_mem_create("OpenSSL", &isc__crypto_mctx); + isc_mem_setdebugging(isc__crypto_mctx, 0); + isc_mem_setdestroycheck(isc__crypto_mctx, false); + + /* + * CRYPTO_set_mem_(_ex)_functions() returns 1 on success or 0 on + * failure, which means OpenSSL already allocated some memory. There's + * nothing we can do about it. + */ + (void)CRYPTO_set_mem_functions(isc__crypto_malloc_ex, + isc__crypto_realloc_ex, + isc__crypto_free_ex); + + RUNTIME_CHECK(OPENSSL_init_ssl(opts, NULL) == 1); + + register_algorithms(); + +#if defined(ENABLE_FIPS_MODE) + if (isc_crypto_fips_enable() != ISC_R_SUCCESS) { + ERR_clear_error(); + FATAL_ERROR("Failed to toggle FIPS mode but is " + "required for this build"); + } +#endif + + /* Protect ourselves against unseeded PRNG */ + if (RAND_status() != 1) { + isc_ossl_wrap_logged_toresult( + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, + "RAND_status", ISC_R_CRYPTOFAILURE); + FATAL_ERROR("OpenSSL pseudorandom number generator " + "cannot be initialized (see the `PRNG not " + "seeded' message in the OpenSSL FAQ)"); + } +} + +void +isc__crypto_shutdown(void) { + unregister_algorithms(); + + if (base != NULL) { + OSSL_PROVIDER_unload(base); + } + + if (fips != NULL) { + OSSL_PROVIDER_unload(fips); + } + + OPENSSL_cleanup(); + + isc_mem_detach(&isc__crypto_mctx); +} diff --git a/lib/isc/crypto/ossl_common.c b/lib/isc/crypto/ossl_common.c new file mode 100644 index 0000000000..8b5d56925b --- /dev/null +++ b/lib/isc/crypto/ossl_common.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include + +EVP_MD *isc__crypto_md[] = { + [ISC_MD_UNKNOWN] = NULL, [ISC_MD_MD5] = NULL, [ISC_MD_SHA1] = NULL, + [ISC_MD_SHA224] = NULL, [ISC_MD_SHA256] = NULL, [ISC_MD_SHA384] = NULL, + [ISC_MD_SHA512] = NULL, +}; diff --git a/lib/isc/hmac.c b/lib/isc/hmac.c deleted file mode 100644 index 46582ea9ec..0000000000 --- a/lib/isc/hmac.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * SPDX-License-Identifier: MPL-2.0 - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "openssl_shim.h" - -isc_hmac_t * -isc_hmac_new(void) { - EVP_MD_CTX *hmac_st = EVP_MD_CTX_new(); - RUNTIME_CHECK(hmac_st != NULL); - return (isc_hmac_t *)hmac_st; -} - -void -isc_hmac_free(isc_hmac_t *hmac_st) { - if (hmac_st == NULL) { - return; - } - - EVP_MD_CTX_free((EVP_MD_CTX *)hmac_st); -} - -isc_result_t -isc_hmac_init(isc_hmac_t *hmac_st, const void *key, const size_t keylen, - const isc_md_type_t *md_type) { - EVP_PKEY *pkey; - - REQUIRE(hmac_st != NULL); - REQUIRE(key != NULL); - REQUIRE(keylen <= INT_MAX); - - if (md_type == NULL) { - return ISC_R_NOTIMPLEMENTED; - } - - pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, keylen); - if (pkey == NULL) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - if (EVP_DigestSignInit(hmac_st, NULL, md_type, NULL, pkey) != 1) { - EVP_PKEY_free(pkey); - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - EVP_PKEY_free(pkey); - - return ISC_R_SUCCESS; -} - -isc_result_t -isc_hmac_reset(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - if (EVP_MD_CTX_reset(hmac_st) != 1) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - return ISC_R_SUCCESS; -} - -isc_result_t -isc_hmac_update(isc_hmac_t *hmac_st, const unsigned char *buf, - const size_t len) { - REQUIRE(hmac_st != NULL); - - if (buf == NULL || len == 0) { - return ISC_R_SUCCESS; - } - - if (EVP_DigestSignUpdate(hmac_st, buf, len) != 1) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - return ISC_R_SUCCESS; -} - -isc_result_t -isc_hmac_final(isc_hmac_t *hmac_st, unsigned char *digest, - unsigned int *digestlen) { - REQUIRE(hmac_st != NULL); - REQUIRE(digest != NULL); - REQUIRE(digestlen != NULL); - - size_t len = *digestlen; - - if (EVP_DigestSignFinal(hmac_st, digest, &len) != 1) { - ERR_clear_error(); - return ISC_R_CRYPTOFAILURE; - } - - *digestlen = (unsigned int)len; - - return ISC_R_SUCCESS; -} - -const isc_md_type_t * -isc_hmac_get_md_type(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - return EVP_MD_CTX_get0_md(hmac_st); -} - -size_t -isc_hmac_get_size(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - return (size_t)EVP_MD_CTX_size(hmac_st); -} - -int -isc_hmac_get_block_size(isc_hmac_t *hmac_st) { - REQUIRE(hmac_st != NULL); - - return EVP_MD_CTX_block_size(hmac_st); -} - -isc_result_t -isc_hmac(const isc_md_type_t *type, const void *key, const size_t keylen, - const unsigned char *buf, const size_t len, unsigned char *digest, - unsigned int *digestlen) { - isc_result_t res; - isc_hmac_t *hmac_st = isc_hmac_new(); - - res = isc_hmac_init(hmac_st, key, keylen, type); - if (res != ISC_R_SUCCESS) { - goto end; - } - - res = isc_hmac_update(hmac_st, buf, len); - if (res != ISC_R_SUCCESS) { - goto end; - } - - res = isc_hmac_final(hmac_st, digest, digestlen); - if (res != ISC_R_SUCCESS) { - goto end; - } -end: - isc_hmac_free(hmac_st); - - return res; -} diff --git a/lib/isc/include/isc/crypto.h b/lib/isc/include/isc/crypto.h index 14bdd46933..cd32da9391 100644 --- a/lib/isc/include/isc/crypto.h +++ b/lib/isc/include/isc/crypto.h @@ -13,17 +13,8 @@ #pragma once -#include - #include -extern const EVP_MD *isc__crypto_md5; -extern const EVP_MD *isc__crypto_sha1; -extern const EVP_MD *isc__crypto_sha224; -extern const EVP_MD *isc__crypto_sha256; -extern const EVP_MD *isc__crypto_sha384; -extern const EVP_MD *isc__crypto_sha512; - bool isc_crypto_fips_mode(void); /* diff --git a/lib/isc/include/isc/hmac.h b/lib/isc/include/isc/hmac.h index 0a6ba8c4ff..06f0893f98 100644 --- a/lib/isc/include/isc/hmac.h +++ b/lib/isc/include/isc/hmac.h @@ -18,12 +18,16 @@ #pragma once +#include + #include #include #include typedef void isc_hmac_t; +typedef struct isc_hmac_key isc_hmac_key_t; + /** * isc_hmac: * @type: the digest type @@ -43,10 +47,50 @@ typedef void isc_hmac_t; * of digest written to @digest. */ isc_result_t -isc_hmac(const isc_md_type_t *type, const void *key, const size_t keylen, +isc_hmac(isc_md_type_t type, const void *key, const size_t keylen, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen); +/* + * isc_hmac_key_create: + * @type: the digest type + * @secret: the secret key + * @len: length of the secret key + * @mctx: memory context + * @keyp: pointer to the key pointer + * + * This initializes the an HMAC key bound to a specific digest. + */ +isc_result_t +isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len, + isc_mem_t *mctx, isc_hmac_key_t **keyp); + +void +isc_hmac_key_destroy(isc_hmac_key_t **keyp); + +/** + * isc_hmac_key_expose: + * @key: The key to be exposed + * + * This function exposes the raw bytes of the HMAC key. + * + * The region is bound to the lifetime of the @key and MUST NOT be used after + * calling isc_hmac_key_destroy. + */ +isc_region_t +isc_hmac_key_expose(isc_hmac_key_t *key); + +/** + * isc_hmac_key_equal: + * @key1: The first key to be compared + * @key2: The second key to be compared + * + * Returns true is the two HMAC keys have the same contents and use the same + * digest function. + */ +bool +isc_hmac_key_equal(isc_hmac_key_t *key1, isc_hmac_key_t *key2); + /** * isc_hmac_new: * @@ -68,26 +112,11 @@ isc_hmac_free(isc_hmac_t *hmac); * isc_hmac_init: * @md: HMAC context * @key: HMAC key - * @keylen: HMAC key length - * @type: digest type * - * This function sets up HMAC context to use a hash function of @type and key - * @key which is @keylen bytes long. - */ - -isc_result_t -isc_hmac_init(isc_hmac_t *hmac, const void *key, const size_t keylen, - const isc_md_type_t *type); - -/** - * isc_hmac_reset: - * @hmac: HMAC context - * - * This function resets the HMAC context. This can be used to reuse an already - * existing context. + * This function sets up HMAC context to use the secret specified in @key. */ isc_result_t -isc_hmac_reset(isc_hmac_t *hmac); +isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key); /** * isc_hmac_update: @@ -104,44 +133,13 @@ isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len); /** * isc_hmac_final: * @hmac: HMAC context - * @digest: the output buffer - * @digestlen: in: the length of @digest - * out: the length of the data written to @digest + * @out: the output buffer * * This function retrieves the message authentication code from @hmac and places - * it in @digest, which must have space for the hash function output. @digestlen - * is used to pass in the length of the digest buffer and returns the length - * of digest written to @digest. After calling this function no additional - * calls to isc_hmac_update() can be made. + * it in @out, which must have space for the hash function output. + * + * After calling this function no additional calls to isc_hmac_update() can be + * made. Use isc_hmac_init() to reset/re-initialize the context. */ isc_result_t -isc_hmac_final(isc_hmac_t *hmac, unsigned char *digest, - unsigned int *digestlen); - -/** - * isc_hmac_md_type: - * @hmac: HMAC context - * - * This function return the isc_md_type_t previously set for the supplied - * HMAC context or NULL if no isc_md_type_t has been set. - */ -const isc_md_type_t * -isc_hmac_get_md_type(isc_hmac_t *hmac); - -/** - * isc_hmac_get_size: - * - * This function return the size of the message digest when passed an isc_hmac_t - * structure, i.e. the size of the hash. - */ -size_t -isc_hmac_get_size(isc_hmac_t *hmac); - -/** - * isc_hmac_get_block_size: - * - * This function return the block size of the message digest when passed an - * isc_hmac_t structure. - */ -int -isc_hmac_get_block_size(isc_hmac_t *hmac); +isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out); diff --git a/lib/isc/include/isc/md.h b/lib/isc/include/isc/md.h index 41c3447565..f8f89bba68 100644 --- a/lib/isc/include/isc/md.h +++ b/lib/isc/include/isc/md.h @@ -18,7 +18,6 @@ #pragma once -#include #include #include @@ -35,27 +34,29 @@ typedef void isc_md_t; * * Enumeration of supported message digest algorithms. */ -typedef void isc_md_type_t; +typedef enum isc_md_type { + ISC_MD_UNKNOWN = 0x00, + ISC_MD_MD5 = 0x01, + ISC_MD_SHA1 = 0x02, + ISC_MD_SHA224 = 0x03, + ISC_MD_SHA256 = 0x04, + ISC_MD_SHA384 = 0x05, + ISC_MD_SHA512 = 0x06, + ISC_MD_MAX = 0x07, +} isc_md_type_t; -#define ISC_MD_MD5 isc__crypto_md5 -#define ISC_MD_SHA1 isc__crypto_sha1 -#define ISC_MD_SHA224 isc__crypto_sha224 -#define ISC_MD_SHA256 isc__crypto_sha256 -#define ISC_MD_SHA384 isc__crypto_sha384 -#define ISC_MD_SHA512 isc__crypto_sha512 - -#define ISC_MD5_DIGESTLENGTH isc_md_type_get_size(ISC_MD_MD5) -#define ISC_MD5_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_MD5) -#define ISC_SHA1_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA1) -#define ISC_SHA1_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA1) -#define ISC_SHA224_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA224) -#define ISC_SHA224_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA224) -#define ISC_SHA256_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA256) -#define ISC_SHA256_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA256) -#define ISC_SHA384_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA384) -#define ISC_SHA384_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA384) -#define ISC_SHA512_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA512) -#define ISC_SHA512_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA512) +#define ISC_MD5_DIGESTLENGTH 16 +#define ISC_MD5_BLOCK_LENGTH 64 +#define ISC_SHA1_DIGESTLENGTH 20 +#define ISC_SHA1_BLOCK_LENGTH 64 +#define ISC_SHA224_DIGESTLENGTH 28 +#define ISC_SHA224_BLOCK_LENGTH 64 +#define ISC_SHA256_DIGESTLENGTH 32 +#define ISC_SHA256_BLOCK_LENGTH 64 +#define ISC_SHA384_DIGESTLENGTH 48 +#define ISC_SHA384_BLOCK_LENGTH 128 +#define ISC_SHA512_DIGESTLENGTH 64 +#define ISC_SHA512_BLOCK_LENGTH 128 #define ISC_MAX_MD_SIZE 64U /* EVP_MAX_MD_SIZE */ #define ISC_MAX_BLOCK_SIZE 128U /* ISC_SHA512_BLOCK_LENGTH */ @@ -74,7 +75,7 @@ typedef void isc_md_type_t; * at @digestlen, at most ISC_MAX_MD_SIZE bytes will be written. */ isc_result_t -isc_md(const isc_md_type_t *type, const unsigned char *buf, const size_t len, +isc_md(isc_md_type_t type, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen); /** @@ -93,7 +94,7 @@ isc_md_new(void); * to it. */ void -isc_md_free(isc_md_t *); +isc_md_free(isc_md_t *md); /** * isc_md_init: @@ -104,7 +105,7 @@ isc_md_free(isc_md_t *); * initialized before calling this function. */ isc_result_t -isc_md_init(isc_md_t *, const isc_md_type_t *md_type); +isc_md_init(isc_md_t *md, isc_md_type_t type); /** * isc_md_reset: @@ -144,16 +145,6 @@ isc_md_update(isc_md_t *md, const unsigned char *buf, const size_t len); isc_result_t isc_md_final(isc_md_t *md, unsigned char *digest, unsigned int *digestlen); -/** - * isc_md_get_type: - * @md: message digest contezt - * - * This function return the isc_md_type_t previously set for the supplied - * message digest context or NULL if no isc_md_type_t has been set. - */ -const isc_md_type_t * -isc_md_get_md_type(isc_md_t *md); - /** * isc_md_size: * @@ -172,15 +163,6 @@ isc_md_get_size(isc_md_t *md); size_t isc_md_get_block_size(isc_md_t *md); -/** - * isc_md_size: - * - * This function return the size of the message digest when passed an - * isc_md_type_t , i.e. the size of the hash. - */ -size_t -isc_md_type_get_size(const isc_md_type_t *md_type); - /** * isc_md_block_size: * @@ -188,4 +170,4 @@ isc_md_type_get_size(const isc_md_type_t *md_type); * isc_md_type_t. */ size_t -isc_md_type_get_block_size(const isc_md_type_t *md_type); +isc_md_type_get_block_size(isc_md_type_t type); diff --git a/lib/isc/include/isc/ossl_wrap.h b/lib/isc/include/isc/ossl_wrap.h new file mode 100644 index 0000000000..4831fab405 --- /dev/null +++ b/lib/isc/include/isc/ossl_wrap.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include +#include + +#include +#include + +#include +#include + +#define isc_ossl_wrap_logged_toresult(category, module, funcname, fallback) \ + isc__ossl_wrap_logged_toresult(category, module, funcname, fallback, \ + __FILE__, __LINE__) + +typedef struct isc_ossl_wrap_rsa_components { + bool needs_cleanup; + BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; +} isc_ossl_wrap_rsa_components_t; + +isc_result_t +isc_ossl_wrap_generate_p256_key(EVP_PKEY **pkeyp); +/*% + * Generates an uncompressed, named P-256 secret key. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_p256_key(char *uri, EVP_PKEY **pkeyp); +/*% + * Generates a P-256 secret key using the PKCS#11 label specified at `uri`. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + * \li `uri != NULL` and is a NUL-terminated string + */ + +isc_result_t +isc_ossl_wrap_validate_p256_pkey(EVP_PKEY *pkey); +/*% + * Validatest that a EVP_PKEY is a P-256 EC key. + * + * Requires: + * \li `pkey != NULL` + * \li pkey is a valid EVP_PKEY + */ + +isc_result_t +isc_ossl_wrap_load_p256_public_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a verifying `EVP_PKEY` using the P-256 public key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 64` + */ + +isc_result_t +isc_ossl_wrap_load_p256_secret_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a signing `EVP_PKEY` using the P-256 secret key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 32` + */ + +isc_result_t +isc_ossl_wrap_p256_public_region(EVP_PKEY *pkey, isc_region_t pub); +/*% + * Export the P-256 public key to the region pointed by `pub` + * + * Requires: + * \li `pkey` is a non-NULL, valid, P-256 public key. + * \li `pub` has to a non-NULL pointer with enough space to fit the public key. + */ + +isc_result_t +isc_ossl_wrap_p256_secret_region(EVP_PKEY *pkey, isc_region_t sec); +/*% + * Export the P-256 curve secret key to the region pointed by `sec` + * + * Requires: + * \li `pkey` is a non-NULL, valid P-256 secret key. + * \li `sec` has to a non-NULL pointer with enough space to fit the secret key. + */ + +isc_result_t +isc_ossl_wrap_generate_p384_key(EVP_PKEY **pkeyp); +/*% + * Generates an uncompressed, named P-256 secret key. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_p384_key(char *uri, EVP_PKEY **pkeyp); +/*% + * Generates a P-384 secret key using the PKCS#11 label specified at `uri`. + * + * Requires: + * \li pkeyp != NULL + * \li *pkeyp == NULL + * \li `uri != NULL` and is a NUL-terminated string + */ + +isc_result_t +isc_ossl_wrap_load_p384_public_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a verifying `EVP_PKEY` using the P-384 public key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 64` + */ + +isc_result_t +isc_ossl_wrap_load_p384_secret_from_region(isc_region_t region, + EVP_PKEY **pkeyp); +/*% + * Create a signing `EVP_PKEY` using the P-384 secret key pointed by + * `region`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `region.base != NULL` + * \li `region.length == 32` + */ + +isc_result_t +isc_ossl_wrap_validate_p384_pkey(EVP_PKEY *pkey); + +isc_result_t +isc_ossl_wrap_p384_public_region(EVP_PKEY *pkey, isc_region_t pub); +/*% + * Export the P-384 public key to the region pointed by `pub` + * + * Requires: + * \li `pkey` is a non-NULL, valid, P-384 public key. + * \li `pub` has to a non-NULL pointer with enough space to fit the public key. + */ + +isc_result_t +isc_ossl_wrap_p384_secret_region(EVP_PKEY *pkey, isc_region_t sec); +/*% + * Export the P-384 curve secret key to the region pointed by `sec` + * + * Requires: + * \li `pkey` is a non-NULL, valid P-384 secret key. + * \li `sec` has to a non-NULL pointer with enough space to fit the secret key. + */ + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash); +/* + * Use deterministic ECDSA to generate signatures. + * + * Returns: + * \li #ISC_R_SUCCESS -- signature set to use RFC6979 + * \li #ISC_R_IGNORE -- FIPS mode is active + * \li #ISC_R_NOTIMPLEMENTED -- libcrypto doesn't support + */ + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash); +/* + * Use deterministic ECDSA to generate signatures. + * + * Returns: + * \li #ISC_R_SUCCESS -- signature set to use RFC6979 + * \li #ISC_R_IGNORE -- FIPS mode is active + * \li #ISC_R_NOTIMPLEMENTED -- libcrypto doesn't support RFC6979 + */ + +isc_result_t +isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, + EVP_PKEY **pkeyp); +/*% + * Creates a RSA key with the specified bit-size + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + */ + +isc_result_t +isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, + EVP_PKEY **pkeyp); +/*% + * Creates a RSA key with the specified bit-size using the PKCS11 label + * specified at `uri`. + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `uri != NULL` and is a NUL-terminated string + */ + +bool +isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit); + +isc_result_t +isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c); + +isc_result_t +isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c); + +isc_result_t +isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp); +/*% + * Create a verifying `EVP_PKEY` using the public RSA components at `c` + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `c != NULL` + * \li `c.n != NULL` + * \li `c.e != NULL` + */ + +isc_result_t +isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp); +/*% + * Create a signing `EVP_PKEY` using the public and secret RSA components at `c` + * + * Requires: + * \li `pkeyp != NULL` + * \li `*pkeyp == NULL` + * \li `c != NULL` + * \li `c.n != NULL` + * \li `c.e != NULL` + */ + +void +isc_ossl_wrap_rsa_components_cleanup(isc_ossl_wrap_rsa_components_t *comp); + +isc_result_t +isc_ossl_wrap_toresult(isc_result_t fallback); + +isc_result_t +isc__ossl_wrap_logged_toresult(isc_logcategory_t category, + isc_logmodule_t module, const char *funcname, + isc_result_t fallback, const char *file, + int line); + +/* + * This is a bit of a namespace convention violation but it fits the spirit of + * this header since it is exposing OpenSSL-isms to others. + */ + +extern EVP_MD *isc__crypto_md[]; diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 50755ac2b1..1e10a7d649 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -615,11 +615,3 @@ isc_tls_valid_sni_hostname(const char *hostname); * string. Returns 'true' if the hostname is likely a domain name, and * 'false' if it represents an IP address. */ - -#define isc_tlserr2result(category, module, funcname, fallback) \ - isc__tlserr2result(category, module, funcname, fallback, __FILE__, \ - __LINE__) -isc_result_t -isc__tlserr2result(isc_logcategory_t category, isc_logmodule_t module, - const char *funcname, isc_result_t fallback, - const char *file, int line); diff --git a/lib/isc/iterated_hash.c b/lib/isc/iterated_hash.c index dfffe3b129..7d8c68a396 100644 --- a/lib/isc/iterated_hash.c +++ b/lib/isc/iterated_hash.c @@ -17,8 +17,9 @@ #include #include -#include #include +#include +#include #include #include @@ -150,7 +151,8 @@ isc__iterated_hash_initialize(void) { mdctx = EVP_MD_CTX_new(); INSIST(mdctx != NULL); - RUNTIME_CHECK(EVP_DigestInit_ex(basectx, isc__crypto_sha1, NULL) == 1); + RUNTIME_CHECK(EVP_DigestInit_ex(basectx, isc__crypto_md[ISC_MD_SHA1], + NULL) == 1); initialized = true; } diff --git a/lib/isc/md.c b/lib/isc/md.c index 8f461d60ca..0c6688f48e 100644 --- a/lib/isc/md.c +++ b/lib/isc/md.c @@ -18,6 +18,7 @@ #include #include +#include #include #include "openssl_shim.h" @@ -39,14 +40,18 @@ isc_md_free(isc_md_t *md) { } isc_result_t -isc_md_init(isc_md_t *md, const isc_md_type_t *md_type) { - REQUIRE(md != NULL); +isc_md_init(isc_md_t *md, isc_md_type_t type) { + EVP_MD *evp; - if (md_type == NULL) { + REQUIRE(md != NULL); + REQUIRE(type < ISC_MD_MAX); + + evp = isc__crypto_md[type]; + if (evp == NULL) { return ISC_R_NOTIMPLEMENTED; } - if (EVP_DigestInit_ex(md, md_type, NULL) != 1) { + if (EVP_DigestInit_ex(md, evp, NULL) != 1) { ERR_clear_error(); return ISC_R_CRYPTOFAILURE; } @@ -95,13 +100,6 @@ isc_md_final(isc_md_t *md, unsigned char *digest, unsigned int *digestlen) { return ISC_R_SUCCESS; } -const isc_md_type_t * -isc_md_get_md_type(isc_md_t *md) { - REQUIRE(md != NULL); - - return EVP_MD_CTX_get0_md(md); -} - size_t isc_md_get_size(isc_md_t *md) { REQUIRE(md != NULL); @@ -117,38 +115,31 @@ isc_md_get_block_size(isc_md_t *md) { } size_t -isc_md_type_get_size(const isc_md_type_t *md_type) { +isc_md_type_get_block_size(isc_md_type_t type) { + EVP_MD *evp; + + REQUIRE(type < ISC_MD_MAX); STATIC_ASSERT(ISC_MAX_MD_SIZE >= EVP_MAX_MD_SIZE, "Change ISC_MAX_MD_SIZE to be greater than or equal to " "EVP_MAX_MD_SIZE"); - if (md_type != NULL) { - return (size_t)EVP_MD_size(md_type); - } - return ISC_MAX_MD_SIZE; -} - -size_t -isc_md_type_get_block_size(const isc_md_type_t *md_type) { - STATIC_ASSERT(ISC_MAX_MD_SIZE >= EVP_MAX_MD_SIZE, - "Change ISC_MAX_MD_SIZE to be greater than or equal to " - "EVP_MAX_MD_SIZE"); - if (md_type != NULL) { - return (size_t)EVP_MD_block_size(md_type); + evp = isc__crypto_md[type]; + if (evp != NULL) { + return (size_t)EVP_MD_block_size(evp); } return ISC_MAX_MD_SIZE; } isc_result_t -isc_md(const isc_md_type_t *md_type, const unsigned char *buf, const size_t len, +isc_md(isc_md_type_t type, const unsigned char *buf, const size_t len, unsigned char *digest, unsigned int *digestlen) { isc_md_t *md; isc_result_t res; md = isc_md_new(); - res = isc_md_init(md, md_type); + res = isc_md_init(md, type); if (res != ISC_R_SUCCESS) { goto end; } diff --git a/lib/isc/meson.build b/lib/isc/meson.build index d4db21672e..f2c164a5b7 100644 --- a/lib/isc/meson.build +++ b/lib/isc/meson.build @@ -20,7 +20,9 @@ endif # isc_inc += include_directories('include') isc_inc_p += include_directories('.') +subdir('crypto') subdir('netmgr') +subdir('ossl_wrap') isc_srcset.add( m_dep, @@ -75,7 +77,6 @@ isc_srcset.add( 'base64.c', 'commandline.c', 'counter.c', - 'crypto.c', 'dir.c', 'errno.c', 'errno2result.c', @@ -88,7 +89,6 @@ isc_srcset.add( 'helper.c', 'hex.c', 'histo.c', - 'hmac.c', 'ht.c', 'httpd.c', 'interfaceiter.c', diff --git a/lib/isc/openssl_shim.h b/lib/isc/openssl_shim.h index d2f8eeda72..316d7ae7dd 100644 --- a/lib/isc/openssl_shim.h +++ b/lib/isc/openssl_shim.h @@ -18,10 +18,6 @@ #include #include -#if !HAVE_EVP_MD_CTX_GET0_MD -#define EVP_MD_CTX_get0_md EVP_MD_CTX_md -#endif /* if !HAVE_EVP_MD_CTX_GET0_MD */ - #if !HAVE_BIO_READ_EX int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes); diff --git a/lib/isc/ossl_wrap/meson.build b/lib/isc/ossl_wrap/meson.build new file mode 100644 index 0000000000..e610fbe817 --- /dev/null +++ b/lib/isc/ossl_wrap/meson.build @@ -0,0 +1,16 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +isc_srcset.add( + when: 'HAVE_OPENSSL_3', + if_true: files('ossl3.c', 'ossl_common.c'), + if_false: files('ossl1_1.c', 'ossl_common.c'), +) diff --git a/lib/isc/ossl_wrap/ossl1_1.c b/lib/isc/ossl_wrap/ossl1_1.c new file mode 100644 index 0000000000..7726e9cac3 --- /dev/null +++ b/lib/isc/ossl_wrap/ossl1_1.c @@ -0,0 +1,599 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_PUBLIC_KEY_SIZE 96 +#define MAX_SECRET_KEY_SIZE 48 + +#define OSSL_WRAP_ERROR(fn) \ + isc__ossl_wrap_logged_toresult( \ + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \ + ISC_R_CRYPTOFAILURE, __FILE__, __LINE__) + +#define P_CURVE_IMPL(curve, nid) \ + isc_result_t isc_ossl_wrap_generate_##curve##_key(EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + return generate_ec_key(pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_generate_pkcs11_##curve##_key( \ + char *uri, EVP_PKEY **pkeyp) { \ + UNUSED(uri); \ + return isc_ossl_wrap_generate_##curve##_key(pkeyp); \ + } \ + isc_result_t isc_ossl_wrap_validate_##curve##_pkey(EVP_PKEY *pkey) { \ + REQUIRE(pkey != NULL); \ + return validate_ec_pkey(pkey, nid); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_public_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(region.base != NULL && \ + region.length >= curve##_public_key_size); \ + region.length = curve##_public_key_size; \ + return load_ec_public_from_region(region, pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_secret_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(region.base != NULL && \ + region.length >= curve##_secret_key_size); \ + region.length = curve##_secret_key_size; \ + return load_ec_secret_from_region(region, pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_public_region(EVP_PKEY *pkey, \ + isc_region_t pub) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(pub.base != NULL && \ + pub.length >= curve##_public_key_size); \ + pub.length = curve##_public_key_size; \ + return ec_public_region(pkey, pub); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_secret_region(EVP_PKEY *pkey, \ + isc_region_t sec) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(sec.base != NULL && \ + sec.length >= curve##_secret_key_size); \ + sec.length = curve##_secret_key_size; \ + return ec_secret_region(pkey, sec); \ + } + +constexpr size_t p256_public_key_size = 64; +constexpr size_t p384_public_key_size = 96; + +constexpr size_t p256_secret_key_size = 32; +constexpr size_t p384_secret_key_size = 48; + +static int +BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { + int bytes = size - BN_num_bytes(bn); + + INSIST(bytes >= 0); + + while (bytes-- > 0) { + *buf++ = 0; + } + BN_bn2bin(bn, buf); + return size; +} + +static int +rsa_keygen_progress_cb(int p, int n, BN_GENCB *cb) { + void (*fptr)(int); + + UNUSED(n); + + fptr = BN_GENCB_get_arg(cb); + if (fptr != NULL) { + fptr(p); + } + return 1; +} + +static isc_result_t +generate_ec_key(EVP_PKEY **pkeyp, const int nid) { + isc_result_t result; + EC_KEY *eckey = NULL; + EVP_PKEY *pkey = NULL; + + eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_new_by_curve_name")); + } + + if (EC_KEY_generate_key(eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_generate_key")); + } + + EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED); + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_EC_KEY")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EC_KEY_free(eckey); + EVP_PKEY_free(pkey); + return result; +} + +static isc_result_t +validate_ec_pkey(EVP_PKEY *pkey, const int nid) { + const EC_GROUP *group; + const EC_KEY *eckey; + isc_result_t result; + + eckey = EVP_PKEY_get0_EC_KEY(pkey); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_EC_KEY")); + } + + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_group")); + } + + if (EC_GROUP_get_curve_name(group) != nid) { + return DST_R_INVALIDPRIVATEKEY; + } + + result = ISC_R_SUCCESS; +cleanup: + return result; +} + +static isc_result_t +load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const int nid) { + isc_result_t result; + const unsigned char *buf_launder; + uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + EC_KEY *eckey = NULL; + EVP_PKEY *pkey = NULL; + + eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_new_curve_by_name")); + } + + buffer[0] = POINT_CONVERSION_UNCOMPRESSED; + memmove(buffer + 1, region.base, region.length); + + buf_launder = buffer; + if (o2i_ECPublicKey(&eckey, &buf_launder, region.length + 1) == NULL) { + CLEANUP(OSSL_WRAP_ERROR("o2i_ECPublicKey")); + } + + if (EC_KEY_check_key(eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_check_key")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_EC_KEY")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + EC_KEY_free(eckey); + return result; +} + +static isc_result_t +load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const int nid) { + isc_result_t result; + const EC_GROUP *group = NULL; + EC_POINT *public = NULL; + EVP_PKEY *pkey = NULL; + BIGNUM *private = NULL; + EC_KEY *eckey = NULL; + + eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_new_curve_by_name")); + } + + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_group")); + } + + private = BN_bin2bn(region.base, region.length, NULL); + if (private == NULL) { + CLEANUP(OSSL_WRAP_ERROR("BN_bin2bn")); + } + + if (EC_KEY_set_private_key(eckey, private) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_set_private_key")); + } + + /* + * OpenSSL requires us to set the public key portion, but since our + * private key file format does not contain it directly, we generate it + * as needed. + */ + public = EC_POINT_new(group); + if (public == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_new")); + } + + if (EC_POINT_mul(group, public, private, NULL, NULL, NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_mul")); + } + + if (EC_KEY_set_public_key(eckey, public) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_set_public_key")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_EC_KEY")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + EC_POINT_free(public); + BN_clear_free(private); + EC_KEY_free(eckey); + return result; +} + +static isc_result_t +ec_public_region(EVP_PKEY *pkey, isc_region_t pub) { + isc_result_t result; + uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + const EC_POINT *public; + const EC_GROUP *group; + const EC_KEY *eckey; + size_t len; + + eckey = EVP_PKEY_get0_EC_KEY(pkey); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_EC_KEY")); + } + + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_group")); + } + + public = EC_KEY_get0_public_key(eckey); + if (public == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_public_key")); + } + + len = EC_POINT_point2oct(group, public, POINT_CONVERSION_UNCOMPRESSED, + buffer, sizeof(buffer), NULL); + if (len != pub.length + 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_point2oct")); + } + + memmove(pub.base, buffer + 1, pub.length); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +static isc_result_t +ec_secret_region(EVP_PKEY *pkey, isc_region_t pub) { + const BIGNUM *private; + isc_result_t result; + const EC_KEY *eckey; + + eckey = EVP_PKEY_get0_EC_KEY(pkey); + if (eckey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_EC_KEY")); + } + + private = EC_KEY_get0_private_key(eckey); + if (private == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_KEY_get0_private_key")); + } + + BN_bn2bin_fixed(private, pub.base, pub.length); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +P_CURVE_IMPL(p256, NID_X9_62_prime256v1); +P_CURVE_IMPL(p384, NID_secp384r1); + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) { + UNUSED(pctx); + UNUSED(hash); + + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t +isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, + EVP_PKEY **pkeyp) { + RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; + BN_GENCB *cb = NULL; + isc_result_t result; + BIGNUM *e; + + e = BN_new(); + + /* e = 65537 (0x10001, F4) */ + BN_set_bit(e, 0); + BN_set_bit(e, 16); + + rsa = RSA_new(); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_new")); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_RSA")); + } + + if (callback != NULL) { + cb = BN_GENCB_new(); + if (cb == NULL) { + CLEANUP(OSSL_WRAP_ERROR("BN_GENCB_new")); + } + + BN_GENCB_set(cb, rsa_keygen_progress_cb, (void *)callback); + } + + if (RSA_generate_key_ex(rsa, bit_size, e, cb) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_generate_key_ex")); + } + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + RSA_free(rsa); + BN_GENCB_free(cb); + BN_free(e); + return result; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, + EVP_PKEY **pkeyp) { + UNUSED(uri); + + return isc_ossl_wrap_generate_rsa_key(NULL, bit_size, pkeyp); +} + +bool +isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) { + const RSA *rsa; + const BIGNUM *ce; + size_t bits = SIZE_MAX; + + REQUIRE(pkey != NULL); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa != NULL) { + ce = NULL; + RSA_get0_key(rsa, NULL, &ce, NULL); + if (ce != NULL) { + bits = BN_num_bits(ce); + } + } + + return bits <= limit; +} + +isc_result_t +isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + isc_result_t result; + const RSA *rsa; + + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->e == NULL && c->n == NULL); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_RSA")); + } + + RSA_get0_key(rsa, (const BIGNUM **)&c->n, (const BIGNUM **)&c->e, NULL); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + isc_result_t result; + const RSA *rsa; + + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->d == NULL && c->p == NULL && c->q == NULL && + c->dmp1 == NULL && c->dmq1 == NULL && c->iqmp == NULL); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get0_RSA")); + } + + /* + * We don't support PKCS11 with OpenSSL <=1.1.1a + * d *must* succeed. + */ + RSA_get0_key(rsa, NULL, NULL, (const BIGNUM **)&c->d); + if (c->d == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_get0_key")); + } + + RSA_get0_factors(rsa, (const BIGNUM **)&c->p, (const BIGNUM **)&c->q); + RSA_get0_crt_params(rsa, (const BIGNUM **)&c->dmp1, + (const BIGNUM **)&c->dmq1, + (const BIGNUM **)&c->iqmp); + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + isc_result_t result; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(c != NULL && c->e != NULL && c->n != NULL); + REQUIRE(c->needs_cleanup); + + rsa = RSA_new(); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_new")); + } + + if (RSA_set0_key(rsa, c->n, c->e, NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_key")); + } + + c->n = NULL; + c->e = NULL; + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_RSA")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + RSA_free(rsa); + return result; +} + +isc_result_t +isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + isc_result_t result; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(c != NULL); + + result = ISC_R_SUCCESS; + + rsa = RSA_new(); + if (rsa == NULL) { + CLEANUP(OSSL_WRAP_ERROR("RSA_new")); + } + + if (RSA_set0_key(rsa, c->n, c->e, c->d) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_key")); + } + + c->n = NULL; + c->e = NULL; + c->d = NULL; + + if (c->p != NULL || c->q != NULL) { + if (RSA_set0_factors(rsa, c->p, c->q) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_factors")); + } + + c->p = NULL; + c->q = NULL; + } + + if (c->dmp1 != NULL || c->dmq1 != NULL || c->iqmp != NULL) { + if (RSA_set0_crt_params(rsa, c->dmp1, c->dmq1, c->iqmp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("RSA_set0_crt_params")); + } + c->dmp1 = NULL; + c->dmq1 = NULL; + c->iqmp = NULL; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_new")); + } + + if (EVP_PKEY_set1_RSA(pkey, rsa) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_set1_RSA")); + } + + *pkeyp = pkey; + pkey = NULL; + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_free(pkey); + RSA_free(rsa); + isc_ossl_wrap_rsa_components_cleanup(c); + return result; +} diff --git a/lib/isc/ossl_wrap/ossl3.c b/lib/isc/ossl_wrap/ossl3.c new file mode 100644 index 0000000000..b8da16e8e0 --- /dev/null +++ b/lib/isc/ossl_wrap/ossl3.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PUBLIC_KEY_SIZE 96 +#define MAX_SECRET_KEY_SIZE 48 + +#define OSSL_WRAP_ERROR(fn) \ + isc__ossl_wrap_logged_toresult( \ + ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_CRYPTO, fn, \ + ISC_R_CRYPTOFAILURE, __FILE__, __LINE__) + +#define P_CURVE_IMPL(curve, nid) \ + isc_result_t isc_ossl_wrap_generate_##curve##_key(EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + return generate_ec_key(pkeyp, curve##_params); \ + } \ + isc_result_t isc_ossl_wrap_generate_pkcs11_##curve##_key( \ + char *uri, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(uri != NULL); \ + return generate_pkcs11_ec_key(uri, pkeyp, nid); \ + } \ + isc_result_t isc_ossl_wrap_validate_##curve##_pkey(EVP_PKEY *pkey) { \ + REQUIRE(pkey != NULL); \ + return validate_ec_pkey(pkey, curve##_params); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_public_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(region.base != NULL && \ + region.length <= MAX_PUBLIC_KEY_SIZE); \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + region.length = curve##_public_key_size; \ + return load_ec_public_from_region(region, pkeyp, \ + curve##_params); \ + } \ + isc_result_t isc_ossl_wrap_load_##curve##_secret_from_region( \ + isc_region_t region, EVP_PKEY **pkeyp) { \ + REQUIRE(pkeyp != NULL && *pkeyp == NULL); \ + REQUIRE(region.base != NULL && \ + region.length >= curve##_secret_key_size); \ + region.length = curve##_secret_key_size; \ + return load_ec_secret_from_region(region, pkeyp, \ + curve##_params); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_public_region(EVP_PKEY *pkey, \ + isc_region_t pub) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(pub.base != NULL && \ + pub.length >= curve##_public_key_size); \ + pub.length = curve##_public_key_size; \ + return ec_public_region(pkey, pub); \ + } \ + isc_result_t isc_ossl_wrap_##curve##_secret_region(EVP_PKEY *pkey, \ + isc_region_t sec) { \ + REQUIRE(pkey != NULL); \ + REQUIRE(sec.base != NULL && \ + sec.length >= curve##_secret_key_size); \ + sec.length = curve##_secret_key_size; \ + return ec_secret_region(pkey, sec); \ + } + +static char pkcs11_key_usage[] = "digitalSignature"; + +constexpr size_t p256_public_key_size = 64; +constexpr size_t p384_public_key_size = 96; + +constexpr size_t p256_secret_key_size = 32; +constexpr size_t p384_secret_key_size = 48; + +/* + * "group" MUST be the first parameter, we rely on it to get the group name. + */ + +/* clang-format off */ +static const OSSL_PARAM p256_params[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + UNCONST("prime256v1"), sizeof("prime256v1") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, + UNCONST("named_curve"), sizeof("named_curve") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + UNCONST("uncompressed"), sizeof("uncompressed") - 1), + OSSL_PARAM_END, +}; + +static const OSSL_PARAM p384_params[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + UNCONST("secp384r1"), sizeof("secp384r1") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, + UNCONST("named_curve"), sizeof("named_curve") - 1), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + UNCONST("uncompressed"), sizeof("uncompressed") - 1), + OSSL_PARAM_END, +}; +/* clang-format on */ + +static void +BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { + int bytes = size - BN_num_bytes(bn); + + INSIST(bytes >= 0); + + while (bytes-- > 0) { + *buf++ = 0; + } + BN_bn2bin(bn, buf); +} + +static int +rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) { + void (*fptr)(int); + + fptr = EVP_PKEY_CTX_get_app_data(ctx); + if (fptr != NULL) { + int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + fptr(p); + } + return 1; +} + +static isc_result_t +generate_ec_key(EVP_PKEY **pkeyp, const OSSL_PARAM *const params) { + isc_result_t result; + EVP_PKEY_CTX *pctx = NULL; + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_keygen_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ + if (EVP_PKEY_generate(pctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +generate_pkcs11_ec_key(char *uri, EVP_PKEY **pkeyp, int nid) { + isc_result_t result; + EVP_PKEY_CTX *pctx; + size_t len; + + INSIST(uri != NULL); + len = strlen(uri); + + const OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", uri, len), + OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage, + sizeof(pkcs11_key_usage) - 1), + OSSL_PARAM_END, + }; + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11"); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_keygen_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + /* + * Setting the P-384 curve doesn't work correctly when using: + * OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0); + * + * Instead use the OpenSSL function to set the curve nid param. + */ + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_" + "nid")); + } + + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ + if (EVP_PKEY_generate(pctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +validate_ec_pkey(EVP_PKEY *pkey, const OSSL_PARAM *const curve_params) { + isc_result_t result; + const char *expected = curve_params[0].data; + char actual[64]; + + if (EVP_PKEY_get_group_name(pkey, actual, sizeof(actual), NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_group_name")); + } + + if (strncmp(expected, actual, curve_params[0].data_size) != 0) { + return ISC_R_FAILURE; + } + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +static isc_result_t +load_ec_public_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const OSSL_PARAM *const curve_params) { + isc_result_t result; + EVP_PKEY_CTX *pctx = NULL; + uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1]; + OSSL_PARAM params[] = { + curve_params[0], /* group */ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, buffer, + region.length + 1), + OSSL_PARAM_END, + }; + + buffer[0] = POINT_CONVERSION_UNCOMPRESSED; + memmove(buffer + 1, region.base, region.length); + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp, + const OSSL_PARAM *const curve_params) { + uint8_t public[MAX_PUBLIC_KEY_SIZE + 1]; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + EC_POINT *pub_point = NULL; + EC_GROUP *group = NULL; + BIGNUM *private = NULL; + isc_result_t result; + size_t public_len; + + /* + * OpenSSL requires us to set the public key portion, but since our + * private key file format does not contain it directly, we generate it + * as needed. + */ + group = EC_GROUP_new_from_params(curve_params, NULL, NULL); + if (group == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_GROUP_new_by_curve_name")); + } + + private = BN_bin2bn(region.base, region.length, NULL); + if (private == NULL) { + CLEANUP(OSSL_WRAP_ERROR("BN_bin2bn")); + } + + pub_point = EC_POINT_new(group); + if (pub_point == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_new")); + } + + if (EC_POINT_mul(group, pub_point, private, NULL, NULL, NULL) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_mul")); + } + + public_len = EC_POINT_point2oct(group, pub_point, + POINT_CONVERSION_UNCOMPRESSED, public, + sizeof(public), NULL); + if (public_len == 0) { + CLEANUP(OSSL_WRAP_ERROR("EC_POINT_point2oct")); + } + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_utf8_string(bld, curve_params[0].key, + curve_params[0].data, + curve_params[0].data_size) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, private) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, + public, public_len) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_octet_string")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + EC_POINT_free(pub_point); + BN_clear_free(private); + EC_GROUP_free(group); + EVP_PKEY_CTX_free(pctx); + return result; +} + +static isc_result_t +ec_public_region(EVP_PKEY *pkey, isc_region_t pub) { + isc_result_t result; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + BN_bn2bin_fixed(x, &pub.base[0], pub.length / 2); + BN_bn2bin_fixed(y, &pub.base[pub.length / 2], pub.length / 2); + + result = ISC_R_SUCCESS; + +cleanup: + BN_clear_free(x); + BN_clear_free(y); + return result; +} + +static isc_result_t +ec_secret_region(EVP_PKEY *pkey, isc_region_t sec) { + isc_result_t result; + BIGNUM *priv = NULL; + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + BN_bn2bin_fixed(priv, sec.base, sec.length); + + result = ISC_R_SUCCESS; + +cleanup: + BN_clear_free(priv); + return result; +} + +P_CURVE_IMPL(p256, NID_X9_62_prime256v1); +P_CURVE_IMPL(p384, NID_secp384r1); + +isc_result_t +isc_ossl_wrap_ecdsa_set_deterministic(EVP_PKEY_CTX *pctx, const char *hash) { + unsigned int rfc6979 = 1; + isc_result_t result; + OSSL_PARAM params[3] = { + OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash), 0), + OSSL_PARAM_construct_uint("nonce-type", &rfc6979), + OSSL_PARAM_END, + }; + + REQUIRE(pctx != NULL && hash != NULL); + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_generate_rsa_key(void (*callback)(int), size_t bit_size, + EVP_PKEY **pkeyp) { + isc_result_t result; + EVP_PKEY_CTX *ctx; + uint32_t e = 65537; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + + /* + * https://docs.openssl.org/master/man7/EVP_PKEY-RSA/#rsa-key-generation-parameters + */ + const OSSL_PARAM params[3] = { + OSSL_PARAM_uint(OSSL_PKEY_PARAM_RSA_E, &e), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size), + OSSL_PARAM_END, + }; + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (ctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_keygen_init(ctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + if (EVP_PKEY_CTX_set_params(ctx, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + if (callback != NULL) { + EVP_PKEY_CTX_set_app_data(ctx, (void *)callback); + EVP_PKEY_CTX_set_cb(ctx, rsa_keygen_progress_cb); + } + + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ + if (EVP_PKEY_generate(ctx, pkeyp) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(ctx); + return result; +} + +isc_result_t +isc_ossl_wrap_generate_pkcs11_rsa_key(char *uri, size_t bit_size, + EVP_PKEY **pkeyp) { + EVP_PKEY_CTX *ctx = NULL; + isc_result_t result; + int status; + size_t len; + + len = strlen(uri); + INSIST(len != 0); + + /* NUL-terminator should be left out */ + const OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", uri, len), + OSSL_PARAM_utf8_string("pkcs11_key_usage", pkcs11_key_usage, + sizeof(pkcs11_key_usage) - 1), + OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bit_size), + OSSL_PARAM_END, + }; + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); + if (ctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + status = EVP_PKEY_keygen_init(ctx); + if (status != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init")); + } + + status = EVP_PKEY_CTX_set_params(ctx, params); + if (status != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_params")); + } + + /* + * EVP_PKEY_keygen is an older function now equivalent to + * EVP_PKEY_generate with an additional check that EVP_PKEY_CTX has been + * initialized with EVP_PKEY_keygen_init. + * + * Since we can guarantee such condition we use EVP_PKEY_generate + * directly. + */ + status = EVP_PKEY_generate(ctx, pkeyp); + if (status != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_generate")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(ctx); + return result; +} + +bool +isc_ossl_wrap_rsa_key_bits_leq(EVP_PKEY *pkey, size_t limit) { + size_t bits = SIZE_MAX; + BIGNUM *e = NULL; + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 1) { + bits = BN_num_bits(e); + BN_free(e); + } + return bits <= limit; +} + +isc_result_t +isc_ossl_wrap_rsa_public_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + isc_result_t result; + + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->e == NULL && c->n == NULL); + + c->needs_cleanup = true; + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &c->e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &c->n) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_get_bn_param")); + } + + result = ISC_R_SUCCESS; + +cleanup: + return result; +} + +isc_result_t +isc_ossl_wrap_rsa_secret_components(EVP_PKEY *pkey, + isc_ossl_wrap_rsa_components_t *c) { + REQUIRE(pkey != NULL); + REQUIRE(c != NULL && c->d == NULL && c->p == NULL && c->q == NULL && + c->dmp1 == NULL && c->dmq1 == NULL && c->iqmp == NULL); + + c->needs_cleanup = true; + + /* + * NOTE: Errors regarding private compoments are ignored. + * + * OpenSSL allows omitting the parameters for CRT based calculations + * (factors, exponents, coefficients). Only the 'd' parameter is + * mandatory for software keys. + * + * However, for a label based keys, all private key component queries + * can fail if they key is e.g. on a hardware device. + */ + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &c->d); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &c->p); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &c->q); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, + &c->dmp1); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, + &c->dmq1); + (void)EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, + &c->iqmp); + + ERR_clear_error(); + + return ISC_R_SUCCESS; +} + +isc_result_t +isc_ossl_wrap_load_rsa_public_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + OSSL_PARAM_BLD *bld = NULL; + EVP_PKEY_CTX *pctx = NULL; + OSSL_PARAM *params = NULL; + isc_result_t result; + + result = ISC_R_SUCCESS; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + REQUIRE(c != NULL && c->n != NULL && c->e != NULL); + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_PUBLIC_KEY, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return result; +} + +isc_result_t +isc_ossl_wrap_load_rsa_secret_from_components(isc_ossl_wrap_rsa_components_t *c, + EVP_PKEY **pkeyp) { + isc_result_t result; + OSSL_PARAM_BLD *bld = NULL; + EVP_PKEY_CTX *pctx = NULL; + OSSL_PARAM *params = NULL; + + REQUIRE(pkeyp != NULL && *pkeyp == NULL); + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, c->n) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, c->e) != 1) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->d != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, c->d) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->p != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, c->p) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->q != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, c->q) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->dmp1 != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, + c->dmp1) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->dmq1 != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, + c->dmq1) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + if (c->iqmp != NULL && + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, + c->iqmp) != 1) + { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_BN")); + } + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_to_param")); + } + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (pctx == NULL) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new_from_name")); + } + + if (EVP_PKEY_fromdata_init(pctx) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata_init")); + } + + if (EVP_PKEY_fromdata(pctx, pkeyp, EVP_PKEY_KEYPAIR, params) != 1) { + CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata")); + } + + result = ISC_R_SUCCESS; + +cleanup: + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return result; +} diff --git a/lib/isc/ossl_wrap/ossl_common.c b/lib/isc/ossl_wrap/ossl_common.c new file mode 100644 index 0000000000..0828a37ff0 --- /dev/null +++ b/lib/isc/ossl_wrap/ossl_common.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include + +#include +#include + +#include "../openssl_shim.h" + +void +isc_ossl_wrap_rsa_components_cleanup(isc_ossl_wrap_rsa_components_t *c) { + REQUIRE(c != NULL); + + if (!c->needs_cleanup) { + return; + } + + /* + * NOTE: BN_free() frees the components of the BIGNUM, and if it was + * created by BN_new(), also the structure itself. BN_clear_free() + * additionally overwrites the data before the memory is returned to the + * system. If a is NULL, nothing is done. + */ + BN_free(c->e); + BN_free(c->n); + BN_clear_free(c->d); + BN_clear_free(c->p); + BN_clear_free(c->q); + BN_clear_free(c->dmp1); + BN_clear_free(c->dmq1); + BN_clear_free(c->iqmp); + + c->needs_cleanup = false; +} + +isc_result_t +isc_ossl_wrap_toresult(isc_result_t fallback) { + isc_result_t result = fallback; + unsigned long err = ERR_peek_error(); +#ifdef ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED + int lib = ERR_GET_LIB(err); +#endif /* ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED */ + int reason = ERR_GET_REASON(err); + + switch (reason) { + /* + * ERR_* errors are globally unique; others + * are unique per sublibrary + */ + case ERR_R_MALLOC_FAILURE: + result = ISC_R_NOMEMORY; + break; + default: +#ifdef ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED + if (lib == ERR_R_ECDSA_LIB && + reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) + { + result = ISC_R_NOENTROPY; + break; + } +#endif /* ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED */ + break; + } + + return result; +} + +isc_result_t +isc__ossl_wrap_logged_toresult(isc_logcategory_t category, + isc_logmodule_t module, const char *funcname, + isc_result_t fallback, const char *file, + int line) { + isc_result_t result = isc_ossl_wrap_toresult(fallback); + + /* + * This is an exception - normally, we don't allow this, but the + * compatibility shims in dst_openssl.h needs a call that just + * translates the error code and don't do any logging. + */ + if (category == ISC_LOGCATEGORY_INVALID) { + goto done; + } + + isc_log_write(category, module, ISC_LOG_WARNING, + "%s (%s:%d) failed (%s)", funcname, file, line, + isc_result_totext(result)); + + if (result == ISC_R_NOMEMORY) { + goto done; + } + + for (;;) { + const char *func, *data; + int flags; + unsigned long err = ERR_get_error_all(&file, &line, &func, + &data, &flags); + if (err == 0U) { + break; + } + + char buf[256]; + ERR_error_string_n(err, buf, sizeof(buf)); + + isc_log_write(category, module, ISC_LOG_INFO, "%s:%s:%d:%s", + buf, file, line, + ((flags & ERR_TXT_STRING) != 0) ? data : ""); + } + +done: + ERR_clear_error(); + return result; +} diff --git a/lib/isc/tls.c b/lib/isc/tls.c index 215730d76b..9f1aa63969 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -38,9 +38,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -179,12 +181,6 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, X509 *cert = NULL; EVP_PKEY *pkey = NULL; SSL_CTX *ctx = NULL; -#if OPENSSL_VERSION_NUMBER < 0x30000000L - EC_KEY *eckey = NULL; -#else - EVP_PKEY_CTX *pkey_ctx = NULL; - EVP_PKEY *params_pkey = NULL; -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ char errbuf[256]; const SSL_METHOD *method = NULL; @@ -206,79 +202,10 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); if (ephemeral) { - const int group_nid = NID_X9_62_prime256v1; - -#if OPENSSL_VERSION_NUMBER < 0x30000000L - eckey = EC_KEY_new_by_curve_name(group_nid); - if (eckey == NULL) { + if (isc_ossl_wrap_generate_p256_key(&pkey) != ISC_R_SUCCESS) { goto ssl_error; } - /* Generate the key. */ - rv = EC_KEY_generate_key(eckey); - if (rv != 1) { - goto ssl_error; - } - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - goto ssl_error; - } - rv = EVP_PKEY_set1_EC_KEY(pkey, eckey); - if (rv != 1) { - goto ssl_error; - } - - /* Use a named curve and uncompressed point conversion form. */ - EC_KEY_set_asn1_flag(EVP_PKEY_get0_EC_KEY(pkey), - OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(EVP_PKEY_get0_EC_KEY(pkey), - POINT_CONVERSION_UNCOMPRESSED); - - /* Cleanup */ - EC_KEY_free(eckey); - eckey = NULL; -#else - /* Generate the key's parameters. */ - pkey_ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - if (pkey_ctx == NULL) { - goto ssl_error; - } - rv = EVP_PKEY_paramgen_init(pkey_ctx); - if (rv != 1) { - goto ssl_error; - } - rv = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, - group_nid); - if (rv != 1) { - goto ssl_error; - } - rv = EVP_PKEY_paramgen(pkey_ctx, ¶ms_pkey); - if (rv != 1 || params_pkey == NULL) { - goto ssl_error; - } - EVP_PKEY_CTX_free(pkey_ctx); - - /* Generate the key. */ - pkey_ctx = EVP_PKEY_CTX_new(params_pkey, NULL); - if (pkey_ctx == NULL) { - goto ssl_error; - } - rv = EVP_PKEY_keygen_init(pkey_ctx); - if (rv != 1) { - goto ssl_error; - } - rv = EVP_PKEY_keygen(pkey_ctx, &pkey); - if (rv != 1 || pkey == NULL) { - goto ssl_error; - } - - /* Cleanup */ - EVP_PKEY_free(params_pkey); - params_pkey = NULL; - EVP_PKEY_CTX_free(pkey_ctx); - pkey_ctx = NULL; -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ - cert = X509_new(); if (cert == NULL) { goto ssl_error; @@ -315,7 +242,7 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, -1, -1, 0); X509_set_issuer_name(cert, name); - X509_sign(cert, pkey, isc__crypto_sha256); + X509_sign(cert, pkey, isc__crypto_md[ISC_MD_SHA256]); rv = SSL_CTX_use_certificate(ctx, cert); if (rv != 1) { goto ssl_error; @@ -356,18 +283,6 @@ ssl_error: if (pkey != NULL) { EVP_PKEY_free(pkey); } -#if OPENSSL_VERSION_NUMBER < 0x30000000L - if (eckey != NULL) { - EC_KEY_free(eckey); - } -#else - if (params_pkey != NULL) { - EVP_PKEY_free(params_pkey); - } - if (pkey_ctx != NULL) { - EVP_PKEY_CTX_free(pkey_ctx); - } -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ return ISC_R_TLSERROR; } @@ -1546,80 +1461,3 @@ isc_tls_valid_sni_hostname(const char *hostname) { return true; } - -static isc_result_t -isc__tls_toresult(isc_result_t fallback) { - isc_result_t result = fallback; - unsigned long err = ERR_peek_error(); -#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) - int lib = ERR_GET_LIB(err); -#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ - int reason = ERR_GET_REASON(err); - - switch (reason) { - /* - * ERR_* errors are globally unique; others - * are unique per sublibrary - */ - case ERR_R_MALLOC_FAILURE: - result = ISC_R_NOMEMORY; - break; - default: -#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) - if (lib == ERR_R_ECDSA_LIB && - reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) - { - result = ISC_R_NOENTROPY; - break; - } -#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */ - break; - } - - return result; -} - -isc_result_t -isc__tlserr2result(isc_logcategory_t category, isc_logmodule_t module, - const char *funcname, isc_result_t fallback, - const char *file, int line) { - isc_result_t result = isc__tls_toresult(fallback); - - /* - * This is an exception - normally, we don't allow this, but the - * compatibility shims in dst_openssl.h needs a call that just - * translates the error code and don't do any logging. - */ - if (category == ISC_LOGCATEGORY_INVALID) { - goto done; - } - - isc_log_write(category, module, ISC_LOG_WARNING, - "%s (%s:%d) failed (%s)", funcname, file, line, - isc_result_totext(result)); - - if (result == ISC_R_NOMEMORY) { - goto done; - } - - for (;;) { - const char *func, *data; - int flags; - unsigned long err = ERR_get_error_all(&file, &line, &func, - &data, &flags); - if (err == 0U) { - break; - } - - char buf[256]; - ERR_error_string_n(err, buf, sizeof(buf)); - - isc_log_write(category, module, ISC_LOG_INFO, "%s:%s:%d:%s", - buf, file, line, - ((flags & ERR_TXT_STRING) != 0) ? data : ""); - } - -done: - ERR_clear_error(); - return result; -} diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c index a8f1a759af..bb3f3530d5 100644 --- a/lib/isccc/cc.c +++ b/lib/isccc/cc.c @@ -242,7 +242,7 @@ list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) { static isc_result_t sign(unsigned char *data, unsigned int length, unsigned char *out, uint32_t algorithm, isccc_region_t *secret) { - const isc_md_type_t *md_type; + isc_md_type_t md_type; isccc_region_t source, target; unsigned char digest[ISC_MAX_MD_SIZE]; unsigned int digestlen = sizeof(digest); @@ -353,7 +353,7 @@ isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer, uint32_t algorithm, static isc_result_t verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length, uint32_t algorithm, isccc_region_t *secret) { - const isc_md_type_t *md_type; + isc_md_type_t md_type; isccc_region_t source; isccc_region_t target; isccc_sexpr_t *_auth, *hmacvalue; diff --git a/meson.build b/meson.build index e979c79040..443c5760db 100644 --- a/meson.build +++ b/meson.build @@ -602,21 +602,37 @@ openssl_dep = [ dependency('libssl', version: '>=1.1.1'), ] -foreach fn, header : { - 'EVP_default_properties_enable_fips': '#include ', - 'FIPS_mode': '#include ', -} - if cc.has_function(fn, prefix: header, dependencies: openssl_dep) - config.set('HAVE_OPENSSL_FIPS_TOGGLE', 1) - config.set('HAVE_@0@'.format(fn.to_upper()), 1) - endif -endforeach - -fips_opt.require( - config.has('HAVE_OPENSSL_FIPS_TOGGLE'), - error_message: 'OpenSSL FIPS mode requested but not available', +# OpenSSL-forks usually set their own version number which can be greater than 3.0.0. +# To understand if the library is pre or post-3.0, use the OPENSSL_VERSION_NUMBER value. +openssl_version_number = cc.get_define( + 'OPENSSL_VERSION_NUMBER', + dependencies: openssl_dep, + prefix: '#include ', ) +config.set('OPENSSL_NO_DEPRECATED', true) +if openssl_version_number.version_compare('>=3.0.0') + config.set('HAVE_OPENSSL_3', true) + config.set('OPENSSL_API_COMPAT', 30000) +else + config.set('HAVE_OPENSSL_3', false) + config.set('OPENSSL_API_COMPAT', 10100) + + config.set( + 'HAVE_FIPS_MODE', + cc.has_function( + 'FIPS_mode', + prefix: '#include ', + dependencies: openssl_dep, + ), + ) + + fips_opt.require( + config.get('HAVE_FIPS_MODE'), + error_message: 'OpenSSL FIPS mode requested but not available', + ) +endif + # Hash and curve probe if cc.has_header_symbol('openssl/evp.h', 'NID_ED448', dependencies: openssl_dep) config.set('HAVE_OPENSSL_ED448', 1) @@ -626,7 +642,6 @@ foreach fn, header : { 'ERR_get_error_all': '#include ', 'BIO_read_ex': '#include ', 'BIO_write_ex': '#include ', - 'EVP_MD_CTX_get0_md': '#include ', 'EVP_PKEY_eq': '#include ', 'SSL_CTX_set1_cert_store': '#include ', } diff --git a/tests/isc/hmac_test.c b/tests/isc/hmac_test.c index 05b93bf79a..31797f7e44 100644 --- a/tests/isc/hmac_test.c +++ b/tests/isc/hmac_test.c @@ -21,13 +21,6 @@ #include #include -/* - * As a workaround, include an OpenSSL header file before including cmocka.h, - * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a - * redefined malloc in cmocka.h. - */ -#include - #define UNIT_TESTING #include @@ -39,14 +32,11 @@ #include #include -#include "hmac.c" - #include #define TEST_INPUT(x) (x), sizeof(x) - 1 -static int -_setup(void **state) { +ISC_SETUP_TEST_IMPL(hmac_state) { isc_hmac_t *hmac_st = isc_hmac_new(); if (hmac_st == NULL) { return -1; @@ -69,9 +59,7 @@ _reset(void **state) { if (*state == NULL) { return -1; } - if (isc_hmac_reset(*state) != ISC_R_SUCCESS) { - return -1; - } + return 0; } @@ -94,13 +82,18 @@ ISC_RUN_TEST_IMPL(isc_hmac_free) { static void isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, - const isc_md_type_t *type, const char *buf, size_t buflen, + isc_md_type_t type, const char *buf, size_t buflen, const char *result, const size_t repeats) { + isc_hmac_key_t *hkey = NULL; isc_result_t res; + assert_int_equal( + isc_hmac_key_create(type, key, keylen, isc_g_mctx, &hkey), + ISC_R_SUCCESS); assert_non_null(hmac_st); - assert_int_equal(isc_hmac_init(hmac_st, key, keylen, type), - ISC_R_SUCCESS); + + res = isc_hmac_init(hmac_st, hkey); + assert_return_code(res, ISC_R_SUCCESS); for (size_t i = 0; i < repeats; i++) { assert_int_equal(isc_hmac_update(hmac_st, @@ -109,14 +102,16 @@ isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, ISC_R_SUCCESS); } - unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); - assert_int_equal(isc_hmac_final(hmac_st, digest, &digestlen), - ISC_R_SUCCESS); + unsigned char raw_digest[ISC_MAX_MD_SIZE]; + isc_buffer_t digest; + + isc_buffer_init(&digest, raw_digest, sizeof(raw_digest)); + assert_int_equal(isc_hmac_final(hmac_st, &digest), ISC_R_SUCCESS); char hexdigest[ISC_MAX_MD_SIZE * 2 + 3]; - isc_region_t r = { .base = digest, .length = digestlen }; + isc_region_t r; isc_buffer_t b; + isc_buffer_usedregion(&digest, &r); isc_buffer_init(&b, hexdigest, sizeof(hexdigest)); res = isc_hex_totext(&r, 0, "", &b); @@ -124,106 +119,86 @@ isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen, assert_return_code(res, ISC_R_SUCCESS); assert_memory_equal(hexdigest, result, result ? strlen(result) : 0); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + + isc_hmac_key_destroy(&hkey); } -ISC_RUN_TEST_IMPL(isc_hmac_init) { - isc_hmac_t *hmac_st = *state; - assert_non_null(hmac_st); +ISC_RUN_TEST_IMPL(isc_hmac_key_create) { + isc_hmac_key_t *key = NULL; - assert_int_equal(isc_hmac_init(hmac_st, "", 0, NULL), - ISC_R_NOTIMPLEMENTED); + assert_int_equal( + isc_hmac_key_create(ISC_MD_UNKNOWN, "", 0, isc_g_mctx, &key), + ISC_R_NOTIMPLEMENTED); if (!isc_crypto_fips_mode()) { - expect_assert_failure(isc_hmac_init(NULL, "", 0, ISC_MD_MD5)); + /* + expect_assert_failure(isc_hmac_key_create(ISC_MD_MD5, NULL, 0, + isc_g_mctx, &key)); + */ - expect_assert_failure( - isc_hmac_init(hmac_st, NULL, 0, ISC_MD_MD5)); - - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_MD5), + assert_int_equal(isc_hmac_key_create(ISC_MD_MD5, "", 0, + isc_g_mctx, &key), ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); } - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA1), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA1, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA224), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA224, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA256), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA256, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA384), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA384, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512), - ISC_R_SUCCESS); - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + isc_hmac_key_destroy(&key); } ISC_RUN_TEST_IMPL(isc_hmac_update) { isc_hmac_t *hmac_st = *state; assert_non_null(hmac_st); - /* Uses message digest context initialized in isc_hmac_init_test() */ - expect_assert_failure(isc_hmac_update(NULL, NULL, 0)); - assert_int_equal(isc_hmac_update(hmac_st, NULL, 100), ISC_R_SUCCESS); assert_int_equal(isc_hmac_update(hmac_st, (const unsigned char *)"", 0), ISC_R_SUCCESS); } -ISC_RUN_TEST_IMPL(isc_hmac_reset) { - isc_hmac_t *hmac_st = *state; -#if 0 - unsigned char digest[ISC_MAX_MD_SIZE] ISC_ATTR_UNUSED; - unsigned int digestlen ISC_ATTR_UNUSED; -#endif /* if 0 */ - - assert_non_null(hmac_st); - - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512), - ISC_R_SUCCESS); - assert_int_equal( - isc_hmac_update(hmac_st, (const unsigned char *)"a", 1), - ISC_R_SUCCESS); - assert_int_equal( - isc_hmac_update(hmac_st, (const unsigned char *)"b", 1), - ISC_R_SUCCESS); - - assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS); - -#if 0 - /* - * This test would require OpenSSL compiled with mock_assert(), - * so this could be only manually checked that the test will - * segfault when called by hand - */ - expect_assert_failure(isc_hmac_final(hmac_st, digest, &digestlen)); -#endif /* if 0 */ -} - ISC_RUN_TEST_IMPL(isc_hmac_final) { + isc_hmac_key_t *key = NULL; isc_hmac_t *hmac_st = *state; assert_non_null(hmac_st); + assert_int_equal( + isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key), + ISC_R_SUCCESS); + unsigned char digest[ISC_MAX_MD_SIZE]; - unsigned int digestlen = sizeof(digest); + isc_buffer_t digestbuf; - /* Fail when message digest context is empty */ - expect_assert_failure(isc_hmac_final(NULL, digest, &digestlen)); /* Fail when output buffer is empty */ - expect_assert_failure(isc_hmac_final(hmac_st, NULL, &digestlen)); + isc_buffer_init(&digestbuf, NULL, 0); + assert_int_equal(isc_hmac_final(hmac_st, &digestbuf), ISC_R_NOSPACE); - assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512), - ISC_R_SUCCESS); - /* Fail when the digest length pointer is empty */ - expect_assert_failure(isc_hmac_final(hmac_st, digest, NULL)); + /* Fail when the digest length is empty */ + assert_int_equal(isc_hmac_init(hmac_st, key), ISC_R_SUCCESS); + isc_buffer_init(&digestbuf, digest, 0); + assert_int_equal(isc_hmac_final(hmac_st, &digestbuf), ISC_R_NOSPACE); + + isc_hmac_key_destroy(&key); } ISC_RUN_TEST_IMPL(isc_hmac_md5) { @@ -919,10 +894,7 @@ ISC_RUN_TEST_IMPL(isc_hmac_sha512) { ISC_TEST_LIST_START ISC_TEST_ENTRY(isc_hmac_new) -ISC_TEST_ENTRY_CUSTOM(isc_hmac_init, _reset, _reset) - -ISC_TEST_ENTRY_CUSTOM(isc_hmac_reset, _reset, _reset) - +ISC_TEST_ENTRY(isc_hmac_key_create) ISC_TEST_ENTRY(isc_hmac_md5) ISC_TEST_ENTRY(isc_hmac_sha1) ISC_TEST_ENTRY(isc_hmac_sha224) @@ -937,4 +909,4 @@ ISC_TEST_ENTRY(isc_hmac_free) ISC_TEST_LIST_END -ISC_TEST_MAIN_CUSTOM(_setup, _teardown) +ISC_TEST_MAIN_CUSTOM(setup_test_hmac_state, _teardown) diff --git a/tests/isc/md_test.c b/tests/isc/md_test.c index 3602f968e7..b217a25b9c 100644 --- a/tests/isc/md_test.c +++ b/tests/isc/md_test.c @@ -82,8 +82,8 @@ ISC_RUN_TEST_IMPL(isc_md_free) { } static void -isc_md_test(isc_md_t *md, const isc_md_type_t *type, const char *buf, - size_t buflen, const char *result, const size_t repeats) { +isc_md_test(isc_md_t *md, isc_md_type_t type, const char *buf, size_t buflen, + const char *result, const size_t repeats) { isc_result_t res; assert_non_null(md); @@ -118,7 +118,7 @@ ISC_RUN_TEST_IMPL(isc_md_init) { expect_assert_failure(isc_md_init(NULL, ISC_MD_MD5)); - assert_int_equal(isc_md_init(md, NULL), ISC_R_NOTIMPLEMENTED); + assert_int_equal(isc_md_init(md, ISC_MD_UNKNOWN), ISC_R_NOTIMPLEMENTED); if (isc_crypto_fips_mode()) { assert_int_equal(isc_md_init(md, ISC_MD_MD5),