2 * Copyright (C) 2010, 2011 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);
125 return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
127 return (ISC_R_SUCCESS);
131 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
132 EVP_PKEY *pkey1, *pkey2;
134 pkey1 = key1->keydata.pkey;
135 pkey2 = key2->keydata.pkey;
137 if (pkey1 == NULL && pkey2 == NULL)
139 else if (pkey1 == NULL || pkey2 == NULL)
142 if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
148 progress_cb(EVP_PKEY_CTX *ctx)
156 u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
157 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
164 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
170 EVP_PKEY *pkey = NULL;
173 ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
176 if (callback != NULL) {
178 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
179 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
181 if (EVP_PKEY_keygen_init(ctx) <= 0)
183 if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0)
185 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
187 key->keydata.pkey = pkey;
188 EVP_PKEY_CTX_free(ctx);
189 return (ISC_R_SUCCESS);
195 EVP_PKEY_CTX_free(ctx);
196 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
200 opensslgost_isprivate(const dst_key_t *key) {
201 EVP_PKEY *pkey = key->keydata.pkey;
204 INSIST(pkey != NULL);
206 ec = EVP_PKEY_get0(pkey);
207 return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
211 opensslgost_destroy(dst_key_t *key) {
212 EVP_PKEY *pkey = key->keydata.pkey;
215 key->keydata.pkey = NULL;
218 unsigned char gost_prefix[37] = {
219 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
220 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
221 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
222 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
223 0x03, 0x43, 0x00, 0x04, 0x40
227 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
230 unsigned char der[37 + 64], *p;
233 REQUIRE(key->keydata.pkey != NULL);
235 pkey = key->keydata.pkey;
237 isc_buffer_availableregion(data, &r);
239 return (ISC_R_NOSPACE);
242 len = i2d_PUBKEY(pkey, &p);
243 INSIST(len == sizeof(der));
244 INSIST(memcmp(gost_prefix, der, 37) == 0);
245 memcpy(r.base, der + 37, 64);
246 isc_buffer_add(data, 64);
248 return (ISC_R_SUCCESS);
252 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
254 EVP_PKEY *pkey = NULL;
255 unsigned char der[37 + 64];
256 const unsigned char *p;
258 isc_buffer_remainingregion(data, &r);
260 return (ISC_R_SUCCESS);
263 return (DST_R_INVALIDPUBLICKEY);
264 memcpy(der, gost_prefix, 37);
265 memcpy(der + 37, r.base, 64);
266 isc_buffer_forward(data, 64);
269 if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
270 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
271 key->keydata.pkey = pkey;
273 return (ISC_R_SUCCESS);
277 opensslgost_tofile(const dst_key_t *key, const char *directory) {
281 unsigned char *der, *p;
284 if (key->keydata.pkey == NULL)
285 return (DST_R_NULLKEY);
287 pkey = key->keydata.pkey;
289 len = i2d_PrivateKey(pkey, NULL);
290 der = isc_mem_get(key->mctx, (size_t) len);
292 return (ISC_R_NOMEMORY);
295 if (i2d_PrivateKey(pkey, &p) != len) {
296 result = dst__openssl_toresult(DST_R_OPENSSLFAILURE);
300 priv.elements[0].tag = TAG_GOST_PRIVASN1;
301 priv.elements[0].length = len;
302 priv.elements[0].data = der;
303 priv.nelements = GOST_NTAGS;
305 result = dst__privstruct_writefile(key, &priv, directory);
308 isc_mem_put(key->mctx, der, (size_t) len);
313 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
316 isc_mem_t *mctx = key->mctx;
317 EVP_PKEY *pkey = NULL;
318 const unsigned char *p;
322 /* read private key file */
323 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
324 if (ret != ISC_R_SUCCESS)
327 INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
328 p = priv.elements[0].data;
329 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
330 (long) priv.elements[0].length) == NULL)
331 DST_RET(DST_R_INVALIDPRIVATEKEY);
332 key->keydata.pkey = pkey;
333 key->key_size = EVP_PKEY_bits(pkey);
334 dst__privstruct_free(&priv, mctx);
335 memset(&priv, 0, sizeof(priv));
336 return (ISC_R_SUCCESS);
341 opensslgost_destroy(key);
342 dst__privstruct_free(&priv, mctx);
343 memset(&priv, 0, sizeof(priv));
348 opensslgost_cleanup(void) {
356 static dst_func_t opensslgost_functions = {
357 opensslgost_createctx,
358 opensslgost_destroyctx,
362 NULL, /*%< computesecret */
364 NULL, /*%< paramcompare */
365 opensslgost_generate,
366 opensslgost_isprivate,
373 NULL, /*%< fromlabel */
379 dst__opensslgost_init(dst_func_t **funcp) {
380 REQUIRE(funcp != NULL);
382 /* check if the gost engine works properly */
383 e = ENGINE_by_id("gost");
385 return (DST_R_OPENSSLFAILURE);
386 if (ENGINE_init(e) <= 0) {
389 return (DST_R_OPENSSLFAILURE);
391 /* better than to rely on digest_gost symbol */
392 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
393 /* from openssl.cnf */
394 if ((opensslgost_digest == NULL) ||
395 (ENGINE_register_pkey_asn1_meths(e) <= 0) ||
396 (ENGINE_ctrl_cmd_string(e,
398 "id-Gost28147-89-CryptoPro-A-ParamSet",
403 return (DST_R_OPENSSLFAILURE);
407 *funcp = &opensslgost_functions;
408 return (ISC_R_SUCCESS);
411 #else /* HAVE_OPENSSL_GOST */
413 #include <isc/util.h>
415 EMPTY_TRANSLATION_UNIT
417 #endif /* HAVE_OPENSSL_GOST */