1 /* $NetBSD: openssldh_link.c,v 1.9 2015/09/03 07:33:34 christos Exp $ */
4 * Portions Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * Principal Author: Brian Wellington
36 * Id: openssldh_link.c,v 1.20 2011/01/11 23:47:13 tbox Exp
46 #include <isc/string.h>
49 #include <dst/result.h>
51 #include "dst_internal.h"
52 #include "dst_openssl.h"
53 #include "dst_parse.h"
55 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
56 "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
57 "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
59 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
60 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
61 "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
62 "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
64 #define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
65 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
66 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
67 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
68 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
69 "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
70 "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
71 "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
74 static isc_result_t
openssldh_todns(const dst_key_t
*key
, isc_buffer_t
*data
);
76 static BIGNUM bn2
, bn768
, bn1024
, bn1536
;
79 openssldh_computesecret(const dst_key_t
*pub
, const dst_key_t
*priv
,
87 REQUIRE(pub
->keydata
.dh
!= NULL
);
88 REQUIRE(priv
->keydata
.dh
!= NULL
);
90 dhpub
= pub
->keydata
.dh
;
91 dhpriv
= priv
->keydata
.dh
;
93 len
= DH_size(dhpriv
);
94 isc_buffer_availableregion(secret
, &r
);
96 return (ISC_R_NOSPACE
);
97 ret
= DH_compute_key(r
.base
, dhpub
->pub_key
, dhpriv
);
99 return (dst__openssl_toresult2("DH_compute_key",
100 DST_R_COMPUTESECRETFAILURE
));
101 isc_buffer_add(secret
, len
);
102 return (ISC_R_SUCCESS
);
106 openssldh_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
110 dh1
= key1
->keydata
.dh
;
111 dh2
= key2
->keydata
.dh
;
113 if (dh1
== NULL
&& dh2
== NULL
)
115 else if (dh1
== NULL
|| dh2
== NULL
)
118 status
= BN_cmp(dh1
->p
, dh2
->p
) ||
119 BN_cmp(dh1
->g
, dh2
->g
) ||
120 BN_cmp(dh1
->pub_key
, dh2
->pub_key
);
125 if (dh1
->priv_key
!= NULL
|| dh2
->priv_key
!= NULL
) {
126 if (dh1
->priv_key
== NULL
|| dh2
->priv_key
== NULL
)
128 if (BN_cmp(dh1
->priv_key
, dh2
->priv_key
) != 0)
135 openssldh_paramcompare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
139 dh1
= key1
->keydata
.dh
;
140 dh2
= key2
->keydata
.dh
;
142 if (dh1
== NULL
&& dh2
== NULL
)
144 else if (dh1
== NULL
|| dh2
== NULL
)
147 status
= BN_cmp(dh1
->p
, dh2
->p
) ||
148 BN_cmp(dh1
->g
, dh2
->g
);
155 #if OPENSSL_VERSION_NUMBER > 0x00908000L
157 progress_cb(int p
, int n
, BN_GENCB
*cb
)
174 openssldh_generate(dst_key_t
*key
, int generator
, void (*callback
)(int)) {
176 #if OPENSSL_VERSION_NUMBER > 0x00908000L
187 if (generator
== 0) {
188 if (key
->key_size
== 768 ||
189 key
->key_size
== 1024 ||
190 key
->key_size
== 1536)
194 return (dst__openssl_toresult(ISC_R_NOMEMORY
));
195 if (key
->key_size
== 768)
197 else if (key
->key_size
== 1024)
206 if (generator
!= 0) {
207 #if OPENSSL_VERSION_NUMBER > 0x00908000L
210 return (dst__openssl_toresult(ISC_R_NOMEMORY
));
212 if (callback
== NULL
) {
213 BN_GENCB_set_old(&cb
, NULL
, NULL
);
216 BN_GENCB_set(&cb
, &progress_cb
, u
.dptr
);
219 if (!DH_generate_parameters_ex(dh
, key
->key_size
, generator
,
222 return (dst__openssl_toresult2(
223 "DH_generate_parameters_ex",
224 DST_R_OPENSSLFAILURE
));
227 dh
= DH_generate_parameters(key
->key_size
, generator
,
233 return (dst__openssl_toresult2("DH_generate_parameters",
234 DST_R_OPENSSLFAILURE
));
236 if (DH_generate_key(dh
) == 0) {
238 return (dst__openssl_toresult2("DH_generate_key",
239 DST_R_OPENSSLFAILURE
));
241 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
243 key
->keydata
.dh
= dh
;
245 return (ISC_R_SUCCESS
);
249 openssldh_isprivate(const dst_key_t
*key
) {
250 DH
*dh
= key
->keydata
.dh
;
251 return (ISC_TF(dh
!= NULL
&& dh
->priv_key
!= NULL
));
255 openssldh_destroy(dst_key_t
*key
) {
256 DH
*dh
= key
->keydata
.dh
;
261 if (dh
->p
== &bn768
|| dh
->p
== &bn1024
|| dh
->p
== &bn1536
)
266 key
->keydata
.dh
= NULL
;
270 uint16_toregion(isc_uint16_t val
, isc_region_t
*region
) {
271 *region
->base
= (val
& 0xff00) >> 8;
272 isc_region_consume(region
, 1);
273 *region
->base
= (val
& 0x00ff);
274 isc_region_consume(region
, 1);
278 uint16_fromregion(isc_region_t
*region
) {
280 unsigned char *cp
= region
->base
;
282 val
= ((unsigned int)(cp
[0])) << 8;
283 val
|= ((unsigned int)(cp
[1]));
285 isc_region_consume(region
, 2);
291 openssldh_todns(const dst_key_t
*key
, isc_buffer_t
*data
) {
294 isc_uint16_t dnslen
, plen
, glen
, publen
;
296 REQUIRE(key
->keydata
.dh
!= NULL
);
298 dh
= key
->keydata
.dh
;
300 isc_buffer_availableregion(data
, &r
);
303 (dh
->p
== &bn768
|| dh
->p
== &bn1024
|| dh
->p
== &bn1536
)) {
308 plen
= BN_num_bytes(dh
->p
);
309 glen
= BN_num_bytes(dh
->g
);
311 publen
= BN_num_bytes(dh
->pub_key
);
312 dnslen
= plen
+ glen
+ publen
+ 6;
313 if (r
.length
< (unsigned int) dnslen
)
314 return (ISC_R_NOSPACE
);
316 uint16_toregion(plen
, &r
);
320 else if (dh
->p
== &bn1024
)
326 BN_bn2bin(dh
->p
, r
.base
);
327 isc_region_consume(&r
, plen
);
329 uint16_toregion(glen
, &r
);
331 BN_bn2bin(dh
->g
, r
.base
);
332 isc_region_consume(&r
, glen
);
334 uint16_toregion(publen
, &r
);
335 BN_bn2bin(dh
->pub_key
, r
.base
);
336 isc_region_consume(&r
, publen
);
338 isc_buffer_add(data
, dnslen
);
340 return (ISC_R_SUCCESS
);
344 openssldh_fromdns(dst_key_t
*key
, isc_buffer_t
*data
) {
347 isc_uint16_t plen
, glen
, publen
;
350 isc_buffer_remainingregion(data
, &r
);
352 return (ISC_R_SUCCESS
);
356 return (dst__openssl_toresult(ISC_R_NOMEMORY
));
357 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
360 * Read the prime length. 1 & 2 are table entries, > 16 means a
361 * prime follows, otherwise an error.
365 return (DST_R_INVALIDPUBLICKEY
);
367 plen
= uint16_fromregion(&r
);
368 if (plen
< 16 && plen
!= 1 && plen
!= 2) {
370 return (DST_R_INVALIDPUBLICKEY
);
372 if (r
.length
< plen
) {
374 return (DST_R_INVALIDPUBLICKEY
);
376 if (plen
== 1 || plen
== 2) {
379 isc_region_consume(&r
, 1);
381 special
= uint16_fromregion(&r
);
395 return (DST_R_INVALIDPUBLICKEY
);
398 dh
->p
= BN_bin2bn(r
.base
, plen
, NULL
);
399 isc_region_consume(&r
, plen
);
403 * Read the generator length. This should be 0 if the prime was
404 * special, but it might not be. If it's 0 and the prime is not
405 * special, we have a problem.
409 return (DST_R_INVALIDPUBLICKEY
);
411 glen
= uint16_fromregion(&r
);
412 if (r
.length
< glen
) {
414 return (DST_R_INVALIDPUBLICKEY
);
420 dh
->g
= BN_bin2bn(r
.base
, glen
, NULL
);
421 if (BN_cmp(dh
->g
, &bn2
) == 0) {
427 return (DST_R_INVALIDPUBLICKEY
);
433 return (DST_R_INVALIDPUBLICKEY
);
435 dh
->g
= BN_bin2bn(r
.base
, glen
, NULL
);
437 isc_region_consume(&r
, glen
);
441 return (DST_R_INVALIDPUBLICKEY
);
443 publen
= uint16_fromregion(&r
);
444 if (r
.length
< publen
) {
446 return (DST_R_INVALIDPUBLICKEY
);
448 dh
->pub_key
= BN_bin2bn(r
.base
, publen
, NULL
);
449 isc_region_consume(&r
, publen
);
451 key
->key_size
= BN_num_bits(dh
->p
);
453 isc_buffer_forward(data
, plen
+ glen
+ publen
+ 6);
455 key
->keydata
.dh
= dh
;
457 return (ISC_R_SUCCESS
);
461 openssldh_tofile(const dst_key_t
*key
, const char *directory
) {
465 unsigned char *bufs
[4];
468 if (key
->keydata
.dh
== NULL
)
469 return (DST_R_NULLKEY
);
472 return (DST_R_EXTERNALKEY
);
474 dh
= key
->keydata
.dh
;
476 memset(bufs
, 0, sizeof(bufs
));
477 for (i
= 0; i
< 4; i
++) {
478 bufs
[i
] = isc_mem_get(key
->mctx
, BN_num_bytes(dh
->p
));
479 if (bufs
[i
] == NULL
) {
480 result
= ISC_R_NOMEMORY
;
487 priv
.elements
[i
].tag
= TAG_DH_PRIME
;
488 priv
.elements
[i
].length
= BN_num_bytes(dh
->p
);
489 BN_bn2bin(dh
->p
, bufs
[i
]);
490 priv
.elements
[i
].data
= bufs
[i
];
493 priv
.elements
[i
].tag
= TAG_DH_GENERATOR
;
494 priv
.elements
[i
].length
= BN_num_bytes(dh
->g
);
495 BN_bn2bin(dh
->g
, bufs
[i
]);
496 priv
.elements
[i
].data
= bufs
[i
];
499 priv
.elements
[i
].tag
= TAG_DH_PRIVATE
;
500 priv
.elements
[i
].length
= BN_num_bytes(dh
->priv_key
);
501 BN_bn2bin(dh
->priv_key
, bufs
[i
]);
502 priv
.elements
[i
].data
= bufs
[i
];
505 priv
.elements
[i
].tag
= TAG_DH_PUBLIC
;
506 priv
.elements
[i
].length
= BN_num_bytes(dh
->pub_key
);
507 BN_bn2bin(dh
->pub_key
, bufs
[i
]);
508 priv
.elements
[i
].data
= bufs
[i
];
512 result
= dst__privstruct_writefile(key
, &priv
, directory
);
514 for (i
= 0; i
< 4; i
++) {
517 isc_mem_put(key
->mctx
, bufs
[i
], BN_num_bytes(dh
->p
));
523 openssldh_parse(dst_key_t
*key
, isc_lex_t
*lexer
, dst_key_t
*pub
) {
529 #define DST_RET(a) {ret = a; goto err;}
534 /* read private key file */
535 ret
= dst__privstruct_parse(key
, DST_ALG_DH
, lexer
, mctx
, &priv
);
536 if (ret
!= ISC_R_SUCCESS
)
540 DST_RET(DST_R_EXTERNALKEY
);
544 DST_RET(ISC_R_NOMEMORY
);
545 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
546 key
->keydata
.dh
= dh
;
548 for (i
= 0; i
< priv
.nelements
; i
++) {
550 bn
= BN_bin2bn(priv
.elements
[i
].data
,
551 priv
.elements
[i
].length
, NULL
);
553 DST_RET(ISC_R_NOMEMORY
);
555 switch (priv
.elements
[i
].tag
) {
559 case TAG_DH_GENERATOR
:
570 dst__privstruct_free(&priv
, mctx
);
572 key
->key_size
= BN_num_bits(dh
->p
);
574 if ((key
->key_size
== 768 ||
575 key
->key_size
== 1024 ||
576 key
->key_size
== 1536) &&
577 BN_cmp(dh
->g
, &bn2
) == 0)
579 if (key
->key_size
== 768 && BN_cmp(dh
->p
, &bn768
) == 0) {
584 } else if (key
->key_size
== 1024 &&
585 BN_cmp(dh
->p
, &bn1024
) == 0) {
590 } else if (key
->key_size
== 1536 &&
591 BN_cmp(dh
->p
, &bn1536
) == 0) {
599 return (ISC_R_SUCCESS
);
602 openssldh_destroy(key
);
603 dst__privstruct_free(&priv
, mctx
);
604 memset(&priv
, 0, sizeof(priv
));
609 BN_fromhex(BIGNUM
*b
, const char *str
) {
610 static const char hexdigits
[] = "0123456789abcdef";
611 unsigned char data
[512];
615 RUNTIME_CHECK(strlen(str
) < 1024U && strlen(str
) % 2 == 0U);
616 for (i
= 0; i
< strlen(str
); i
+= 2) {
618 unsigned int high
, low
;
620 s
= strchr(hexdigits
, tolower((unsigned char)str
[i
]));
621 RUNTIME_CHECK(s
!= NULL
);
622 high
= (unsigned int)(s
- hexdigits
);
624 s
= strchr(hexdigits
, tolower((unsigned char)str
[i
+ 1]));
625 RUNTIME_CHECK(s
!= NULL
);
626 low
= (unsigned int)(s
- hexdigits
);
628 data
[i
/2] = (unsigned char)((high
<< 4) + low
);
630 out
= BN_bin2bn(data
, strlen(str
)/2, b
);
631 RUNTIME_CHECK(out
!= NULL
);
635 openssldh_cleanup(void) {
642 static dst_func_t openssldh_functions
= {
643 NULL
, /*%< createctx */
644 NULL
, /*%< createctx2 */
645 NULL
, /*%< destroyctx */
646 NULL
, /*%< adddata */
647 NULL
, /*%< openssldh_sign */
648 NULL
, /*%< openssldh_verify */
649 NULL
, /*%< openssldh_verify2 */
650 openssldh_computesecret
,
652 openssldh_paramcompare
,
661 NULL
, /*%< fromlabel */
663 NULL
, /*%< restore */
667 dst__openssldh_init(dst_func_t
**funcp
) {
668 REQUIRE(funcp
!= NULL
);
669 if (*funcp
== NULL
) {
674 BN_set_word(&bn2
, 2);
675 BN_fromhex(&bn768
, PRIME768
);
676 BN_fromhex(&bn1024
, PRIME1024
);
677 BN_fromhex(&bn1536
, PRIME1536
);
678 *funcp
= &openssldh_functions
;
680 return (ISC_R_SUCCESS
);
685 #include <isc/util.h>
687 EMPTY_TRANSLATION_UNIT