2 * Copyright (C) 2010-2012 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_toresult2("EVP_VerifyFinal",
131 DST_R_VERIFYFAILURE));
136 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
137 EVP_PKEY *pkey1, *pkey2;
139 pkey1 = key1->keydata.pkey;
140 pkey2 = key2->keydata.pkey;
142 if (pkey1 == NULL && pkey2 == NULL)
144 else if (pkey1 == NULL || pkey2 == NULL)
147 if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
153 progress_cb(EVP_PKEY_CTX *ctx)
161 u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
162 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
169 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
175 EVP_PKEY *pkey = NULL;
179 ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
181 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
182 DST_R_OPENSSLFAILURE));
183 if (callback != NULL) {
185 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
186 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
188 if (EVP_PKEY_keygen_init(ctx) <= 0)
189 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
190 DST_R_OPENSSLFAILURE));
191 if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0)
192 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_ctrl_str",
193 DST_R_OPENSSLFAILURE));
194 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
195 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
196 DST_R_OPENSSLFAILURE));
197 key->keydata.pkey = pkey;
198 EVP_PKEY_CTX_free(ctx);
199 return (ISC_R_SUCCESS);
205 EVP_PKEY_CTX_free(ctx);
210 opensslgost_isprivate(const dst_key_t *key) {
211 EVP_PKEY *pkey = key->keydata.pkey;
214 INSIST(pkey != NULL);
216 ec = EVP_PKEY_get0(pkey);
217 return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
221 opensslgost_destroy(dst_key_t *key) {
222 EVP_PKEY *pkey = key->keydata.pkey;
225 key->keydata.pkey = NULL;
228 unsigned char gost_prefix[37] = {
229 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
230 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
231 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
232 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
233 0x03, 0x43, 0x00, 0x04, 0x40
237 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
240 unsigned char der[37 + 64], *p;
243 REQUIRE(key->keydata.pkey != NULL);
245 pkey = key->keydata.pkey;
247 isc_buffer_availableregion(data, &r);
249 return (ISC_R_NOSPACE);
252 len = i2d_PUBKEY(pkey, &p);
253 INSIST(len == sizeof(der));
254 INSIST(memcmp(gost_prefix, der, 37) == 0);
255 memcpy(r.base, der + 37, 64);
256 isc_buffer_add(data, 64);
258 return (ISC_R_SUCCESS);
262 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
264 EVP_PKEY *pkey = NULL;
265 unsigned char der[37 + 64];
266 const unsigned char *p;
268 isc_buffer_remainingregion(data, &r);
270 return (ISC_R_SUCCESS);
273 return (DST_R_INVALIDPUBLICKEY);
274 memcpy(der, gost_prefix, 37);
275 memcpy(der + 37, r.base, 64);
276 isc_buffer_forward(data, 64);
279 if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
280 return (dst__openssl_toresult2("d2i_PUBKEY",
281 DST_R_OPENSSLFAILURE));
282 key->keydata.pkey = pkey;
284 return (ISC_R_SUCCESS);
288 opensslgost_tofile(const dst_key_t *key, const char *directory) {
292 unsigned char *der, *p;
295 if (key->keydata.pkey == NULL)
296 return (DST_R_NULLKEY);
298 pkey = key->keydata.pkey;
300 len = i2d_PrivateKey(pkey, NULL);
301 der = isc_mem_get(key->mctx, (size_t) len);
303 return (ISC_R_NOMEMORY);
306 if (i2d_PrivateKey(pkey, &p) != len) {
307 result = dst__openssl_toresult2("i2d_PrivateKey",
308 DST_R_OPENSSLFAILURE);
312 priv.elements[0].tag = TAG_GOST_PRIVASN1;
313 priv.elements[0].length = len;
314 priv.elements[0].data = der;
315 priv.nelements = GOST_NTAGS;
317 result = dst__privstruct_writefile(key, &priv, directory);
320 isc_mem_put(key->mctx, der, (size_t) len);
325 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
328 isc_mem_t *mctx = key->mctx;
329 EVP_PKEY *pkey = NULL;
330 const unsigned char *p;
334 /* read private key file */
335 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
336 if (ret != ISC_R_SUCCESS)
339 INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
340 p = priv.elements[0].data;
341 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
342 (long) priv.elements[0].length) == NULL)
343 DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
344 DST_R_INVALIDPRIVATEKEY));
345 key->keydata.pkey = pkey;
346 key->key_size = EVP_PKEY_bits(pkey);
347 dst__privstruct_free(&priv, mctx);
348 memset(&priv, 0, sizeof(priv));
349 return (ISC_R_SUCCESS);
354 opensslgost_destroy(key);
355 dst__privstruct_free(&priv, mctx);
356 memset(&priv, 0, sizeof(priv));
361 opensslgost_cleanup(void) {
369 static dst_func_t opensslgost_functions = {
370 opensslgost_createctx,
371 opensslgost_destroyctx,
375 NULL, /*%< computesecret */
377 NULL, /*%< paramcompare */
378 opensslgost_generate,
379 opensslgost_isprivate,
386 NULL, /*%< fromlabel */
392 dst__opensslgost_init(dst_func_t **funcp) {
395 REQUIRE(funcp != NULL);
397 /* check if the gost engine works properly */
398 e = ENGINE_by_id("gost");
400 return (dst__openssl_toresult2("ENGINE_by_id",
401 DST_R_OPENSSLFAILURE));
402 if (ENGINE_init(e) <= 0) {
405 return (dst__openssl_toresult2("ENGINE_init",
406 DST_R_OPENSSLFAILURE));
408 /* better than to rely on digest_gost symbol */
409 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
410 if (opensslgost_digest == NULL)
411 DST_RET(dst__openssl_toresult2("ENGINE_get_digest",
412 DST_R_OPENSSLFAILURE));
413 /* from openssl.cnf */
414 if (ENGINE_register_pkey_asn1_meths(e) <= 0)
415 DST_RET(dst__openssl_toresult2(
416 "ENGINE_register_pkey_asn1_meths",
417 DST_R_OPENSSLFAILURE));
418 if (ENGINE_ctrl_cmd_string(e,
420 "id-Gost28147-89-CryptoPro-A-ParamSet",
422 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
423 DST_R_OPENSSLFAILURE));
426 *funcp = &opensslgost_functions;
427 return (ISC_R_SUCCESS);
436 #else /* HAVE_OPENSSL_GOST */
438 #include <isc/util.h>
440 EMPTY_TRANSLATION_UNIT
442 #endif /* HAVE_OPENSSL_GOST */