1 /*	$NetBSD: openssldsa_link.c,v 1.10 2015/09/03 07:33:34 christos Exp $	*/
2 
3 /*
4  * Portions Copyright (C) 2004-2009, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
5  * Portions Copyright (C) 1999-2002  Internet Software Consortium.
6  *
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.
10  *
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.
18  *
19  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
20  *
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.
24  *
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.
32  */
33 
34 #ifdef OPENSSL
35 #ifndef USE_EVP
36 #define USE_EVP 1
37 #endif
38 
39 #include <config.h>
40 
41 #include <string.h>
42 
43 #include <isc/entropy.h>
44 #include <isc/mem.h>
45 #include <isc/sha1.h>
46 #include <isc/util.h>
47 
48 #include <dst/result.h>
49 
50 #include "dst_internal.h"
51 #include "dst_openssl.h"
52 #include "dst_parse.h"
53 
54 #include <openssl/dsa.h>
55 
56 static isc_result_t openssldsa_todns(const dst_key_t *key, isc_buffer_t *data);
57 
58 static isc_result_t
59 openssldsa_createctx(dst_key_t *key, dst_context_t *dctx) {
60 #if USE_EVP
61 	EVP_MD_CTX *evp_md_ctx;
62 
63 	UNUSED(key);
64 
65 	evp_md_ctx = EVP_MD_CTX_create();
66 	if (evp_md_ctx == NULL)
67 		return (ISC_R_NOMEMORY);
68 
69 	if (!EVP_DigestInit_ex(evp_md_ctx, EVP_dss1(), NULL)) {
70 		EVP_MD_CTX_destroy(evp_md_ctx);
71 			return (ISC_R_FAILURE);
72 	}
73 
74 	dctx->ctxdata.evp_md_ctx = evp_md_ctx;
75 
76 	return (ISC_R_SUCCESS);
77 #else
78 	isc_sha1_t *sha1ctx;
79 
80 	UNUSED(key);
81 
82 	sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t));
83 	isc_sha1_init(sha1ctx);
84 	dctx->ctxdata.sha1ctx = sha1ctx;
85 	return (ISC_R_SUCCESS);
86 #endif
87 }
88 
89 static void
90 openssldsa_destroyctx(dst_context_t *dctx) {
91 #if USE_EVP
92 	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
93 
94 	if (evp_md_ctx != NULL) {
95 		EVP_MD_CTX_destroy(evp_md_ctx);
96 		dctx->ctxdata.evp_md_ctx = NULL;
97 	}
98 #else
99 	isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
100 
101 	if (sha1ctx != NULL) {
102 		isc_sha1_invalidate(sha1ctx);
103 		isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t));
104 		dctx->ctxdata.sha1ctx = NULL;
105 	}
106 #endif
107 }
108 
109 static isc_result_t
110 openssldsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
111 #if USE_EVP
112 	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
113 
114 	if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) {
115 		return (ISC_R_FAILURE);
116 	}
117 #else
118 	isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
119 
120 	isc_sha1_update(sha1ctx, data->base, data->length);
121 #endif
122 	return (ISC_R_SUCCESS);
123 }
124 
125 static int
126 BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
127 	int bytes = size - BN_num_bytes(bn);
128 	while (bytes-- > 0)
129 		*buf++ = 0;
130 	BN_bn2bin(bn, buf);
131 	return (size);
132 }
133 
134 static isc_result_t
135 openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
136 	dst_key_t *key = dctx->key;
137 	DSA *dsa = key->keydata.dsa;
138 	isc_region_t r;
139 	DSA_SIG *dsasig;
140 	unsigned int klen;
141 #if USE_EVP
142 	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
143 	EVP_PKEY *pkey;
144 	unsigned char *sigbuf;
145 	const unsigned char *sb;
146 	unsigned int siglen;
147 #else
148 	isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
149 	unsigned char digest[ISC_SHA1_DIGESTLENGTH];
150 #endif
151 
152 	isc_buffer_availableregion(sig, &r);
153 	if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1)
154 		return (ISC_R_NOSPACE);
155 
156 #if USE_EVP
157 	pkey = EVP_PKEY_new();
158 	if (pkey == NULL)
159 		return (ISC_R_NOMEMORY);
160 	if (!EVP_PKEY_set1_DSA(pkey, dsa)) {
161 		EVP_PKEY_free(pkey);
162 		return (ISC_R_FAILURE);
163 	}
164 	sigbuf = malloc(EVP_PKEY_size(pkey));
165 	if (sigbuf == NULL) {
166 		EVP_PKEY_free(pkey);
167 		return (ISC_R_NOMEMORY);
168 	}
169 	if (!EVP_SignFinal(evp_md_ctx, sigbuf, &siglen, pkey)) {
170 		EVP_PKEY_free(pkey);
171 		free(sigbuf);
172 		return (dst__openssl_toresult3(dctx->category,
173 					       "EVP_SignFinal",
174 					       ISC_R_FAILURE));
175 	}
176 	INSIST(EVP_PKEY_size(pkey) >= (int) siglen);
177 	EVP_PKEY_free(pkey);
178 	/* Convert from Dss-Sig-Value (RFC2459). */
179 	dsasig = DSA_SIG_new();
180 	if (dsasig == NULL) {
181 		free(sigbuf);
182 		return (ISC_R_NOMEMORY);
183 	}
184 	sb = sigbuf;
185 	if (d2i_DSA_SIG(&dsasig, &sb, (long) siglen) == NULL) {
186 		free(sigbuf);
187 		return (dst__openssl_toresult3(dctx->category,
188 					       "d2i_DSA_SIG",
189 					       ISC_R_FAILURE));
190 	}
191 	free(sigbuf);
192 
193 #elif 0
194 	/* Only use EVP for the Digest */
195 	if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &siglen)) {
196 		return (dst__openssl_toresult3(dctx->category,
197 					       "EVP_DigestFinal_ex",
198 					       ISC_R_FAILURE));
199 	}
200 	dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa);
201 	if (dsasig == NULL)
202 		return (dst__openssl_toresult3(dctx->category,
203 					       "DSA_do_sign",
204 					       DST_R_SIGNFAILURE));
205 #else
206 	isc_sha1_final(sha1ctx, digest);
207 
208 	dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa);
209 	if (dsasig == NULL)
210 		return (dst__openssl_toresult3(dctx->category,
211 					       "DSA_do_sign",
212 					       DST_R_SIGNFAILURE));
213 #endif
214 
215 	klen = (key->key_size - 512)/64;
216 	if (klen > 255)
217 		return (ISC_R_FAILURE);
218 	*r.base = klen;
219 	isc_region_consume(&r, 1);
220 
221 	BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH);
222 	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
223 	BN_bn2bin_fixed(dsasig->s, r.base, ISC_SHA1_DIGESTLENGTH);
224 	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
225 	DSA_SIG_free(dsasig);
226 	isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1);
227 
228 	return (ISC_R_SUCCESS);
229 }
230 
231 static isc_result_t
232 openssldsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
233 	dst_key_t *key = dctx->key;
234 	DSA *dsa = key->keydata.dsa;
235 	int status = 0;
236 	unsigned char *cp = sig->base;
237 	DSA_SIG *dsasig;
238 #if USE_EVP
239 	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
240 #if 0
241 	EVP_PKEY *pkey;
242 	unsigned char *sigbuf;
243 #endif
244 	unsigned int siglen;
245 #else
246 	isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
247 #endif
248 	unsigned char digest[ISC_SHA1_DIGESTLENGTH];
249 
250 
251 #if USE_EVP
252 #if 1
253 	/* Only use EVP for the digest */
254 	if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &siglen)) {
255 		return (ISC_R_FAILURE);
256 	}
257 #endif
258 #else
259 	isc_sha1_final(sha1ctx, digest);
260 #endif
261 
262 	if (sig->length != 2 * ISC_SHA1_DIGESTLENGTH + 1) {
263 		return (DST_R_VERIFYFAILURE);
264 	}
265 
266 	cp++;	/*%< Skip T */
267 	dsasig = DSA_SIG_new();
268 	if (dsasig == NULL)
269 		return (ISC_R_NOMEMORY);
270 	dsasig->r = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL);
271 	cp += ISC_SHA1_DIGESTLENGTH;
272 	dsasig->s = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL);
273 
274 #if 0
275 	pkey = EVP_PKEY_new();
276 	if (pkey == NULL)
277 		return (ISC_R_NOMEMORY);
278 	if (!EVP_PKEY_set1_DSA(pkey, dsa)) {
279 		EVP_PKEY_free(pkey);
280 		return (ISC_R_FAILURE);
281 	}
282 	/* Convert to Dss-Sig-Value (RFC2459). */
283 	sigbuf = malloc(EVP_PKEY_size(pkey) + 50);
284 	if (sigbuf == NULL) {
285 		EVP_PKEY_free(pkey);
286 		return (ISC_R_NOMEMORY);
287 	}
288 	siglen = (unsigned) i2d_DSA_SIG(dsasig, &sigbuf);
289 	INSIST(EVP_PKEY_size(pkey) >= (int) siglen);
290 	status = EVP_VerifyFinal(evp_md_ctx, sigbuf, siglen, pkey);
291 	EVP_PKEY_free(pkey);
292 	free(sigbuf);
293 #else
294 	status = DSA_do_verify(digest, ISC_SHA1_DIGESTLENGTH, dsasig, dsa);
295 #endif
296 	DSA_SIG_free(dsasig);
297 	switch (status) {
298 	case 1:
299 	return (ISC_R_SUCCESS);
300 	case 0:
301 		return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
302 	default:
303 		return (dst__openssl_toresult3(dctx->category,
304 					       "DSA_do_verify",
305 					       DST_R_VERIFYFAILURE));
306 	}
307 }
308 
309 static isc_boolean_t
310 openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
311 	int status;
312 	DSA *dsa1, *dsa2;
313 
314 	dsa1 = key1->keydata.dsa;
315 	dsa2 = key2->keydata.dsa;
316 
317 	if (dsa1 == NULL && dsa2 == NULL)
318 		return (ISC_TRUE);
319 	else if (dsa1 == NULL || dsa2 == NULL)
320 		return (ISC_FALSE);
321 
322 	status = BN_cmp(dsa1->p, dsa2->p) ||
323 		 BN_cmp(dsa1->q, dsa2->q) ||
324 		 BN_cmp(dsa1->g, dsa2->g) ||
325 		 BN_cmp(dsa1->pub_key, dsa2->pub_key);
326 
327 	if (status != 0)
328 		return (ISC_FALSE);
329 
330 	if (dsa1->priv_key != NULL || dsa2->priv_key != NULL) {
331 		if (dsa1->priv_key == NULL || dsa2->priv_key == NULL)
332 			return (ISC_FALSE);
333 		if (BN_cmp(dsa1->priv_key, dsa2->priv_key))
334 			return (ISC_FALSE);
335 	}
336 	return (ISC_TRUE);
337 }
338 
339 #if OPENSSL_VERSION_NUMBER > 0x00908000L
340 static int
341 progress_cb(int p, int n, BN_GENCB *cb)
342 {
343 	union {
344 		void *dptr;
345 		void (*fptr)(int);
346 	} u;
347 
348 	UNUSED(n);
349 
350 	u.dptr = cb->arg;
351 	if (u.fptr != NULL)
352 		u.fptr(p);
353 	return (1);
354 }
355 #endif
356 
357 static isc_result_t
358 openssldsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
359 	DSA *dsa;
360 	unsigned char rand_array[ISC_SHA1_DIGESTLENGTH];
361 	isc_result_t result;
362 #if OPENSSL_VERSION_NUMBER > 0x00908000L
363 	BN_GENCB cb;
364 	union {
365 		void *dptr;
366 		void (*fptr)(int);
367 	} u;
368 
369 #else
370 
371 	UNUSED(callback);
372 #endif
373 	UNUSED(unused);
374 
375 	result = dst__entropy_getdata(rand_array, sizeof(rand_array),
376 				      ISC_FALSE);
377 	if (result != ISC_R_SUCCESS)
378 		return (result);
379 
380 #if OPENSSL_VERSION_NUMBER > 0x00908000L
381 	dsa = DSA_new();
382 	if (dsa == NULL)
383 		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
384 
385 	if (callback == NULL) {
386 		BN_GENCB_set_old(&cb, NULL, NULL);
387 	} else {
388 		u.fptr = callback;
389 		BN_GENCB_set(&cb, &progress_cb, u.dptr);
390 	}
391 
392 	if (!DSA_generate_parameters_ex(dsa, key->key_size, rand_array,
393 					ISC_SHA1_DIGESTLENGTH,  NULL, NULL,
394 					&cb))
395 	{
396 		DSA_free(dsa);
397 		return (dst__openssl_toresult2("DSA_generate_parameters_ex",
398 					       DST_R_OPENSSLFAILURE));
399 	}
400 #else
401 	dsa = DSA_generate_parameters(key->key_size, rand_array,
402 				      ISC_SHA1_DIGESTLENGTH, NULL, NULL,
403 				      NULL, NULL);
404 	if (dsa == NULL)
405 		return (dst__openssl_toresult2("DSA_generate_parameters",
406 					       DST_R_OPENSSLFAILURE));
407 #endif
408 
409 	if (DSA_generate_key(dsa) == 0) {
410 		DSA_free(dsa);
411 		return (dst__openssl_toresult2("DSA_generate_key",
412 					       DST_R_OPENSSLFAILURE));
413 	}
414 	dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
415 
416 	key->keydata.dsa = dsa;
417 
418 	return (ISC_R_SUCCESS);
419 }
420 
421 static isc_boolean_t
422 openssldsa_isprivate(const dst_key_t *key) {
423 	DSA *dsa = key->keydata.dsa;
424 	return (ISC_TF(dsa != NULL && dsa->priv_key != NULL));
425 }
426 
427 static void
428 openssldsa_destroy(dst_key_t *key) {
429 	DSA *dsa = key->keydata.dsa;
430 	DSA_free(dsa);
431 	key->keydata.dsa = NULL;
432 }
433 
434 
435 static isc_result_t
436 openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) {
437 	DSA *dsa;
438 	isc_region_t r;
439 	int dnslen;
440 	unsigned int t, p_bytes;
441 
442 	REQUIRE(key->keydata.dsa != NULL);
443 
444 	dsa = key->keydata.dsa;
445 
446 	isc_buffer_availableregion(data, &r);
447 
448 	t = (BN_num_bytes(dsa->p) - 64) / 8;
449 	if (t > 8)
450 		return (DST_R_INVALIDPUBLICKEY);
451 	p_bytes = 64 + 8 * t;
452 
453 	dnslen = 1 + (key->key_size * 3)/8 + ISC_SHA1_DIGESTLENGTH;
454 	if (r.length < (unsigned int) dnslen)
455 		return (ISC_R_NOSPACE);
456 
457 	*r.base = t;
458 	isc_region_consume(&r, 1);
459 	BN_bn2bin_fixed(dsa->q, r.base, ISC_SHA1_DIGESTLENGTH);
460 	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
461 	BN_bn2bin_fixed(dsa->p, r.base, key->key_size/8);
462 	isc_region_consume(&r, p_bytes);
463 	BN_bn2bin_fixed(dsa->g, r.base, key->key_size/8);
464 	isc_region_consume(&r, p_bytes);
465 	BN_bn2bin_fixed(dsa->pub_key, r.base, key->key_size/8);
466 	isc_region_consume(&r, p_bytes);
467 
468 	isc_buffer_add(data, dnslen);
469 
470 	return (ISC_R_SUCCESS);
471 }
472 
473 static isc_result_t
474 openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
475 	DSA *dsa;
476 	isc_region_t r;
477 	unsigned int t, p_bytes;
478 	isc_mem_t *mctx = key->mctx;
479 
480 	UNUSED(mctx);
481 
482 	isc_buffer_remainingregion(data, &r);
483 	if (r.length == 0)
484 		return (ISC_R_SUCCESS);
485 
486 	dsa = DSA_new();
487 	if (dsa == NULL)
488 		return (ISC_R_NOMEMORY);
489 	dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
490 
491 	t = (unsigned int) *r.base;
492 	isc_region_consume(&r, 1);
493 	if (t > 8) {
494 		DSA_free(dsa);
495 		return (DST_R_INVALIDPUBLICKEY);
496 	}
497 	p_bytes = 64 + 8 * t;
498 
499 	if (r.length < ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
500 		DSA_free(dsa);
501 		return (DST_R_INVALIDPUBLICKEY);
502 	}
503 
504 	dsa->q = BN_bin2bn(r.base, ISC_SHA1_DIGESTLENGTH, NULL);
505 	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
506 
507 	dsa->p = BN_bin2bn(r.base, p_bytes, NULL);
508 	isc_region_consume(&r, p_bytes);
509 
510 	dsa->g = BN_bin2bn(r.base, p_bytes, NULL);
511 	isc_region_consume(&r, p_bytes);
512 
513 	dsa->pub_key = BN_bin2bn(r.base, p_bytes, NULL);
514 	isc_region_consume(&r, p_bytes);
515 
516 	key->key_size = p_bytes * 8;
517 
518 	isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes);
519 
520 	key->keydata.dsa = dsa;
521 
522 	return (ISC_R_SUCCESS);
523 }
524 
525 
526 static isc_result_t
527 openssldsa_tofile(const dst_key_t *key, const char *directory) {
528 	int cnt = 0;
529 	DSA *dsa;
530 	dst_private_t priv;
531 	unsigned char bufs[5][128];
532 
533 	if (key->keydata.dsa == NULL)
534 		return (DST_R_NULLKEY);
535 
536 	if (key->external) {
537 		priv.nelements = 0;
538 		return (dst__privstruct_writefile(key, &priv, directory));
539 	}
540 
541 	dsa = key->keydata.dsa;
542 
543 	priv.elements[cnt].tag = TAG_DSA_PRIME;
544 	priv.elements[cnt].length = BN_num_bytes(dsa->p);
545 	BN_bn2bin(dsa->p, bufs[cnt]);
546 	priv.elements[cnt].data = bufs[cnt];
547 	cnt++;
548 
549 	priv.elements[cnt].tag = TAG_DSA_SUBPRIME;
550 	priv.elements[cnt].length = BN_num_bytes(dsa->q);
551 	BN_bn2bin(dsa->q, bufs[cnt]);
552 	priv.elements[cnt].data = bufs[cnt];
553 	cnt++;
554 
555 	priv.elements[cnt].tag = TAG_DSA_BASE;
556 	priv.elements[cnt].length = BN_num_bytes(dsa->g);
557 	BN_bn2bin(dsa->g, bufs[cnt]);
558 	priv.elements[cnt].data = bufs[cnt];
559 	cnt++;
560 
561 	priv.elements[cnt].tag = TAG_DSA_PRIVATE;
562 	priv.elements[cnt].length = BN_num_bytes(dsa->priv_key);
563 	BN_bn2bin(dsa->priv_key, bufs[cnt]);
564 	priv.elements[cnt].data = bufs[cnt];
565 	cnt++;
566 
567 	priv.elements[cnt].tag = TAG_DSA_PUBLIC;
568 	priv.elements[cnt].length = BN_num_bytes(dsa->pub_key);
569 	BN_bn2bin(dsa->pub_key, bufs[cnt]);
570 	priv.elements[cnt].data = bufs[cnt];
571 	cnt++;
572 
573 	priv.nelements = cnt;
574 	return (dst__privstruct_writefile(key, &priv, directory));
575 }
576 
577 static isc_result_t
578 openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
579 	dst_private_t priv;
580 	isc_result_t ret;
581 	int i;
582 	DSA *dsa = NULL;
583 	isc_mem_t *mctx = key->mctx;
584 #define DST_RET(a) {ret = a; goto err;}
585 
586 	/* read private key file */
587 	ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
588 	if (ret != ISC_R_SUCCESS)
589 		return (ret);
590 
591 	if (key->external) {
592 		if (priv.nelements != 0)
593 			DST_RET(DST_R_INVALIDPRIVATEKEY);
594 		if (pub == NULL)
595 			DST_RET(DST_R_INVALIDPRIVATEKEY);
596 		key->keydata.pkey = pub->keydata.pkey;
597 		pub->keydata.pkey = NULL;
598 		key->key_size = pub->key_size;
599 		dst__privstruct_free(&priv, mctx);
600 		memset(&priv, 0, sizeof(priv));
601 		return (ISC_R_SUCCESS);
602 	}
603 
604 	dsa = DSA_new();
605 	if (dsa == NULL)
606 		DST_RET(ISC_R_NOMEMORY);
607 	dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
608 	key->keydata.dsa = dsa;
609 
610 	for (i = 0; i < priv.nelements; i++) {
611 		BIGNUM *bn;
612 		bn = BN_bin2bn(priv.elements[i].data,
613 			       priv.elements[i].length, NULL);
614 		if (bn == NULL)
615 			DST_RET(ISC_R_NOMEMORY);
616 
617 		switch (priv.elements[i].tag) {
618 			case TAG_DSA_PRIME:
619 				dsa->p = bn;
620 				break;
621 			case TAG_DSA_SUBPRIME:
622 				dsa->q = bn;
623 				break;
624 			case TAG_DSA_BASE:
625 				dsa->g = bn;
626 				break;
627 			case TAG_DSA_PRIVATE:
628 				dsa->priv_key = bn;
629 				break;
630 			case TAG_DSA_PUBLIC:
631 				dsa->pub_key = bn;
632 				break;
633 		}
634 	}
635 	dst__privstruct_free(&priv, mctx);
636 	memset(&priv, 0, sizeof(priv));
637 	key->key_size = BN_num_bits(dsa->p);
638 	return (ISC_R_SUCCESS);
639 
640  err:
641 	openssldsa_destroy(key);
642 	dst__privstruct_free(&priv, mctx);
643 	memset(&priv, 0, sizeof(priv));
644 	return (ret);
645 }
646 
647 static dst_func_t openssldsa_functions = {
648 	openssldsa_createctx,
649 	NULL, /*%< createctx2 */
650 	openssldsa_destroyctx,
651 	openssldsa_adddata,
652 	openssldsa_sign,
653 	openssldsa_verify,
654 	NULL, /*%< verify2 */
655 	NULL, /*%< computesecret */
656 	openssldsa_compare,
657 	NULL, /*%< paramcompare */
658 	openssldsa_generate,
659 	openssldsa_isprivate,
660 	openssldsa_destroy,
661 	openssldsa_todns,
662 	openssldsa_fromdns,
663 	openssldsa_tofile,
664 	openssldsa_parse,
665 	NULL, /*%< cleanup */
666 	NULL, /*%< fromlabel */
667 	NULL, /*%< dump */
668 	NULL, /*%< restore */
669 };
670 
671 isc_result_t
672 dst__openssldsa_init(dst_func_t **funcp) {
673 	REQUIRE(funcp != NULL);
674 	if (*funcp == NULL)
675 		*funcp = &openssldsa_functions;
676 	return (ISC_R_SUCCESS);
677 }
678 
679 #else /* OPENSSL */
680 
681 #include <isc/util.h>
682 
683 EMPTY_TRANSLATION_UNIT
684 
685 #endif /* OPENSSL */
686 /*! \file */
687