Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / opensslecdsa_link.c
blob309f6dd81f3ce4849d36a30cefef28f68a77f37c
1 /* $NetBSD: opensslecdsa_link.c,v 1.9 2015/09/03 07:33:34 christos Exp $ */
3 /*
4 * Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 #include <config.h>
21 #if defined(OPENSSL) && defined(HAVE_OPENSSL_ECDSA)
23 #if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
24 #error "ECDSA without EVP for SHA2?"
25 #endif
27 #include <isc/entropy.h>
28 #include <isc/mem.h>
29 #include <isc/sha2.h>
30 #include <isc/string.h>
31 #include <isc/util.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)"
47 #endif
48 #ifndef NID_secp384r1
49 #error "P-384 group is not known (NID_secp384r1)"
50 #endif
52 #define DST_RET(a) {ret = a; goto err;}
54 static isc_result_t opensslecdsa_todns(const dst_key_t *key,
55 isc_buffer_t *data);
57 static isc_result_t
58 opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
59 EVP_MD_CTX *evp_md_ctx;
60 const EVP_MD *type = NULL;
62 UNUSED(key);
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)
70 type = EVP_sha256();
71 else
72 type = EVP_sha384();
74 if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
75 EVP_MD_CTX_destroy(evp_md_ctx);
76 return (dst__openssl_toresult3(dctx->category,
77 "EVP_DigestInit_ex",
78 ISC_R_FAILURE));
81 dctx->ctxdata.evp_md_ctx = evp_md_ctx;
83 return (ISC_R_SUCCESS);
86 static void
87 opensslecdsa_destroyctx(dst_context_t *dctx) {
88 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
90 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
91 dctx->key->key_alg == DST_ALG_ECDSA384);
93 if (evp_md_ctx != NULL) {
94 EVP_MD_CTX_destroy(evp_md_ctx);
95 dctx->ctxdata.evp_md_ctx = NULL;
99 static isc_result_t
100 opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
101 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
103 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
104 dctx->key->key_alg == DST_ALG_ECDSA384);
106 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
107 return (dst__openssl_toresult3(dctx->category,
108 "EVP_DigestUpdate",
109 ISC_R_FAILURE));
111 return (ISC_R_SUCCESS);
114 static int
115 BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
116 int bytes = size - BN_num_bytes(bn);
118 while (bytes-- > 0)
119 *buf++ = 0;
120 BN_bn2bin(bn, buf);
121 return (size);
124 static isc_result_t
125 opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
126 isc_result_t ret;
127 dst_key_t *key = dctx->key;
128 isc_region_t r;
129 ECDSA_SIG *ecdsasig;
130 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
131 EVP_PKEY *pkey = key->keydata.pkey;
132 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
133 unsigned int dgstlen, siglen;
134 unsigned char digest[EVP_MAX_MD_SIZE];
136 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
137 key->key_alg == DST_ALG_ECDSA384);
139 if (eckey == NULL)
140 return (ISC_R_FAILURE);
142 if (key->key_alg == DST_ALG_ECDSA256)
143 siglen = DNS_SIG_ECDSA256SIZE;
144 else
145 siglen = DNS_SIG_ECDSA384SIZE;
147 isc_buffer_availableregion(sig, &r);
148 if (r.length < siglen)
149 DST_RET(ISC_R_NOSPACE);
151 if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen))
152 DST_RET(dst__openssl_toresult3(dctx->category,
153 "EVP_DigestFinal",
154 ISC_R_FAILURE));
156 ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
157 if (ecdsasig == NULL)
158 DST_RET(dst__openssl_toresult3(dctx->category,
159 "ECDSA_do_sign",
160 DST_R_SIGNFAILURE));
161 BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
162 isc_region_consume(&r, siglen / 2);
163 BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
164 isc_region_consume(&r, siglen / 2);
165 ECDSA_SIG_free(ecdsasig);
166 isc_buffer_add(sig, siglen);
167 ret = ISC_R_SUCCESS;
169 err:
170 if (eckey != NULL)
171 EC_KEY_free(eckey);
172 return (ret);
175 static isc_result_t
176 opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
177 isc_result_t ret;
178 dst_key_t *key = dctx->key;
179 int status;
180 unsigned char *cp = sig->base;
181 ECDSA_SIG *ecdsasig = NULL;
182 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
183 EVP_PKEY *pkey = key->keydata.pkey;
184 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
185 unsigned int dgstlen, siglen;
186 unsigned char digest[EVP_MAX_MD_SIZE];
188 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
189 key->key_alg == DST_ALG_ECDSA384);
191 if (eckey == NULL)
192 return (ISC_R_FAILURE);
194 if (key->key_alg == DST_ALG_ECDSA256)
195 siglen = DNS_SIG_ECDSA256SIZE;
196 else
197 siglen = DNS_SIG_ECDSA384SIZE;
199 if (sig->length != siglen)
200 return (DST_R_VERIFYFAILURE);
202 if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
203 DST_RET (dst__openssl_toresult3(dctx->category,
204 "EVP_DigestFinal_ex",
205 ISC_R_FAILURE));
207 ecdsasig = ECDSA_SIG_new();
208 if (ecdsasig == NULL)
209 DST_RET (ISC_R_NOMEMORY);
210 if (ecdsasig->r != NULL)
211 BN_free(ecdsasig->r);
212 ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
213 cp += siglen / 2;
214 if (ecdsasig->s != NULL)
215 BN_free(ecdsasig->s);
216 ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
217 /* cp += siglen / 2; */
219 status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
220 switch (status) {
221 case 1:
222 ret = ISC_R_SUCCESS;
223 break;
224 case 0:
225 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
226 break;
227 default:
228 ret = dst__openssl_toresult3(dctx->category,
229 "ECDSA_do_verify",
230 DST_R_VERIFYFAILURE);
231 break;
234 err:
235 if (ecdsasig != NULL)
236 ECDSA_SIG_free(ecdsasig);
237 if (eckey != NULL)
238 EC_KEY_free(eckey);
239 return (ret);
242 static isc_boolean_t
243 opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
244 isc_boolean_t ret;
245 int status;
246 EVP_PKEY *pkey1 = key1->keydata.pkey;
247 EVP_PKEY *pkey2 = key2->keydata.pkey;
248 EC_KEY *eckey1 = NULL;
249 EC_KEY *eckey2 = NULL;
250 const BIGNUM *priv1, *priv2;
252 if (pkey1 == NULL && pkey2 == NULL)
253 return (ISC_TRUE);
254 else if (pkey1 == NULL || pkey2 == NULL)
255 return (ISC_FALSE);
257 eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
258 eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
259 if (eckey1 == NULL && eckey2 == NULL) {
260 DST_RET (ISC_TRUE);
261 } else if (eckey1 == NULL || eckey2 == NULL)
262 DST_RET (ISC_FALSE);
264 status = EVP_PKEY_cmp(pkey1, pkey2);
265 if (status != 1)
266 DST_RET (ISC_FALSE);
268 priv1 = EC_KEY_get0_private_key(eckey1);
269 priv2 = EC_KEY_get0_private_key(eckey2);
270 if (priv1 != NULL || priv2 != NULL) {
271 if (priv1 == NULL || priv2 == NULL)
272 DST_RET (ISC_FALSE);
273 if (BN_cmp(priv1, priv2) != 0)
274 DST_RET (ISC_FALSE);
276 ret = ISC_TRUE;
278 err:
279 if (eckey1 != NULL)
280 EC_KEY_free(eckey1);
281 if (eckey2 != NULL)
282 EC_KEY_free(eckey2);
283 return (ret);
286 static isc_result_t
287 opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
288 isc_result_t ret;
289 EVP_PKEY *pkey;
290 EC_KEY *eckey = NULL;
291 int group_nid;
293 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
294 key->key_alg == DST_ALG_ECDSA384);
295 UNUSED(unused);
296 UNUSED(callback);
298 if (key->key_alg == DST_ALG_ECDSA256) {
299 group_nid = NID_X9_62_prime256v1;
300 key->key_size = DNS_KEY_ECDSA256SIZE * 4;
301 } else {
302 group_nid = NID_secp384r1;
303 key->key_size = DNS_KEY_ECDSA384SIZE * 4;
306 eckey = EC_KEY_new_by_curve_name(group_nid);
307 if (eckey == NULL)
308 return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
309 DST_R_OPENSSLFAILURE));
311 if (EC_KEY_generate_key(eckey) != 1)
312 DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
313 DST_R_OPENSSLFAILURE));
315 pkey = EVP_PKEY_new();
316 if (pkey == NULL)
317 DST_RET (ISC_R_NOMEMORY);
318 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
319 EVP_PKEY_free(pkey);
320 DST_RET (ISC_R_FAILURE);
322 key->keydata.pkey = pkey;
323 ret = ISC_R_SUCCESS;
325 err:
326 if (eckey != NULL)
327 EC_KEY_free(eckey);
328 return (ret);
331 static isc_boolean_t
332 opensslecdsa_isprivate(const dst_key_t *key) {
333 isc_boolean_t ret;
334 EVP_PKEY *pkey = key->keydata.pkey;
335 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
337 ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
338 if (eckey != NULL)
339 EC_KEY_free(eckey);
340 return (ret);
343 static void
344 opensslecdsa_destroy(dst_key_t *key) {
345 EVP_PKEY *pkey = key->keydata.pkey;
347 EVP_PKEY_free(pkey);
348 key->keydata.pkey = NULL;
351 static isc_result_t
352 opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
353 isc_result_t ret;
354 EVP_PKEY *pkey;
355 EC_KEY *eckey = NULL;
356 isc_region_t r;
357 int len;
358 unsigned char *cp;
359 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
361 REQUIRE(key->keydata.pkey != NULL);
363 pkey = key->keydata.pkey;
364 eckey = EVP_PKEY_get1_EC_KEY(pkey);
365 if (eckey == NULL)
366 return (dst__openssl_toresult(ISC_R_FAILURE));
367 len = i2o_ECPublicKey(eckey, NULL);
368 /* skip form */
369 len--;
371 isc_buffer_availableregion(data, &r);
372 if (r.length < (unsigned int) len)
373 DST_RET (ISC_R_NOSPACE);
374 cp = buf;
375 if (!i2o_ECPublicKey(eckey, &cp))
376 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
377 memmove(r.base, buf + 1, len);
378 isc_buffer_add(data, len);
379 ret = ISC_R_SUCCESS;
381 err:
382 if (eckey != NULL)
383 EC_KEY_free(eckey);
384 return (ret);
387 static isc_result_t
388 opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
389 isc_result_t ret;
390 EVP_PKEY *pkey;
391 EC_KEY *eckey = NULL;
392 isc_region_t r;
393 int group_nid;
394 unsigned int len;
395 const unsigned char *cp;
396 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
398 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
399 key->key_alg == DST_ALG_ECDSA384);
401 if (key->key_alg == DST_ALG_ECDSA256) {
402 len = DNS_KEY_ECDSA256SIZE;
403 group_nid = NID_X9_62_prime256v1;
404 } else {
405 len = DNS_KEY_ECDSA384SIZE;
406 group_nid = NID_secp384r1;
409 isc_buffer_remainingregion(data, &r);
410 if (r.length == 0)
411 return (ISC_R_SUCCESS);
412 if (r.length < len)
413 return (DST_R_INVALIDPUBLICKEY);
415 eckey = EC_KEY_new_by_curve_name(group_nid);
416 if (eckey == NULL)
417 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
419 buf[0] = POINT_CONVERSION_UNCOMPRESSED;
420 memmove(buf + 1, r.base, len);
421 cp = buf;
422 if (o2i_ECPublicKey(&eckey,
423 (const unsigned char **) &cp,
424 (long) len + 1) == NULL)
425 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
426 if (EC_KEY_check_key(eckey) != 1)
427 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
429 pkey = EVP_PKEY_new();
430 if (pkey == NULL)
431 DST_RET (ISC_R_NOMEMORY);
432 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
433 EVP_PKEY_free(pkey);
434 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
437 isc_buffer_forward(data, len);
438 key->keydata.pkey = pkey;
439 key->key_size = len * 4;
440 ret = ISC_R_SUCCESS;
442 err:
443 if (eckey != NULL)
444 EC_KEY_free(eckey);
445 return (ret);
448 static isc_result_t
449 opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
450 isc_result_t ret;
451 EVP_PKEY *pkey;
452 EC_KEY *eckey = NULL;
453 const BIGNUM *privkey;
454 dst_private_t priv;
455 unsigned char *buf = NULL;
457 if (key->keydata.pkey == NULL)
458 return (DST_R_NULLKEY);
460 if (key->external) {
461 priv.nelements = 0;
462 return (dst__privstruct_writefile(key, &priv, directory));
465 pkey = key->keydata.pkey;
466 eckey = EVP_PKEY_get1_EC_KEY(pkey);
467 if (eckey == NULL)
468 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
469 privkey = EC_KEY_get0_private_key(eckey);
470 if (privkey == NULL)
471 DST_RET (ISC_R_FAILURE);
473 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
474 if (buf == NULL)
475 DST_RET (ISC_R_NOMEMORY);
477 priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY;
478 priv.elements[0].length = BN_num_bytes(privkey);
479 BN_bn2bin(privkey, buf);
480 priv.elements[0].data = buf;
481 priv.nelements = 1;
482 ret = dst__privstruct_writefile(key, &priv, directory);
484 err:
485 if (eckey != NULL)
486 EC_KEY_free(eckey);
487 if (buf != NULL)
488 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
489 return (ret);
492 static isc_result_t
493 ecdsa_check(EC_KEY *eckey, dst_key_t *pub)
495 isc_result_t ret = ISC_R_FAILURE;
496 EVP_PKEY *pkey;
497 EC_KEY *pubeckey = NULL;
498 const EC_POINT *pubkey;
500 if (pub == NULL)
501 return (ISC_R_SUCCESS);
502 pkey = pub->keydata.pkey;
503 if (pkey == NULL)
504 return (ISC_R_SUCCESS);
505 pubeckey = EVP_PKEY_get1_EC_KEY(pkey);
506 if (pubeckey == NULL)
507 return (ISC_R_SUCCESS);
508 pubkey = EC_KEY_get0_public_key(pubeckey);
509 if (pubkey == NULL)
510 DST_RET (ISC_R_SUCCESS);
511 if (EC_KEY_set_public_key(eckey, pubkey) != 1)
512 DST_RET (ISC_R_SUCCESS);
513 if (EC_KEY_check_key(eckey) == 1)
514 DST_RET (ISC_R_SUCCESS);
516 err:
517 if (pubeckey != NULL)
518 EC_KEY_free(pubeckey);
519 return (ret);
522 static isc_result_t
523 opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
524 dst_private_t priv;
525 isc_result_t ret;
526 EVP_PKEY *pkey;
527 EC_KEY *eckey = NULL;
528 BIGNUM *privkey = NULL;
529 int group_nid;
530 isc_mem_t *mctx = key->mctx;
532 REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
533 key->key_alg == DST_ALG_ECDSA384);
535 /* read private key file */
536 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
537 if (ret != ISC_R_SUCCESS)
538 goto err;
540 if (key->external) {
541 if (priv.nelements != 0)
542 DST_RET(DST_R_INVALIDPRIVATEKEY);
543 if (pub == NULL)
544 DST_RET(DST_R_INVALIDPRIVATEKEY);
545 key->keydata.pkey = pub->keydata.pkey;
546 pub->keydata.pkey = NULL;
547 dst__privstruct_free(&priv, mctx);
548 memset(&priv, 0, sizeof(priv));
549 return (ISC_R_SUCCESS);
552 if (key->key_alg == DST_ALG_ECDSA256)
553 group_nid = NID_X9_62_prime256v1;
554 else
555 group_nid = NID_secp384r1;
557 eckey = EC_KEY_new_by_curve_name(group_nid);
558 if (eckey == NULL)
559 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
561 privkey = BN_bin2bn(priv.elements[0].data,
562 priv.elements[0].length, NULL);
563 if (privkey == NULL)
564 DST_RET(ISC_R_NOMEMORY);
565 if (!EC_KEY_set_private_key(eckey, privkey))
566 DST_RET(ISC_R_NOMEMORY);
567 if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
568 DST_RET(DST_R_INVALIDPRIVATEKEY);
570 pkey = EVP_PKEY_new();
571 if (pkey == NULL)
572 DST_RET (ISC_R_NOMEMORY);
573 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
574 EVP_PKEY_free(pkey);
575 DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
577 key->keydata.pkey = pkey;
578 if (key->key_alg == DST_ALG_ECDSA256)
579 key->key_size = DNS_KEY_ECDSA256SIZE * 4;
580 else
581 key->key_size = DNS_KEY_ECDSA384SIZE * 4;
582 ret = ISC_R_SUCCESS;
584 err:
585 if (privkey != NULL)
586 BN_clear_free(privkey);
587 if (eckey != NULL)
588 EC_KEY_free(eckey);
589 dst__privstruct_free(&priv, mctx);
590 memset(&priv, 0, sizeof(priv));
591 return (ret);
594 static dst_func_t opensslecdsa_functions = {
595 opensslecdsa_createctx,
596 NULL, /*%< createctx2 */
597 opensslecdsa_destroyctx,
598 opensslecdsa_adddata,
599 opensslecdsa_sign,
600 opensslecdsa_verify,
601 NULL, /*%< verify2 */
602 NULL, /*%< computesecret */
603 opensslecdsa_compare,
604 NULL, /*%< paramcompare */
605 opensslecdsa_generate,
606 opensslecdsa_isprivate,
607 opensslecdsa_destroy,
608 opensslecdsa_todns,
609 opensslecdsa_fromdns,
610 opensslecdsa_tofile,
611 opensslecdsa_parse,
612 NULL, /*%< cleanup */
613 NULL, /*%< fromlabel */
614 NULL, /*%< dump */
615 NULL, /*%< restore */
618 isc_result_t
619 dst__opensslecdsa_init(dst_func_t **funcp) {
620 REQUIRE(funcp != NULL);
621 if (*funcp == NULL)
622 *funcp = &opensslecdsa_functions;
623 return (ISC_R_SUCCESS);
626 #else /* HAVE_OPENSSL_ECDSA */
628 #include <isc/util.h>
630 EMPTY_TRANSLATION_UNIT
632 #endif /* HAVE_OPENSSL_ECDSA */
633 /*! \file */