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 EVP_PKEY_CTX_free(ctx);
200 return (ISC_R_SUCCESS);
206 EVP_PKEY_CTX_free(ctx);
211 opensslgost_isprivate(const dst_key_t *key) {
212 EVP_PKEY *pkey = key->keydata.pkey;
215 INSIST(pkey != NULL);
217 ec = EVP_PKEY_get0(pkey);
218 return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
222 opensslgost_destroy(dst_key_t *key) {
223 EVP_PKEY *pkey = key->keydata.pkey;
226 key->keydata.pkey = NULL;
229 unsigned char gost_prefix[37] = {
230 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
231 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
232 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
233 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
234 0x03, 0x43, 0x00, 0x04, 0x40
238 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
241 unsigned char der[37 + 64], *p;
244 REQUIRE(key->keydata.pkey != NULL);
246 pkey = key->keydata.pkey;
248 isc_buffer_availableregion(data, &r);
250 return (ISC_R_NOSPACE);
253 len = i2d_PUBKEY(pkey, &p);
254 INSIST(len == sizeof(der));
255 INSIST(memcmp(gost_prefix, der, 37) == 0);
256 memmove(r.base, der + 37, 64);
257 isc_buffer_add(data, 64);
259 return (ISC_R_SUCCESS);
263 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
265 EVP_PKEY *pkey = NULL;
266 unsigned char der[37 + 64];
267 const unsigned char *p;
269 isc_buffer_remainingregion(data, &r);
271 return (ISC_R_SUCCESS);
274 return (DST_R_INVALIDPUBLICKEY);
275 memmove(der, gost_prefix, 37);
276 memmove(der + 37, r.base, 64);
277 isc_buffer_forward(data, 64);
280 if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
281 return (dst__openssl_toresult2("d2i_PUBKEY",
282 DST_R_OPENSSLFAILURE));
283 key->keydata.pkey = pkey;
285 return (ISC_R_SUCCESS);
289 opensslgost_tofile(const dst_key_t *key, const char *directory) {
293 unsigned char *der, *p;
296 if (key->keydata.pkey == NULL)
297 return (DST_R_NULLKEY);
301 return (dst__privstruct_writefile(key, &priv, directory));
304 pkey = key->keydata.pkey;
306 len = i2d_PrivateKey(pkey, NULL);
307 der = isc_mem_get(key->mctx, (size_t) len);
309 return (ISC_R_NOMEMORY);
312 if (i2d_PrivateKey(pkey, &p) != len) {
313 result = dst__openssl_toresult2("i2d_PrivateKey",
314 DST_R_OPENSSLFAILURE);
318 priv.elements[0].tag = TAG_GOST_PRIVASN1;
319 priv.elements[0].length = len;
320 priv.elements[0].data = der;
321 priv.nelements = GOST_NTAGS;
323 result = dst__privstruct_writefile(key, &priv, directory);
326 isc_mem_put(key->mctx, der, (size_t) len);
331 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
334 isc_mem_t *mctx = key->mctx;
335 EVP_PKEY *pkey = NULL;
336 const unsigned char *p;
340 /* read private key file */
341 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
342 if (ret != ISC_R_SUCCESS)
346 INSIST(priv.nelements == 0);
348 DST_RET(DST_R_INVALIDPRIVATEKEY);
349 key->keydata.pkey = pub->keydata.pkey;
350 pub->keydata.pkey = NULL;
352 INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
353 p = priv.elements[0].data;
354 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
355 (long) priv.elements[0].length) == NULL)
356 DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
357 DST_R_INVALIDPRIVATEKEY));
358 key->keydata.pkey = pkey;
360 key->key_size = EVP_PKEY_bits(pkey);
361 dst__privstruct_free(&priv, mctx);
362 memset(&priv, 0, sizeof(priv));
363 return (ISC_R_SUCCESS);
368 opensslgost_destroy(key);
369 dst__privstruct_free(&priv, mctx);
370 memset(&priv, 0, sizeof(priv));
375 opensslgost_cleanup(void) {
383 static dst_func_t opensslgost_functions = {
384 opensslgost_createctx,
385 opensslgost_destroyctx,
389 NULL, /*%< verify2 */
390 NULL, /*%< computesecret */
392 NULL, /*%< paramcompare */
393 opensslgost_generate,
394 opensslgost_isprivate,
401 NULL, /*%< fromlabel */
407 dst__opensslgost_init(dst_func_t **funcp) {
410 REQUIRE(funcp != NULL);
412 /* check if the gost engine works properly */
413 e = ENGINE_by_id("gost");
415 return (dst__openssl_toresult2("ENGINE_by_id",
416 DST_R_OPENSSLFAILURE));
417 if (ENGINE_init(e) <= 0) {
420 return (dst__openssl_toresult2("ENGINE_init",
421 DST_R_OPENSSLFAILURE));
423 /* better than to rely on digest_gost symbol */
424 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
425 if (opensslgost_digest == NULL)
426 DST_RET(dst__openssl_toresult2("ENGINE_get_digest",
427 DST_R_OPENSSLFAILURE));
428 /* from openssl.cnf */
429 if (ENGINE_register_pkey_asn1_meths(e) <= 0)
430 DST_RET(dst__openssl_toresult2(
431 "ENGINE_register_pkey_asn1_meths",
432 DST_R_OPENSSLFAILURE));
433 if (ENGINE_ctrl_cmd_string(e,
435 "id-Gost28147-89-CryptoPro-A-ParamSet",
437 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
438 DST_R_OPENSSLFAILURE));
441 *funcp = &opensslgost_functions;
442 return (ISC_R_SUCCESS);
451 #else /* HAVE_OPENSSL_GOST */
453 #include <isc/util.h>
455 EMPTY_TRANSLATION_UNIT
457 #endif /* HAVE_OPENSSL_GOST */