Merge from vendor branch GCC:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / sec / dst / openssldh_link.c
1 /*
2  * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2001  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.38.2.4 2004/03/16 12:45:41 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_parse.h"
38
39 #include <openssl/dh.h>
40
41 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
42         "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
43         "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
44
45 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
46         "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
47         "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
48         "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
49
50 static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
51
52 static BIGNUM bn2, bn768, bn1024;
53
54 static isc_result_t
55 openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
56                         isc_buffer_t *secret)
57 {
58         DH *dhpub, *dhpriv;
59         int ret;
60         isc_region_t r;
61         unsigned int len;
62
63         REQUIRE(pub->opaque != NULL);
64         REQUIRE(priv->opaque != NULL);
65
66         dhpub = (DH *) pub->opaque;
67         dhpriv = (DH *) priv->opaque;
68
69         len = DH_size(dhpriv);
70         isc_buffer_availableregion(secret, &r);
71         if (r.length < len)
72                 return (ISC_R_NOSPACE);
73         ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
74         if (ret == 0)
75                 return (DST_R_COMPUTESECRETFAILURE);
76         isc_buffer_add(secret, len);
77         return (ISC_R_SUCCESS);
78 }
79
80 static isc_boolean_t
81 openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
82         int status;
83         DH *dh1, *dh2;
84
85         dh1 = (DH *) key1->opaque;
86         dh2 = (DH *) key2->opaque;
87
88         if (dh1 == NULL && dh2 == NULL)
89                 return (ISC_TRUE);
90         else if (dh1 == NULL || dh2 == NULL)
91                 return (ISC_FALSE);
92
93         status = BN_cmp(dh1->p, dh2->p) ||
94                  BN_cmp(dh1->g, dh2->g) ||
95                  BN_cmp(dh1->pub_key, dh2->pub_key);
96
97         if (status != 0)
98                 return (ISC_FALSE);
99
100         if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
101                 if (dh1->priv_key == NULL || dh2->priv_key == NULL)
102                         return (ISC_FALSE);
103                 if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
104                         return (ISC_FALSE);
105         }
106         return (ISC_TRUE);
107 }
108
109 static isc_boolean_t
110 openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
111         int status;
112         DH *dh1, *dh2;
113
114         dh1 = (DH *) key1->opaque;
115         dh2 = (DH *) key2->opaque;
116
117         if (dh1 == NULL && dh2 == NULL)
118                 return (ISC_TRUE);
119         else if (dh1 == NULL || dh2 == NULL)
120                 return (ISC_FALSE);
121
122         status = BN_cmp(dh1->p, dh2->p) ||
123                  BN_cmp(dh1->g, dh2->g);
124
125         if (status != 0)
126                 return (ISC_FALSE);
127         return (ISC_TRUE);
128 }
129
130 static isc_result_t
131 openssldh_generate(dst_key_t *key, int generator) {
132         DH *dh = NULL;
133
134         if (generator == 0) {
135                 if (key->key_size == 768 || key->key_size == 1024) {
136                         dh = DH_new();
137                         if (dh == NULL)
138                                 return (ISC_R_NOMEMORY);
139                         if (key->key_size == 768)
140                                 dh->p = &bn768;
141                         else
142                                 dh->p = &bn1024;
143                         dh->g = &bn2;
144                 }
145                 else
146                         generator = 2;
147         }
148
149         if (generator != 0)
150                 dh = DH_generate_parameters(key->key_size, generator,
151                                             NULL, NULL);
152
153         if (dh == NULL)
154                 return (DST_R_OPENSSLFAILURE);
155
156         if (DH_generate_key(dh) == 0) {
157                 DH_free(dh);
158                 return (DST_R_OPENSSLFAILURE);
159         }
160         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
161
162         key->opaque = dh;
163
164         return (ISC_R_SUCCESS);
165 }
166
167 static isc_boolean_t
168 openssldh_isprivate(const dst_key_t *key) {
169         DH *dh = (DH *) key->opaque;
170         return (ISC_TF(dh != NULL && dh->priv_key != NULL));
171 }
172
173 static isc_boolean_t
174 openssldh_issymmetric(void) {
175         return (ISC_FALSE);
176 }
177
178 static void
179 openssldh_destroy(dst_key_t *key) {
180         DH *dh = key->opaque;
181
182         if (dh == NULL)
183                 return;
184
185         if (dh->p == &bn768 || dh->p == &bn1024)
186                 dh->p = NULL;
187         if (dh->g == &bn2)
188                 dh->g = NULL;
189         DH_free(dh);
190         key->opaque = NULL;
191 }
192
193 static void
194 uint16_toregion(isc_uint16_t val, isc_region_t *region) {
195         *region->base++ = (val & 0xff00) >> 8;
196         *region->base++ = (val & 0x00ff);
197 }
198
199 static isc_uint16_t
200 uint16_fromregion(isc_region_t *region) {
201         isc_uint16_t val;
202         unsigned char *cp = region->base;
203
204         val = ((unsigned int)(cp[0])) << 8;
205         val |= ((unsigned int)(cp[1]));
206
207         region->base += 2;
208         return (val);
209 }
210
211 static isc_result_t
212 openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
213         DH *dh;
214         isc_region_t r;
215         isc_uint16_t dnslen, plen, glen, publen;
216
217         REQUIRE(key->opaque != NULL);
218
219         dh = (DH *) key->opaque;
220
221         isc_buffer_availableregion(data, &r);
222
223         if (dh->g == &bn2 && (dh->p == &bn768 || dh->p == &bn1024)) {
224                 plen = 1;
225                 glen = 0;
226         }
227         else {
228                 plen = BN_num_bytes(dh->p);
229                 glen = BN_num_bytes(dh->g);
230         }
231         publen = BN_num_bytes(dh->pub_key);
232         dnslen = plen + glen + publen + 6;
233         if (r.length < (unsigned int) dnslen)
234                 return (ISC_R_NOSPACE);
235
236         uint16_toregion(plen, &r);
237         if (plen == 1) {
238                 if (dh->p == &bn768)
239                         *r.base = 1;
240                 else
241                         *r.base = 2;
242         }
243         else
244                 BN_bn2bin(dh->p, r.base);
245         r.base += plen;
246
247         uint16_toregion(glen, &r);
248         if (glen > 0)
249                 BN_bn2bin(dh->g, r.base);
250         r.base += glen;
251
252         uint16_toregion(publen, &r);
253         BN_bn2bin(dh->pub_key, r.base);
254         r.base += publen;
255
256         isc_buffer_add(data, dnslen);
257
258         return (ISC_R_SUCCESS);
259 }
260
261 static isc_result_t
262 openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
263         DH *dh;
264         isc_region_t r;
265         isc_uint16_t plen, glen, publen;
266         int special = 0;
267
268         isc_buffer_remainingregion(data, &r);
269         if (r.length == 0)
270                 return (ISC_R_SUCCESS);
271
272         dh = DH_new();
273         if (dh == NULL)
274                 return (ISC_R_NOMEMORY);
275         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
276
277         /*
278          * Read the prime length.  1 & 2 are table entries, > 16 means a
279          * prime follows, otherwise an error.
280          */
281         if (r.length < 2) {
282                 DH_free(dh);
283                 return (DST_R_INVALIDPUBLICKEY);
284         }
285         plen = uint16_fromregion(&r);
286         if (plen < 16 && plen != 1 && plen != 2) {
287                 DH_free(dh);
288                 return (DST_R_INVALIDPUBLICKEY);
289         }
290         if (r.length < plen) {
291                 DH_free(dh);
292                 return (DST_R_INVALIDPUBLICKEY);
293         }
294         if (plen == 1 || plen == 2) {
295                 if (plen == 1)
296                         special = *r.base++;
297                 else
298                         special = uint16_fromregion(&r);
299                 switch (special) {
300                         case 1:
301                                 dh->p = &bn768;
302                                 break;
303                         case 2:
304                                 dh->p = &bn1024;
305                                 break;
306                         default:
307                                 DH_free(dh);
308                                 return (DST_R_INVALIDPUBLICKEY);
309                 }
310         }
311         else {
312                 dh->p = BN_bin2bn(r.base, plen, NULL);
313                 r.base += plen;
314         }
315
316         /*
317          * Read the generator length.  This should be 0 if the prime was
318          * special, but it might not be.  If it's 0 and the prime is not
319          * special, we have a problem.
320          */
321         if (r.length < 2) {
322                 DH_free(dh);
323                 return (DST_R_INVALIDPUBLICKEY);
324         }
325         glen = uint16_fromregion(&r);
326         if (r.length < glen) {
327                 DH_free(dh);
328                 return (DST_R_INVALIDPUBLICKEY);
329         }
330         if (special != 0) {
331                 if (glen == 0)
332                         dh->g = &bn2;
333                 else {
334                         dh->g = BN_bin2bn(r.base, glen, NULL);
335                         if (BN_cmp(dh->g, &bn2) == 0) {
336                                 BN_free(dh->g);
337                                 dh->g = &bn2;
338                         }
339                         else {
340                                 DH_free(dh);
341                                 return (DST_R_INVALIDPUBLICKEY);
342                         }
343                 }
344         }
345         else {
346                 if (glen == 0) {
347                         DH_free(dh);
348                         return (DST_R_INVALIDPUBLICKEY);
349                 }
350                 dh->g = BN_bin2bn(r.base, glen, NULL);
351         }
352         r.base += glen;
353
354         if (r.length < 2) {
355                 DH_free(dh);
356                 return (DST_R_INVALIDPUBLICKEY);
357         }
358         publen = uint16_fromregion(&r);
359         if (r.length < publen) {
360                 DH_free(dh);
361                 return (DST_R_INVALIDPUBLICKEY);
362         }
363         dh->pub_key = BN_bin2bn(r.base, publen, NULL);
364         r.base += publen;
365
366         key->key_size = BN_num_bits(dh->p);
367
368         isc_buffer_forward(data, plen + glen + publen + 6);
369
370         key->opaque = (void *) dh;
371
372         return (ISC_R_SUCCESS);
373 }
374
375 static isc_result_t
376 openssldh_tofile(const dst_key_t *key, const char *directory) {
377         int i;
378         DH *dh;
379         dst_private_t priv;
380         unsigned char *bufs[4];
381         isc_result_t result;
382
383         if (key->opaque == NULL)
384                 return (DST_R_NULLKEY);
385
386         dh = (DH *) key->opaque;
387
388         for (i = 0; i < 4; i++) {
389                 bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
390                 if (bufs[i] == NULL) {
391                         result = ISC_R_NOMEMORY;
392                         goto fail;
393                 }
394         }
395
396         i = 0;
397
398         priv.elements[i].tag = TAG_DH_PRIME;
399         priv.elements[i].length = BN_num_bytes(dh->p);
400         BN_bn2bin(dh->p, bufs[i]);
401         priv.elements[i].data = bufs[i];
402         i++;
403
404         priv.elements[i].tag = TAG_DH_GENERATOR;
405         priv.elements[i].length = BN_num_bytes(dh->g);
406         BN_bn2bin(dh->g, bufs[i]);
407         priv.elements[i].data = bufs[i];
408         i++;
409
410         priv.elements[i].tag = TAG_DH_PRIVATE;
411         priv.elements[i].length = BN_num_bytes(dh->priv_key);
412         BN_bn2bin(dh->priv_key, bufs[i]);
413         priv.elements[i].data = bufs[i];
414         i++;
415
416         priv.elements[i].tag = TAG_DH_PUBLIC;
417         priv.elements[i].length = BN_num_bytes(dh->pub_key);
418         BN_bn2bin(dh->pub_key, bufs[i]);
419         priv.elements[i].data = bufs[i];
420         i++;
421
422         priv.nelements = i;
423         result = dst__privstruct_writefile(key, &priv, directory);
424  fail:
425         for (i = 0; i < 4; i++) {
426                 if (bufs[i] == NULL)
427                         break;
428                 isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p));
429         }
430         return (result);
431 }
432
433 static isc_result_t
434 openssldh_fromfile(dst_key_t *key, const char *filename) {
435         dst_private_t priv;
436         isc_result_t ret;
437         int i;
438         DH *dh = NULL;
439         isc_mem_t *mctx;
440 #define DST_RET(a) {ret = a; goto err;}
441
442         mctx = key->mctx;
443
444         /* read private key file */
445         ret = dst__privstruct_parsefile(key, filename, mctx, &priv);
446         if (ret != ISC_R_SUCCESS)
447                 return (ret);
448
449         dh = DH_new();
450         if (dh == NULL)
451                 DST_RET(ISC_R_NOMEMORY);
452         dh->flags &= ~DH_FLAG_CACHE_MONT_P;
453         key->opaque = dh;
454
455         for (i = 0; i < priv.nelements; i++) {
456                 BIGNUM *bn;
457                 bn = BN_bin2bn(priv.elements[i].data,
458                                priv.elements[i].length, NULL);
459                 if (bn == NULL)
460                         DST_RET(ISC_R_NOMEMORY);
461
462                 switch (priv.elements[i].tag) {
463                         case TAG_DH_PRIME:
464                                 dh->p = bn;
465                                 break;
466                         case TAG_DH_GENERATOR:
467                                 dh->g = bn;
468                                 break;
469                         case TAG_DH_PRIVATE:
470                                 dh->priv_key = bn;
471                                 break;
472                         case TAG_DH_PUBLIC:
473                                 dh->pub_key = bn;
474                                 break;
475                 }
476         }
477         dst__privstruct_free(&priv, mctx);
478
479         key->key_size = BN_num_bits(dh->p);
480
481         if ((key->key_size == 768 || key->key_size == 1024) &&
482             BN_cmp(dh->g, &bn2) == 0)
483         {
484                 if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
485                         BN_free(dh->p);
486                         BN_free(dh->g);
487                         dh->p = &bn768;
488                         dh->g = &bn2;
489                 } else if (key->key_size == 1024 &&
490                            BN_cmp(dh->p, &bn1024) == 0) {
491                         BN_free(dh->p);
492                         BN_free(dh->g);
493                         dh->p = &bn1024;
494                         dh->g = &bn2;
495                 }
496         }
497
498         return (ISC_R_SUCCESS);
499
500  err:
501         openssldh_destroy(key);
502         dst__privstruct_free(&priv, mctx);
503         memset(&priv, 0, sizeof(priv));
504         return (ret);
505 }
506
507 static void
508 BN_fromhex(BIGNUM *b, const char *str) {
509         static const char hexdigits[] = "0123456789abcdef";
510         unsigned char data[512];
511         unsigned int i;
512         BIGNUM *out;
513
514         RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U);
515         for (i = 0; i < strlen(str); i += 2) {
516                 char *s;
517                 unsigned int high, low;
518
519                 s = strchr(hexdigits, tolower((unsigned char)str[i]));
520                 RUNTIME_CHECK(s != NULL);
521                 high = s - hexdigits;
522
523                 s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
524                 RUNTIME_CHECK(s != NULL);
525                 low = s - hexdigits;
526
527                 data[i/2] = (unsigned char)((high << 4) + low);
528         }
529         out = BN_bin2bn(data, strlen(str)/2, b);
530         RUNTIME_CHECK(out != NULL);
531 }
532
533 static dst_func_t openssldh_functions = {
534         NULL, /* createctx */
535         NULL, /* destroyctx */
536         NULL, /* adddata */
537         NULL, /* openssldh_sign */
538         NULL, /* openssldh_verify */
539         openssldh_computesecret,
540         openssldh_compare,
541         openssldh_paramcompare,
542         openssldh_generate,
543         openssldh_isprivate,
544         openssldh_issymmetric,
545         openssldh_destroy,
546         openssldh_todns,
547         openssldh_fromdns,
548         openssldh_tofile,
549         openssldh_fromfile,
550 };
551
552 isc_result_t
553 dst__openssldh_init(dst_func_t **funcp) {
554         REQUIRE(funcp != NULL && *funcp == NULL);
555         BN_init(&bn2);
556         BN_init(&bn768);
557         BN_init(&bn1024);
558         BN_set_word(&bn2, 2);
559         BN_fromhex(&bn768, PRIME768);
560         BN_fromhex(&bn1024, PRIME1024);
561         *funcp = &openssldh_functions;
562         return (ISC_R_SUCCESS);
563 }
564
565 void
566 dst__openssldh_destroy(void) {
567         BN_free(&bn2);
568         BN_free(&bn768);
569         BN_free(&bn1024);
570 }
571
572 #endif /* OPENSSL */