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