mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 10:10:06 +00:00
The DST API has been cleaned up, duplicate functions has been squashed into single call (verify and verify2 functions), and couple of unused functions have been completely removed (createctx2, computesecret, paramcompare, and cleanup).
1200 lines
29 KiB
C
1200 lines
29 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <stdbool.h>
|
|
|
|
#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/mem.h>
|
|
#include <isc/result.h>
|
|
#include <isc/safe.h>
|
|
#include <isc/string.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/keyvalues.h>
|
|
|
|
#include "dst_internal.h"
|
|
#include "dst_openssl.h"
|
|
#include "dst_parse.h"
|
|
#include "openssl_shim.h"
|
|
|
|
#ifndef NID_X9_62_prime256v1
|
|
#error "P-256 group is not known (NID_X9_62_prime256v1)"
|
|
#endif /* ifndef NID_X9_62_prime256v1 */
|
|
#ifndef NID_secp384r1
|
|
#error "P-384 group is not known (NID_secp384r1)"
|
|
#endif /* ifndef NID_secp384r1 */
|
|
|
|
#define MAX_PUBKEY_SIZE DNS_KEY_ECDSA384SIZE
|
|
|
|
#define MAX_PRIVKEY_SIZE (MAX_PUBKEY_SIZE / 2)
|
|
|
|
#define DST_RET(a) \
|
|
{ \
|
|
ret = a; \
|
|
goto err; \
|
|
}
|
|
|
|
#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) {
|
|
case DST_ALG_ECDSA256:
|
|
case DST_ALG_ECDSA384:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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) {
|
|
case DST_ALG_ECDSA256:
|
|
return DNS_KEY_ECDSA256SIZE;
|
|
case DST_ALG_ECDSA384:
|
|
return DNS_KEY_ECDSA384SIZE;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
|
|
INSIST(bytes >= 0);
|
|
|
|
while (bytes-- > 0) {
|
|
*buf++ = 0;
|
|
}
|
|
BN_bn2bin(bn, buf);
|
|
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 ret;
|
|
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) {
|
|
DST_RET(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) {
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult2("EC_GROUP_new_by_"
|
|
"curve_name",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
priv = BN_bin2bn(key, key_len, NULL);
|
|
if (priv == NULL) {
|
|
DST_RET(dst__openssl_toresult2("BN_bin2bn",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
status = OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
|
|
priv);
|
|
if (status != 1) {
|
|
DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
pubkey = opensslecdsa_generate_public_key(group, priv);
|
|
if (pubkey == NULL) {
|
|
DST_RET(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) {
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_"
|
|
"octet_string",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
params = OSSL_PARAM_BLD_to_param(bld);
|
|
if (params == NULL) {
|
|
DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
|
|
if (ctx == NULL) {
|
|
DST_RET(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. */
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
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 ret;
|
|
}
|
|
|
|
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 ret = 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) {
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
|
|
}
|
|
if (!EC_KEY_set_private_key(eckey, privkey)) {
|
|
DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
|
|
}
|
|
|
|
pubkey = opensslecdsa_generate_public_key(group, privkey);
|
|
if (pubkey == NULL) {
|
|
DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
|
|
}
|
|
if (EC_KEY_set_public_key(eckey, pubkey) != 1) {
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
|
|
}
|
|
if (EC_KEY_check_key(eckey) != 1) {
|
|
DST_RET(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
|
|
}
|
|
}
|
|
|
|
pkey = EVP_PKEY_new();
|
|
if (pkey == NULL) {
|
|
DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
|
|
DST_RET(dst__openssl_toresult(ISC_R_FAILURE));
|
|
}
|
|
|
|
*retkey = pkey;
|
|
pkey = NULL;
|
|
|
|
err:
|
|
BN_clear_free(privkey);
|
|
EC_POINT_free(pubkey);
|
|
EC_KEY_free(eckey);
|
|
EVP_PKEY_free(pkey);
|
|
return ret;
|
|
}
|
|
|
|
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 ret;
|
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
ret = opensslecdsa_create_pkey_params(key_alg, private, key, key_len,
|
|
retkey);
|
|
if (ret != ISC_R_FAILURE) {
|
|
return ret;
|
|
}
|
|
#else
|
|
ret = opensslecdsa_create_pkey_legacy(key_alg, private, key, key_len,
|
|
retkey);
|
|
if (ret == ISC_R_SUCCESS) {
|
|
return ret;
|
|
}
|
|
#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 ret;
|
|
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) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
status = EVP_PKEY_keygen_init(ctx);
|
|
if (status != 1) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
status = EVP_PKEY_CTX_set_params(ctx, params);
|
|
if (status != 1) {
|
|
DST_RET(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) {
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_generate",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
EVP_PKEY_CTX_free(ctx);
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_generate_pkey(unsigned int key_alg, const char *label,
|
|
EVP_PKEY **retkey) {
|
|
isc_result_t ret;
|
|
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) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
status = EVP_PKEY_paramgen_init(ctx);
|
|
if (status != 1) {
|
|
DST_RET(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) {
|
|
DST_RET(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) {
|
|
DST_RET(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) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
status = EVP_PKEY_keygen_init(ctx);
|
|
if (status != 1) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
status = EVP_PKEY_keygen(ctx, retkey);
|
|
if (status != 1) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
EVP_PKEY_free(params_pkey);
|
|
EVP_PKEY_CTX_free(ctx);
|
|
return ret;
|
|
}
|
|
|
|
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 ret;
|
|
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) {
|
|
DST_RET(dst__openssl_toresult2("EC_KEY_new_by_curve_name",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
if (EC_KEY_generate_key(eckey) != 1) {
|
|
DST_RET(dst__openssl_toresult2("EC_KEY_generate_key",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
pkey = EVP_PKEY_new();
|
|
if (pkey == NULL) {
|
|
DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
|
|
DST_RET(dst__openssl_toresult2("EVP_PKEY_set1_EC_KEY",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
*retkey = pkey;
|
|
pkey = NULL;
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
EC_KEY_free(eckey);
|
|
EVP_PKEY_free(pkey);
|
|
return ret;
|
|
}
|
|
|
|
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 ret = ISC_R_SUCCESS;
|
|
EVP_MD_CTX *evp_md_ctx;
|
|
EVP_PKEY_CTX *pctx = NULL;
|
|
const EVP_MD *type = NULL;
|
|
|
|
UNUSED(key);
|
|
REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg));
|
|
REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
|
|
|
|
evp_md_ctx = EVP_MD_CTX_create();
|
|
if (evp_md_ctx == NULL) {
|
|
DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
if (dctx->key->key_alg == DST_ALG_ECDSA256) {
|
|
type = isc__crypto_sha256;
|
|
} else {
|
|
type = isc__crypto_sha384;
|
|
}
|
|
|
|
if (dctx->use == DO_SIGN) {
|
|
if (EVP_DigestSignInit(evp_md_ctx, &pctx, type, NULL,
|
|
dctx->key->keydata.pkeypair.priv) != 1)
|
|
{
|
|
EVP_MD_CTX_destroy(evp_md_ctx);
|
|
DST_RET(dst__openssl_toresult3(dctx->category,
|
|
"EVP_DigestSignInit",
|
|
ISC_R_FAILURE));
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x30200000L
|
|
if (!isc_crypto_fips_mode()) {
|
|
ret = opensslecdsa_set_deterministic(
|
|
pctx, dctx->key->key_alg);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
}
|
|
#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */
|
|
|
|
} else {
|
|
if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL,
|
|
dctx->key->keydata.pkeypair.pub) != 1)
|
|
{
|
|
EVP_MD_CTX_destroy(evp_md_ctx);
|
|
DST_RET(dst__openssl_toresult3(dctx->category,
|
|
"EVP_DigestVerifyInit",
|
|
ISC_R_FAILURE));
|
|
}
|
|
}
|
|
|
|
dctx->ctxdata.evp_md_ctx = evp_md_ctx;
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
opensslecdsa_destroyctx(dst_context_t *dctx) {
|
|
EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg));
|
|
REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
|
|
|
|
if (evp_md_ctx != NULL) {
|
|
EVP_MD_CTX_destroy(evp_md_ctx);
|
|
dctx->ctxdata.evp_md_ctx = NULL;
|
|
}
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
|
|
isc_result_t ret = ISC_R_SUCCESS;
|
|
EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg));
|
|
REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
|
|
|
|
if (dctx->use == DO_SIGN) {
|
|
if (EVP_DigestSignUpdate(evp_md_ctx, data->base,
|
|
data->length) != 1)
|
|
{
|
|
DST_RET(dst__openssl_toresult3(dctx->category,
|
|
"EVP_DigestSignUpdate",
|
|
ISC_R_FAILURE));
|
|
}
|
|
} else {
|
|
if (EVP_DigestVerifyUpdate(evp_md_ctx, data->base,
|
|
data->length) != 1)
|
|
{
|
|
DST_RET(dst__openssl_toresult3(dctx->category,
|
|
"EVP_DigestVerifyUpdate",
|
|
ISC_R_FAILURE));
|
|
}
|
|
}
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
|
|
isc_result_t ret;
|
|
dst_key_t *key = dctx->key;
|
|
isc_region_t region;
|
|
EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
|
|
ECDSA_SIG *ecdsasig = NULL;
|
|
size_t siglen, sigder_len = 0, sigder_alloced = 0;
|
|
unsigned char *sigder = NULL;
|
|
const unsigned char *sigder_copy;
|
|
const BIGNUM *r, *s;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
REQUIRE(dctx->use == DO_SIGN);
|
|
|
|
if (key->key_alg == DST_ALG_ECDSA256) {
|
|
siglen = DNS_SIG_ECDSA256SIZE;
|
|
} else {
|
|
siglen = DNS_SIG_ECDSA384SIZE;
|
|
}
|
|
|
|
isc_buffer_availableregion(sig, ®ion);
|
|
if (region.length < siglen) {
|
|
DST_RET(ISC_R_NOSPACE);
|
|
}
|
|
|
|
if (EVP_DigestSignFinal(evp_md_ctx, NULL, &sigder_len) != 1) {
|
|
DST_RET(dst__openssl_toresult3(
|
|
dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE));
|
|
}
|
|
if (sigder_len == 0) {
|
|
DST_RET(ISC_R_FAILURE);
|
|
}
|
|
sigder = isc_mem_get(dctx->mctx, sigder_len);
|
|
sigder_alloced = sigder_len;
|
|
if (EVP_DigestSignFinal(evp_md_ctx, sigder, &sigder_len) != 1) {
|
|
DST_RET(dst__openssl_toresult3(
|
|
dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE));
|
|
}
|
|
sigder_copy = sigder;
|
|
if (d2i_ECDSA_SIG(&ecdsasig, &sigder_copy, sigder_len) == NULL) {
|
|
DST_RET(dst__openssl_toresult3(dctx->category, "d2i_ECDSA_SIG",
|
|
ISC_R_FAILURE));
|
|
}
|
|
|
|
ECDSA_SIG_get0(ecdsasig, &r, &s);
|
|
BN_bn2bin_fixed(r, region.base, siglen / 2);
|
|
isc_region_consume(®ion, siglen / 2);
|
|
BN_bn2bin_fixed(s, region.base, siglen / 2);
|
|
isc_region_consume(®ion, siglen / 2);
|
|
ECDSA_SIG_free(ecdsasig);
|
|
isc_buffer_add(sig, siglen);
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
if (sigder != NULL && sigder_alloced != 0) {
|
|
isc_mem_put(dctx->mctx, sigder, sigder_alloced);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_verify(dst_context_t *dctx, int maxbits ISC_ATTR_UNUSED,
|
|
const isc_region_t *sig) {
|
|
isc_result_t ret;
|
|
dst_key_t *key = dctx->key;
|
|
int status;
|
|
unsigned char *cp = sig->base;
|
|
ECDSA_SIG *ecdsasig = NULL;
|
|
EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
|
|
size_t siglen, sigder_len = 0, sigder_alloced = 0;
|
|
unsigned char *sigder = NULL;
|
|
unsigned char *sigder_copy;
|
|
BIGNUM *r = NULL, *s = NULL;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
REQUIRE(dctx->use == DO_VERIFY);
|
|
|
|
if (key->key_alg == DST_ALG_ECDSA256) {
|
|
siglen = DNS_SIG_ECDSA256SIZE;
|
|
} else {
|
|
siglen = DNS_SIG_ECDSA384SIZE;
|
|
}
|
|
|
|
if (sig->length != siglen) {
|
|
DST_RET(DST_R_VERIFYFAILURE);
|
|
}
|
|
|
|
ecdsasig = ECDSA_SIG_new();
|
|
if (ecdsasig == NULL) {
|
|
DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
r = BN_bin2bn(cp, siglen / 2, NULL);
|
|
cp += siglen / 2;
|
|
s = BN_bin2bn(cp, siglen / 2, NULL);
|
|
/* cp += siglen / 2; */
|
|
ECDSA_SIG_set0(ecdsasig, r, s);
|
|
|
|
status = i2d_ECDSA_SIG(ecdsasig, NULL);
|
|
if (status < 0) {
|
|
DST_RET(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG",
|
|
DST_R_VERIFYFAILURE));
|
|
}
|
|
|
|
sigder_len = (size_t)status;
|
|
sigder = isc_mem_get(dctx->mctx, sigder_len);
|
|
sigder_alloced = sigder_len;
|
|
|
|
sigder_copy = sigder;
|
|
status = i2d_ECDSA_SIG(ecdsasig, &sigder_copy);
|
|
if (status < 0) {
|
|
DST_RET(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG",
|
|
DST_R_VERIFYFAILURE));
|
|
}
|
|
|
|
status = EVP_DigestVerifyFinal(evp_md_ctx, sigder, sigder_len);
|
|
|
|
switch (status) {
|
|
case 1:
|
|
ret = ISC_R_SUCCESS;
|
|
break;
|
|
case 0:
|
|
ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
|
|
break;
|
|
default:
|
|
ret = dst__openssl_toresult3(dctx->category,
|
|
"EVP_DigestVerifyFinal",
|
|
DST_R_VERIFYFAILURE);
|
|
break;
|
|
}
|
|
|
|
err:
|
|
if (ecdsasig != NULL) {
|
|
ECDSA_SIG_free(ecdsasig);
|
|
}
|
|
if (sigder != NULL && sigder_alloced != 0) {
|
|
isc_mem_put(dctx->mctx, sigder, sigder_alloced);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
|
|
isc_result_t ret;
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
UNUSED(unused);
|
|
UNUSED(callback);
|
|
|
|
ret = opensslecdsa_generate_pkey(key->key_alg, key->label, &pkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
key->key_size = EVP_PKEY_bits(pkey);
|
|
key->keydata.pkeypair.priv = pkey;
|
|
key->keydata.pkeypair.pub = pkey;
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
|
|
isc_result_t ret;
|
|
isc_region_t r;
|
|
size_t keysize;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
REQUIRE(key->keydata.pkeypair.pub != NULL);
|
|
|
|
keysize = opensslecdsa_key_alg_to_publickey_size(key->key_alg);
|
|
isc_buffer_availableregion(data, &r);
|
|
if (r.length < keysize) {
|
|
DST_RET(ISC_R_NOSPACE);
|
|
}
|
|
if (!opensslecdsa_extract_public_key(key, r.base, keysize)) {
|
|
DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
|
|
}
|
|
|
|
isc_buffer_add(data, keysize);
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
|
|
isc_result_t ret;
|
|
EVP_PKEY *pkey = NULL;
|
|
isc_region_t r;
|
|
size_t len;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
len = opensslecdsa_key_alg_to_publickey_size(key->key_alg);
|
|
|
|
isc_buffer_remainingregion(data, &r);
|
|
if (r.length == 0) {
|
|
DST_RET(ISC_R_SUCCESS);
|
|
}
|
|
if (r.length != len) {
|
|
DST_RET(DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
|
|
ret = opensslecdsa_create_pkey(key->key_alg, false, r.base, len, &pkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
DST_RET(ret);
|
|
}
|
|
|
|
isc_buffer_forward(data, len);
|
|
key->key_size = EVP_PKEY_bits(pkey);
|
|
key->keydata.pkeypair.pub = pkey;
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
|
|
isc_result_t ret;
|
|
dst_private_t priv;
|
|
unsigned char buf[MAX_PRIVKEY_SIZE];
|
|
size_t keylen = 0;
|
|
unsigned short i;
|
|
|
|
if (key->keydata.pkeypair.pub == NULL) {
|
|
DST_RET(DST_R_NULLKEY);
|
|
}
|
|
|
|
if (key->external) {
|
|
priv.nelements = 0;
|
|
DST_RET(dst__privstruct_writefile(key, &priv, directory));
|
|
}
|
|
|
|
if (key->keydata.pkeypair.priv == NULL) {
|
|
DST_RET(DST_R_NULLKEY);
|
|
}
|
|
|
|
keylen = opensslecdsa_key_alg_to_publickey_size(key->key_alg) / 2;
|
|
INSIST(keylen <= sizeof(buf));
|
|
|
|
i = 0;
|
|
if (opensslecdsa_extract_private_key(key, buf, keylen)) {
|
|
priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY;
|
|
priv.elements[i].length = keylen;
|
|
priv.elements[i].data = buf;
|
|
i++;
|
|
}
|
|
|
|
if (key->label != NULL) {
|
|
priv.elements[i].tag = TAG_ECDSA_LABEL;
|
|
priv.elements[i].length = (unsigned short)strlen(key->label) +
|
|
1;
|
|
priv.elements[i].data = (unsigned char *)key->label;
|
|
i++;
|
|
}
|
|
|
|
priv.nelements = i;
|
|
ret = dst__privstruct_writefile(key, &priv, directory);
|
|
|
|
err:
|
|
isc_safe_memwipe(buf, keylen);
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_fromlabel(dst_key_t *key, const char *label, const char *pin);
|
|
|
|
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 ret;
|
|
EVP_PKEY *pkey = NULL;
|
|
const char *label = NULL;
|
|
int i, privkey_index = -1;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
|
|
/* read private key file */
|
|
ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, key->mctx,
|
|
&priv);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
|
|
if (key->external) {
|
|
if (priv.nelements != 0 || pub == NULL) {
|
|
DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
|
|
}
|
|
key->keydata.pkeypair.priv = pub->keydata.pkeypair.priv;
|
|
key->keydata.pkeypair.pub = pub->keydata.pkeypair.pub;
|
|
pub->keydata.pkeypair.priv = NULL;
|
|
pub->keydata.pkeypair.pub = NULL;
|
|
DST_RET(ISC_R_SUCCESS);
|
|
}
|
|
|
|
for (i = 0; i < priv.nelements; i++) {
|
|
switch (priv.elements[i].tag) {
|
|
case TAG_ECDSA_ENGINE:
|
|
/* The Engine: tag is explicitly ignored */
|
|
break;
|
|
case TAG_ECDSA_LABEL:
|
|
label = (char *)priv.elements[i].data;
|
|
break;
|
|
case TAG_ECDSA_PRIVATEKEY:
|
|
privkey_index = i;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (label != NULL) {
|
|
ret = opensslecdsa_fromlabel(key, label, NULL);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
/* Check that the public component matches if given */
|
|
if (pub != NULL && EVP_PKEY_eq(key->keydata.pkeypair.pub,
|
|
pub->keydata.pkeypair.pub) != 1)
|
|
{
|
|
DST_RET(DST_R_INVALIDPRIVATEKEY);
|
|
}
|
|
DST_RET(ISC_R_SUCCESS);
|
|
}
|
|
|
|
if (privkey_index < 0) {
|
|
DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
|
|
}
|
|
|
|
ret = opensslecdsa_create_pkey(
|
|
key->key_alg, true, priv.elements[privkey_index].data,
|
|
priv.elements[privkey_index].length, &pkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
|
|
/* Check that the public component matches if given */
|
|
if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) {
|
|
DST_RET(DST_R_INVALIDPRIVATEKEY);
|
|
}
|
|
|
|
key->key_size = EVP_PKEY_bits(pkey);
|
|
key->keydata.pkeypair.priv = pkey;
|
|
key->keydata.pkeypair.pub = pkey;
|
|
pkey = NULL;
|
|
|
|
err:
|
|
EVP_PKEY_free(pkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
key->keydata.generic = NULL;
|
|
}
|
|
dst__privstruct_free(&priv, key->mctx);
|
|
isc_safe_memwipe(&priv, sizeof(priv));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static isc_result_t
|
|
opensslecdsa_fromlabel(dst_key_t *key, const char *label, const char *pin) {
|
|
EVP_PKEY *privpkey = NULL, *pubpkey = NULL;
|
|
isc_result_t ret;
|
|
|
|
REQUIRE(opensslecdsa_valid_key_alg(key->key_alg));
|
|
UNUSED(pin);
|
|
|
|
ret = dst__openssl_fromlabel(EVP_PKEY_EC, label, pin, &pubpkey,
|
|
&privpkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
|
|
ret = opensslecdsa_validate_pkey_group(key->key_alg, privpkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
ret = opensslecdsa_validate_pkey_group(key->key_alg, pubpkey);
|
|
if (ret != ISC_R_SUCCESS) {
|
|
goto err;
|
|
}
|
|
|
|
key->label = isc_mem_strdup(key->mctx, label);
|
|
key->key_size = EVP_PKEY_bits(privpkey);
|
|
key->keydata.pkeypair.priv = privpkey;
|
|
key->keydata.pkeypair.pub = pubpkey;
|
|
privpkey = NULL;
|
|
pubpkey = NULL;
|
|
|
|
err:
|
|
EVP_PKEY_free(privpkey);
|
|
EVP_PKEY_free(pubpkey);
|
|
return ret;
|
|
}
|
|
|
|
static dst_func_t opensslecdsa_functions = {
|
|
.createctx = opensslecdsa_createctx,
|
|
.destroyctx = opensslecdsa_destroyctx,
|
|
.adddata = opensslecdsa_adddata,
|
|
.sign = opensslecdsa_sign,
|
|
.verify = opensslecdsa_verify,
|
|
.compare = dst__openssl_keypair_compare,
|
|
.generate = opensslecdsa_generate,
|
|
.isprivate = dst__openssl_keypair_isprivate,
|
|
.destroy = dst__openssl_keypair_destroy,
|
|
.todns = opensslecdsa_todns,
|
|
.fromdns = opensslecdsa_fromdns,
|
|
.tofile = opensslecdsa_tofile,
|
|
.parse = opensslecdsa_parse,
|
|
.fromlabel = opensslecdsa_fromlabel,
|
|
};
|
|
|
|
void
|
|
dst__opensslecdsa_init(dst_func_t **funcp) {
|
|
REQUIRE(funcp != NULL);
|
|
|
|
if (*funcp == NULL) {
|
|
*funcp = &opensslecdsa_functions;
|
|
}
|
|
}
|