]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/opensslgost_link.c
Update BIND to 9.9.7.
[FreeBSD/stable/9.git] / contrib / bind9 / lib / dns / opensslgost_link.c
1 /*
2  * Copyright (C) 2010-2014  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_toresult3(dctx->category,
131                                                "EVP_VerifyFinal",
132                                                DST_R_VERIFYFAILURE));
133         }
134 }
135
136 static isc_boolean_t
137 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
138         EVP_PKEY *pkey1, *pkey2;
139
140         pkey1 = key1->keydata.pkey;
141         pkey2 = key2->keydata.pkey;
142
143         if (pkey1 == NULL && pkey2 == NULL)
144                 return (ISC_TRUE);
145         else if (pkey1 == NULL || pkey2 == NULL)
146                 return (ISC_FALSE);
147
148         if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
149                 return (ISC_FALSE);
150         return (ISC_TRUE);
151 }
152
153 static int
154 progress_cb(EVP_PKEY_CTX *ctx)
155 {
156         union {
157                 void *dptr;
158                 void (*fptr)(int);
159         } u;
160         int p;
161
162         u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
163         p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
164         if (u.fptr != NULL)
165                 u.fptr(p);
166         return (1);
167 }
168
169 static isc_result_t
170 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
171         EVP_PKEY_CTX *ctx;
172         union {
173                 void *dptr;
174                 void (*fptr)(int);
175         } u;
176         EVP_PKEY *pkey = NULL;
177         isc_result_t ret;
178
179         UNUSED(unused);
180         ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
181         if (ctx == NULL)
182                 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
183                                                DST_R_OPENSSLFAILURE));
184         if (callback != NULL) {
185                 u.fptr = callback;
186                 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
187                 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
188         }
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         key->key_size = EVP_PKEY_bits(pkey);
200         EVP_PKEY_CTX_free(ctx);
201         return (ISC_R_SUCCESS);
202
203 err:
204         if (pkey != NULL)
205                 EVP_PKEY_free(pkey);
206         if (ctx != NULL)
207                 EVP_PKEY_CTX_free(ctx);
208         return (ret);
209 }
210
211 static isc_boolean_t
212 opensslgost_isprivate(const dst_key_t *key) {
213         EVP_PKEY *pkey = key->keydata.pkey;
214         EC_KEY *ec;
215
216         INSIST(pkey != NULL);
217
218         ec = EVP_PKEY_get0(pkey);
219         return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
220 }
221
222 static void
223 opensslgost_destroy(dst_key_t *key) {
224         EVP_PKEY *pkey = key->keydata.pkey;
225
226         EVP_PKEY_free(pkey);
227         key->keydata.pkey = NULL;
228 }
229
230 unsigned char gost_prefix[37] = {
231         0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
232         0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07,
233         0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06,
234         0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01,
235         0x03, 0x43, 0x00, 0x04, 0x40
236 };
237
238 static isc_result_t
239 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
240         EVP_PKEY *pkey;
241         isc_region_t r;
242         unsigned char der[37 + 64], *p;
243         int len;
244
245         REQUIRE(key->keydata.pkey != NULL);
246
247         pkey = key->keydata.pkey;
248
249         isc_buffer_availableregion(data, &r);
250         if (r.length < 64)
251                 return (ISC_R_NOSPACE);
252
253         p = der;
254         len = i2d_PUBKEY(pkey, &p);
255         INSIST(len == sizeof(der));
256         INSIST(memcmp(gost_prefix, der, 37) == 0);
257         memmove(r.base, der + 37, 64);
258         isc_buffer_add(data, 64);
259
260         return (ISC_R_SUCCESS);
261 }
262
263 static isc_result_t
264 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
265         isc_region_t r;
266         EVP_PKEY *pkey = NULL;
267         unsigned char der[37 + 64];
268         const unsigned char *p;
269
270         isc_buffer_remainingregion(data, &r);
271         if (r.length == 0)
272                 return (ISC_R_SUCCESS);
273
274         if (r.length != 64)
275                 return (DST_R_INVALIDPUBLICKEY);
276         memmove(der, gost_prefix, 37);
277         memmove(der + 37, r.base, 64);
278         isc_buffer_forward(data, 64);
279
280         p = der;
281         if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
282                 return (dst__openssl_toresult2("d2i_PUBKEY",
283                                                DST_R_OPENSSLFAILURE));
284         key->keydata.pkey = pkey;
285         key->key_size = EVP_PKEY_bits(pkey);
286
287         return (ISC_R_SUCCESS);
288 }
289
290 static isc_result_t
291 opensslgost_tofile(const dst_key_t *key, const char *directory) {
292         EVP_PKEY *pkey;
293         dst_private_t priv;
294         isc_result_t result;
295         unsigned char *der, *p;
296         int len;
297
298         if (key->keydata.pkey == NULL)
299                 return (DST_R_NULLKEY);
300
301         if (key->external) {
302                 priv.nelements = 0;
303                 return (dst__privstruct_writefile(key, &priv, directory));
304         }
305
306         pkey = key->keydata.pkey;
307
308         len = i2d_PrivateKey(pkey, NULL);
309         der = isc_mem_get(key->mctx, (size_t) len);
310         if (der == NULL)
311                 return (ISC_R_NOMEMORY);
312
313         p = der;
314         if (i2d_PrivateKey(pkey, &p) != len) {
315                 result = dst__openssl_toresult2("i2d_PrivateKey",
316                                                 DST_R_OPENSSLFAILURE);
317                 goto fail;
318         }
319
320         priv.elements[0].tag = TAG_GOST_PRIVASN1;
321         priv.elements[0].length = len;
322         priv.elements[0].data = der;
323         priv.nelements = GOST_NTAGS;
324
325         result = dst__privstruct_writefile(key, &priv, directory);
326  fail:
327         if (der != NULL)
328                 isc_mem_put(key->mctx, der, (size_t) len);
329         return (result);
330 }
331
332 static isc_result_t
333 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
334         dst_private_t priv;
335         isc_result_t ret;
336         isc_mem_t *mctx = key->mctx;
337         EVP_PKEY *pkey = NULL;
338         const unsigned char *p;
339
340         UNUSED(pub);
341
342         /* read private key file */
343         ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
344         if (ret != ISC_R_SUCCESS)
345                 return (ret);
346
347         if (key->external) {
348                 INSIST(priv.nelements == 0);
349                 if (pub == NULL)
350                         DST_RET(DST_R_INVALIDPRIVATEKEY);
351                 key->keydata.pkey = pub->keydata.pkey;
352                 pub->keydata.pkey = NULL;
353         } else {
354                 INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
355                 p = priv.elements[0].data;
356                 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
357                                    (long) priv.elements[0].length) == NULL)
358                         DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
359                                                      DST_R_INVALIDPRIVATEKEY));
360                 key->keydata.pkey = pkey;
361         }
362         key->key_size = EVP_PKEY_bits(pkey);
363         dst__privstruct_free(&priv, mctx);
364         memset(&priv, 0, sizeof(priv));
365         return (ISC_R_SUCCESS);
366
367  err:
368         if (pkey != NULL)
369                 EVP_PKEY_free(pkey);
370         opensslgost_destroy(key);
371         dst__privstruct_free(&priv, mctx);
372         memset(&priv, 0, sizeof(priv));
373         return (ret);
374 }
375
376 static void
377 opensslgost_cleanup(void) {
378         if (e != NULL) {
379                 ENGINE_finish(e);
380                 ENGINE_free(e);
381                 e = NULL;
382         }
383 }
384
385 static dst_func_t opensslgost_functions = {
386         opensslgost_createctx,
387         opensslgost_destroyctx,
388         opensslgost_adddata,
389         opensslgost_sign,
390         opensslgost_verify,
391         NULL, /*%< verify2 */
392         NULL, /*%< computesecret */
393         opensslgost_compare,
394         NULL, /*%< paramcompare */
395         opensslgost_generate,
396         opensslgost_isprivate,
397         opensslgost_destroy,
398         opensslgost_todns,
399         opensslgost_fromdns,
400         opensslgost_tofile,
401         opensslgost_parse,
402         opensslgost_cleanup,
403         NULL, /*%< fromlabel */
404         NULL, /*%< dump */
405         NULL  /*%< restore */
406 };
407
408 isc_result_t
409 dst__opensslgost_init(dst_func_t **funcp) {
410         isc_result_t ret;
411
412         REQUIRE(funcp != NULL);
413
414         /* check if the gost engine works properly */
415         e = ENGINE_by_id("gost");
416         if (e == NULL)
417                 return (dst__openssl_toresult2("ENGINE_by_id",
418                                                DST_R_OPENSSLFAILURE));
419         if (ENGINE_init(e) <= 0) {
420                 ENGINE_free(e);
421                 e = NULL;
422                 return (dst__openssl_toresult2("ENGINE_init",
423                                                DST_R_OPENSSLFAILURE));
424         }
425         /* better than to rely on digest_gost symbol */
426         opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94);
427         if (opensslgost_digest == NULL)
428                 DST_RET(dst__openssl_toresult2("ENGINE_get_digest",
429                                                DST_R_OPENSSLFAILURE));
430         /* from openssl.cnf */
431         if (ENGINE_register_pkey_asn1_meths(e) <= 0)
432                 DST_RET(dst__openssl_toresult2(
433                                 "ENGINE_register_pkey_asn1_meths",
434                                 DST_R_OPENSSLFAILURE));
435         if (ENGINE_ctrl_cmd_string(e,
436                                    "CRYPT_PARAMS",
437                                    "id-Gost28147-89-CryptoPro-A-ParamSet",
438                                    0) <= 0)
439                 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
440                                                DST_R_OPENSSLFAILURE));
441
442         if (*funcp == NULL)
443                 *funcp = &opensslgost_functions;
444         return (ISC_R_SUCCESS);
445
446  err:
447         ENGINE_finish(e);
448         ENGINE_free(e);
449         e = NULL;
450         return (ret);
451 }
452
453 #else /* HAVE_OPENSSL_GOST */
454
455 #include <isc/util.h>
456
457 EMPTY_TRANSLATION_UNIT
458
459 #endif /* HAVE_OPENSSL_GOST */
460 /*! \file */