2 * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
21 #ifdef HAVE_OPENSSL_ECDSA
23 #if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
24 #error "ECDSA without EVP for SHA2?"
27 #include <isc/entropy.h>
30 #include <isc/string.h>
33 #include <dns/keyvalues.h>
34 #include <dst/result.h>
36 #include "dst_internal.h"
37 #include "dst_openssl.h"
38 #include "dst_parse.h"
40 #include <openssl/err.h>
41 #include <openssl/objects.h>
42 #include <openssl/ecdsa.h>
43 #include <openssl/bn.h>
45 #ifndef NID_X9_62_prime256v1
46 #error "P-256 group is not known (NID_X9_62_prime256v1)"
49 #error "P-384 group is not known (NID_secp384r1)"
52 #define DST_RET(a) {ret = a; goto err;}
54 static isc_result_t opensslecdsa_todns(const dst_key_t *key,
58 opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
59 EVP_MD_CTX *evp_md_ctx;
60 const EVP_MD *type = NULL;
63 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
64 dctx->key->key_alg == DST_ALG_ECDSA384);
66 evp_md_ctx = EVP_MD_CTX_create();
67 if (evp_md_ctx == NULL)
68 return (ISC_R_NOMEMORY);
69 if (dctx->key->key_alg == DST_ALG_ECDSA256)
74 if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
75 EVP_MD_CTX_destroy(evp_md_ctx);
76 return (dst__openssl_toresult2("EVP_DigestInit_ex",
80 dctx->ctxdata.evp_md_ctx = evp_md_ctx;
82 return (ISC_R_SUCCESS);
86 opensslecdsa_destroyctx(dst_context_t *dctx) {
87 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
89 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
90 dctx->key->key_alg == DST_ALG_ECDSA384);
92 if (evp_md_ctx != NULL) {
93 EVP_MD_CTX_destroy(evp_md_ctx);
94 dctx->ctxdata.evp_md_ctx = NULL;
99 opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
100 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
102 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
103 dctx->key->key_alg == DST_ALG_ECDSA384);
105 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
106 return (dst__openssl_toresult2("EVP_DigestUpdate",
109 return (ISC_R_SUCCESS);
113 BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
114 int bytes = size - BN_num_bytes(bn);
123 opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
125 dst_key_t *key = dctx->key;
128 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
129 EVP_PKEY *pkey = key->keydata.pkey;
130 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
131 unsigned int dgstlen, siglen;
132 unsigned char digest[EVP_MAX_MD_SIZE];
134 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
135 key->key_alg == DST_ALG_ECDSA384);
138 return (ISC_R_FAILURE);
140 if (key->key_alg == DST_ALG_ECDSA256)
141 siglen = DNS_SIG_ECDSA256SIZE;
143 siglen = DNS_SIG_ECDSA384SIZE;
145 isc_buffer_availableregion(sig, &r);
146 if (r.length < siglen)
147 DST_RET(ISC_R_NOSPACE);
149 if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen))
150 DST_RET(dst__openssl_toresult2("EVP_DigestFinal",
153 ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
154 if (ecdsasig == NULL)
155 DST_RET(dst__openssl_toresult2("ECDSA_do_sign",
157 BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
158 r.base += siglen / 2;
159 BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
160 r.base += siglen / 2;
161 ECDSA_SIG_free(ecdsasig);
162 isc_buffer_add(sig, siglen);
172 opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
174 dst_key_t *key = dctx->key;
176 unsigned char *cp = sig->base;
177 ECDSA_SIG *ecdsasig = NULL;
178 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
179 EVP_PKEY *pkey = key->keydata.pkey;
180 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
181 unsigned int dgstlen, siglen;
182 unsigned char digest[EVP_MAX_MD_SIZE];
184 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
185 key->key_alg == DST_ALG_ECDSA384);
188 return (ISC_R_FAILURE);
190 if (key->key_alg == DST_ALG_ECDSA256)
191 siglen = DNS_SIG_ECDSA256SIZE;
193 siglen = DNS_SIG_ECDSA384SIZE;
195 if (sig->length != siglen)
196 return (DST_R_VERIFYFAILURE);
198 if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
199 DST_RET (dst__openssl_toresult2("EVP_DigestFinal_ex",
202 ecdsasig = ECDSA_SIG_new();
203 if (ecdsasig == NULL)
204 DST_RET (ISC_R_NOMEMORY);
205 ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
207 ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
208 /* cp += siglen / 2; */
210 status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
216 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
219 ret = dst__openssl_toresult2("ECDSA_do_verify",
220 DST_R_VERIFYFAILURE);
225 if (ecdsasig != NULL)
226 ECDSA_SIG_free(ecdsasig);
233 opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
236 EVP_PKEY *pkey1 = key1->keydata.pkey;
237 EVP_PKEY *pkey2 = key2->keydata.pkey;
238 EC_KEY *eckey1 = NULL;
239 EC_KEY *eckey2 = NULL;
240 const BIGNUM *priv1, *priv2;
242 if (pkey1 == NULL && pkey2 == NULL)
244 else if (pkey1 == NULL || pkey2 == NULL)
247 eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
248 eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
249 if (eckey1 == NULL && eckey2 == NULL) {
251 } else if (eckey1 == NULL || eckey2 == NULL)
254 status = EVP_PKEY_cmp(pkey1, pkey2);
258 priv1 = EC_KEY_get0_private_key(eckey1);
259 priv2 = EC_KEY_get0_private_key(eckey2);
260 if (priv1 != NULL || priv2 != NULL) {
261 if (priv1 == NULL || priv2 == NULL)
263 if (BN_cmp(priv1, priv2) != 0)
277 opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
280 EC_KEY *eckey = NULL;
283 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
284 key->key_alg == DST_ALG_ECDSA384);
288 if (key->key_alg == DST_ALG_ECDSA256)
289 group_nid = NID_X9_62_prime256v1;
291 group_nid = NID_secp384r1;
293 eckey = EC_KEY_new_by_curve_name(group_nid);
295 return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
296 DST_R_OPENSSLFAILURE));
298 if (EC_KEY_generate_key(eckey) != 1)
299 DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
300 DST_R_OPENSSLFAILURE));
302 pkey = EVP_PKEY_new();
304 DST_RET (ISC_R_NOMEMORY);
305 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
307 DST_RET (ISC_R_FAILURE);
309 key->keydata.pkey = pkey;
319 opensslecdsa_isprivate(const dst_key_t *key) {
321 EVP_PKEY *pkey = key->keydata.pkey;
322 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
324 ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
331 opensslecdsa_destroy(dst_key_t *key) {
332 EVP_PKEY *pkey = key->keydata.pkey;
335 key->keydata.pkey = NULL;
339 opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
342 EC_KEY *eckey = NULL;
346 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
348 REQUIRE(key->keydata.pkey != NULL);
350 pkey = key->keydata.pkey;
351 eckey = EVP_PKEY_get1_EC_KEY(pkey);
353 return (dst__openssl_toresult(ISC_R_FAILURE));
354 len = i2o_ECPublicKey(eckey, NULL);
358 isc_buffer_availableregion(data, &r);
359 if (r.length < (unsigned int) len)
360 DST_RET (ISC_R_NOSPACE);
362 if (!i2o_ECPublicKey(eckey, &cp))
363 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
364 memcpy(r.base, buf + 1, len);
365 isc_buffer_add(data, len);
375 opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
378 EC_KEY *eckey = NULL;
382 const unsigned char *cp;
383 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
385 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
386 key->key_alg == DST_ALG_ECDSA384);
388 if (key->key_alg == DST_ALG_ECDSA256) {
389 len = DNS_KEY_ECDSA256SIZE;
390 group_nid = NID_X9_62_prime256v1;
392 len = DNS_KEY_ECDSA384SIZE;
393 group_nid = NID_secp384r1;
396 isc_buffer_remainingregion(data, &r);
398 return (ISC_R_SUCCESS);
400 return (DST_R_INVALIDPUBLICKEY);
402 eckey = EC_KEY_new_by_curve_name(group_nid);
404 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
406 buf[0] = POINT_CONVERSION_UNCOMPRESSED;
407 memcpy(buf + 1, r.base, len);
409 if (o2i_ECPublicKey(&eckey,
410 (const unsigned char **) &cp,
411 (long) len + 1) == NULL)
412 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
413 if (EC_KEY_check_key(eckey) != 1)
414 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
416 pkey = EVP_PKEY_new();
418 DST_RET (ISC_R_NOMEMORY);
419 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
421 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
424 isc_buffer_forward(data, len);
425 key->keydata.pkey = pkey;
435 opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
438 EC_KEY *eckey = NULL;
439 const BIGNUM *privkey;
441 unsigned char *buf = NULL;
443 if (key->keydata.pkey == NULL)
444 return (DST_R_NULLKEY);
446 pkey = key->keydata.pkey;
447 eckey = EVP_PKEY_get1_EC_KEY(pkey);
449 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
450 privkey = EC_KEY_get0_private_key(eckey);
452 DST_RET (ISC_R_FAILURE);
454 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
456 DST_RET (ISC_R_NOMEMORY);
458 priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY;
459 priv.elements[0].length = BN_num_bytes(privkey);
460 BN_bn2bin(privkey, buf);
461 priv.elements[0].data = buf;
462 priv.nelements = ECDSA_NTAGS;
463 ret = dst__privstruct_writefile(key, &priv, directory);
469 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
474 ecdsa_check(EC_KEY *eckey, dst_key_t *pub)
476 isc_result_t ret = ISC_R_FAILURE;
478 EC_KEY *pubeckey = NULL;
479 const EC_POINT *pubkey;
482 return (ISC_R_SUCCESS);
483 pkey = pub->keydata.pkey;
485 return (ISC_R_SUCCESS);
486 pubeckey = EVP_PKEY_get1_EC_KEY(pkey);
487 if (pubeckey == NULL)
488 return (ISC_R_SUCCESS);
489 pubkey = EC_KEY_get0_public_key(pubeckey);
491 DST_RET (ISC_R_SUCCESS);
492 if (EC_KEY_set_public_key(eckey, pubkey) != 1)
493 DST_RET (ISC_R_SUCCESS);
494 if (EC_KEY_check_key(eckey) == 1)
495 DST_RET (ISC_R_SUCCESS);
498 if (pubeckey != NULL)
499 EC_KEY_free(pubeckey);
504 opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
508 EC_KEY *eckey = NULL;
511 isc_mem_t *mctx = key->mctx;
513 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
514 key->key_alg == DST_ALG_ECDSA384);
516 if (key->key_alg == DST_ALG_ECDSA256)
517 group_nid = NID_X9_62_prime256v1;
519 group_nid = NID_secp384r1;
521 eckey = EC_KEY_new_by_curve_name(group_nid);
523 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
525 /* read private key file */
526 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
527 if (ret != ISC_R_SUCCESS)
530 privkey = BN_bin2bn(priv.elements[0].data,
531 priv.elements[0].length, NULL);
533 DST_RET(ISC_R_NOMEMORY);
534 if (!EC_KEY_set_private_key(eckey, privkey))
535 DST_RET(ISC_R_NOMEMORY);
536 if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
537 DST_RET(DST_R_INVALIDPRIVATEKEY);
538 dst__privstruct_free(&priv, mctx);
539 memset(&priv, 0, sizeof(priv));
541 pkey = EVP_PKEY_new();
543 DST_RET (ISC_R_NOMEMORY);
544 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
546 DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
548 key->keydata.pkey = pkey;
554 dst__privstruct_free(&priv, mctx);
555 memset(&priv, 0, sizeof(priv));
559 static dst_func_t opensslecdsa_functions = {
560 opensslecdsa_createctx,
561 opensslecdsa_destroyctx,
562 opensslecdsa_adddata,
565 NULL, /*%< computesecret */
566 opensslecdsa_compare,
567 NULL, /*%< paramcompare */
568 opensslecdsa_generate,
569 opensslecdsa_isprivate,
570 opensslecdsa_destroy,
572 opensslecdsa_fromdns,
575 NULL, /*%< cleanup */
576 NULL, /*%< fromlabel */
578 NULL, /*%< restore */
582 dst__opensslecdsa_init(dst_func_t **funcp) {
583 REQUIRE(funcp != NULL);
585 *funcp = &opensslecdsa_functions;
586 return (ISC_R_SUCCESS);
589 #else /* HAVE_OPENSSL_ECDSA */
591 #include <isc/util.h>
593 EMPTY_TRANSLATION_UNIT
595 #endif /* HAVE_OPENSSL_ECDSA */