]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/bind9/lib/dns/opensslgost_link.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / bind9 / lib / dns / opensslgost_link.c
1 /*
2  * Copyright (C) 2010, 2011  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         if (status != 1)
125                 return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
126
127         return (ISC_R_SUCCESS);
128 }
129
130 static isc_boolean_t
131 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) {
132         EVP_PKEY *pkey1, *pkey2;
133
134         pkey1 = key1->keydata.pkey;
135         pkey2 = key2->keydata.pkey;
136
137         if (pkey1 == NULL && pkey2 == NULL)
138                 return (ISC_TRUE);
139         else if (pkey1 == NULL || pkey2 == NULL)
140                 return (ISC_FALSE);
141
142         if (EVP_PKEY_cmp(pkey1, pkey2) != 1)
143                 return (ISC_FALSE);
144         return (ISC_TRUE);
145 }
146
147 static int
148 progress_cb(EVP_PKEY_CTX *ctx)
149 {
150         union {
151                 void *dptr;
152                 void (*fptr)(int);
153         } u;
154         int p;
155
156         u.dptr = EVP_PKEY_CTX_get_app_data(ctx);
157         p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
158         if (u.fptr != NULL)
159                 u.fptr(p);
160         return (1);
161 }
162
163 static isc_result_t
164 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
165         EVP_PKEY_CTX *ctx;
166         union {
167                 void *dptr;
168                 void (*fptr)(int);
169         } u;
170         EVP_PKEY *pkey = NULL;
171
172         UNUSED(unused);
173         ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL);
174         if (ctx == NULL)
175                 goto err;
176         if (callback != NULL) {
177                 u.fptr = callback;
178                 EVP_PKEY_CTX_set_app_data(ctx, u.dptr);
179                 EVP_PKEY_CTX_set_cb(ctx, &progress_cb);
180         }
181         if (EVP_PKEY_keygen_init(ctx) <= 0)
182                 goto err;
183         if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0)
184                 goto err;
185         if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
186                 goto err;
187         key->keydata.pkey = pkey;
188         EVP_PKEY_CTX_free(ctx);
189         return (ISC_R_SUCCESS);
190
191 err:
192         if (pkey != NULL)
193                 EVP_PKEY_free(pkey);
194         if (ctx != NULL)
195                 EVP_PKEY_CTX_free(ctx);
196         return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
197 }
198
199 static isc_boolean_t
200 opensslgost_isprivate(const dst_key_t *key) {
201         EVP_PKEY *pkey = key->keydata.pkey;
202         EC_KEY *ec;
203
204         INSIST(pkey != NULL);
205
206         ec = EVP_PKEY_get0(pkey);
207         return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
208 }
209
210 static void
211 opensslgost_destroy(dst_key_t *key) {
212         EVP_PKEY *pkey = key->keydata.pkey;
213
214         EVP_PKEY_free(pkey);
215         key->keydata.pkey = NULL;
216 }
217
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
224 };
225
226 static isc_result_t
227 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
228         EVP_PKEY *pkey;
229         isc_region_t r;
230         unsigned char der[37 + 64], *p;
231         int len;
232
233         REQUIRE(key->keydata.pkey != NULL);
234
235         pkey = key->keydata.pkey;
236
237         isc_buffer_availableregion(data, &r);
238         if (r.length < 64)
239                 return (ISC_R_NOSPACE);
240
241         p = der;
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);
247
248         return (ISC_R_SUCCESS);
249 }
250
251 static isc_result_t
252 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
253         isc_region_t r;
254         EVP_PKEY *pkey = NULL;
255         unsigned char der[37 + 64];
256         const unsigned char *p;
257
258         isc_buffer_remainingregion(data, &r);
259         if (r.length == 0)
260                 return (ISC_R_SUCCESS);
261
262         if (r.length != 64)
263                 return (DST_R_INVALIDPUBLICKEY);
264         memcpy(der, gost_prefix, 37);
265         memcpy(der + 37, r.base, 64);
266         isc_buffer_forward(data, 64);
267
268         p = der;
269         if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL)
270                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
271         key->keydata.pkey = pkey;
272
273         return (ISC_R_SUCCESS);
274 }
275
276 static isc_result_t
277 opensslgost_tofile(const dst_key_t *key, const char *directory) {
278         EVP_PKEY *pkey;
279         dst_private_t priv;
280         isc_result_t result;
281         unsigned char *der, *p;
282         int len;
283
284         if (key->keydata.pkey == NULL)
285                 return (DST_R_NULLKEY);
286
287         pkey = key->keydata.pkey;
288
289         len = i2d_PrivateKey(pkey, NULL);
290         der = isc_mem_get(key->mctx, (size_t) len);
291         if (der == NULL)
292                 return (ISC_R_NOMEMORY);
293
294         p = der;
295         if (i2d_PrivateKey(pkey, &p) != len) {
296                 result = dst__openssl_toresult(DST_R_OPENSSLFAILURE);
297                 goto fail;
298         }
299
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;
304
305         result = dst__privstruct_writefile(key, &priv, directory);
306  fail:
307         if (der != NULL)
308                 isc_mem_put(key->mctx, der, (size_t) len);
309         return (result);
310 }
311
312 static isc_result_t
313 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
314         dst_private_t priv;
315         isc_result_t ret;
316         isc_mem_t *mctx = key->mctx;
317         EVP_PKEY *pkey = NULL;
318         const unsigned char *p;
319
320         UNUSED(pub);
321
322         /* read private key file */
323         ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
324         if (ret != ISC_R_SUCCESS)
325                 return (ret);
326
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);
337
338  err:
339         if (pkey != NULL)
340                 EVP_PKEY_free(pkey);
341         opensslgost_destroy(key);
342         dst__privstruct_free(&priv, mctx);
343         memset(&priv, 0, sizeof(priv));
344         return (ret);
345 }
346
347 static void
348 opensslgost_cleanup(void) {
349         if (e != NULL) {
350                 ENGINE_finish(e);
351                 ENGINE_free(e);
352                 e = NULL;
353         }
354 }
355
356 static dst_func_t opensslgost_functions = {
357         opensslgost_createctx,
358         opensslgost_destroyctx,
359         opensslgost_adddata,
360         opensslgost_sign,
361         opensslgost_verify,
362         NULL, /*%< computesecret */
363         opensslgost_compare,
364         NULL, /*%< paramcompare */
365         opensslgost_generate,
366         opensslgost_isprivate,
367         opensslgost_destroy,
368         opensslgost_todns,
369         opensslgost_fromdns,
370         opensslgost_tofile,
371         opensslgost_parse,
372         opensslgost_cleanup,
373         NULL, /*%< fromlabel */
374         NULL, /*%< dump */
375         NULL  /*%< restore */
376 };
377
378 isc_result_t
379 dst__opensslgost_init(dst_func_t **funcp) {
380         REQUIRE(funcp != NULL);
381
382         /* check if the gost engine works properly */
383         e = ENGINE_by_id("gost");
384         if (e == NULL)
385                 return (DST_R_OPENSSLFAILURE);
386         if (ENGINE_init(e) <= 0) {
387                 ENGINE_free(e);
388                 e = NULL;
389                 return (DST_R_OPENSSLFAILURE);
390         }
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,
397                                     "CRYPT_PARAMS",
398                                     "id-Gost28147-89-CryptoPro-A-ParamSet",
399                                     0) <= 0)) {
400                 ENGINE_finish(e);
401                 ENGINE_free(e);
402                 e = NULL;
403                 return (DST_R_OPENSSLFAILURE);
404         }
405
406         if (*funcp == NULL)
407                 *funcp = &opensslgost_functions;
408         return (ISC_R_SUCCESS);
409 }
410
411 #else /* HAVE_OPENSSL_GOST */
412
413 #include <isc/util.h>
414
415 EMPTY_TRANSLATION_UNIT
416
417 #endif /* HAVE_OPENSSL_GOST */
418 /*! \file */