mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-23 10:37:43 -04:00
remove libcrypto version specific code in opensslecdsa_link
Using `EVP_SIGNATURE` explicit algoritms for signatures have been added in OpenSSL 3.4 and so is skipped for the initial OpenSSL version specific code splitting.
This commit is contained in:
parent
f4d88404e2
commit
3bd3754994
4 changed files with 1016 additions and 603 deletions
|
|
@ -17,14 +17,8 @@
|
|||
|
||||
#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>
|
||||
|
|
@ -55,37 +49,6 @@ extern EVP_MD *isc__crypto_md[];
|
|||
|
||||
#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) {
|
||||
|
|
@ -97,18 +60,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) {
|
||||
|
|
@ -121,23 +72,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);
|
||||
|
|
@ -151,534 +85,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));
|
||||
|
|
@ -690,8 +103,10 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
|
|||
}
|
||||
if (dctx->key->key_alg == DST_ALG_ECDSA256) {
|
||||
type = isc__crypto_md[ISC_MD_SHA256];
|
||||
md = "SHA256";
|
||||
} else {
|
||||
type = isc__crypto_md[ISC_MD_SHA384];
|
||||
md = "SHA384";
|
||||
}
|
||||
|
||||
if (dctx->use == DO_SIGN) {
|
||||
|
|
@ -704,12 +119,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,
|
||||
|
|
@ -723,6 +141,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;
|
||||
|
|
@ -921,7 +340,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;
|
||||
|
|
@ -933,6 +376,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));
|
||||
|
|
@ -943,8 +387,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);
|
||||
|
|
@ -972,8 +431,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);
|
||||
|
|
@ -991,6 +458,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);
|
||||
|
|
@ -1008,8 +476,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;
|
||||
|
|
@ -1039,6 +522,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;
|
||||
|
|
@ -1091,9 +575,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) {
|
||||
|
|
@ -1127,8 +623,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);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,179 @@ typedef struct isc_ossl_wrap_rsa_components {
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -12,17 +12,88 @@
|
|||
*/
|
||||
|
||||
#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);
|
||||
|
|
@ -36,6 +107,251 @@ rsa_keygen_progress_cb(int p, int n, BN_GENCB *cb) {
|
|||
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"));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -15,19 +15,97 @@
|
|||
|
||||
#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/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) { \
|
||||
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##_group_name); \
|
||||
} \
|
||||
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##_group_name); \
|
||||
} \
|
||||
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##_group_name, 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); \
|
||||
}
|
||||
|
||||
static char pkcs11_key_usage[] = "digitalSignature";
|
||||
|
||||
constexpr char *p256_group_name = "prime256v1";
|
||||
constexpr char *p384_group_name = "secp384r1";
|
||||
|
||||
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 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);
|
||||
|
|
@ -40,6 +118,346 @@ rsa_keygen_progress_cb(EVP_PKEY_CTX *ctx) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
generate_ec_key(EVP_PKEY **pkeyp, const int nid) {
|
||||
isc_result_t result;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *params_pkey = NULL;
|
||||
|
||||
/* Generate the key's parameters. */
|
||||
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_paramgen_init(pctx) != 1) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen_init"));
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_"
|
||||
"nid"));
|
||||
}
|
||||
|
||||
if (EVP_PKEY_paramgen(pctx, ¶ms_pkey) != 1) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen"));
|
||||
}
|
||||
|
||||
if (params_pkey == NULL) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_paramgen"));
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
|
||||
/* Generate the key. */
|
||||
pctx = EVP_PKEY_CTX_new(params_pkey, NULL);
|
||||
if (pctx == NULL) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_CTX_new"));
|
||||
}
|
||||
|
||||
if (EVP_PKEY_keygen_init(pctx) != 1) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen_init"));
|
||||
}
|
||||
|
||||
if (EVP_PKEY_keygen(pctx, pkeyp) != 1) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_keygen"));
|
||||
}
|
||||
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(params_pkey);
|
||||
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;
|
||||
OSSL_PARAM params[3];
|
||||
|
||||
params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0);
|
||||
params[1] = OSSL_PARAM_construct_utf8_string(
|
||||
"pkcs11_key_usage", pkcs11_key_usage,
|
||||
sizeof(pkcs11_key_usage) - 1);
|
||||
params[2] = OSSL_PARAM_construct_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"));
|
||||
}
|
||||
|
||||
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 char *expected) {
|
||||
isc_result_t result;
|
||||
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 (strcmp(expected, actual) != 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 char *group_name) {
|
||||
isc_result_t result;
|
||||
OSSL_PARAM_BLD *bld = NULL;
|
||||
OSSL_PARAM *params = NULL;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
uint8_t buffer[MAX_PUBLIC_KEY_SIZE + 1];
|
||||
|
||||
buffer[0] = POINT_CONVERSION_UNCOMPRESSED;
|
||||
memmove(buffer + 1, region.base, region.length);
|
||||
|
||||
bld = OSSL_PARAM_BLD_new();
|
||||
if (bld == NULL) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_new"));
|
||||
}
|
||||
|
||||
if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
|
||||
group_name, 0) != 1)
|
||||
{
|
||||
CLEANUP(OSSL_WRAP_ERROR("OSSL_PARAM_BLD_push_utf8_string"));
|
||||
}
|
||||
|
||||
if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
|
||||
buffer, region.length + 1) != 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_PUBLIC_KEY, params) != 1) {
|
||||
CLEANUP(OSSL_WRAP_ERROR("EVP_PKEY_fromdata"));
|
||||
}
|
||||
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
OSSL_PARAM_free(params);
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
load_ec_secret_from_region(isc_region_t region, EVP_PKEY **pkeyp,
|
||||
const char *group_name, const int nid) {
|
||||
uint8_t public[MAX_PUBLIC_KEY_SIZE + 1];
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
OSSL_PARAM_BLD *bld = NULL;
|
||||
OSSL_PARAM *params = 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_by_curve_name(nid);
|
||||
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, OSSL_PKEY_PARAM_GROUP_NAME,
|
||||
group_name, 0) != 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];
|
||||
|
||||
REQUIRE(pctx != NULL && hash != NULL);
|
||||
|
||||
params[0] = OSSL_PARAM_construct_utf8_string("digest", UNCONST(hash),
|
||||
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) {
|
||||
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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue