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.
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.
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.
20 * Principal Author: Brian Wellington
21 * $Id: openssldh_link.c,v 1.38.2.4 2004/03/16 12:45:41 marka Exp $
31 #include <isc/string.h>
34 #include <dst/result.h>
36 #include "dst_internal.h"
37 #include "dst_parse.h"
39 #include <openssl/dh.h>
41 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
42 "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
43 "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
45 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
46 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
47 "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
48 "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
50 static isc_result_t
openssldh_todns(const dst_key_t
*key
, isc_buffer_t
*data
);
52 static BIGNUM bn2
, bn768
, bn1024
;
55 openssldh_computesecret(const dst_key_t
*pub
, const dst_key_t
*priv
,
63 REQUIRE(pub
->opaque
!= NULL
);
64 REQUIRE(priv
->opaque
!= NULL
);
66 dhpub
= (DH
*) pub
->opaque
;
67 dhpriv
= (DH
*) priv
->opaque
;
69 len
= DH_size(dhpriv
);
70 isc_buffer_availableregion(secret
, &r
);
72 return (ISC_R_NOSPACE
);
73 ret
= DH_compute_key(r
.base
, dhpub
->pub_key
, dhpriv
);
75 return (DST_R_COMPUTESECRETFAILURE
);
76 isc_buffer_add(secret
, len
);
77 return (ISC_R_SUCCESS
);
81 openssldh_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
85 dh1
= (DH
*) key1
->opaque
;
86 dh2
= (DH
*) key2
->opaque
;
88 if (dh1
== NULL
&& dh2
== NULL
)
90 else if (dh1
== NULL
|| dh2
== NULL
)
93 status
= BN_cmp(dh1
->p
, dh2
->p
) ||
94 BN_cmp(dh1
->g
, dh2
->g
) ||
95 BN_cmp(dh1
->pub_key
, dh2
->pub_key
);
100 if (dh1
->priv_key
!= NULL
|| dh2
->priv_key
!= NULL
) {
101 if (dh1
->priv_key
== NULL
|| dh2
->priv_key
== NULL
)
103 if (BN_cmp(dh1
->priv_key
, dh2
->priv_key
) != 0)
110 openssldh_paramcompare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
114 dh1
= (DH
*) key1
->opaque
;
115 dh2
= (DH
*) key2
->opaque
;
117 if (dh1
== NULL
&& dh2
== NULL
)
119 else if (dh1
== NULL
|| dh2
== NULL
)
122 status
= BN_cmp(dh1
->p
, dh2
->p
) ||
123 BN_cmp(dh1
->g
, dh2
->g
);
131 openssldh_generate(dst_key_t
*key
, int generator
) {
134 if (generator
== 0) {
135 if (key
->key_size
== 768 || key
->key_size
== 1024) {
138 return (ISC_R_NOMEMORY
);
139 if (key
->key_size
== 768)
150 dh
= DH_generate_parameters(key
->key_size
, generator
,
154 return (DST_R_OPENSSLFAILURE
);
156 if (DH_generate_key(dh
) == 0) {
158 return (DST_R_OPENSSLFAILURE
);
160 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
164 return (ISC_R_SUCCESS
);
168 openssldh_isprivate(const dst_key_t
*key
) {
169 DH
*dh
= (DH
*) key
->opaque
;
170 return (ISC_TF(dh
!= NULL
&& dh
->priv_key
!= NULL
));
174 openssldh_issymmetric(void) {
179 openssldh_destroy(dst_key_t
*key
) {
180 DH
*dh
= key
->opaque
;
185 if (dh
->p
== &bn768
|| dh
->p
== &bn1024
)
194 uint16_toregion(isc_uint16_t val
, isc_region_t
*region
) {
195 *region
->base
++ = (val
& 0xff00) >> 8;
196 *region
->base
++ = (val
& 0x00ff);
200 uint16_fromregion(isc_region_t
*region
) {
202 unsigned char *cp
= region
->base
;
204 val
= ((unsigned int)(cp
[0])) << 8;
205 val
|= ((unsigned int)(cp
[1]));
212 openssldh_todns(const dst_key_t
*key
, isc_buffer_t
*data
) {
215 isc_uint16_t dnslen
, plen
, glen
, publen
;
217 REQUIRE(key
->opaque
!= NULL
);
219 dh
= (DH
*) key
->opaque
;
221 isc_buffer_availableregion(data
, &r
);
223 if (dh
->g
== &bn2
&& (dh
->p
== &bn768
|| dh
->p
== &bn1024
)) {
228 plen
= BN_num_bytes(dh
->p
);
229 glen
= BN_num_bytes(dh
->g
);
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
);
236 uint16_toregion(plen
, &r
);
244 BN_bn2bin(dh
->p
, r
.base
);
247 uint16_toregion(glen
, &r
);
249 BN_bn2bin(dh
->g
, r
.base
);
252 uint16_toregion(publen
, &r
);
253 BN_bn2bin(dh
->pub_key
, r
.base
);
256 isc_buffer_add(data
, dnslen
);
258 return (ISC_R_SUCCESS
);
262 openssldh_fromdns(dst_key_t
*key
, isc_buffer_t
*data
) {
265 isc_uint16_t plen
, glen
, publen
;
268 isc_buffer_remainingregion(data
, &r
);
270 return (ISC_R_SUCCESS
);
274 return (ISC_R_NOMEMORY
);
275 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
278 * Read the prime length. 1 & 2 are table entries, > 16 means a
279 * prime follows, otherwise an error.
283 return (DST_R_INVALIDPUBLICKEY
);
285 plen
= uint16_fromregion(&r
);
286 if (plen
< 16 && plen
!= 1 && plen
!= 2) {
288 return (DST_R_INVALIDPUBLICKEY
);
290 if (r
.length
< plen
) {
292 return (DST_R_INVALIDPUBLICKEY
);
294 if (plen
== 1 || plen
== 2) {
298 special
= uint16_fromregion(&r
);
308 return (DST_R_INVALIDPUBLICKEY
);
312 dh
->p
= BN_bin2bn(r
.base
, plen
, NULL
);
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.
323 return (DST_R_INVALIDPUBLICKEY
);
325 glen
= uint16_fromregion(&r
);
326 if (r
.length
< glen
) {
328 return (DST_R_INVALIDPUBLICKEY
);
334 dh
->g
= BN_bin2bn(r
.base
, glen
, NULL
);
335 if (BN_cmp(dh
->g
, &bn2
) == 0) {
341 return (DST_R_INVALIDPUBLICKEY
);
348 return (DST_R_INVALIDPUBLICKEY
);
350 dh
->g
= BN_bin2bn(r
.base
, glen
, NULL
);
356 return (DST_R_INVALIDPUBLICKEY
);
358 publen
= uint16_fromregion(&r
);
359 if (r
.length
< publen
) {
361 return (DST_R_INVALIDPUBLICKEY
);
363 dh
->pub_key
= BN_bin2bn(r
.base
, publen
, NULL
);
366 key
->key_size
= BN_num_bits(dh
->p
);
368 isc_buffer_forward(data
, plen
+ glen
+ publen
+ 6);
370 key
->opaque
= (void *) dh
;
372 return (ISC_R_SUCCESS
);
376 openssldh_tofile(const dst_key_t
*key
, const char *directory
) {
380 unsigned char *bufs
[4];
383 if (key
->opaque
== NULL
)
384 return (DST_R_NULLKEY
);
386 dh
= (DH
*) key
->opaque
;
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
;
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
];
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
];
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
];
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
];
423 result
= dst__privstruct_writefile(key
, &priv
, directory
);
425 for (i
= 0; i
< 4; i
++) {
428 isc_mem_put(key
->mctx
, bufs
[i
], BN_num_bytes(dh
->p
));
434 openssldh_fromfile(dst_key_t
*key
, const char *filename
) {
440 #define DST_RET(a) {ret = a; goto err;}
444 /* read private key file */
445 ret
= dst__privstruct_parsefile(key
, filename
, mctx
, &priv
);
446 if (ret
!= ISC_R_SUCCESS
)
451 DST_RET(ISC_R_NOMEMORY
);
452 dh
->flags
&= ~DH_FLAG_CACHE_MONT_P
;
455 for (i
= 0; i
< priv
.nelements
; i
++) {
457 bn
= BN_bin2bn(priv
.elements
[i
].data
,
458 priv
.elements
[i
].length
, NULL
);
460 DST_RET(ISC_R_NOMEMORY
);
462 switch (priv
.elements
[i
].tag
) {
466 case TAG_DH_GENERATOR
:
477 dst__privstruct_free(&priv
, mctx
);
479 key
->key_size
= BN_num_bits(dh
->p
);
481 if ((key
->key_size
== 768 || key
->key_size
== 1024) &&
482 BN_cmp(dh
->g
, &bn2
) == 0)
484 if (key
->key_size
== 768 && BN_cmp(dh
->p
, &bn768
) == 0) {
489 } else if (key
->key_size
== 1024 &&
490 BN_cmp(dh
->p
, &bn1024
) == 0) {
498 return (ISC_R_SUCCESS
);
501 openssldh_destroy(key
);
502 dst__privstruct_free(&priv
, mctx
);
503 memset(&priv
, 0, sizeof(priv
));
508 BN_fromhex(BIGNUM
*b
, const char *str
) {
509 static const char hexdigits
[] = "0123456789abcdef";
510 unsigned char data
[512];
514 RUNTIME_CHECK(strlen(str
) < 1024U && strlen(str
) % 2 == 0U);
515 for (i
= 0; i
< strlen(str
); i
+= 2) {
517 unsigned int high
, low
;
519 s
= strchr(hexdigits
, tolower((unsigned char)str
[i
]));
520 RUNTIME_CHECK(s
!= NULL
);
521 high
= s
- hexdigits
;
523 s
= strchr(hexdigits
, tolower((unsigned char)str
[i
+ 1]));
524 RUNTIME_CHECK(s
!= NULL
);
527 data
[i
/2] = (unsigned char)((high
<< 4) + low
);
529 out
= BN_bin2bn(data
, strlen(str
)/2, b
);
530 RUNTIME_CHECK(out
!= NULL
);
533 static dst_func_t openssldh_functions
= {
534 NULL
, /* createctx */
535 NULL
, /* destroyctx */
537 NULL
, /* openssldh_sign */
538 NULL
, /* openssldh_verify */
539 openssldh_computesecret
,
541 openssldh_paramcompare
,
544 openssldh_issymmetric
,
553 dst__openssldh_init(dst_func_t
**funcp
) {
554 REQUIRE(funcp
!= NULL
&& *funcp
== NULL
);
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
);
566 dst__openssldh_destroy(void) {