2 * Copyright (C) 2012-2014 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.
19 #ifdef HAVE_OPENSSL_ECDSA
21 #if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
22 #error "ECDSA without EVP for SHA2?"
25 #include <isc/entropy.h>
28 #include <isc/string.h>
31 #include <dns/keyvalues.h>
32 #include <dst/result.h>
34 #include "dst_internal.h"
35 #include "dst_openssl.h"
36 #include "dst_parse.h"
38 #include <openssl/err.h>
39 #include <openssl/objects.h>
40 #include <openssl/ecdsa.h>
41 #include <openssl/bn.h>
43 #ifndef NID_X9_62_prime256v1
44 #error "P-256 group is not known (NID_X9_62_prime256v1)"
47 #error "P-384 group is not known (NID_secp384r1)"
50 #define DST_RET(a) {ret = a; goto err;}
52 static isc_result_t opensslecdsa_todns(const dst_key_t *key,
56 opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
57 EVP_MD_CTX *evp_md_ctx;
58 const EVP_MD *type = NULL;
61 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
62 dctx->key->key_alg == DST_ALG_ECDSA384);
64 evp_md_ctx = EVP_MD_CTX_create();
65 if (evp_md_ctx == NULL)
66 return (ISC_R_NOMEMORY);
67 if (dctx->key->key_alg == DST_ALG_ECDSA256)
72 if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
73 EVP_MD_CTX_destroy(evp_md_ctx);
74 return (dst__openssl_toresult3(dctx->category,
79 dctx->ctxdata.evp_md_ctx = evp_md_ctx;
81 return (ISC_R_SUCCESS);
85 opensslecdsa_destroyctx(dst_context_t *dctx) {
86 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
88 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
89 dctx->key->key_alg == DST_ALG_ECDSA384);
91 if (evp_md_ctx != NULL) {
92 EVP_MD_CTX_destroy(evp_md_ctx);
93 dctx->ctxdata.evp_md_ctx = NULL;
98 opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
99 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
101 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
102 dctx->key->key_alg == DST_ALG_ECDSA384);
104 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
105 return (dst__openssl_toresult3(dctx->category,
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_toresult3(dctx->category,
154 ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
155 if (ecdsasig == NULL)
156 DST_RET(dst__openssl_toresult3(dctx->category,
159 BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
160 isc_region_consume(&r, siglen / 2);
161 BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
162 isc_region_consume(&r, siglen / 2);
163 ECDSA_SIG_free(ecdsasig);
164 isc_buffer_add(sig, siglen);
174 opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
176 dst_key_t *key = dctx->key;
178 unsigned char *cp = sig->base;
179 ECDSA_SIG *ecdsasig = NULL;
180 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
181 EVP_PKEY *pkey = key->keydata.pkey;
182 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
183 unsigned int dgstlen, siglen;
184 unsigned char digest[EVP_MAX_MD_SIZE];
186 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
187 key->key_alg == DST_ALG_ECDSA384);
190 return (ISC_R_FAILURE);
192 if (key->key_alg == DST_ALG_ECDSA256)
193 siglen = DNS_SIG_ECDSA256SIZE;
195 siglen = DNS_SIG_ECDSA384SIZE;
197 if (sig->length != siglen)
198 return (DST_R_VERIFYFAILURE);
200 if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
201 DST_RET (dst__openssl_toresult3(dctx->category,
202 "EVP_DigestFinal_ex",
205 ecdsasig = ECDSA_SIG_new();
206 if (ecdsasig == NULL)
207 DST_RET (ISC_R_NOMEMORY);
208 if (ecdsasig->r != NULL)
209 BN_free(ecdsasig->r);
210 ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
212 if (ecdsasig->s != NULL)
213 BN_free(ecdsasig->s);
214 ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
215 /* cp += siglen / 2; */
217 status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
223 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
226 ret = dst__openssl_toresult3(dctx->category,
228 DST_R_VERIFYFAILURE);
233 if (ecdsasig != NULL)
234 ECDSA_SIG_free(ecdsasig);
241 opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
244 EVP_PKEY *pkey1 = key1->keydata.pkey;
245 EVP_PKEY *pkey2 = key2->keydata.pkey;
246 EC_KEY *eckey1 = NULL;
247 EC_KEY *eckey2 = NULL;
248 const BIGNUM *priv1, *priv2;
250 if (pkey1 == NULL && pkey2 == NULL)
252 else if (pkey1 == NULL || pkey2 == NULL)
255 eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
256 eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
257 if (eckey1 == NULL && eckey2 == NULL) {
259 } else if (eckey1 == NULL || eckey2 == NULL)
262 status = EVP_PKEY_cmp(pkey1, pkey2);
266 priv1 = EC_KEY_get0_private_key(eckey1);
267 priv2 = EC_KEY_get0_private_key(eckey2);
268 if (priv1 != NULL || priv2 != NULL) {
269 if (priv1 == NULL || priv2 == NULL)
271 if (BN_cmp(priv1, priv2) != 0)
285 opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
288 EC_KEY *eckey = NULL;
291 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
292 key->key_alg == DST_ALG_ECDSA384);
296 if (key->key_alg == DST_ALG_ECDSA256)
297 group_nid = NID_X9_62_prime256v1;
299 group_nid = NID_secp384r1;
301 eckey = EC_KEY_new_by_curve_name(group_nid);
303 return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
304 DST_R_OPENSSLFAILURE));
306 if (EC_KEY_generate_key(eckey) != 1)
307 DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
308 DST_R_OPENSSLFAILURE));
310 pkey = EVP_PKEY_new();
312 DST_RET (ISC_R_NOMEMORY);
313 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
315 DST_RET (ISC_R_FAILURE);
317 key->keydata.pkey = pkey;
327 opensslecdsa_isprivate(const dst_key_t *key) {
329 EVP_PKEY *pkey = key->keydata.pkey;
330 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
332 ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
339 opensslecdsa_destroy(dst_key_t *key) {
340 EVP_PKEY *pkey = key->keydata.pkey;
343 key->keydata.pkey = NULL;
347 opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
350 EC_KEY *eckey = NULL;
354 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
356 REQUIRE(key->keydata.pkey != NULL);
358 pkey = key->keydata.pkey;
359 eckey = EVP_PKEY_get1_EC_KEY(pkey);
361 return (dst__openssl_toresult(ISC_R_FAILURE));
362 len = i2o_ECPublicKey(eckey, NULL);
366 isc_buffer_availableregion(data, &r);
367 if (r.length < (unsigned int) len)
368 DST_RET (ISC_R_NOSPACE);
370 if (!i2o_ECPublicKey(eckey, &cp))
371 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
372 memmove(r.base, buf + 1, len);
373 isc_buffer_add(data, len);
383 opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
386 EC_KEY *eckey = NULL;
390 const unsigned char *cp;
391 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
393 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
394 key->key_alg == DST_ALG_ECDSA384);
396 if (key->key_alg == DST_ALG_ECDSA256) {
397 len = DNS_KEY_ECDSA256SIZE;
398 group_nid = NID_X9_62_prime256v1;
400 len = DNS_KEY_ECDSA384SIZE;
401 group_nid = NID_secp384r1;
404 isc_buffer_remainingregion(data, &r);
406 return (ISC_R_SUCCESS);
408 return (DST_R_INVALIDPUBLICKEY);
410 eckey = EC_KEY_new_by_curve_name(group_nid);
412 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
414 buf[0] = POINT_CONVERSION_UNCOMPRESSED;
415 memmove(buf + 1, r.base, len);
417 if (o2i_ECPublicKey(&eckey,
418 (const unsigned char **) &cp,
419 (long) len + 1) == NULL)
420 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
421 if (EC_KEY_check_key(eckey) != 1)
422 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
424 pkey = EVP_PKEY_new();
426 DST_RET (ISC_R_NOMEMORY);
427 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
429 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
432 isc_buffer_forward(data, len);
433 key->keydata.pkey = pkey;
443 opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
446 EC_KEY *eckey = NULL;
447 const BIGNUM *privkey;
449 unsigned char *buf = NULL;
451 if (key->keydata.pkey == NULL)
452 return (DST_R_NULLKEY);
456 return (dst__privstruct_writefile(key, &priv, directory));
459 pkey = key->keydata.pkey;
460 eckey = EVP_PKEY_get1_EC_KEY(pkey);
462 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
463 privkey = EC_KEY_get0_private_key(eckey);
465 DST_RET (ISC_R_FAILURE);
467 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
469 DST_RET (ISC_R_NOMEMORY);
471 priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY;
472 priv.elements[0].length = BN_num_bytes(privkey);
473 BN_bn2bin(privkey, buf);
474 priv.elements[0].data = buf;
475 priv.nelements = ECDSA_NTAGS;
476 ret = dst__privstruct_writefile(key, &priv, directory);
482 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
487 ecdsa_check(EC_KEY *eckey, dst_key_t *pub)
489 isc_result_t ret = ISC_R_FAILURE;
491 EC_KEY *pubeckey = NULL;
492 const EC_POINT *pubkey;
495 return (ISC_R_SUCCESS);
496 pkey = pub->keydata.pkey;
498 return (ISC_R_SUCCESS);
499 pubeckey = EVP_PKEY_get1_EC_KEY(pkey);
500 if (pubeckey == NULL)
501 return (ISC_R_SUCCESS);
502 pubkey = EC_KEY_get0_public_key(pubeckey);
504 DST_RET (ISC_R_SUCCESS);
505 if (EC_KEY_set_public_key(eckey, pubkey) != 1)
506 DST_RET (ISC_R_SUCCESS);
507 if (EC_KEY_check_key(eckey) == 1)
508 DST_RET (ISC_R_SUCCESS);
511 if (pubeckey != NULL)
512 EC_KEY_free(pubeckey);
517 opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
520 EVP_PKEY *pkey, *pubpkey;
521 EC_KEY *eckey = NULL, *pubeckey = NULL;
522 const EC_POINT *pubkey;
525 isc_mem_t *mctx = key->mctx;
527 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
528 key->key_alg == DST_ALG_ECDSA384);
530 if (key->key_alg == DST_ALG_ECDSA256)
531 group_nid = NID_X9_62_prime256v1;
533 group_nid = NID_secp384r1;
535 eckey = EC_KEY_new_by_curve_name(group_nid);
537 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
539 /* read private key file */
540 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
541 if (ret != ISC_R_SUCCESS)
546 * Copy the public key to this new key.
549 DST_RET(DST_R_INVALIDPRIVATEKEY);
550 pubpkey = pub->keydata.pkey;
551 pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
552 if (pubeckey == NULL)
553 DST_RET(DST_R_INVALIDPRIVATEKEY);
554 pubkey = EC_KEY_get0_public_key(pubeckey);
556 DST_RET(DST_R_INVALIDPRIVATEKEY);
557 if (EC_KEY_set_public_key(eckey, pubkey) != 1)
558 DST_RET(DST_R_INVALIDPRIVATEKEY);
559 if (EC_KEY_check_key(eckey) != 1)
560 DST_RET(DST_R_INVALIDPRIVATEKEY);
562 privkey = BN_bin2bn(priv.elements[0].data,
563 priv.elements[0].length, NULL);
565 DST_RET(ISC_R_NOMEMORY);
566 if (!EC_KEY_set_private_key(eckey, privkey))
567 DST_RET(ISC_R_NOMEMORY);
568 if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
569 DST_RET(DST_R_INVALIDPRIVATEKEY);
570 dst__privstruct_free(&priv, mctx);
571 memset(&priv, 0, sizeof(priv));
574 pkey = EVP_PKEY_new();
576 DST_RET (ISC_R_NOMEMORY);
577 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
579 DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
581 key->keydata.pkey = pkey;
587 if (pubeckey != NULL)
588 EC_KEY_free(pubeckey);
589 dst__privstruct_free(&priv, mctx);
590 memset(&priv, 0, sizeof(priv));
594 static dst_func_t opensslecdsa_functions = {
595 opensslecdsa_createctx,
596 opensslecdsa_destroyctx,
597 opensslecdsa_adddata,
600 NULL, /*%< verify2 */
601 NULL, /*%< computesecret */
602 opensslecdsa_compare,
603 NULL, /*%< paramcompare */
604 opensslecdsa_generate,
605 opensslecdsa_isprivate,
606 opensslecdsa_destroy,
608 opensslecdsa_fromdns,
611 NULL, /*%< cleanup */
612 NULL, /*%< fromlabel */
614 NULL, /*%< restore */
618 dst__opensslecdsa_init(dst_func_t **funcp) {
619 REQUIRE(funcp != NULL);
621 *funcp = &opensslecdsa_functions;
622 return (ISC_R_SUCCESS);
625 #else /* HAVE_OPENSSL_ECDSA */
627 #include <isc/util.h>
629 EMPTY_TRANSLATION_UNIT
631 #endif /* HAVE_OPENSSL_ECDSA */