2 * Copyright (C) 2010-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.
17 /* $Id: opensslgost_link.c,v 1.5 2011/01/19 23:47:12 tbox Exp $ */
21 #ifdef HAVE_OPENSSL_GOST
23 #include <isc/entropy.h>
25 #include <isc/string.h>
28 #include <dst/result.h>
30 #include "dst_internal.h"
31 #include "dst_openssl.h"
32 #include "dst_parse.h"
34 #include <openssl/err.h>
35 #include <openssl/objects.h>
36 #include <openssl/rsa.h>
37 #include <openssl/engine.h>
39 static ENGINE *e = NULL;
40 static const EVP_MD *opensslgost_digest;
41 extern const EVP_MD *EVP_gost(void);
43 const EVP_MD *EVP_gost(void) {
44 return (opensslgost_digest);
47 #define DST_RET(a) {ret = a; goto err;}
49 static isc_result_t opensslgost_todns(const dst_key_t *key,
53 opensslgost_createctx(dst_key_t *key, dst_context_t *dctx) {
54 EVP_MD_CTX *evp_md_ctx;
55 const EVP_MD *md = EVP_gost();
60 return (DST_R_OPENSSLFAILURE);
62 evp_md_ctx = EVP_MD_CTX_create();
63 if (evp_md_ctx == NULL)
64 return (ISC_R_NOMEMORY);
66 if (!EVP_DigestInit_ex(evp_md_ctx, md, NULL)) {
67 EVP_MD_CTX_destroy(evp_md_ctx);
68 return (ISC_R_FAILURE);
70 dctx->ctxdata.evp_md_ctx = evp_md_ctx;
72 return (ISC_R_SUCCESS);
76 opensslgost_destroyctx(dst_context_t *dctx) {
77 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
79 if (evp_md_ctx != NULL) {
80 EVP_MD_CTX_destroy(evp_md_ctx);
81 dctx->ctxdata.evp_md_ctx = NULL;
86 opensslgost_adddata(dst_context_t *dctx, const isc_region_t *data) {
87 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
89 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
90 return (ISC_R_FAILURE);
92 return (ISC_R_SUCCESS);
96 opensslgost_sign(dst_context_t *dctx, isc_buffer_t *sig) {
97 dst_key_t *key = dctx->key;
99 unsigned int siglen = 0;
100 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
101 EVP_PKEY *pkey = key->keydata.pkey;
103 isc_buffer_availableregion(sig, &r);
105 if (r.length < (unsigned int) EVP_PKEY_size(pkey))
106 return (ISC_R_NOSPACE);
108 if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey))
109 return (ISC_R_FAILURE);
111 isc_buffer_add(sig, siglen);
113 return (ISC_R_SUCCESS);
117 opensslgost_verify(dst_context_t *dctx, const isc_region_t *sig) {
118 dst_key_t *key = dctx->key;
120 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
121 EVP_PKEY *pkey = key->keydata.pkey;
123 status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey);
126 return (ISC_R_SUCCESS);
128 return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
130 return (dst__openssl_toresult3(dctx->category,
132 DST_R_VERIFYFAILURE));
137 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
138 EVP_PKEY *pkey1, *pkey2;
140 pkey1 = key1->keydata.pkey;
141 pkey2 = key2->keydata.pkey;
143 if (pkey1 == NULL && pkey2 == NULL)
145 else if (pkey1 == NULL || pkey2 == NULL)
148 if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
154 progress_cb(EVP_PKEY_CTX *ctx)
162 u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
163 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
170 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
176 EVP_PKEY *pkey = NULL;
180 ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
182 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
183 DST_R_OPENSSLFAILURE));
184 if (callback != NULL) {
186 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
187 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
189 if (EVP_PKEY_keygen_init(ctx) <= 0)
190 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
191 DST_R_OPENSSLFAILURE));
192 if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0)
193 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_ctrl_str",
194 DST_R_OPENSSLFAILURE));
195 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
196 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
197 DST_R_OPENSSLFAILURE));
198 key->keydata.pkey = pkey;
199 key->key_size = EVP_PKEY_bits(pkey);
200 EVP_PKEY_CTX_free(ctx);
201 return (ISC_R_SUCCESS);
207 EVP_PKEY_CTX_free(ctx);
212 opensslgost_isprivate(const dst_key_t *key) {
213 EVP_PKEY *pkey = key->keydata.pkey;
216 INSIST(pkey != NULL);
218 ec = EVP_PKEY_get0(pkey);
219 return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
223 opensslgost_destroy(dst_key_t *key) {
224 EVP_PKEY *pkey = key->keydata.pkey;
227 key->keydata.pkey = NULL;
230 unsigned char gost_prefix[37] = {
231 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
232 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
233 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
234 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
235 0x03, 0x43, 0x00, 0x04, 0x40
239 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
242 unsigned char der[37 + 64], *p;
245 REQUIRE(key->keydata.pkey != NULL);
247 pkey = key->keydata.pkey;
249 isc_buffer_availableregion(data, &r);
251 return (ISC_R_NOSPACE);
254 len = i2d_PUBKEY(pkey, &p);
255 INSIST(len == sizeof(der));
256 INSIST(memcmp(gost_prefix, der, 37) == 0);
257 memmove(r.base, der + 37, 64);
258 isc_buffer_add(data, 64);
260 return (ISC_R_SUCCESS);
264 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
266 EVP_PKEY *pkey = NULL;
267 unsigned char der[37 + 64];
268 const unsigned char *p;
270 isc_buffer_remainingregion(data, &r);
272 return (ISC_R_SUCCESS);
275 return (DST_R_INVALIDPUBLICKEY);
276 memmove(der, gost_prefix, 37);
277 memmove(der + 37, r.base, 64);
278 isc_buffer_forward(data, 64);
281 if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
282 return (dst__openssl_toresult2("d2i_PUBKEY",
283 DST_R_OPENSSLFAILURE));
284 key->keydata.pkey = pkey;
285 key->key_size = EVP_PKEY_bits(pkey);
287 return (ISC_R_SUCCESS);
291 opensslgost_tofile(const dst_key_t *key, const char *directory) {
295 unsigned char *der, *p;
298 if (key->keydata.pkey == NULL)
299 return (DST_R_NULLKEY);
303 return (dst__privstruct_writefile(key, &priv, directory));
306 pkey = key->keydata.pkey;
308 len = i2d_PrivateKey(pkey, NULL);
309 der = isc_mem_get(key->mctx, (size_t) len);
311 return (ISC_R_NOMEMORY);
314 if (i2d_PrivateKey(pkey, &p) != len) {
315 result = dst__openssl_toresult2("i2d_PrivateKey",
316 DST_R_OPENSSLFAILURE);
320 priv.elements[0].tag = TAG_GOST_PRIVASN1;
321 priv.elements[0].length = len;
322 priv.elements[0].data = der;
323 priv.nelements = GOST_NTAGS;
325 result = dst__privstruct_writefile(key, &priv, directory);
328 isc_mem_put(key->mctx, der, (size_t) len);
333 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
336 isc_mem_t *mctx = key->mctx;
337 EVP_PKEY *pkey = NULL;
338 const unsigned char *p;
342 /* read private key file */
343 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
344 if (ret != ISC_R_SUCCESS)
348 INSIST(priv.nelements == 0);
350 DST_RET(DST_R_INVALIDPRIVATEKEY);
351 key->keydata.pkey = pub->keydata.pkey;
352 pub->keydata.pkey = NULL;
354 INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
355 p = priv.elements[0].data;
356 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
357 (long) priv.elements[0].length) == NULL)
358 DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
359 DST_R_INVALIDPRIVATEKEY));
360 key->keydata.pkey = pkey;
362 key->key_size = EVP_PKEY_bits(pkey);
363 dst__privstruct_free(&priv, mctx);
364 memset(&priv, 0, sizeof(priv));
365 return (ISC_R_SUCCESS);
370 opensslgost_destroy(key);
371 dst__privstruct_free(&priv, mctx);
372 memset(&priv, 0, sizeof(priv));
377 opensslgost_cleanup(void) {
385 static dst_func_t opensslgost_functions = {
386 opensslgost_createctx,
387 opensslgost_destroyctx,
391 NULL, /*%< verify2 */
392 NULL, /*%< computesecret */
394 NULL, /*%< paramcompare */
395 opensslgost_generate,
396 opensslgost_isprivate,
403 NULL, /*%< fromlabel */
409 dst__opensslgost_init(dst_func_t **funcp) {
412 REQUIRE(funcp != NULL);
414 /* check if the gost engine works properly */
415 e = ENGINE_by_id("gost");
417 return (dst__openssl_toresult2("ENGINE_by_id",
418 DST_R_OPENSSLFAILURE));
419 if (ENGINE_init(e) <= 0) {
422 return (dst__openssl_toresult2("ENGINE_init",
423 DST_R_OPENSSLFAILURE));
425 /* better than to rely on digest_gost symbol */
426 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
427 if (opensslgost_digest == NULL)
428 DST_RET(dst__openssl_toresult2("ENGINE_get_digest",
429 DST_R_OPENSSLFAILURE));
430 /* from openssl.cnf */
431 if (ENGINE_register_pkey_asn1_meths(e) <= 0)
432 DST_RET(dst__openssl_toresult2(
433 "ENGINE_register_pkey_asn1_meths",
434 DST_R_OPENSSLFAILURE));
435 if (ENGINE_ctrl_cmd_string(e,
437 "id-Gost28147-89-CryptoPro-A-ParamSet",
439 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
440 DST_R_OPENSSLFAILURE));
443 *funcp = &opensslgost_functions;
444 return (ISC_R_SUCCESS);
453 #else /* HAVE_OPENSSL_GOST */
455 #include <isc/util.h>
457 EMPTY_TRANSLATION_UNIT
459 #endif /* HAVE_OPENSSL_GOST */