1 /* $NetBSD: opensslgost_link.c,v 1.10 2015/07/08 17:28:58 christos Exp $ */
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 */
23 #if defined(OPENSSL) && defined(HAVE_OPENSSL_GOST)
25 #include <isc/entropy.h>
27 #include <isc/string.h>
30 #include <dst/result.h>
32 #include "dst_internal.h"
33 #include "dst_openssl.h"
34 #include "dst_parse.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
);
53 isc_gost_init(isc_gost_t
*ctx
) {
61 return (DST_R_CRYPTOFAILURE
);
63 ret
= EVP_DigestInit(ctx
, md
);
65 return (DST_R_CRYPTOFAILURE
);
66 return (ISC_R_SUCCESS
);
70 isc_gost_invalidate(isc_gost_t
*ctx
) {
71 EVP_MD_CTX_cleanup(ctx
);
75 isc_gost_update(isc_gost_t
*ctx
, const unsigned char *data
,
83 ret
= EVP_DigestUpdate(ctx
, (const void *) data
, (size_t) len
);
85 return (DST_R_CRYPTOFAILURE
);
86 return (ISC_R_SUCCESS
);
90 isc_gost_final(isc_gost_t
*ctx
, unsigned char *digest
) {
94 INSIST(digest
!= NULL
);
96 ret
= EVP_DigestFinal(ctx
, digest
, NULL
);
98 return (DST_R_CRYPTOFAILURE
);
99 return (ISC_R_SUCCESS
);
104 #define DST_RET(a) {ret = a; goto err;}
106 static isc_result_t
opensslgost_todns(const dst_key_t
*key
,
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();
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
);
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
;
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
);
153 opensslgost_sign(dst_context_t
*dctx
, isc_buffer_t
*sig
) {
154 dst_key_t
*key
= dctx
->key
;
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
);
174 opensslgost_verify(dst_context_t
*dctx
, const isc_region_t
*sig
) {
175 dst_key_t
*key
= dctx
->key
;
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
);
183 return (ISC_R_SUCCESS
);
185 return (dst__openssl_toresult(DST_R_VERIFYFAILURE
));
187 return (dst__openssl_toresult3(dctx
->category
,
189 DST_R_VERIFYFAILURE
));
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
)
202 else if (pkey1
== NULL
|| pkey2
== NULL
)
205 if (EVP_PKEY_cmp(pkey1
, pkey2
) != 1)
211 progress_cb(EVP_PKEY_CTX
*ctx
)
219 u
.dptr
= EVP_PKEY_CTX_get_app_data(ctx
);
220 p
= EVP_PKEY_CTX_get_keygen_info(ctx
, 0);
227 opensslgost_generate(dst_key_t
*key
, int unused
, void (*callback
)(int)) {
233 EVP_PKEY
*pkey
= NULL
;
237 ctx
= EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001
, NULL
);
239 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
240 DST_R_OPENSSLFAILURE
));
241 if (callback
!= NULL
) {
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
);
264 EVP_PKEY_CTX_free(ctx
);
269 opensslgost_isprivate(const dst_key_t
*key
) {
270 EVP_PKEY
*pkey
= key
->keydata
.pkey
;
273 INSIST(pkey
!= NULL
);
275 ec
= EVP_PKEY_get0(pkey
);
276 return (ISC_TF(ec
!= NULL
&& EC_KEY_get0_private_key(ec
) != NULL
));
280 opensslgost_destroy(dst_key_t
*key
) {
281 EVP_PKEY
*pkey
= key
->keydata
.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
296 opensslgost_todns(const dst_key_t
*key
, isc_buffer_t
*data
) {
299 unsigned char der
[37 + 64], *p
;
302 REQUIRE(key
->keydata
.pkey
!= NULL
);
304 pkey
= key
->keydata
.pkey
;
306 isc_buffer_availableregion(data
, &r
);
308 return (ISC_R_NOSPACE
);
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
);
321 opensslgost_fromdns(dst_key_t
*key
, isc_buffer_t
*data
) {
323 EVP_PKEY
*pkey
= NULL
;
324 unsigned char der
[37 + 64];
325 const unsigned char *p
;
327 isc_buffer_remainingregion(data
, &r
);
329 return (ISC_R_SUCCESS
);
332 return (DST_R_INVALIDPUBLICKEY
);
333 memmove(der
, gost_prefix
, 37);
334 memmove(der
+ 37, r
.base
, 64);
335 isc_buffer_forward(data
, 64);
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
350 opensslgost_tofile(const dst_key_t
*key
, const char *directory
) {
354 unsigned char *der
, *p
;
357 if (key
->keydata
.pkey
== NULL
)
358 return (DST_R_NULLKEY
);
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
);
370 return (ISC_R_NOMEMORY
);
373 if (i2d_PrivateKey(pkey
, &p
) != len
) {
374 result
= dst__openssl_toresult2("i2d_PrivateKey",
375 DST_R_OPENSSLFAILURE
);
379 priv
.elements
[0].tag
= TAG_GOST_PRIVASN1
;
380 priv
.elements
[0].length
= len
;
381 priv
.elements
[0].data
= der
;
384 result
= dst__privstruct_writefile(key
, &priv
, directory
);
387 isc_mem_put(key
->mctx
, der
, (size_t) len
);
394 opensslgost_tofile(const dst_key_t
*key
, const char *directory
) {
397 const BIGNUM
*privkey
;
400 unsigned char *buf
= NULL
;
402 if (key
->keydata
.pkey
== NULL
)
403 return (DST_R_NULLKEY
);
407 return (dst__privstruct_writefile(key
, &priv
, directory
));
410 pkey
= key
->keydata
.pkey
;
411 eckey
= EVP_PKEY_get0(pkey
);
413 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE
));
414 privkey
= EC_KEY_get0_private_key(eckey
);
416 return (ISC_R_FAILURE
);
418 buf
= isc_mem_get(key
->mctx
, BN_num_bytes(privkey
));
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
;
428 ret
= dst__privstruct_writefile(key
, &priv
, directory
);
431 isc_mem_put(key
->mctx
, buf
, BN_num_bytes(privkey
));
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
449 opensslgost_parse(dst_key_t
*key
, isc_lex_t
*lexer
, dst_key_t
*pub
) {
452 isc_mem_t
*mctx
= key
->mctx
;
453 EVP_PKEY
*pkey
= NULL
;
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
)
465 if (priv
.nelements
!= 0)
466 DST_RET(DST_R_INVALIDPRIVATEKEY
);
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(
486 DST_R_INVALIDPRIVATEKEY
));
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
);
496 DST_RET(ISC_R_NOMEMORY
);
498 /* can't create directly the whole key */
500 if (d2i_PrivateKey(NID_id_GostR3410_2001
, &pkey
, &p
,
501 (long) sizeof(gost_dummy_key
)) == NULL
)
502 DST_RET(dst__openssl_toresult2(
504 DST_R_INVALIDPRIVATEKEY
));
506 eckey
= EVP_PKEY_get0(pkey
);
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 */
514 (void) gost2001_compute_public(eckey
);
516 if ((pubkey
!= NULL
) && !EC_KEY_set_public_key(eckey
, pubkey
))
517 DST_RET(ISC_R_NOMEMORY
);
519 BN_clear_free(privkey
);
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
);
530 BN_clear_free(privkey
);
533 opensslgost_destroy(key
);
534 dst__privstruct_free(&priv
, mctx
);
535 memset(&priv
, 0, sizeof(priv
));
540 opensslgost_cleanup(void) {
548 static dst_func_t opensslgost_functions
= {
549 opensslgost_createctx
,
550 NULL
, /*%< createctx2 */
551 opensslgost_destroyctx
,
555 NULL
, /*%< verify2 */
556 NULL
, /*%< computesecret */
558 NULL
, /*%< paramcompare */
559 opensslgost_generate
,
560 opensslgost_isprivate
,
567 NULL
, /*%< fromlabel */
573 dst__opensslgost_init(dst_func_t
**funcp
) {
576 REQUIRE(funcp
!= NULL
);
578 /* check if the gost engine works properly */
579 e
= ENGINE_by_id("gost");
581 return (dst__openssl_toresult2("ENGINE_by_id",
582 DST_R_OPENSSLFAILURE
));
583 if (ENGINE_init(e
) <= 0) {
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
,
601 "id-Gost28147-89-CryptoPro-A-ParamSet",
603 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
604 DST_R_OPENSSLFAILURE
));
607 *funcp
= &opensslgost_functions
;
608 return (ISC_R_SUCCESS
);
617 #else /* HAVE_OPENSSL_GOST */
619 #include <isc/util.h>
621 EMPTY_TRANSLATION_UNIT
623 #endif /* HAVE_OPENSSL_GOST */