]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/opensslecdsa_link.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / opensslecdsa_link.c
1 /*
2  * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
3  *
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.
7  *
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.
15  */
16
17 /* $Id$ */
18
19 #include <config.h>
20
21 #ifdef HAVE_OPENSSL_ECDSA
22
23 #if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
24 #error "ECDSA without EVP for SHA2?"
25 #endif
26
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>
32
33 #include <dns/keyvalues.h>
34 #include <dst/result.h>
35
36 #include "dst_internal.h"
37 #include "dst_openssl.h"
38 #include "dst_parse.h"
39
40 #include <openssl/err.h>
41 #include <openssl/objects.h>
42 #include <openssl/ecdsa.h>
43 #include <openssl/bn.h>
44
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
51
52 #define DST_RET(a) {ret = a; goto err;}
53
54 static isc_result_t opensslecdsa_todns(const dst_key_t *key,
55                                        isc_buffer_t *data);
56
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;
61
62         UNUSED(key);
63         REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
64                 dctx->key->key_alg == DST_ALG_ECDSA384);
65
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();
73
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",
77                                                ISC_R_FAILURE));
78         }
79
80         dctx->ctxdata.evp_md_ctx = evp_md_ctx;
81
82         return (ISC_R_SUCCESS);
83 }
84
85 static void
86 opensslecdsa_destroyctx(dst_context_t *dctx) {
87         EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
88
89         REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
90                 dctx->key->key_alg == DST_ALG_ECDSA384);
91
92         if (evp_md_ctx != NULL) {
93                 EVP_MD_CTX_destroy(evp_md_ctx);
94                 dctx->ctxdata.evp_md_ctx = NULL;
95         }
96 }
97
98 static isc_result_t
99 opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
100         EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
101
102         REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
103                 dctx->key->key_alg == DST_ALG_ECDSA384);
104
105         if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
106                 return (dst__openssl_toresult2("EVP_DigestUpdate",
107                                                ISC_R_FAILURE));
108
109         return (ISC_R_SUCCESS);
110 }
111
112 static int
113 BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
114         int bytes = size - BN_num_bytes(bn);
115
116         while (bytes-- > 0)
117                 *buf++ = 0;
118         BN_bn2bin(bn, buf);
119         return (size);
120 }
121
122 static isc_result_t
123 opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
124         isc_result_t ret;
125         dst_key_t *key = dctx->key;
126         isc_region_t r;
127         ECDSA_SIG *ecdsasig;
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];
133
134         REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
135                 key->key_alg == DST_ALG_ECDSA384);
136
137         if (eckey == NULL)
138                 return (ISC_R_FAILURE);
139
140         if (key->key_alg == DST_ALG_ECDSA256)
141                 siglen = DNS_SIG_ECDSA256SIZE;
142         else
143                 siglen = DNS_SIG_ECDSA384SIZE;
144
145         isc_buffer_availableregion(sig, &r);
146         if (r.length < siglen)
147                 DST_RET(ISC_R_NOSPACE);
148
149         if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen))
150                 DST_RET(dst__openssl_toresult2("EVP_DigestFinal",
151                                                ISC_R_FAILURE));
152
153         ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
154         if (ecdsasig == NULL)
155                 DST_RET(dst__openssl_toresult2("ECDSA_do_sign",
156                                                DST_R_SIGNFAILURE));
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);
163         ret = ISC_R_SUCCESS;
164
165  err:
166         if (eckey != NULL)
167                 EC_KEY_free(eckey);
168         return (ret);
169 }
170
171 static isc_result_t
172 opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
173         isc_result_t ret;
174         dst_key_t *key = dctx->key;
175         int status;
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];
183
184         REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
185                 key->key_alg == DST_ALG_ECDSA384);
186
187         if (eckey == NULL)
188                 return (ISC_R_FAILURE);
189
190         if (key->key_alg == DST_ALG_ECDSA256)
191                 siglen = DNS_SIG_ECDSA256SIZE;
192         else
193                 siglen = DNS_SIG_ECDSA384SIZE;
194
195         if (sig->length != siglen)
196                 return (DST_R_VERIFYFAILURE);
197
198         if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
199                 DST_RET (dst__openssl_toresult2("EVP_DigestFinal_ex",
200                                                 ISC_R_FAILURE));
201
202         ecdsasig = ECDSA_SIG_new();
203         if (ecdsasig == NULL)
204                 DST_RET (ISC_R_NOMEMORY);
205         ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
206         cp += siglen / 2;
207         ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
208         /* cp += siglen / 2; */
209
210         status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
211         switch (status) {
212         case 1:
213                 ret = ISC_R_SUCCESS;
214                 break;
215         case 0:
216                 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
217                 break;
218         default:
219                 ret = dst__openssl_toresult2("ECDSA_do_verify",
220                                              DST_R_VERIFYFAILURE);
221                 break;
222         }
223
224  err:
225         if (ecdsasig != NULL)
226                 ECDSA_SIG_free(ecdsasig);
227         if (eckey != NULL)
228                 EC_KEY_free(eckey);
229         return (ret);
230 }
231
232 static isc_boolean_t
233 opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
234         isc_boolean_t ret;
235         int status;
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;
241
242         if (pkey1 == NULL && pkey2 == NULL)
243                 return (ISC_TRUE);
244         else if (pkey1 == NULL || pkey2 == NULL)
245                 return (ISC_FALSE);
246
247         eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
248         eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
249         if (eckey1 == NULL && eckey2 == NULL) {
250                 DST_RET (ISC_TRUE);
251         } else if (eckey1 == NULL || eckey2 == NULL)
252                 DST_RET (ISC_FALSE);
253
254         status = EVP_PKEY_cmp(pkey1, pkey2);
255         if (status != 1)
256                 DST_RET (ISC_FALSE);
257
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)
262                         DST_RET (ISC_FALSE);
263                 if (BN_cmp(priv1, priv2) != 0)
264                         DST_RET (ISC_FALSE);
265         }
266         ret = ISC_TRUE;
267
268  err:
269         if (eckey1 != NULL)
270                 EC_KEY_free(eckey1);
271         if (eckey2 != NULL)
272                 EC_KEY_free(eckey2);
273         return (ret);
274 }
275
276 static isc_result_t
277 opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
278         isc_result_t ret;
279         EVP_PKEY *pkey;
280         EC_KEY *eckey = NULL;
281         int group_nid;
282
283         REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
284                 key->key_alg == DST_ALG_ECDSA384);
285         UNUSED(unused);
286         UNUSED(callback);
287
288         if (key->key_alg == DST_ALG_ECDSA256)
289                 group_nid = NID_X9_62_prime256v1;
290         else
291                 group_nid = NID_secp384r1;
292
293         eckey = EC_KEY_new_by_curve_name(group_nid);
294         if (eckey == NULL)
295                 return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
296                                                DST_R_OPENSSLFAILURE));
297
298         if (EC_KEY_generate_key(eckey) != 1)
299                 DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
300                                                 DST_R_OPENSSLFAILURE));
301
302         pkey = EVP_PKEY_new();
303         if (pkey == NULL)
304                 DST_RET (ISC_R_NOMEMORY);
305         if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
306                 EVP_PKEY_free(pkey);
307                 DST_RET (ISC_R_FAILURE);
308         }
309         key->keydata.pkey = pkey;
310         ret = ISC_R_SUCCESS;
311
312  err:
313         if (eckey != NULL)
314                 EC_KEY_free(eckey);
315         return (ret);
316 }
317
318 static isc_boolean_t
319 opensslecdsa_isprivate(const dst_key_t *key) {
320         isc_boolean_t ret;
321         EVP_PKEY *pkey = key->keydata.pkey;
322         EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
323
324         ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
325         if (eckey != NULL)
326                 EC_KEY_free(eckey);
327         return (ret);
328 }
329
330 static void
331 opensslecdsa_destroy(dst_key_t *key) {
332         EVP_PKEY *pkey = key->keydata.pkey;
333
334         EVP_PKEY_free(pkey);
335         key->keydata.pkey = NULL;
336 }
337
338 static isc_result_t
339 opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
340         isc_result_t ret;
341         EVP_PKEY *pkey;
342         EC_KEY *eckey = NULL;
343         isc_region_t r;
344         int len;
345         unsigned char *cp;
346         unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
347
348         REQUIRE(key->keydata.pkey != NULL);
349
350         pkey = key->keydata.pkey;
351         eckey = EVP_PKEY_get1_EC_KEY(pkey);
352         if (eckey == NULL)
353                 return (dst__openssl_toresult(ISC_R_FAILURE));
354         len = i2o_ECPublicKey(eckey, NULL);
355         /* skip form */
356         len--;
357
358         isc_buffer_availableregion(data, &r);
359         if (r.length < (unsigned int) len)
360                 DST_RET (ISC_R_NOSPACE);
361         cp = buf;
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);
366         ret = ISC_R_SUCCESS;
367
368  err:
369         if (eckey != NULL)
370                 EC_KEY_free(eckey);
371         return (ret);
372 }
373
374 static isc_result_t
375 opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
376         isc_result_t ret;
377         EVP_PKEY *pkey;
378         EC_KEY *eckey = NULL;
379         isc_region_t r;
380         int group_nid;
381         unsigned int len;
382         const unsigned char *cp;
383         unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
384
385         REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
386                 key->key_alg == DST_ALG_ECDSA384);
387
388         if (key->key_alg == DST_ALG_ECDSA256) {
389                 len = DNS_KEY_ECDSA256SIZE;
390                 group_nid = NID_X9_62_prime256v1;
391         } else {
392                 len = DNS_KEY_ECDSA384SIZE;
393                 group_nid = NID_secp384r1;
394         }
395
396         isc_buffer_remainingregion(data, &r);
397         if (r.length == 0)
398                 return (ISC_R_SUCCESS);
399         if (r.length < len)
400                 return (DST_R_INVALIDPUBLICKEY);
401
402         eckey = EC_KEY_new_by_curve_name(group_nid);
403         if (eckey == NULL)
404                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
405
406         buf[0] = POINT_CONVERSION_UNCOMPRESSED;
407         memcpy(buf + 1, r.base, len);
408         cp = buf;
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));
415
416         pkey = EVP_PKEY_new();
417         if (pkey == NULL)
418                 DST_RET (ISC_R_NOMEMORY);
419         if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
420                 EVP_PKEY_free(pkey);
421                 DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
422         }
423
424         isc_buffer_forward(data, len);
425         key->keydata.pkey = pkey;
426         ret = ISC_R_SUCCESS;
427
428  err:
429         if (eckey != NULL)
430                 EC_KEY_free(eckey);
431         return (ret);
432 }
433
434 static isc_result_t
435 opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
436         isc_result_t ret;
437         EVP_PKEY *pkey;
438         EC_KEY *eckey = NULL;
439         const BIGNUM *privkey;
440         dst_private_t priv;
441         unsigned char *buf = NULL;
442
443         if (key->keydata.pkey == NULL)
444                 return (DST_R_NULLKEY);
445
446         pkey = key->keydata.pkey;
447         eckey = EVP_PKEY_get1_EC_KEY(pkey);
448         if (eckey == NULL)
449                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
450         privkey = EC_KEY_get0_private_key(eckey);
451         if (privkey == NULL)
452                 DST_RET (ISC_R_FAILURE);
453
454         buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
455         if (buf == NULL)
456                 DST_RET (ISC_R_NOMEMORY);
457
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);
464
465  err:
466         if (eckey != NULL)
467                 EC_KEY_free(eckey);
468         if (buf != NULL)
469                 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
470         return (ret);
471 }
472
473 static isc_result_t
474 ecdsa_check(EC_KEY *eckey, dst_key_t *pub)
475 {
476         isc_result_t ret = ISC_R_FAILURE;
477         EVP_PKEY *pkey;
478         EC_KEY *pubeckey = NULL;
479         const EC_POINT *pubkey;
480
481         if (pub == NULL)
482                 return (ISC_R_SUCCESS);
483         pkey = pub->keydata.pkey;
484         if (pkey == NULL)
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);
490         if (pubkey == NULL)
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);
496
497  err:
498         if (pubeckey != NULL)
499                 EC_KEY_free(pubeckey);
500         return (ret);
501 }
502
503 static isc_result_t
504 opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
505         dst_private_t priv;
506         isc_result_t ret;
507         EVP_PKEY *pkey;
508         EC_KEY *eckey = NULL;
509         BIGNUM *privkey;
510         int group_nid;
511         isc_mem_t *mctx = key->mctx;
512
513         REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
514                 key->key_alg == DST_ALG_ECDSA384);
515
516         if (key->key_alg == DST_ALG_ECDSA256)
517                 group_nid = NID_X9_62_prime256v1;
518         else
519                 group_nid = NID_secp384r1;
520
521         eckey = EC_KEY_new_by_curve_name(group_nid);
522         if (eckey == NULL)
523                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
524
525         /* read private key file */
526         ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
527         if (ret != ISC_R_SUCCESS)
528                 goto err;
529
530         privkey = BN_bin2bn(priv.elements[0].data,
531                             priv.elements[0].length, NULL);
532         if (privkey == 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));
540
541         pkey = EVP_PKEY_new();
542         if (pkey == NULL)
543                 DST_RET (ISC_R_NOMEMORY);
544         if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
545                 EVP_PKEY_free(pkey);
546                 DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
547         }
548         key->keydata.pkey = pkey;
549         ret = ISC_R_SUCCESS;
550
551  err:
552         if (eckey != NULL)
553                 EC_KEY_free(eckey);
554         dst__privstruct_free(&priv, mctx);
555         memset(&priv, 0, sizeof(priv));
556         return (ret);
557 }
558
559 static dst_func_t opensslecdsa_functions = {
560         opensslecdsa_createctx,
561         opensslecdsa_destroyctx,
562         opensslecdsa_adddata,
563         opensslecdsa_sign,
564         opensslecdsa_verify,
565         NULL, /*%< computesecret */
566         opensslecdsa_compare,
567         NULL, /*%< paramcompare */
568         opensslecdsa_generate,
569         opensslecdsa_isprivate,
570         opensslecdsa_destroy,
571         opensslecdsa_todns,
572         opensslecdsa_fromdns,
573         opensslecdsa_tofile,
574         opensslecdsa_parse,
575         NULL, /*%< cleanup */
576         NULL, /*%< fromlabel */
577         NULL, /*%< dump */
578         NULL, /*%< restore */
579 };
580
581 isc_result_t
582 dst__opensslecdsa_init(dst_func_t **funcp) {
583         REQUIRE(funcp != NULL);
584         if (*funcp == NULL)
585                 *funcp = &opensslecdsa_functions;
586         return (ISC_R_SUCCESS);
587 }
588
589 #else /* HAVE_OPENSSL_ECDSA */
590
591 #include <isc/util.h>
592
593 EMPTY_TRANSLATION_UNIT
594
595 #endif /* HAVE_OPENSSL_ECDSA */
596 /*! \file */