2 * Copyright (C) 2010-2012, 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);
299 pkey = key->keydata.pkey;
301 len = i2d_PrivateKey(pkey, NULL);
302 der = isc_mem_get(key->mctx, (size_t) len);
304 return (ISC_R_NOMEMORY);
307 if (i2d_PrivateKey(pkey, &p) != len) {
308 result = dst__openssl_toresult2("i2d_PrivateKey",
309 DST_R_OPENSSLFAILURE);
313 priv.elements[0].tag = TAG_GOST_PRIVASN1;
314 priv.elements[0].length = len;
315 priv.elements[0].data = der;
316 priv.nelements = GOST_NTAGS;
318 result = dst__privstruct_writefile(key, &priv, directory);
321 isc_mem_put(key->mctx, der, (size_t) len);
326 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
329 isc_mem_t *mctx = key->mctx;
330 EVP_PKEY *pkey = NULL;
331 const unsigned char *p;
335 /* read private key file */
336 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
337 if (ret != ISC_R_SUCCESS)
340 INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
341 p = priv.elements[0].data;
342 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
343 (long) priv.elements[0].length) == NULL)
344 DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
345 DST_R_INVALIDPRIVATEKEY));
346 key->keydata.pkey = pkey;
347 key->key_size = EVP_PKEY_bits(pkey);
348 dst__privstruct_free(&priv, mctx);
349 memset(&priv, 0, sizeof(priv));
350 return (ISC_R_SUCCESS);
355 opensslgost_destroy(key);
356 dst__privstruct_free(&priv, mctx);
357 memset(&priv, 0, sizeof(priv));
362 opensslgost_cleanup(void) {
370 static dst_func_t opensslgost_functions = {
371 opensslgost_createctx,
372 opensslgost_destroyctx,
376 NULL, /*%< computesecret */
378 NULL, /*%< paramcompare */
379 opensslgost_generate,
380 opensslgost_isprivate,
387 NULL, /*%< fromlabel */
393 dst__opensslgost_init(dst_func_t **funcp) {
396 REQUIRE(funcp != NULL);
398 /* check if the gost engine works properly */
399 e = ENGINE_by_id("gost");
401 return (dst__openssl_toresult2("ENGINE_by_id",
402 DST_R_OPENSSLFAILURE));
403 if (ENGINE_init(e) <= 0) {
406 return (dst__openssl_toresult2("ENGINE_init",
407 DST_R_OPENSSLFAILURE));
409 /* better than to rely on digest_gost symbol */
410 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
411 if (opensslgost_digest == NULL)
412 DST_RET(dst__openssl_toresult2("ENGINE_get_digest",
413 DST_R_OPENSSLFAILURE));
414 /* from openssl.cnf */
415 if (ENGINE_register_pkey_asn1_meths(e) <= 0)
416 DST_RET(dst__openssl_toresult2(
417 "ENGINE_register_pkey_asn1_meths",
418 DST_R_OPENSSLFAILURE));
419 if (ENGINE_ctrl_cmd_string(e,
421 "id-Gost28147-89-CryptoPro-A-ParamSet",
423 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
424 DST_R_OPENSSLFAILURE));
427 *funcp = &opensslgost_functions;
428 return (ISC_R_SUCCESS);
437 #else /* HAVE_OPENSSL_GOST */
439 #include <isc/util.h>
441 EMPTY_TRANSLATION_UNIT
443 #endif /* HAVE_OPENSSL_GOST */