]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/opensslgost_link.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / opensslgost_link.c
1 /*
2  * Copyright (C) 2010-2012  Internet Systems Consortium, Inc. ("ISC")
3  *
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.
7  *
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.
15  */
16
17 /* $Id: opensslgost_link.c,v 1.5 2011/01/19 23:47:12 tbox Exp $ */
18
19 #include <config.h>
20
21 #ifdef HAVE_OPENSSL_GOST
22
23 #include <isc/entropy.h>
24 #include <isc/mem.h>
25 #include <isc/string.h>
26 #include <isc/util.h>
27
28 #include <dst/result.h>
29
30 #include "dst_internal.h"
31 #include "dst_openssl.h"
32 #include "dst_parse.h"
33
34 #include <openssl/err.h>
35 #include <openssl/objects.h>
36 #include <openssl/rsa.h>
37 #include <openssl/engine.h>
38
39 static ENGINE *e = NULL;
40 static const EVP_MD *opensslgost_digest;
41 extern const EVP_MD *EVP_gost(void);
42
43 const EVP_MD *EVP_gost(void) {
44         return (opensslgost_digest);
45 }
46
47 #define DST_RET(a) {ret = a; goto err;}
48
49 static isc_result_t opensslgost_todns(const dst_key_t *key,
50                                       isc_buffer_t *data);
51
52 static isc_result_t
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();
56
57         UNUSED(key);
58
59         if (md == NULL)
60                 return (DST_R_OPENSSLFAILURE);
61
62         evp_md_ctx = EVP_MD_CTX_create();
63         if (evp_md_ctx == NULL)
64                 return (ISC_R_NOMEMORY);
65
66         if (!EVP_DigestInit_ex(evp_md_ctx, md, NULL)) {
67                 EVP_MD_CTX_destroy(evp_md_ctx);
68                 return (ISC_R_FAILURE);
69         }
70         dctx->ctxdata.evp_md_ctx = evp_md_ctx;
71
72         return (ISC_R_SUCCESS);
73 }
74
75 static void
76 opensslgost_destroyctx(dst_context_t *dctx) {
77         EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
78
79         if (evp_md_ctx != NULL) {
80                 EVP_MD_CTX_destroy(evp_md_ctx);
81                 dctx->ctxdata.evp_md_ctx = NULL;
82         }
83 }
84
85 static isc_result_t
86 opensslgost_adddata(dst_context_t *dctx, const isc_region_t *data) {
87         EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
88
89         if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
90                 return (ISC_R_FAILURE);
91
92         return (ISC_R_SUCCESS);
93 }
94
95 static isc_result_t
96 opensslgost_sign(dst_context_t *dctx, isc_buffer_t *sig) {
97         dst_key_t *key = dctx->key;
98         isc_region_t r;
99         unsigned int siglen = 0;
100         EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
101         EVP_PKEY *pkey = key->keydata.pkey;
102
103         isc_buffer_availableregion(sig, &r);
104
105         if (r.length < (unsigned int) EVP_PKEY_size(pkey))
106                 return (ISC_R_NOSPACE);
107
108         if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey))
109                 return (ISC_R_FAILURE);
110
111         isc_buffer_add(sig, siglen);
112
113         return (ISC_R_SUCCESS);
114 }
115
116 static isc_result_t
117 opensslgost_verify(dst_context_t *dctx, const isc_region_t *sig) {
118         dst_key_t *key = dctx->key;
119         int status = 0;
120         EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
121         EVP_PKEY *pkey = key->keydata.pkey;
122
123         status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey);
124         switch (status) {
125         case 1:
126                 return (ISC_R_SUCCESS);
127         case 0:
128                 return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
129         default:
130                 return (dst__openssl_toresult2("EVP_VerifyFinal",
131                                                DST_R_VERIFYFAILURE));
132         }
133 }
134
135 static isc_boolean_t
136 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
137         EVP_PKEY *pkey1, *pkey2;
138
139         pkey1 = key1->keydata.pkey;
140         pkey2 = key2->keydata.pkey;
141
142         if (pkey1 == NULL && pkey2 == NULL)
143                 return (ISC_TRUE);
144         else if (pkey1 == NULL || pkey2 == NULL)
145                 return (ISC_FALSE);
146
147         if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
148                 return (ISC_FALSE);
149         return (ISC_TRUE);
150 }
151
152 static int
153 progress_cb(EVP_PKEY_CTX *ctx)
154 {
155         union {
156                 void *dptr;
157                 void (*fptr)(int);
158         } u;
159         int p;
160
161         u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
162         p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
163         if (u.fptr != NULL)
164                 u.fptr(p);
165         return (1);
166 }
167
168 static isc_result_t
169 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
170         EVP_PKEY_CTX *ctx;
171         union {
172                 void *dptr;
173                 void (*fptr)(int);
174         } u;
175         EVP_PKEY *pkey = NULL;
176         isc_result_t ret;
177
178         UNUSED(unused);
179         ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
180         if (ctx == NULL)
181                 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
182                                                DST_R_OPENSSLFAILURE));
183         if (callback != NULL) {
184                 u.fptr = callback;
185                 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
186                 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
187         }
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);
200
201 err:
202         if (pkey != NULL)
203                 EVP_PKEY_free(pkey);
204         if (ctx != NULL)
205                 EVP_PKEY_CTX_free(ctx);
206         return (ret);
207 }
208
209 static isc_boolean_t
210 opensslgost_isprivate(const dst_key_t *key) {
211         EVP_PKEY *pkey = key->keydata.pkey;
212         EC_KEY *ec;
213
214         INSIST(pkey != NULL);
215
216         ec = EVP_PKEY_get0(pkey);
217         return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
218 }
219
220 static void
221 opensslgost_destroy(dst_key_t *key) {
222         EVP_PKEY *pkey = key->keydata.pkey;
223
224         EVP_PKEY_free(pkey);
225         key->keydata.pkey = NULL;
226 }
227
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
234 };
235
236 static isc_result_t
237 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
238         EVP_PKEY *pkey;
239         isc_region_t r;
240         unsigned char der[37 + 64], *p;
241         int len;
242
243         REQUIRE(key->keydata.pkey != NULL);
244
245         pkey = key->keydata.pkey;
246
247         isc_buffer_availableregion(data, &r);
248         if (r.length < 64)
249                 return (ISC_R_NOSPACE);
250
251         p = der;
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);
257
258         return (ISC_R_SUCCESS);
259 }
260
261 static isc_result_t
262 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
263         isc_region_t r;
264         EVP_PKEY *pkey = NULL;
265         unsigned char der[37 + 64];
266         const unsigned char *p;
267
268         isc_buffer_remainingregion(data, &r);
269         if (r.length == 0)
270                 return (ISC_R_SUCCESS);
271
272         if (r.length != 64)
273                 return (DST_R_INVALIDPUBLICKEY);
274         memcpy(der, gost_prefix, 37);
275         memcpy(der + 37, r.base, 64);
276         isc_buffer_forward(data, 64);
277
278         p = der;
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;
283
284         return (ISC_R_SUCCESS);
285 }
286
287 static isc_result_t
288 opensslgost_tofile(const dst_key_t *key, const char *directory) {
289         EVP_PKEY *pkey;
290         dst_private_t priv;
291         isc_result_t result;
292         unsigned char *der, *p;
293         int len;
294
295         if (key->keydata.pkey == NULL)
296                 return (DST_R_NULLKEY);
297
298         pkey = key->keydata.pkey;
299
300         len = i2d_PrivateKey(pkey, NULL);
301         der = isc_mem_get(key->mctx, (size_t) len);
302         if (der == NULL)
303                 return (ISC_R_NOMEMORY);
304
305         p = der;
306         if (i2d_PrivateKey(pkey, &p) != len) {
307                 result = dst__openssl_toresult2("i2d_PrivateKey",
308                                                 DST_R_OPENSSLFAILURE);
309                 goto fail;
310         }
311
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;
316
317         result = dst__privstruct_writefile(key, &priv, directory);
318  fail:
319         if (der != NULL)
320                 isc_mem_put(key->mctx, der, (size_t) len);
321         return (result);
322 }
323
324 static isc_result_t
325 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
326         dst_private_t priv;
327         isc_result_t ret;
328         isc_mem_t *mctx = key->mctx;
329         EVP_PKEY *pkey = NULL;
330         const unsigned char *p;
331
332         UNUSED(pub);
333
334         /* read private key file */
335         ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
336         if (ret != ISC_R_SUCCESS)
337                 return (ret);
338
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);
350
351  err:
352         if (pkey != NULL)
353                 EVP_PKEY_free(pkey);
354         opensslgost_destroy(key);
355         dst__privstruct_free(&priv, mctx);
356         memset(&priv, 0, sizeof(priv));
357         return (ret);
358 }
359
360 static void
361 opensslgost_cleanup(void) {
362         if (e != NULL) {
363                 ENGINE_finish(e);
364                 ENGINE_free(e);
365                 e = NULL;
366         }
367 }
368
369 static dst_func_t opensslgost_functions = {
370         opensslgost_createctx,
371         opensslgost_destroyctx,
372         opensslgost_adddata,
373         opensslgost_sign,
374         opensslgost_verify,
375         NULL, /*%< computesecret */
376         opensslgost_compare,
377         NULL, /*%< paramcompare */
378         opensslgost_generate,
379         opensslgost_isprivate,
380         opensslgost_destroy,
381         opensslgost_todns,
382         opensslgost_fromdns,
383         opensslgost_tofile,
384         opensslgost_parse,
385         opensslgost_cleanup,
386         NULL, /*%< fromlabel */
387         NULL, /*%< dump */
388         NULL  /*%< restore */
389 };
390
391 isc_result_t
392 dst__opensslgost_init(dst_func_t **funcp) {
393         isc_result_t ret;
394
395         REQUIRE(funcp != NULL);
396
397         /* check if the gost engine works properly */
398         e = ENGINE_by_id("gost");
399         if (e == NULL)
400                 return (dst__openssl_toresult2("ENGINE_by_id",
401                                                DST_R_OPENSSLFAILURE));
402         if (ENGINE_init(e) <= 0) {
403                 ENGINE_free(e);
404                 e = NULL;
405                 return (dst__openssl_toresult2("ENGINE_init",
406                                                DST_R_OPENSSLFAILURE));
407         }
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,
419                                    "CRYPT_PARAMS",
420                                    "id-Gost28147-89-CryptoPro-A-ParamSet",
421                                    0) <= 0)
422                 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
423                                                DST_R_OPENSSLFAILURE));
424
425         if (*funcp == NULL)
426                 *funcp = &opensslgost_functions;
427         return (ISC_R_SUCCESS);
428
429  err:
430         ENGINE_finish(e);
431         ENGINE_free(e);
432         e = NULL;
433         return (ret);
434 }
435
436 #else /* HAVE_OPENSSL_GOST */
437
438 #include <isc/util.h>
439
440 EMPTY_TRANSLATION_UNIT
441
442 #endif /* HAVE_OPENSSL_GOST */
443 /*! \file */