Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / opensslgost_link.c
blob897d3ecd47166763e56772eb39c15dbcd95b26be
1 /* $NetBSD: opensslgost_link.c,v 1.10 2015/07/08 17:28:58 christos Exp $ */
3 /*
4 * Copyright (C) 2010-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 /* Id: opensslgost_link.c,v 1.5 2011/01/19 23:47:12 tbox Exp */
21 #include <config.h>
23 #if defined(OPENSSL) && defined(HAVE_OPENSSL_GOST)
25 #include <isc/entropy.h>
26 #include <isc/mem.h>
27 #include <isc/string.h>
28 #include <isc/util.h>
30 #include <dst/result.h>
32 #include "dst_internal.h"
33 #include "dst_openssl.h"
34 #include "dst_parse.h"
35 #include "dst_gost.h"
37 #include <openssl/err.h>
38 #include <openssl/objects.h>
39 #include <openssl/rsa.h>
40 #include <openssl/engine.h>
42 static ENGINE *e = NULL;
43 static const EVP_MD *opensslgost_digest;
44 extern const EVP_MD *EVP_gost(void);
46 const EVP_MD *EVP_gost(void) {
47 return (opensslgost_digest);
50 /* ISC methods */
52 isc_result_t
53 isc_gost_init(isc_gost_t *ctx) {
54 const EVP_MD *md;
55 int ret;
57 INSIST(ctx != NULL);
59 md = EVP_gost();
60 if (md == NULL)
61 return (DST_R_CRYPTOFAILURE);
62 EVP_MD_CTX_init(ctx);
63 ret = EVP_DigestInit(ctx, md);
64 if (ret != 1)
65 return (DST_R_CRYPTOFAILURE);
66 return (ISC_R_SUCCESS);
69 void
70 isc_gost_invalidate(isc_gost_t *ctx) {
71 EVP_MD_CTX_cleanup(ctx);
74 isc_result_t
75 isc_gost_update(isc_gost_t *ctx, const unsigned char *data,
76 unsigned int len)
78 int ret;
80 INSIST(ctx != NULL);
81 INSIST(data != NULL);
83 ret = EVP_DigestUpdate(ctx, (const void *) data, (size_t) len);
84 if (ret != 1)
85 return (DST_R_CRYPTOFAILURE);
86 return (ISC_R_SUCCESS);
89 isc_result_t
90 isc_gost_final(isc_gost_t *ctx, unsigned char *digest) {
91 int ret;
93 INSIST(ctx != NULL);
94 INSIST(digest != NULL);
96 ret = EVP_DigestFinal(ctx, digest, NULL);
97 if (ret != 1)
98 return (DST_R_CRYPTOFAILURE);
99 return (ISC_R_SUCCESS);
102 /* DST methods */
104 #define DST_RET(a) {ret = a; goto err;}
106 static isc_result_t opensslgost_todns(const dst_key_t *key,
107 isc_buffer_t *data);
109 static isc_result_t
110 opensslgost_createctx(dst_key_t *key, dst_context_t *dctx) {
111 EVP_MD_CTX *evp_md_ctx;
112 const EVP_MD *md = EVP_gost();
114 UNUSED(key);
116 if (md == NULL)
117 return (DST_R_OPENSSLFAILURE);
119 evp_md_ctx = EVP_MD_CTX_create();
120 if (evp_md_ctx == NULL)
121 return (ISC_R_NOMEMORY);
123 if (!EVP_DigestInit_ex(evp_md_ctx, md, NULL)) {
124 EVP_MD_CTX_destroy(evp_md_ctx);
125 return (ISC_R_FAILURE);
127 dctx->ctxdata.evp_md_ctx = evp_md_ctx;
129 return (ISC_R_SUCCESS);
132 static void
133 opensslgost_destroyctx(dst_context_t *dctx) {
134 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
136 if (evp_md_ctx != NULL) {
137 EVP_MD_CTX_destroy(evp_md_ctx);
138 dctx->ctxdata.evp_md_ctx = NULL;
142 static isc_result_t
143 opensslgost_adddata(dst_context_t *dctx, const isc_region_t *data) {
144 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
146 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
147 return (ISC_R_FAILURE);
149 return (ISC_R_SUCCESS);
152 static isc_result_t
153 opensslgost_sign(dst_context_t *dctx, isc_buffer_t *sig) {
154 dst_key_t *key = dctx->key;
155 isc_region_t r;
156 unsigned int siglen = 0;
157 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
158 EVP_PKEY *pkey = key->keydata.pkey;
160 isc_buffer_availableregion(sig, &r);
162 if (r.length < (unsigned int) EVP_PKEY_size(pkey))
163 return (ISC_R_NOSPACE);
165 if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey))
166 return (ISC_R_FAILURE);
168 isc_buffer_add(sig, siglen);
170 return (ISC_R_SUCCESS);
173 static isc_result_t
174 opensslgost_verify(dst_context_t *dctx, const isc_region_t *sig) {
175 dst_key_t *key = dctx->key;
176 int status = 0;
177 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
178 EVP_PKEY *pkey = key->keydata.pkey;
180 status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey);
181 switch (status) {
182 case 1:
183 return (ISC_R_SUCCESS);
184 case 0:
185 return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
186 default:
187 return (dst__openssl_toresult3(dctx->category,
188 "EVP_VerifyFinal",
189 DST_R_VERIFYFAILURE));
193 static isc_boolean_t
194 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
195 EVP_PKEY *pkey1, *pkey2;
197 pkey1 = key1->keydata.pkey;
198 pkey2 = key2->keydata.pkey;
200 if (pkey1 == NULL && pkey2 == NULL)
201 return (ISC_TRUE);
202 else if (pkey1 == NULL || pkey2 == NULL)
203 return (ISC_FALSE);
205 if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
206 return (ISC_FALSE);
207 return (ISC_TRUE);
210 static int
211 progress_cb(EVP_PKEY_CTX *ctx)
213 union {
214 void *dptr;
215 void (*fptr)(int);
216 } u;
217 int p;
219 u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
220 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
221 if (u.fptr != NULL)
222 u.fptr(p);
223 return (1);
226 static isc_result_t
227 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
228 EVP_PKEY_CTX *ctx;
229 union {
230 void *dptr;
231 void (*fptr)(int);
232 } u;
233 EVP_PKEY *pkey = NULL;
234 isc_result_t ret;
236 UNUSED(unused);
237 ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
238 if (ctx == NULL)
239 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
240 DST_R_OPENSSLFAILURE));
241 if (callback != NULL) {
242 u.fptr = callback;
243 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
244 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
246 if (EVP_PKEY_keygen_init(ctx) <= 0)
247 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
248 DST_R_OPENSSLFAILURE));
249 if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0)
250 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_ctrl_str",
251 DST_R_OPENSSLFAILURE));
252 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
253 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
254 DST_R_OPENSSLFAILURE));
255 key->keydata.pkey = pkey;
256 key->key_size = EVP_PKEY_bits(pkey);
257 EVP_PKEY_CTX_free(ctx);
258 return (ISC_R_SUCCESS);
260 err:
261 if (pkey != NULL)
262 EVP_PKEY_free(pkey);
263 if (ctx != NULL)
264 EVP_PKEY_CTX_free(ctx);
265 return (ret);
268 static isc_boolean_t
269 opensslgost_isprivate(const dst_key_t *key) {
270 EVP_PKEY *pkey = key->keydata.pkey;
271 EC_KEY *ec;
273 INSIST(pkey != NULL);
275 ec = EVP_PKEY_get0(pkey);
276 return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
279 static void
280 opensslgost_destroy(dst_key_t *key) {
281 EVP_PKEY *pkey = key->keydata.pkey;
283 EVP_PKEY_free(pkey);
284 key->keydata.pkey = NULL;
287 unsigned char gost_prefix[37] = {
288 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
289 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
290 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
291 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
292 0x03, 0x43, 0x00, 0x04, 0x40
295 static isc_result_t
296 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
297 EVP_PKEY *pkey;
298 isc_region_t r;
299 unsigned char der[37 + 64], *p;
300 int len;
302 REQUIRE(key->keydata.pkey != NULL);
304 pkey = key->keydata.pkey;
306 isc_buffer_availableregion(data, &r);
307 if (r.length < 64)
308 return (ISC_R_NOSPACE);
310 p = der;
311 len = i2d_PUBKEY(pkey, &p);
312 INSIST(len == sizeof(der));
313 INSIST(memcmp(gost_prefix, der, 37) == 0);
314 memmove(r.base, der + 37, 64);
315 isc_buffer_add(data, 64);
317 return (ISC_R_SUCCESS);
320 static isc_result_t
321 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
322 isc_region_t r;
323 EVP_PKEY *pkey = NULL;
324 unsigned char der[37 + 64];
325 const unsigned char *p;
327 isc_buffer_remainingregion(data, &r);
328 if (r.length == 0)
329 return (ISC_R_SUCCESS);
331 if (r.length != 64)
332 return (DST_R_INVALIDPUBLICKEY);
333 memmove(der, gost_prefix, 37);
334 memmove(der + 37, r.base, 64);
335 isc_buffer_forward(data, 64);
337 p = der;
338 if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
339 return (dst__openssl_toresult2("d2i_PUBKEY",
340 DST_R_OPENSSLFAILURE));
341 key->keydata.pkey = pkey;
342 key->key_size = EVP_PKEY_bits(pkey);
344 return (ISC_R_SUCCESS);
347 #ifdef PREFER_GOSTASN1
349 static isc_result_t
350 opensslgost_tofile(const dst_key_t *key, const char *directory) {
351 EVP_PKEY *pkey;
352 dst_private_t priv;
353 isc_result_t result;
354 unsigned char *der, *p;
355 int len;
357 if (key->keydata.pkey == NULL)
358 return (DST_R_NULLKEY);
360 if (key->external) {
361 priv.nelements = 0;
362 return (dst__privstruct_writefile(key, &priv, directory));
365 pkey = key->keydata.pkey;
367 len = i2d_PrivateKey(pkey, NULL);
368 der = isc_mem_get(key->mctx, (size_t) len);
369 if (der == NULL)
370 return (ISC_R_NOMEMORY);
372 p = der;
373 if (i2d_PrivateKey(pkey, &p) != len) {
374 result = dst__openssl_toresult2("i2d_PrivateKey",
375 DST_R_OPENSSLFAILURE);
376 goto fail;
379 priv.elements[0].tag = TAG_GOST_PRIVASN1;
380 priv.elements[0].length = len;
381 priv.elements[0].data = der;
382 priv.nelements = 1;
384 result = dst__privstruct_writefile(key, &priv, directory);
385 fail:
386 if (der != NULL)
387 isc_mem_put(key->mctx, der, (size_t) len);
388 return (result);
391 #else
393 static isc_result_t
394 opensslgost_tofile(const dst_key_t *key, const char *directory) {
395 EVP_PKEY *pkey;
396 EC_KEY *eckey;
397 const BIGNUM *privkey;
398 dst_private_t priv;
399 isc_result_t ret;
400 unsigned char *buf = NULL;
402 if (key->keydata.pkey == NULL)
403 return (DST_R_NULLKEY);
405 if (key->external) {
406 priv.nelements = 0;
407 return (dst__privstruct_writefile(key, &priv, directory));
410 pkey = key->keydata.pkey;
411 eckey = EVP_PKEY_get0(pkey);
412 if (eckey == NULL)
413 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
414 privkey = EC_KEY_get0_private_key(eckey);
415 if (privkey == NULL)
416 return (ISC_R_FAILURE);
418 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
419 if (buf == NULL)
420 return (ISC_R_NOMEMORY);
422 priv.elements[0].tag = TAG_GOST_PRIVRAW;
423 priv.elements[0].length = BN_num_bytes(privkey);
424 BN_bn2bin(privkey, buf);
425 priv.elements[0].data = buf;
426 priv.nelements = 1;
428 ret = dst__privstruct_writefile(key, &priv, directory);
430 if (buf != NULL)
431 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
432 return (ret);
434 #endif
436 static unsigned char gost_dummy_key[71] = {
437 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
438 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
439 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
440 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
441 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b,
442 0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5,
443 0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65,
444 0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63,
445 0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6
448 static isc_result_t
449 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
450 dst_private_t priv;
451 isc_result_t ret;
452 isc_mem_t *mctx = key->mctx;
453 EVP_PKEY *pkey = NULL;
454 EC_KEY *eckey;
455 const EC_POINT *pubkey = NULL;
456 BIGNUM *privkey = NULL;
457 const unsigned char *p;
459 /* read private key file */
460 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
461 if (ret != ISC_R_SUCCESS)
462 return (ret);
464 if (key->external) {
465 if (priv.nelements != 0)
466 DST_RET(DST_R_INVALIDPRIVATEKEY);
467 if (pub == NULL)
468 DST_RET(DST_R_INVALIDPRIVATEKEY);
469 key->keydata.pkey = pub->keydata.pkey;
470 pub->keydata.pkey = NULL;
471 key->key_size = pub->key_size;
472 dst__privstruct_free(&priv, mctx);
473 memset(&priv, 0, sizeof(priv));
474 return (ISC_R_SUCCESS);
477 INSIST((priv.elements[0].tag == TAG_GOST_PRIVASN1) ||
478 (priv.elements[0].tag == TAG_GOST_PRIVRAW));
480 if (priv.elements[0].tag == TAG_GOST_PRIVASN1) {
481 p = priv.elements[0].data;
482 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
483 (long) priv.elements[0].length) == NULL)
484 DST_RET(dst__openssl_toresult2(
485 "d2i_PrivateKey",
486 DST_R_INVALIDPRIVATEKEY));
487 } else {
488 if ((pub != NULL) && (pub->keydata.pkey != NULL)) {
489 eckey = EVP_PKEY_get0(pub->keydata.pkey);
490 pubkey = EC_KEY_get0_public_key(eckey);
493 privkey = BN_bin2bn(priv.elements[0].data,
494 priv.elements[0].length, NULL);
495 if (privkey == NULL)
496 DST_RET(ISC_R_NOMEMORY);
498 /* can't create directly the whole key */
499 p = gost_dummy_key;
500 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
501 (long) sizeof(gost_dummy_key)) == NULL)
502 DST_RET(dst__openssl_toresult2(
503 "d2i_PrivateKey",
504 DST_R_INVALIDPRIVATEKEY));
506 eckey = EVP_PKEY_get0(pkey);
507 if (eckey == NULL)
508 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
509 if (!EC_KEY_set_private_key(eckey, privkey))
510 DST_RET(ISC_R_NOMEMORY);
512 /* have to (re)set the public key */
513 #ifdef notyet
514 (void) gost2001_compute_public(eckey);
515 #else
516 if ((pubkey != NULL) && !EC_KEY_set_public_key(eckey, pubkey))
517 DST_RET(ISC_R_NOMEMORY);
518 #endif
519 BN_clear_free(privkey);
520 privkey = NULL;
522 key->keydata.pkey = pkey;
523 key->key_size = EVP_PKEY_bits(pkey);
524 dst__privstruct_free(&priv, mctx);
525 memset(&priv, 0, sizeof(priv));
526 return (ISC_R_SUCCESS);
528 err:
529 if (privkey != NULL)
530 BN_clear_free(privkey);
531 if (pkey != NULL)
532 EVP_PKEY_free(pkey);
533 opensslgost_destroy(key);
534 dst__privstruct_free(&priv, mctx);
535 memset(&priv, 0, sizeof(priv));
536 return (ret);
539 static void
540 opensslgost_cleanup(void) {
541 if (e != NULL) {
542 ENGINE_finish(e);
543 ENGINE_free(e);
544 e = NULL;
548 static dst_func_t opensslgost_functions = {
549 opensslgost_createctx,
550 NULL, /*%< createctx2 */
551 opensslgost_destroyctx,
552 opensslgost_adddata,
553 opensslgost_sign,
554 opensslgost_verify,
555 NULL, /*%< verify2 */
556 NULL, /*%< computesecret */
557 opensslgost_compare,
558 NULL, /*%< paramcompare */
559 opensslgost_generate,
560 opensslgost_isprivate,
561 opensslgost_destroy,
562 opensslgost_todns,
563 opensslgost_fromdns,
564 opensslgost_tofile,
565 opensslgost_parse,
566 opensslgost_cleanup,
567 NULL, /*%< fromlabel */
568 NULL, /*%< dump */
569 NULL /*%< restore */
572 isc_result_t
573 dst__opensslgost_init(dst_func_t **funcp) {
574 isc_result_t ret;
576 REQUIRE(funcp != NULL);
578 /* check if the gost engine works properly */
579 e = ENGINE_by_id("gost");
580 if (e == NULL)
581 return (dst__openssl_toresult2("ENGINE_by_id",
582 DST_R_OPENSSLFAILURE));
583 if (ENGINE_init(e) <= 0) {
584 ENGINE_free(e);
585 e = NULL;
586 return (dst__openssl_toresult2("ENGINE_init",
587 DST_R_OPENSSLFAILURE));
589 /* better than to rely on digest_gost symbol */
590 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
591 if (opensslgost_digest == NULL)
592 DST_RET(dst__openssl_toresult2("ENGINE_get_digest",
593 DST_R_OPENSSLFAILURE));
594 /* from openssl.cnf */
595 if (ENGINE_register_pkey_asn1_meths(e) <= 0)
596 DST_RET(dst__openssl_toresult2(
597 "ENGINE_register_pkey_asn1_meths",
598 DST_R_OPENSSLFAILURE));
599 if (ENGINE_ctrl_cmd_string(e,
600 "CRYPT_PARAMS",
601 "id-Gost28147-89-CryptoPro-A-ParamSet",
602 0) <= 0)
603 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
604 DST_R_OPENSSLFAILURE));
606 if (*funcp == NULL)
607 *funcp = &opensslgost_functions;
608 return (ISC_R_SUCCESS);
610 err:
611 ENGINE_finish(e);
612 ENGINE_free(e);
613 e = NULL;
614 return (ret);
617 #else /* HAVE_OPENSSL_GOST */
619 #include <isc/util.h>
621 EMPTY_TRANSLATION_UNIT
623 #endif /* HAVE_OPENSSL_GOST */
624 /*! \file */