mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 06:49:58 -04:00
chg: dev: initial openssl version splitting
Dealing with OpenSSL has been rapidly turning into an unwieldy situation as post-3.0 changes turn the library into a different beast. Start treating pre and post-3.0 versions differently for easier maintenance. To help with this Sisyphean task, this MR had to shift things around. `OPENSSL_NO_DEPRECATED` is now declared in BIND alongside an appropriate `OPENSSL_API_COMPAT` value. The former value will set to declare either OpenSSL 1.1.0 or 3.0 as the bare minimum version. Instead of splitting `md.c` and `hmac.c` into separate version-specific files, they now live inside `crypto/ossl1_1.c` and `crypto/ossl3.c`. This way, these functions will be able to utilize the same static `OSSL_PARAM` tables, removing redundant reconstruction for HMAC. For pre-3.0, `isc_hmac` has been reverted back to using the `HMAC_` interface. Using `EVP_MD_CTX`-based functions for HMAC will end up libcrypto calling the same `HMAC_` functions in the end, giving no advantage while confusingly using the digest functions. A new API, `isc_ossl_wrap` has been added. This family of functions aim to provide a common interface for libcrypto version specific code while not abstracting away OpenSSL's structures such as `EVP_PKEY`. Currently the main user of this API is the `dst` family of functions where some ECDSA and RSA opeations need to use the new `OSSL_PARAM` functionality by requirement or to avoid speed penalties. Furthermore OpenSSL based logging has been moved from `isc_tls` to `isc_ossl_wrap` as its a more appropriate place for such functionality. Merge branch 'aydin/openssl-version-split' into 'main' See merge request isc-projects/bind9!11094
This commit is contained in:
commit
fe9fee63c6
35 changed files with 2994 additions and 1944 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <isc/attributes.h>
|
||||
#include <isc/base32.h>
|
||||
#include <isc/commandline.h>
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/dir.h>
|
||||
#include <isc/file.h>
|
||||
#include <isc/hash.h>
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <isc/attributes.h>
|
||||
#include <isc/base64.h>
|
||||
#include <isc/commandline.h>
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/dir.h>
|
||||
#include <isc/file.h>
|
||||
#include <isc/hash.h>
|
||||
|
|
|
|||
|
|
@ -1859,7 +1859,7 @@ dns_catz_generate_masterfilename(dns_catz_zone_t *catz, dns_catz_entry_t *entry,
|
|||
isc_buffer_subtract(tbuf, 1);
|
||||
|
||||
/* __catz__<digest>.db */
|
||||
rlen = (isc_md_type_get_size(ISC_MD_SHA256) * 2 + 1) + 12;
|
||||
rlen = (ISC_SHA256_DIGESTLENGTH * 2 + 1) + 12;
|
||||
|
||||
/* optionally prepend with <zonedir>/ */
|
||||
if (entry->opts.zonedir != NULL) {
|
||||
|
|
|
|||
|
|
@ -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 ||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -21,18 +21,20 @@
|
|||
#include <openssl/rand.h>
|
||||
|
||||
#include <isc/log.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/tls.h>
|
||||
|
||||
#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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -17,16 +17,13 @@
|
|||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/param_build.h>
|
||||
#endif
|
||||
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/safe.h>
|
||||
#include <isc/string.h>
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/safe.h>
|
||||
|
|
|
|||
|
|
@ -19,14 +19,10 @@
|
|||
#include <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rsa.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/param_build.h>
|
||||
#endif
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/safe.h>
|
||||
#include <isc/string.h>
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
16
lib/isc/crypto/meson.build
Normal file
16
lib/isc/crypto/meson.build
Normal file
|
|
@ -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'),
|
||||
)
|
||||
|
|
@ -11,92 +11,232 @@
|
|||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/provider.h>
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/hmac.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/tls.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/safe.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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);
|
||||
491
lib/isc/crypto/ossl3.c
Normal file
491
lib/isc/crypto/ossl3.c
Normal file
|
|
@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/provider.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/hmac.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/safe.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
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);
|
||||
}
|
||||
25
lib/isc/crypto/ossl_common.c
Normal file
25
lib/isc/crypto/ossl_common.c
Normal file
|
|
@ -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 <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
|
||||
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,
|
||||
};
|
||||
168
lib/isc/hmac.c
168
lib/isc/hmac.c
|
|
@ -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 <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/hmac.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/safe.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -13,17 +13,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <isc/types.h>
|
||||
|
||||
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);
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -18,12 +18,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/md.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
287
lib/isc/include/isc/ossl_wrap.h
Normal file
287
lib/isc/include/isc/ossl_wrap.h
Normal file
|
|
@ -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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <isc/log.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
#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[];
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
#include <openssl/err.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/iterated_hash.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
45
lib/isc/md.c
45
lib/isc/md.c
|
|
@ -18,6 +18,7 @@
|
|||
#include <openssl/opensslv.h>
|
||||
|
||||
#include <isc/md.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@
|
|||
#include <openssl/opensslv.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#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);
|
||||
|
|
|
|||
16
lib/isc/ossl_wrap/meson.build
Normal file
16
lib/isc/ossl_wrap/meson.build
Normal file
|
|
@ -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'),
|
||||
)
|
||||
599
lib/isc/ossl_wrap/ossl1_1.c
Normal file
599
lib/isc/ossl_wrap/ossl1_1.c
Normal file
|
|
@ -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 <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
782
lib/isc/ossl_wrap/ossl3.c
Normal file
782
lib/isc/ossl_wrap/ossl3.c
Normal file
|
|
@ -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 <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include <isc/crypto.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
124
lib/isc/ossl_wrap/ossl_common.c
Normal file
124
lib/isc/ossl_wrap/ossl_common.c
Normal file
|
|
@ -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 <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
170
lib/isc/tls.c
170
lib/isc/tls.c
|
|
@ -38,9 +38,11 @@
|
|||
#include <isc/ht.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/ossl_wrap.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/rwlock.h>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
43
meson.build
43
meson.build
|
|
@ -602,21 +602,37 @@ openssl_dep = [
|
|||
dependency('libssl', version: '>=1.1.1'),
|
||||
]
|
||||
|
||||
foreach fn, header : {
|
||||
'EVP_default_properties_enable_fips': '#include <openssl/evp.h>',
|
||||
'FIPS_mode': '#include <openssl/crypto.h>',
|
||||
}
|
||||
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 <openssl/opensslv.h>',
|
||||
)
|
||||
|
||||
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 <openssl/crypto.h>',
|
||||
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 <openssl/err.h>',
|
||||
'BIO_read_ex': '#include <openssl/bio.h>',
|
||||
'BIO_write_ex': '#include <openssl/bio.h>',
|
||||
'EVP_MD_CTX_get0_md': '#include <openssl/evp.h>',
|
||||
'EVP_PKEY_eq': '#include <openssl/evp.h>',
|
||||
'SSL_CTX_set1_cert_store': '#include <openssl/ssl.h>',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* 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 <openssl/err.h>
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include <cmocka.h>
|
||||
|
||||
|
|
@ -39,14 +32,11 @@
|
|||
#include <isc/region.h>
|
||||
#include <isc/result.h>
|
||||
|
||||
#include "hmac.c"
|
||||
|
||||
#include <tests/isc.h>
|
||||
|
||||
#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)
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in a new issue