iostat - add read/write details to output
[dragonfly.git] / contrib / bind / lib / dns / openssldh_link.c
1 /*
2  * Portions Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
12  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
24  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
26  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
29  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31
32 /*
33  * Principal Author: Brian Wellington
34  * $Id: openssldh_link.c,v 1.12 2007/08/28 07:20:42 tbox Exp $
35  */
36
37 #ifdef OPENSSL
38
39 #include <config.h>
40
41 #include <ctype.h>
42
43 #include <isc/mem.h>
44 #include <isc/string.h>
45 #include <isc/util.h>
46
47 #include <dst/result.h>
48
49 #include "dst_internal.h"
50 #include "dst_openssl.h"
51 #include "dst_parse.h"
52
53 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
54         "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
55         "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
56
57 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
58         "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
59         "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
60         "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
61
62 #define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
63         "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
64         "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
65         "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
66         "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
67         "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
68         "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
69         "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
70
71
72 static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
73
74 static BIGNUM bn2, bn768, bn1024, bn1536;
75
76 static isc_result_t
77 openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
78                         isc_buffer_t *secret)
79 {
80         DH *dhpub, *dhpriv;
81         int ret;
82         isc_region_t r;
83         unsigned int len;
84
85         REQUIRE(pub->keydata.dh != NULL);
86         REQUIRE(priv->keydata.dh != NULL);
87
88         dhpub = pub->keydata.dh;
89         dhpriv = priv->keydata.dh;
90
91         len = DH_size(dhpriv);
92         isc_buffer_availableregion(secret, &r);
93         if (r.length < len)
94                 return (ISC_R_NOSPACE);
95         ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
96         if (ret == 0)
97                 return (dst__openssl_toresult(DST_R_COMPUTESECRETFAILURE));
98         isc_buffer_add(secret, len);
99         return (ISC_R_SUCCESS);
100 }
101
102 static isc_boolean_t
103 openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
104         int status;
105         DH *dh1, *dh2;
106
107         dh1 = key1->keydata.dh;
108         dh2 = key2->keydata.dh;
109
110         if (dh1 == NULL && dh2 == NULL)
111                 return (ISC_TRUE);
112         else if (dh1 == NULL || dh2 == NULL)
113                 return (ISC_FALSE);
114
115         status = BN_cmp(dh1->p, dh2->p) ||
116                  BN_cmp(dh1->g, dh2->g) ||
117                  BN_cmp(dh1->pub_key, dh2->pub_key);
118
119         if (status != 0)
120                 return (ISC_FALSE);
121
122         if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
123                 if (dh1->priv_key == NULL || dh2->priv_key == NULL)
124                         return (ISC_FALSE);
125                 if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
126                         return (ISC_FALSE);
127         }
128         return (ISC_TRUE);
129 }
130
131 static isc_boolean_t
132 openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
133         int status;
134         DH *dh1, *dh2;
135
136         dh1 = key1->keydata.dh;
137         dh2 = key2->keydata.dh;
138
139         if (dh1 == NULL && dh2 == NULL)
140                 return (ISC_TRUE);
141         else if (dh1 == NULL || dh2 == NULL)
142                 return (ISC_FALSE);
143
144         status = BN_cmp(dh1->p, dh2->p) ||
145                  BN_cmp(dh1->g, dh2->g);
146
147         if (status != 0)
148                 return (ISC_FALSE);
149         return (ISC_TRUE);
150 }
151
152 static isc_result_t
153 openssldh_generate(dst_key_t *key, int generator) {
154 #if OPENSSL_VERSION_NUMBER > 0x00908000L
155         BN_GENCB cb;
156 #endif
157         DH *dh = NULL;
158
159         if (generator == 0) {
160                 if (key->key_size == 768 ||
161                     key->key_size == 1024 ||
162                     key->key_size == 1536)
163                 {
164                         dh = DH_new();
165                         if (dh == NULL)
166                                 return (dst__openssl_toresult(ISC_R_NOMEMORY));
167                         if (key->key_size == 768)
168                                 dh->p = &bn768;
169                         else if (key->key_size == 1024)
170                                 dh->p = &bn1024;
171                         else
172                                 dh->p = &bn1536;
173                         dh->g = &bn2;
174                 } else
175                         generator = 2;
176         }
177
178         if (generator != 0) {
179 #if OPENSSL_VERSION_NUMBER > 0x00908000L
180                 dh = DH_new();
181                 if (dh == NULL)
182                         return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
183
184                 BN_GENCB_set_old(&cb, NULL, NULL);
185
186                 if (!DH_generate_parameters_ex(dh, key->key_size, generator,
187                                                &cb)) {
188                         DH_free(dh);
189                         return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
190                 }
191 #else
192                 dh = DH_generate_parameters(key->key_size, generator,
193                                             NULL, NULL);
194 #endif
195         }
196
197         if (dh == NULL)
198                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
199
200         if (DH_generate_key(dh) == 0) {
201                 DH_free(dh);
202                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
203         }
204         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
205
206         key->keydata.dh = dh;
207
208         return (ISC_R_SUCCESS);
209 }
210
211 static isc_boolean_t
212 openssldh_isprivate(const dst_key_t *key) {
213         DH *dh = key->keydata.dh;
214         return (ISC_TF(dh != NULL && dh->priv_key != NULL));
215 }
216
217 static void
218 openssldh_destroy(dst_key_t *key) {
219         DH *dh = key->keydata.dh;
220
221         if (dh == NULL)
222                 return;
223
224         if (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)
225                 dh->p = NULL;
226         if (dh->g == &bn2)
227                 dh->g = NULL;
228         DH_free(dh);
229         key->keydata.dh = NULL;
230 }
231
232 static void
233 uint16_toregion(isc_uint16_t val, isc_region_t *region) {
234         *region->base++ = (val & 0xff00) >> 8;
235         *region->base++ = (val & 0x00ff);
236 }
237
238 static isc_uint16_t
239 uint16_fromregion(isc_region_t *region) {
240         isc_uint16_t val;
241         unsigned char *cp = region->base;
242
243         val = ((unsigned int)(cp[0])) << 8;
244         val |= ((unsigned int)(cp[1]));
245
246         region->base += 2;
247         return (val);
248 }
249
250 static isc_result_t
251 openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
252         DH *dh;
253         isc_region_t r;
254         isc_uint16_t dnslen, plen, glen, publen;
255
256         REQUIRE(key->keydata.dh != NULL);
257
258         dh = key->keydata.dh;
259
260         isc_buffer_availableregion(data, &r);
261
262         if (dh->g == &bn2 &&
263             (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)) {
264                 plen = 1;
265                 glen = 0;
266         }
267         else {
268                 plen = BN_num_bytes(dh->p);
269                 glen = BN_num_bytes(dh->g);
270         }
271         publen = BN_num_bytes(dh->pub_key);
272         dnslen = plen + glen + publen + 6;
273         if (r.length < (unsigned int) dnslen)
274                 return (ISC_R_NOSPACE);
275
276         uint16_toregion(plen, &r);
277         if (plen == 1) {
278                 if (dh->p == &bn768)
279                         *r.base = 1;
280                 else if (dh->p == &bn1024)
281                         *r.base = 2;
282                 else
283                         *r.base = 3;
284         }
285         else
286                 BN_bn2bin(dh->p, r.base);
287         r.base += plen;
288
289         uint16_toregion(glen, &r);
290         if (glen > 0)
291                 BN_bn2bin(dh->g, r.base);
292         r.base += glen;
293
294         uint16_toregion(publen, &r);
295         BN_bn2bin(dh->pub_key, r.base);
296         r.base += publen;
297
298         isc_buffer_add(data, dnslen);
299
300         return (ISC_R_SUCCESS);
301 }
302
303 static isc_result_t
304 openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
305         DH *dh;
306         isc_region_t r;
307         isc_uint16_t plen, glen, publen;
308         int special = 0;
309
310         isc_buffer_remainingregion(data, &r);
311         if (r.length == 0)
312                 return (ISC_R_SUCCESS);
313
314         dh = DH_new();
315         if (dh == NULL)
316                 return (dst__openssl_toresult(ISC_R_NOMEMORY));
317         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
318
319         /*
320          * Read the prime length.  1 & 2 are table entries, > 16 means a
321          * prime follows, otherwise an error.
322          */
323         if (r.length < 2) {
324                 DH_free(dh);
325                 return (DST_R_INVALIDPUBLICKEY);
326         }
327         plen = uint16_fromregion(&r);
328         if (plen < 16 && plen != 1 && plen != 2) {
329                 DH_free(dh);
330                 return (DST_R_INVALIDPUBLICKEY);
331         }
332         if (r.length < plen) {
333                 DH_free(dh);
334                 return (DST_R_INVALIDPUBLICKEY);
335         }
336         if (plen == 1 || plen == 2) {
337                 if (plen == 1)
338                         special = *r.base++;
339                 else
340                         special = uint16_fromregion(&r);
341                 switch (special) {
342                         case 1:
343                                 dh->p = &bn768;
344                                 break;
345                         case 2:
346                                 dh->p = &bn1024;
347                                 break;
348                         case 3:
349                                 dh->p = &bn1536;
350                                 break;
351                         default:
352                                 DH_free(dh);
353                                 return (DST_R_INVALIDPUBLICKEY);
354                 }
355         }
356         else {
357                 dh->p = BN_bin2bn(r.base, plen, NULL);
358                 r.base += plen;
359         }
360
361         /*
362          * Read the generator length.  This should be 0 if the prime was
363          * special, but it might not be.  If it's 0 and the prime is not
364          * special, we have a problem.
365          */
366         if (r.length < 2) {
367                 DH_free(dh);
368                 return (DST_R_INVALIDPUBLICKEY);
369         }
370         glen = uint16_fromregion(&r);
371         if (r.length < glen) {
372                 DH_free(dh);
373                 return (DST_R_INVALIDPUBLICKEY);
374         }
375         if (special != 0) {
376                 if (glen == 0)
377                         dh->g = &bn2;
378                 else {
379                         dh->g = BN_bin2bn(r.base, glen, NULL);
380                         if (BN_cmp(dh->g, &bn2) == 0) {
381                                 BN_free(dh->g);
382                                 dh->g = &bn2;
383                         }
384                         else {
385                                 DH_free(dh);
386                                 return (DST_R_INVALIDPUBLICKEY);
387                         }
388                 }
389         }
390         else {
391                 if (glen == 0) {
392                         DH_free(dh);
393                         return (DST_R_INVALIDPUBLICKEY);
394                 }
395                 dh->g = BN_bin2bn(r.base, glen, NULL);
396         }
397         r.base += glen;
398
399         if (r.length < 2) {
400                 DH_free(dh);
401                 return (DST_R_INVALIDPUBLICKEY);
402         }
403         publen = uint16_fromregion(&r);
404         if (r.length < publen) {
405                 DH_free(dh);
406                 return (DST_R_INVALIDPUBLICKEY);
407         }
408         dh->pub_key = BN_bin2bn(r.base, publen, NULL);
409         r.base += publen;
410
411         key->key_size = BN_num_bits(dh->p);
412
413         isc_buffer_forward(data, plen + glen + publen + 6);
414
415         key->keydata.dh = dh;
416
417         return (ISC_R_SUCCESS);
418 }
419
420 static isc_result_t
421 openssldh_tofile(const dst_key_t *key, const char *directory) {
422         int i;
423         DH *dh;
424         dst_private_t priv;
425         unsigned char *bufs[4];
426         isc_result_t result;
427
428         if (key->keydata.dh == NULL)
429                 return (DST_R_NULLKEY);
430
431         dh = key->keydata.dh;
432
433         for (i = 0; i < 4; i++) {
434                 bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
435                 if (bufs[i] == NULL) {
436                         result = ISC_R_NOMEMORY;
437                         goto fail;
438                 }
439         }
440
441         i = 0;
442
443         priv.elements[i].tag = TAG_DH_PRIME;
444         priv.elements[i].length = BN_num_bytes(dh->p);
445         BN_bn2bin(dh->p, bufs[i]);
446         priv.elements[i].data = bufs[i];
447         i++;
448
449         priv.elements[i].tag = TAG_DH_GENERATOR;
450         priv.elements[i].length = BN_num_bytes(dh->g);
451         BN_bn2bin(dh->g, bufs[i]);
452         priv.elements[i].data = bufs[i];
453         i++;
454
455         priv.elements[i].tag = TAG_DH_PRIVATE;
456         priv.elements[i].length = BN_num_bytes(dh->priv_key);
457         BN_bn2bin(dh->priv_key, bufs[i]);
458         priv.elements[i].data = bufs[i];
459         i++;
460
461         priv.elements[i].tag = TAG_DH_PUBLIC;
462         priv.elements[i].length = BN_num_bytes(dh->pub_key);
463         BN_bn2bin(dh->pub_key, bufs[i]);
464         priv.elements[i].data = bufs[i];
465         i++;
466
467         priv.nelements = i;
468         result = dst__privstruct_writefile(key, &priv, directory);
469  fail:
470         for (i = 0; i < 4; i++) {
471                 if (bufs[i] == NULL)
472                         break;
473                 isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p));
474         }
475         return (result);
476 }
477
478 static isc_result_t
479 openssldh_parse(dst_key_t *key, isc_lex_t *lexer) {
480         dst_private_t priv;
481         isc_result_t ret;
482         int i;
483         DH *dh = NULL;
484         isc_mem_t *mctx;
485 #define DST_RET(a) {ret = a; goto err;}
486
487         mctx = key->mctx;
488
489         /* read private key file */
490         ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv);
491         if (ret != ISC_R_SUCCESS)
492                 return (ret);
493
494         dh = DH_new();
495         if (dh == NULL)
496                 DST_RET(ISC_R_NOMEMORY);
497         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
498         key->keydata.dh = dh;
499
500         for (i = 0; i < priv.nelements; i++) {
501                 BIGNUM *bn;
502                 bn = BN_bin2bn(priv.elements[i].data,
503                                priv.elements[i].length, NULL);
504                 if (bn == NULL)
505                         DST_RET(ISC_R_NOMEMORY);
506
507                 switch (priv.elements[i].tag) {
508                         case TAG_DH_PRIME:
509                                 dh->p = bn;
510                                 break;
511                         case TAG_DH_GENERATOR:
512                                 dh->g = bn;
513                                 break;
514                         case TAG_DH_PRIVATE:
515                                 dh->priv_key = bn;
516                                 break;
517                         case TAG_DH_PUBLIC:
518                                 dh->pub_key = bn;
519                                 break;
520                 }
521         }
522         dst__privstruct_free(&priv, mctx);
523
524         key->key_size = BN_num_bits(dh->p);
525
526         if ((key->key_size == 768 ||
527              key->key_size == 1024 ||
528              key->key_size == 1536) &&
529             BN_cmp(dh->g, &bn2) == 0)
530         {
531                 if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
532                         BN_free(dh->p);
533                         BN_free(dh->g);
534                         dh->p = &bn768;
535                         dh->g = &bn2;
536                 } else if (key->key_size == 1024 &&
537                            BN_cmp(dh->p, &bn1024) == 0) {
538                         BN_free(dh->p);
539                         BN_free(dh->g);
540                         dh->p = &bn1024;
541                         dh->g = &bn2;
542                 } else if (key->key_size == 1536 &&
543                            BN_cmp(dh->p, &bn1536) == 0) {
544                         BN_free(dh->p);
545                         BN_free(dh->g);
546                         dh->p = &bn1536;
547                         dh->g = &bn2;
548                 }
549         }
550
551         return (ISC_R_SUCCESS);
552
553  err:
554         openssldh_destroy(key);
555         dst__privstruct_free(&priv, mctx);
556         memset(&priv, 0, sizeof(priv));
557         return (ret);
558 }
559
560 static void
561 BN_fromhex(BIGNUM *b, const char *str) {
562         static const char hexdigits[] = "0123456789abcdef";
563         unsigned char data[512];
564         unsigned int i;
565         BIGNUM *out;
566
567         RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U);
568         for (i = 0; i < strlen(str); i += 2) {
569                 char *s;
570                 unsigned int high, low;
571
572                 s = strchr(hexdigits, tolower((unsigned char)str[i]));
573                 RUNTIME_CHECK(s != NULL);
574                 high = s - hexdigits;
575
576                 s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
577                 RUNTIME_CHECK(s != NULL);
578                 low = s - hexdigits;
579
580                 data[i/2] = (unsigned char)((high << 4) + low);
581         }
582         out = BN_bin2bn(data, strlen(str)/2, b);
583         RUNTIME_CHECK(out != NULL);
584 }
585
586 static void
587 openssldh_cleanup(void) {
588         BN_free(&bn2);
589         BN_free(&bn768);
590         BN_free(&bn1024);
591         BN_free(&bn1536);
592 }
593
594 static dst_func_t openssldh_functions = {
595         NULL, /*%< createctx */
596         NULL, /*%< destroyctx */
597         NULL, /*%< adddata */
598         NULL, /*%< openssldh_sign */
599         NULL, /*%< openssldh_verify */
600         openssldh_computesecret,
601         openssldh_compare,
602         openssldh_paramcompare,
603         openssldh_generate,
604         openssldh_isprivate,
605         openssldh_destroy,
606         openssldh_todns,
607         openssldh_fromdns,
608         openssldh_tofile,
609         openssldh_parse,
610         openssldh_cleanup,
611 };
612
613 isc_result_t
614 dst__openssldh_init(dst_func_t **funcp) {
615         REQUIRE(funcp != NULL);
616         if (*funcp == NULL) {
617                 BN_init(&bn2);
618                 BN_init(&bn768);
619                 BN_init(&bn1024);
620                 BN_init(&bn1536);
621                 BN_set_word(&bn2, 2);
622                 BN_fromhex(&bn768, PRIME768);
623                 BN_fromhex(&bn1024, PRIME1024);
624                 BN_fromhex(&bn1536, PRIME1536);
625                 *funcp = &openssldh_functions;
626         }
627         return (ISC_R_SUCCESS);
628 }
629
630 #else /* OPENSSL */
631
632 #include <isc/util.h>
633
634 EMPTY_TRANSLATION_UNIT
635
636 #endif /* OPENSSL */
637 /*! \file */