1/*
2 * Copyright (C) 2012-2014  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <config.h>
18
19#ifdef HAVE_OPENSSL_ECDSA
20
21#if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
22#error "ECDSA without EVP for SHA2?"
23#endif
24
25#include <isc/entropy.h>
26#include <isc/mem.h>
27#include <isc/sha2.h>
28#include <isc/string.h>
29#include <isc/util.h>
30
31#include <dns/keyvalues.h>
32#include <dst/result.h>
33
34#include "dst_internal.h"
35#include "dst_openssl.h"
36#include "dst_parse.h"
37
38#include <openssl/err.h>
39#include <openssl/objects.h>
40#include <openssl/ecdsa.h>
41#include <openssl/bn.h>
42
43#ifndef NID_X9_62_prime256v1
44#error "P-256 group is not known (NID_X9_62_prime256v1)"
45#endif
46#ifndef NID_secp384r1
47#error "P-384 group is not known (NID_secp384r1)"
48#endif
49
50#define DST_RET(a) {ret = a; goto err;}
51
52static isc_result_t opensslecdsa_todns(const dst_key_t *key,
53				       isc_buffer_t *data);
54
55static isc_result_t
56opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
57	EVP_MD_CTX *evp_md_ctx;
58	const EVP_MD *type = NULL;
59
60	UNUSED(key);
61	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
62		dctx->key->key_alg == DST_ALG_ECDSA384);
63
64	evp_md_ctx = EVP_MD_CTX_create();
65	if (evp_md_ctx == NULL)
66		return (ISC_R_NOMEMORY);
67	if (dctx->key->key_alg == DST_ALG_ECDSA256)
68		type = EVP_sha256();
69	else
70		type = EVP_sha384();
71
72	if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
73		EVP_MD_CTX_destroy(evp_md_ctx);
74		return (dst__openssl_toresult3(dctx->category,
75					       "EVP_DigestInit_ex",
76					       ISC_R_FAILURE));
77	}
78
79	dctx->ctxdata.evp_md_ctx = evp_md_ctx;
80
81	return (ISC_R_SUCCESS);
82}
83
84static void
85opensslecdsa_destroyctx(dst_context_t *dctx) {
86	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
87
88	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
89		dctx->key->key_alg == DST_ALG_ECDSA384);
90
91	if (evp_md_ctx != NULL) {
92		EVP_MD_CTX_destroy(evp_md_ctx);
93		dctx->ctxdata.evp_md_ctx = NULL;
94	}
95}
96
97static isc_result_t
98opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
99	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
100
101	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
102		dctx->key->key_alg == DST_ALG_ECDSA384);
103
104	if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
105		return (dst__openssl_toresult3(dctx->category,
106					       "EVP_DigestUpdate",
107					       ISC_R_FAILURE));
108
109	return (ISC_R_SUCCESS);
110}
111
112static int
113BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
114	int bytes = size - BN_num_bytes(bn);
115
116	while (bytes-- > 0)
117		*buf++ = 0;
118	BN_bn2bin(bn, buf);
119	return (size);
120}
121
122static isc_result_t
123opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
124	isc_result_t ret;
125	dst_key_t *key = dctx->key;
126	isc_region_t r;
127	ECDSA_SIG *ecdsasig;
128	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
129	EVP_PKEY *pkey = key->keydata.pkey;
130	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
131	unsigned int dgstlen, siglen;
132	unsigned char digest[EVP_MAX_MD_SIZE];
133
134	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
135		key->key_alg == DST_ALG_ECDSA384);
136
137	if (eckey == NULL)
138		return (ISC_R_FAILURE);
139
140	if (key->key_alg == DST_ALG_ECDSA256)
141		siglen = DNS_SIG_ECDSA256SIZE;
142	else
143		siglen = DNS_SIG_ECDSA384SIZE;
144
145	isc_buffer_availableregion(sig, &r);
146	if (r.length < siglen)
147		DST_RET(ISC_R_NOSPACE);
148
149	if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen))
150		DST_RET(dst__openssl_toresult3(dctx->category,
151					       "EVP_DigestFinal",
152					       ISC_R_FAILURE));
153
154	ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
155	if (ecdsasig == NULL)
156		DST_RET(dst__openssl_toresult3(dctx->category,
157					       "ECDSA_do_sign",
158					       DST_R_SIGNFAILURE));
159	BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
160	isc_region_consume(&r, siglen / 2);
161	BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
162	isc_region_consume(&r, siglen / 2);
163	ECDSA_SIG_free(ecdsasig);
164	isc_buffer_add(sig, siglen);
165	ret = ISC_R_SUCCESS;
166
167 err:
168	if (eckey != NULL)
169		EC_KEY_free(eckey);
170	return (ret);
171}
172
173static isc_result_t
174opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
175	isc_result_t ret;
176	dst_key_t *key = dctx->key;
177	int status;
178	unsigned char *cp = sig->base;
179	ECDSA_SIG *ecdsasig = NULL;
180	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
181	EVP_PKEY *pkey = key->keydata.pkey;
182	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
183	unsigned int dgstlen, siglen;
184	unsigned char digest[EVP_MAX_MD_SIZE];
185
186	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
187		key->key_alg == DST_ALG_ECDSA384);
188
189	if (eckey == NULL)
190		return (ISC_R_FAILURE);
191
192	if (key->key_alg == DST_ALG_ECDSA256)
193		siglen = DNS_SIG_ECDSA256SIZE;
194	else
195		siglen = DNS_SIG_ECDSA384SIZE;
196
197	if (sig->length != siglen)
198		return (DST_R_VERIFYFAILURE);
199
200	if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
201		DST_RET (dst__openssl_toresult3(dctx->category,
202						"EVP_DigestFinal_ex",
203						ISC_R_FAILURE));
204
205	ecdsasig = ECDSA_SIG_new();
206	if (ecdsasig == NULL)
207		DST_RET (ISC_R_NOMEMORY);
208	if (ecdsasig->r != NULL)
209		BN_free(ecdsasig->r);
210	ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
211	cp += siglen / 2;
212	if (ecdsasig->s != NULL)
213		BN_free(ecdsasig->s);
214	ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
215	/* cp += siglen / 2; */
216
217	status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
218	switch (status) {
219	case 1:
220		ret = ISC_R_SUCCESS;
221		break;
222	case 0:
223		ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
224		break;
225	default:
226		ret = dst__openssl_toresult3(dctx->category,
227					     "ECDSA_do_verify",
228					     DST_R_VERIFYFAILURE);
229		break;
230	}
231
232 err:
233	if (ecdsasig != NULL)
234		ECDSA_SIG_free(ecdsasig);
235	if (eckey != NULL)
236		EC_KEY_free(eckey);
237	return (ret);
238}
239
240static isc_boolean_t
241opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
242	isc_boolean_t ret;
243	int status;
244	EVP_PKEY *pkey1 = key1->keydata.pkey;
245	EVP_PKEY *pkey2 = key2->keydata.pkey;
246	EC_KEY *eckey1 = NULL;
247	EC_KEY *eckey2 = NULL;
248	const BIGNUM *priv1, *priv2;
249
250	if (pkey1 == NULL && pkey2 == NULL)
251		return (ISC_TRUE);
252	else if (pkey1 == NULL || pkey2 == NULL)
253		return (ISC_FALSE);
254
255	eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
256	eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
257	if (eckey1 == NULL && eckey2 == NULL) {
258		DST_RET (ISC_TRUE);
259	} else if (eckey1 == NULL || eckey2 == NULL)
260		DST_RET (ISC_FALSE);
261
262	status = EVP_PKEY_cmp(pkey1, pkey2);
263	if (status != 1)
264		DST_RET (ISC_FALSE);
265
266	priv1 = EC_KEY_get0_private_key(eckey1);
267	priv2 = EC_KEY_get0_private_key(eckey2);
268	if (priv1 != NULL || priv2 != NULL) {
269		if (priv1 == NULL || priv2 == NULL)
270			DST_RET (ISC_FALSE);
271		if (BN_cmp(priv1, priv2) != 0)
272			DST_RET (ISC_FALSE);
273	}
274	ret = ISC_TRUE;
275
276 err:
277	if (eckey1 != NULL)
278		EC_KEY_free(eckey1);
279	if (eckey2 != NULL)
280		EC_KEY_free(eckey2);
281	return (ret);
282}
283
284static isc_result_t
285opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
286	isc_result_t ret;
287	EVP_PKEY *pkey;
288	EC_KEY *eckey = NULL;
289	int group_nid;
290
291	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
292		key->key_alg == DST_ALG_ECDSA384);
293	UNUSED(unused);
294	UNUSED(callback);
295
296	if (key->key_alg == DST_ALG_ECDSA256)
297		group_nid = NID_X9_62_prime256v1;
298	else
299		group_nid = NID_secp384r1;
300
301	eckey = EC_KEY_new_by_curve_name(group_nid);
302	if (eckey == NULL)
303		return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
304					       DST_R_OPENSSLFAILURE));
305
306	if (EC_KEY_generate_key(eckey) != 1)
307		DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
308						DST_R_OPENSSLFAILURE));
309
310	pkey = EVP_PKEY_new();
311	if (pkey == NULL)
312		DST_RET (ISC_R_NOMEMORY);
313	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
314		EVP_PKEY_free(pkey);
315		DST_RET (ISC_R_FAILURE);
316	}
317	key->keydata.pkey = pkey;
318	ret = ISC_R_SUCCESS;
319
320 err:
321	if (eckey != NULL)
322		EC_KEY_free(eckey);
323	return (ret);
324}
325
326static isc_boolean_t
327opensslecdsa_isprivate(const dst_key_t *key) {
328	isc_boolean_t ret;
329	EVP_PKEY *pkey = key->keydata.pkey;
330	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
331
332	ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
333	if (eckey != NULL)
334		EC_KEY_free(eckey);
335	return (ret);
336}
337
338static void
339opensslecdsa_destroy(dst_key_t *key) {
340	EVP_PKEY *pkey = key->keydata.pkey;
341
342	EVP_PKEY_free(pkey);
343	key->keydata.pkey = NULL;
344}
345
346static isc_result_t
347opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
348	isc_result_t ret;
349	EVP_PKEY *pkey;
350	EC_KEY *eckey = NULL;
351	isc_region_t r;
352	int len;
353	unsigned char *cp;
354	unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
355
356	REQUIRE(key->keydata.pkey != NULL);
357
358	pkey = key->keydata.pkey;
359	eckey = EVP_PKEY_get1_EC_KEY(pkey);
360	if (eckey == NULL)
361		return (dst__openssl_toresult(ISC_R_FAILURE));
362	len = i2o_ECPublicKey(eckey, NULL);
363	/* skip form */
364	len--;
365
366	isc_buffer_availableregion(data, &r);
367	if (r.length < (unsigned int) len)
368		DST_RET (ISC_R_NOSPACE);
369	cp = buf;
370	if (!i2o_ECPublicKey(eckey, &cp))
371		DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
372	memmove(r.base, buf + 1, len);
373	isc_buffer_add(data, len);
374	ret = ISC_R_SUCCESS;
375
376 err:
377	if (eckey != NULL)
378		EC_KEY_free(eckey);
379	return (ret);
380}
381
382static isc_result_t
383opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
384	isc_result_t ret;
385	EVP_PKEY *pkey;
386	EC_KEY *eckey = NULL;
387	isc_region_t r;
388	int group_nid;
389	unsigned int len;
390	const unsigned char *cp;
391	unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
392
393	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
394		key->key_alg == DST_ALG_ECDSA384);
395
396	if (key->key_alg == DST_ALG_ECDSA256) {
397		len = DNS_KEY_ECDSA256SIZE;
398		group_nid = NID_X9_62_prime256v1;
399	} else {
400		len = DNS_KEY_ECDSA384SIZE;
401		group_nid = NID_secp384r1;
402	}
403
404	isc_buffer_remainingregion(data, &r);
405	if (r.length == 0)
406		return (ISC_R_SUCCESS);
407	if (r.length < len)
408		return (DST_R_INVALIDPUBLICKEY);
409
410	eckey = EC_KEY_new_by_curve_name(group_nid);
411	if (eckey == NULL)
412		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
413
414	buf[0] = POINT_CONVERSION_UNCOMPRESSED;
415	memmove(buf + 1, r.base, len);
416	cp = buf;
417	if (o2i_ECPublicKey(&eckey,
418			    (const unsigned char **) &cp,
419			    (long) len + 1) == NULL)
420		DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
421	if (EC_KEY_check_key(eckey) != 1)
422		DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
423
424	pkey = EVP_PKEY_new();
425	if (pkey == NULL)
426		DST_RET (ISC_R_NOMEMORY);
427	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
428		EVP_PKEY_free(pkey);
429		DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
430	}
431
432	isc_buffer_forward(data, len);
433	key->keydata.pkey = pkey;
434	ret = ISC_R_SUCCESS;
435
436 err:
437	if (eckey != NULL)
438		EC_KEY_free(eckey);
439	return (ret);
440}
441
442static isc_result_t
443opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
444	isc_result_t ret;
445	EVP_PKEY *pkey;
446	EC_KEY *eckey = NULL;
447	const BIGNUM *privkey;
448	dst_private_t priv;
449	unsigned char *buf = NULL;
450
451	if (key->keydata.pkey == NULL)
452		return (DST_R_NULLKEY);
453
454	if (key->external) {
455		priv.nelements = 0;
456		return (dst__privstruct_writefile(key, &priv, directory));
457	}
458
459	pkey = key->keydata.pkey;
460	eckey = EVP_PKEY_get1_EC_KEY(pkey);
461	if (eckey == NULL)
462		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
463	privkey = EC_KEY_get0_private_key(eckey);
464	if (privkey == NULL)
465		DST_RET (ISC_R_FAILURE);
466
467	buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
468	if (buf == NULL)
469		DST_RET (ISC_R_NOMEMORY);
470
471	priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY;
472	priv.elements[0].length = BN_num_bytes(privkey);
473	BN_bn2bin(privkey, buf);
474	priv.elements[0].data = buf;
475	priv.nelements = ECDSA_NTAGS;
476	ret = dst__privstruct_writefile(key, &priv, directory);
477
478 err:
479	if (eckey != NULL)
480		EC_KEY_free(eckey);
481	if (buf != NULL)
482		isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
483	return (ret);
484}
485
486static isc_result_t
487ecdsa_check(EC_KEY *eckey, dst_key_t *pub)
488{
489	isc_result_t ret = ISC_R_FAILURE;
490	EVP_PKEY *pkey;
491	EC_KEY *pubeckey = NULL;
492	const EC_POINT *pubkey;
493
494	if (pub == NULL)
495		return (ISC_R_SUCCESS);
496	pkey = pub->keydata.pkey;
497	if (pkey == NULL)
498		return (ISC_R_SUCCESS);
499	pubeckey = EVP_PKEY_get1_EC_KEY(pkey);
500	if (pubeckey == NULL)
501		return (ISC_R_SUCCESS);
502	pubkey = EC_KEY_get0_public_key(pubeckey);
503	if (pubkey == NULL)
504		DST_RET (ISC_R_SUCCESS);
505	if (EC_KEY_set_public_key(eckey, pubkey) != 1)
506		DST_RET (ISC_R_SUCCESS);
507	if (EC_KEY_check_key(eckey) == 1)
508		DST_RET (ISC_R_SUCCESS);
509
510 err:
511	if (pubeckey != NULL)
512		EC_KEY_free(pubeckey);
513	return (ret);
514}
515
516static isc_result_t
517opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
518	dst_private_t priv;
519	isc_result_t ret;
520	EVP_PKEY *pkey, *pubpkey;
521	EC_KEY *eckey = NULL, *pubeckey = NULL;
522	const EC_POINT *pubkey;
523	BIGNUM *privkey;
524	int group_nid;
525	isc_mem_t *mctx = key->mctx;
526
527	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
528		key->key_alg == DST_ALG_ECDSA384);
529
530	if (key->key_alg == DST_ALG_ECDSA256)
531		group_nid = NID_X9_62_prime256v1;
532	else
533		group_nid = NID_secp384r1;
534
535	eckey = EC_KEY_new_by_curve_name(group_nid);
536	if (eckey == NULL)
537		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
538
539	/* read private key file */
540	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
541	if (ret != ISC_R_SUCCESS)
542		goto err;
543
544	if (key->external) {
545		/*
546		 * Copy the public key to this new key.
547		 */
548		if (pub == NULL)
549			DST_RET(DST_R_INVALIDPRIVATEKEY);
550		pubpkey = pub->keydata.pkey;
551		pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
552		if (pubeckey == NULL)
553			DST_RET(DST_R_INVALIDPRIVATEKEY);
554		pubkey = EC_KEY_get0_public_key(pubeckey);
555		if (pubkey == NULL)
556			DST_RET(DST_R_INVALIDPRIVATEKEY);
557		if (EC_KEY_set_public_key(eckey, pubkey) != 1)
558			DST_RET(DST_R_INVALIDPRIVATEKEY);
559		if (EC_KEY_check_key(eckey) != 1)
560			DST_RET(DST_R_INVALIDPRIVATEKEY);
561	} else {
562		privkey = BN_bin2bn(priv.elements[0].data,
563				    priv.elements[0].length, NULL);
564		if (privkey == NULL)
565			DST_RET(ISC_R_NOMEMORY);
566		if (!EC_KEY_set_private_key(eckey, privkey))
567			DST_RET(ISC_R_NOMEMORY);
568		if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
569			DST_RET(DST_R_INVALIDPRIVATEKEY);
570		dst__privstruct_free(&priv, mctx);
571		memset(&priv, 0, sizeof(priv));
572	}
573
574	pkey = EVP_PKEY_new();
575	if (pkey == NULL)
576		DST_RET (ISC_R_NOMEMORY);
577	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
578		EVP_PKEY_free(pkey);
579		DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
580	}
581	key->keydata.pkey = pkey;
582	ret = ISC_R_SUCCESS;
583
584 err:
585	if (eckey != NULL)
586		EC_KEY_free(eckey);
587	if (pubeckey != NULL)
588		EC_KEY_free(pubeckey);
589	dst__privstruct_free(&priv, mctx);
590	memset(&priv, 0, sizeof(priv));
591	return (ret);
592}
593
594static dst_func_t opensslecdsa_functions = {
595	opensslecdsa_createctx,
596	opensslecdsa_destroyctx,
597	opensslecdsa_adddata,
598	opensslecdsa_sign,
599	opensslecdsa_verify,
600	NULL, /*%< verify2 */
601	NULL, /*%< computesecret */
602	opensslecdsa_compare,
603	NULL, /*%< paramcompare */
604	opensslecdsa_generate,
605	opensslecdsa_isprivate,
606	opensslecdsa_destroy,
607	opensslecdsa_todns,
608	opensslecdsa_fromdns,
609	opensslecdsa_tofile,
610	opensslecdsa_parse,
611	NULL, /*%< cleanup */
612	NULL, /*%< fromlabel */
613	NULL, /*%< dump */
614	NULL, /*%< restore */
615};
616
617isc_result_t
618dst__opensslecdsa_init(dst_func_t **funcp) {
619	REQUIRE(funcp != NULL);
620	if (*funcp == NULL)
621		*funcp = &opensslecdsa_functions;
622	return (ISC_R_SUCCESS);
623}
624
625#else /* HAVE_OPENSSL_ECDSA */
626
627#include <isc/util.h>
628
629EMPTY_TRANSLATION_UNIT
630
631#endif /* HAVE_OPENSSL_ECDSA */
632/*! \file */
633