]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/lib/dns/opensslgost_link.c
Fix BIND resolver remote denial of service when validating.
[FreeBSD/stable/8.git] / contrib / bind9 / lib / dns / opensslgost_link.c
1 /*
2  * Copyright (C) 2010-2012, 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         EVP_PKEY_CTX_free(ctx);
200         return (ISC_R_SUCCESS);
201
202 err:
203         if (pkey != NULL)
204                 EVP_PKEY_free(pkey);
205         if (ctx != NULL)
206                 EVP_PKEY_CTX_free(ctx);
207         return (ret);
208 }
209
210 static isc_boolean_t
211 opensslgost_isprivate(const dst_key_t *key) {
212         EVP_PKEY *pkey = key->keydata.pkey;
213         EC_KEY *ec;
214
215         INSIST(pkey != NULL);
216
217         ec = EVP_PKEY_get0(pkey);
218         return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL));
219 }
220
221 static void
222 opensslgost_destroy(dst_key_t *key) {
223         EVP_PKEY *pkey = key->keydata.pkey;
224
225         EVP_PKEY_free(pkey);
226         key->keydata.pkey = NULL;
227 }
228
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
235 };
236
237 static isc_result_t
238 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) {
239         EVP_PKEY *pkey;
240         isc_region_t r;
241         unsigned char der[37 + 64], *p;
242         int len;
243
244         REQUIRE(key->keydata.pkey != NULL);
245
246         pkey = key->keydata.pkey;
247
248         isc_buffer_availableregion(data, &r);
249         if (r.length < 64)
250                 return (ISC_R_NOSPACE);
251
252         p = der;
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);
258
259         return (ISC_R_SUCCESS);
260 }
261
262 static isc_result_t
263 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
264         isc_region_t r;
265         EVP_PKEY *pkey = NULL;
266         unsigned char der[37 + 64];
267         const unsigned char *p;
268
269         isc_buffer_remainingregion(data, &r);
270         if (r.length == 0)
271                 return (ISC_R_SUCCESS);
272
273         if (r.length != 64)
274                 return (DST_R_INVALIDPUBLICKEY);
275         memmove(der, gost_prefix, 37);
276         memmove(der + 37, r.base, 64);
277         isc_buffer_forward(data, 64);
278
279         p = der;
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;
284
285         return (ISC_R_SUCCESS);
286 }
287
288 static isc_result_t
289 opensslgost_tofile(const dst_key_t *key, const char *directory) {
290         EVP_PKEY *pkey;
291         dst_private_t priv;
292         isc_result_t result;
293         unsigned char *der, *p;
294         int len;
295
296         if (key->keydata.pkey == NULL)
297                 return (DST_R_NULLKEY);
298
299         pkey = key->keydata.pkey;
300
301         len = i2d_PrivateKey(pkey, NULL);
302         der = isc_mem_get(key->mctx, (size_t) len);
303         if (der == NULL)
304                 return (ISC_R_NOMEMORY);
305
306         p = der;
307         if (i2d_PrivateKey(pkey, &p) != len) {
308                 result = dst__openssl_toresult2("i2d_PrivateKey",
309                                                 DST_R_OPENSSLFAILURE);
310                 goto fail;
311         }
312
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;
317
318         result = dst__privstruct_writefile(key, &priv, directory);
319  fail:
320         if (der != NULL)
321                 isc_mem_put(key->mctx, der, (size_t) len);
322         return (result);
323 }
324
325 static isc_result_t
326 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
327         dst_private_t priv;
328         isc_result_t ret;
329         isc_mem_t *mctx = key->mctx;
330         EVP_PKEY *pkey = NULL;
331         const unsigned char *p;
332
333         UNUSED(pub);
334
335         /* read private key file */
336         ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
337         if (ret != ISC_R_SUCCESS)
338                 return (ret);
339
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);
351
352  err:
353         if (pkey != NULL)
354                 EVP_PKEY_free(pkey);
355         opensslgost_destroy(key);
356         dst__privstruct_free(&priv, mctx);
357         memset(&priv, 0, sizeof(priv));
358         return (ret);
359 }
360
361 static void
362 opensslgost_cleanup(void) {
363         if (e != NULL) {
364                 ENGINE_finish(e);
365                 ENGINE_free(e);
366                 e = NULL;
367         }
368 }
369
370 static dst_func_t opensslgost_functions = {
371         opensslgost_createctx,
372         opensslgost_destroyctx,
373         opensslgost_adddata,
374         opensslgost_sign,
375         opensslgost_verify,
376         NULL, /*%< computesecret */
377         opensslgost_compare,
378         NULL, /*%< paramcompare */
379         opensslgost_generate,
380         opensslgost_isprivate,
381         opensslgost_destroy,
382         opensslgost_todns,
383         opensslgost_fromdns,
384         opensslgost_tofile,
385         opensslgost_parse,
386         opensslgost_cleanup,
387         NULL, /*%< fromlabel */
388         NULL, /*%< dump */
389         NULL  /*%< restore */
390 };
391
392 isc_result_t
393 dst__opensslgost_init(dst_func_t **funcp) {
394         isc_result_t ret;
395
396         REQUIRE(funcp != NULL);
397
398         /* check if the gost engine works properly */
399         e = ENGINE_by_id("gost");
400         if (e == NULL)
401                 return (dst__openssl_toresult2("ENGINE_by_id",
402                                                DST_R_OPENSSLFAILURE));
403         if (ENGINE_init(e) <= 0) {
404                 ENGINE_free(e);
405                 e = NULL;
406                 return (dst__openssl_toresult2("ENGINE_init",
407                                                DST_R_OPENSSLFAILURE));
408         }
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,
420                                    "CRYPT_PARAMS",
421                                    "id-Gost28147-89-CryptoPro-A-ParamSet",
422                                    0) <= 0)
423                 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string",
424                                                DST_R_OPENSSLFAILURE));
425
426         if (*funcp == NULL)
427                 *funcp = &opensslgost_functions;
428         return (ISC_R_SUCCESS);
429
430  err:
431         ENGINE_finish(e);
432         ENGINE_free(e);
433         e = NULL;
434         return (ret);
435 }
436
437 #else /* HAVE_OPENSSL_GOST */
438
439 #include <isc/util.h>
440
441 EMPTY_TRANSLATION_UNIT
442
443 #endif /* HAVE_OPENSSL_GOST */
444 /*! \file */