2 * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2002 Internet Software Consortium.
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.
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.
17 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
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.
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.
33 * Principal Author: Brian Wellington
34 * $Id: openssldh_link.c,v 1.12 2007/08/28 07:20:42 tbox Exp $
44 #include <isc/string.h>
47 #include <dst/result.h>
49 #include "dst_internal.h"
50 #include "dst_openssl.h"
51 #include "dst_parse.h"
53 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
54 "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
55 "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
57 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
58 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
59 "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
60 "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
62 #define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
63 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
64 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
65 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
66 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
67 "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
68 "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
69 "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
72 static isc_result_t
openssldh_todns(const dst_key_t
*key
, isc_buffer_t
*data
);
74 static BIGNUM bn2
, bn768
, bn1024
, bn1536
;
77 openssldh_computesecret(const dst_key_t
*pub
, const dst_key_t
*priv
,
85 REQUIRE(pub
->keydata
.dh
!= NULL
);
86 REQUIRE(priv
->keydata
.dh
!= NULL
);
88 dhpub
= pub
->keydata
.dh
;
89 dhpriv
= priv
->keydata
.dh
;
91 len
= DH_size(dhpriv
);
92 isc_buffer_availableregion(secret
, &r
);
94 return (ISC_R_NOSPACE
);
95 ret
= DH_compute_key(r
.base
, dhpub
->pub_key
, dhpriv
);
97 return (dst__openssl_toresult(DST_R_COMPUTESECRETFAILURE
));
98 isc_buffer_add(secret
, len
);
99 return (ISC_R_SUCCESS
);
103 openssldh_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
107 dh1
= key1
->keydata
.dh
;
108 dh2
= key2
->keydata
.dh
;
110 if (dh1
== NULL
&& dh2
== NULL
)
112 else if (dh1
== NULL
|| dh2
== NULL
)
115 status
= BN_cmp(dh1
->p
, dh2
->p
) ||
116 BN_cmp(dh1
->g
, dh2
->g
) ||
117 BN_cmp(dh1
->pub_key
, dh2
->pub_key
);
122 if (dh1
->priv_key
!= NULL
|| dh2
->priv_key
!= NULL
) {
123 if (dh1
->priv_key
== NULL
|| dh2
->priv_key
== NULL
)
125 if (BN_cmp(dh1
->priv_key
, dh2
->priv_key
) != 0)
132 openssldh_paramcompare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
136 dh1
= key1
->keydata
.dh
;
137 dh2
= key2
->keydata
.dh
;
139 if (dh1
== NULL
&& dh2
== NULL
)
141 else if (dh1
== NULL
|| dh2
== NULL
)
144 status
= BN_cmp(dh1
->p
, dh2
->p
) ||
145 BN_cmp(dh1
->g
, dh2
->g
);
153 openssldh_generate(dst_key_t
*key
, int generator
) {
154 #if OPENSSL_VERSION_NUMBER > 0x00908000L
159 if (generator
== 0) {
160 if (key
->key_size
== 768 ||
161 key
->key_size
== 1024 ||
162 key
->key_size
== 1536)
166 return (dst__openssl_toresult(ISC_R_NOMEMORY
));
167 if (key
->key_size
== 768)
169 else if (key
->key_size
== 1024)
178 if (generator
!= 0) {
179 #if OPENSSL_VERSION_NUMBER > 0x00908000L
182 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE
));
184 BN_GENCB_set_old(&cb
, NULL
, NULL
);
186 if (!DH_generate_parameters_ex(dh
, key
->key_size
, generator
,
189 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE
));
192 dh
= DH_generate_parameters(key
->key_size
, generator
,
198 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE
));
200 if (DH_generate_key(dh
) == 0) {
202 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE
));
204 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
206 key
->keydata
.dh
= dh
;
208 return (ISC_R_SUCCESS
);
212 openssldh_isprivate(const dst_key_t
*key
) {
213 DH
*dh
= key
->keydata
.dh
;
214 return (ISC_TF(dh
!= NULL
&& dh
->priv_key
!= NULL
));
218 openssldh_destroy(dst_key_t
*key
) {
219 DH
*dh
= key
->keydata
.dh
;
224 if (dh
->p
== &bn768
|| dh
->p
== &bn1024
|| dh
->p
== &bn1536
)
229 key
->keydata
.dh
= NULL
;
233 uint16_toregion(isc_uint16_t val
, isc_region_t
*region
) {
234 *region
->base
++ = (val
& 0xff00) >> 8;
235 *region
->base
++ = (val
& 0x00ff);
239 uint16_fromregion(isc_region_t
*region
) {
241 unsigned char *cp
= region
->base
;
243 val
= ((unsigned int)(cp
[0])) << 8;
244 val
|= ((unsigned int)(cp
[1]));
251 openssldh_todns(const dst_key_t
*key
, isc_buffer_t
*data
) {
254 isc_uint16_t dnslen
, plen
, glen
, publen
;
256 REQUIRE(key
->keydata
.dh
!= NULL
);
258 dh
= key
->keydata
.dh
;
260 isc_buffer_availableregion(data
, &r
);
263 (dh
->p
== &bn768
|| dh
->p
== &bn1024
|| dh
->p
== &bn1536
)) {
268 plen
= BN_num_bytes(dh
->p
);
269 glen
= BN_num_bytes(dh
->g
);
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
);
276 uint16_toregion(plen
, &r
);
280 else if (dh
->p
== &bn1024
)
286 BN_bn2bin(dh
->p
, r
.base
);
289 uint16_toregion(glen
, &r
);
291 BN_bn2bin(dh
->g
, r
.base
);
294 uint16_toregion(publen
, &r
);
295 BN_bn2bin(dh
->pub_key
, r
.base
);
298 isc_buffer_add(data
, dnslen
);
300 return (ISC_R_SUCCESS
);
304 openssldh_fromdns(dst_key_t
*key
, isc_buffer_t
*data
) {
307 isc_uint16_t plen
, glen
, publen
;
310 isc_buffer_remainingregion(data
, &r
);
312 return (ISC_R_SUCCESS
);
316 return (dst__openssl_toresult(ISC_R_NOMEMORY
));
317 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
320 * Read the prime length. 1 & 2 are table entries, > 16 means a
321 * prime follows, otherwise an error.
325 return (DST_R_INVALIDPUBLICKEY
);
327 plen
= uint16_fromregion(&r
);
328 if (plen
< 16 && plen
!= 1 && plen
!= 2) {
330 return (DST_R_INVALIDPUBLICKEY
);
332 if (r
.length
< plen
) {
334 return (DST_R_INVALIDPUBLICKEY
);
336 if (plen
== 1 || plen
== 2) {
340 special
= uint16_fromregion(&r
);
353 return (DST_R_INVALIDPUBLICKEY
);
357 dh
->p
= BN_bin2bn(r
.base
, plen
, NULL
);
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.
368 return (DST_R_INVALIDPUBLICKEY
);
370 glen
= uint16_fromregion(&r
);
371 if (r
.length
< glen
) {
373 return (DST_R_INVALIDPUBLICKEY
);
379 dh
->g
= BN_bin2bn(r
.base
, glen
, NULL
);
380 if (BN_cmp(dh
->g
, &bn2
) == 0) {
386 return (DST_R_INVALIDPUBLICKEY
);
393 return (DST_R_INVALIDPUBLICKEY
);
395 dh
->g
= BN_bin2bn(r
.base
, glen
, NULL
);
401 return (DST_R_INVALIDPUBLICKEY
);
403 publen
= uint16_fromregion(&r
);
404 if (r
.length
< publen
) {
406 return (DST_R_INVALIDPUBLICKEY
);
408 dh
->pub_key
= BN_bin2bn(r
.base
, publen
, NULL
);
411 key
->key_size
= BN_num_bits(dh
->p
);
413 isc_buffer_forward(data
, plen
+ glen
+ publen
+ 6);
415 key
->keydata
.dh
= dh
;
417 return (ISC_R_SUCCESS
);
421 openssldh_tofile(const dst_key_t
*key
, const char *directory
) {
425 unsigned char *bufs
[4];
428 if (key
->keydata
.dh
== NULL
)
429 return (DST_R_NULLKEY
);
431 dh
= key
->keydata
.dh
;
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
;
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
];
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
];
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
];
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
];
468 result
= dst__privstruct_writefile(key
, &priv
, directory
);
470 for (i
= 0; i
< 4; i
++) {
473 isc_mem_put(key
->mctx
, bufs
[i
], BN_num_bytes(dh
->p
));
479 openssldh_parse(dst_key_t
*key
, isc_lex_t
*lexer
) {
485 #define DST_RET(a) {ret = a; goto err;}
489 /* read private key file */
490 ret
= dst__privstruct_parse(key
, DST_ALG_DH
, lexer
, mctx
, &priv
);
491 if (ret
!= ISC_R_SUCCESS
)
496 DST_RET(ISC_R_NOMEMORY
);
497 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
498 key
->keydata
.dh
= dh
;
500 for (i
= 0; i
< priv
.nelements
; i
++) {
502 bn
= BN_bin2bn(priv
.elements
[i
].data
,
503 priv
.elements
[i
].length
, NULL
);
505 DST_RET(ISC_R_NOMEMORY
);
507 switch (priv
.elements
[i
].tag
) {
511 case TAG_DH_GENERATOR
:
522 dst__privstruct_free(&priv
, mctx
);
524 key
->key_size
= BN_num_bits(dh
->p
);
526 if ((key
->key_size
== 768 ||
527 key
->key_size
== 1024 ||
528 key
->key_size
== 1536) &&
529 BN_cmp(dh
->g
, &bn2
) == 0)
531 if (key
->key_size
== 768 && BN_cmp(dh
->p
, &bn768
) == 0) {
536 } else if (key
->key_size
== 1024 &&
537 BN_cmp(dh
->p
, &bn1024
) == 0) {
542 } else if (key
->key_size
== 1536 &&
543 BN_cmp(dh
->p
, &bn1536
) == 0) {
551 return (ISC_R_SUCCESS
);
554 openssldh_destroy(key
);
555 dst__privstruct_free(&priv
, mctx
);
556 memset(&priv
, 0, sizeof(priv
));
561 BN_fromhex(BIGNUM
*b
, const char *str
) {
562 static const char hexdigits
[] = "0123456789abcdef";
563 unsigned char data
[512];
567 RUNTIME_CHECK(strlen(str
) < 1024U && strlen(str
) % 2 == 0U);
568 for (i
= 0; i
< strlen(str
); i
+= 2) {
570 unsigned int high
, low
;
572 s
= strchr(hexdigits
, tolower((unsigned char)str
[i
]));
573 RUNTIME_CHECK(s
!= NULL
);
574 high
= s
- hexdigits
;
576 s
= strchr(hexdigits
, tolower((unsigned char)str
[i
+ 1]));
577 RUNTIME_CHECK(s
!= NULL
);
580 data
[i
/2] = (unsigned char)((high
<< 4) + low
);
582 out
= BN_bin2bn(data
, strlen(str
)/2, b
);
583 RUNTIME_CHECK(out
!= NULL
);
587 openssldh_cleanup(void) {
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
,
602 openssldh_paramcompare
,
614 dst__openssldh_init(dst_func_t
**funcp
) {
615 REQUIRE(funcp
!= NULL
);
616 if (*funcp
== NULL
) {
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
;
627 return (ISC_R_SUCCESS
);
632 #include <isc/util.h>
634 EMPTY_TRANSLATION_UNIT