xref: /netbsd-src/external/mpl/bind/dist/lib/dns/openssleddsa_link.c (revision 2718af68c3efc72c9769069b5c7f9ed36f6b9def)
1 /*	$NetBSD: openssleddsa_link.c,v 1.6 2021/02/19 16:42:16 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #if !USE_PKCS11
15 
16 #if HAVE_OPENSSL_ED25519 || HAVE_OPENSSL_ED448
17 
18 #include <stdbool.h>
19 
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/objects.h>
23 #include <openssl/x509.h>
24 #if !defined(OPENSSL_NO_ENGINE)
25 #include <openssl/engine.h>
26 #endif /* if !defined(OPENSSL_NO_ENGINE) */
27 
28 #include <isc/mem.h>
29 #include <isc/result.h>
30 #include <isc/safe.h>
31 #include <isc/string.h>
32 #include <isc/util.h>
33 
34 #include <dns/keyvalues.h>
35 
36 #include <dst/result.h>
37 
38 #include "dst_internal.h"
39 #include "dst_openssl.h"
40 #include "dst_parse.h"
41 #include "openssl_shim.h"
42 
43 #define DST_RET(a)        \
44 	{                 \
45 		ret = a;  \
46 		goto err; \
47 	}
48 
49 #if HAVE_OPENSSL_ED25519
50 #ifndef NID_ED25519
51 #error "Ed25519 group is not known (NID_ED25519)"
52 #endif /* ifndef NID_ED25519 */
53 #endif /* HAVE_OPENSSL_ED25519 */
54 
55 #if HAVE_OPENSSL_ED448
56 #ifndef NID_ED448
57 #error "Ed448 group is not known (NID_ED448)"
58 #endif /* ifndef NID_ED448 */
59 #endif /* HAVE_OPENSSL_ED448 */
60 
61 static isc_result_t
62 raw_key_to_ossl(unsigned int key_alg, int private, const unsigned char *key,
63 		size_t *key_len, EVP_PKEY **pkey) {
64 	isc_result_t ret;
65 	int pkey_type = EVP_PKEY_NONE;
66 	size_t len = 0;
67 
68 #if HAVE_OPENSSL_ED25519
69 	if (key_alg == DST_ALG_ED25519) {
70 		pkey_type = EVP_PKEY_ED25519;
71 		len = DNS_KEY_ED25519SIZE;
72 	}
73 #endif /* HAVE_OPENSSL_ED25519 */
74 #if HAVE_OPENSSL_ED448
75 	if (key_alg == DST_ALG_ED448) {
76 		pkey_type = EVP_PKEY_ED448;
77 		len = DNS_KEY_ED448SIZE;
78 	}
79 #endif /* HAVE_OPENSSL_ED448 */
80 	if (pkey_type == EVP_PKEY_NONE) {
81 		return (ISC_R_NOTIMPLEMENTED);
82 	}
83 
84 	ret = (private ? DST_R_INVALIDPRIVATEKEY : DST_R_INVALIDPUBLICKEY);
85 	if (*key_len < len) {
86 		return (ret);
87 	}
88 
89 	if (private) {
90 		*pkey = EVP_PKEY_new_raw_private_key(pkey_type, NULL, key, len);
91 	} else {
92 		*pkey = EVP_PKEY_new_raw_public_key(pkey_type, NULL, key, len);
93 	}
94 	if (*pkey == NULL) {
95 		return (dst__openssl_toresult(ret));
96 	}
97 
98 	*key_len = len;
99 	return (ISC_R_SUCCESS);
100 }
101 
102 static isc_result_t
103 openssleddsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
104 		       const char *pin);
105 
106 static isc_result_t
107 openssleddsa_createctx(dst_key_t *key, dst_context_t *dctx) {
108 	isc_buffer_t *buf = NULL;
109 
110 	UNUSED(key);
111 	REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
112 		dctx->key->key_alg == DST_ALG_ED448);
113 
114 	isc_buffer_allocate(dctx->mctx, &buf, 64);
115 	dctx->ctxdata.generic = buf;
116 
117 	return (ISC_R_SUCCESS);
118 }
119 
120 static void
121 openssleddsa_destroyctx(dst_context_t *dctx) {
122 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
123 
124 	REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
125 		dctx->key->key_alg == DST_ALG_ED448);
126 	if (buf != NULL) {
127 		isc_buffer_free(&buf);
128 	}
129 	dctx->ctxdata.generic = NULL;
130 }
131 
132 static isc_result_t
133 openssleddsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
134 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
135 	isc_buffer_t *nbuf = NULL;
136 	isc_region_t r;
137 	unsigned int length;
138 	isc_result_t result;
139 
140 	REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 ||
141 		dctx->key->key_alg == DST_ALG_ED448);
142 
143 	result = isc_buffer_copyregion(buf, data);
144 	if (result == ISC_R_SUCCESS) {
145 		return (ISC_R_SUCCESS);
146 	}
147 
148 	length = isc_buffer_length(buf) + data->length + 64;
149 	isc_buffer_allocate(dctx->mctx, &nbuf, length);
150 	isc_buffer_usedregion(buf, &r);
151 	(void)isc_buffer_copyregion(nbuf, &r);
152 	(void)isc_buffer_copyregion(nbuf, data);
153 	isc_buffer_free(&buf);
154 	dctx->ctxdata.generic = nbuf;
155 
156 	return (ISC_R_SUCCESS);
157 }
158 
159 static isc_result_t
160 openssleddsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
161 	isc_result_t ret;
162 	dst_key_t *key = dctx->key;
163 	isc_region_t tbsreg;
164 	isc_region_t sigreg;
165 	EVP_PKEY *pkey = key->keydata.pkey;
166 	EVP_MD_CTX *ctx = EVP_MD_CTX_new();
167 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
168 	size_t siglen;
169 
170 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
171 		key->key_alg == DST_ALG_ED448);
172 
173 	if (ctx == NULL) {
174 		return (ISC_R_NOMEMORY);
175 	}
176 
177 	if (key->key_alg == DST_ALG_ED25519) {
178 		siglen = DNS_SIG_ED25519SIZE;
179 	} else {
180 		siglen = DNS_SIG_ED448SIZE;
181 	}
182 
183 	isc_buffer_availableregion(sig, &sigreg);
184 	if (sigreg.length < (unsigned int)siglen) {
185 		DST_RET(ISC_R_NOSPACE);
186 	}
187 
188 	isc_buffer_usedregion(buf, &tbsreg);
189 
190 	if (EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey) != 1) {
191 		DST_RET(dst__openssl_toresult3(
192 			dctx->category, "EVP_DigestSignInit", ISC_R_FAILURE));
193 	}
194 	if (EVP_DigestSign(ctx, sigreg.base, &siglen, tbsreg.base,
195 			   tbsreg.length) != 1) {
196 		DST_RET(dst__openssl_toresult3(dctx->category, "EVP_DigestSign",
197 					       DST_R_SIGNFAILURE));
198 	}
199 	isc_buffer_add(sig, (unsigned int)siglen);
200 	ret = ISC_R_SUCCESS;
201 
202 err:
203 	EVP_MD_CTX_free(ctx);
204 	isc_buffer_free(&buf);
205 	dctx->ctxdata.generic = NULL;
206 
207 	return (ret);
208 }
209 
210 static isc_result_t
211 openssleddsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
212 	isc_result_t ret;
213 	dst_key_t *key = dctx->key;
214 	int status;
215 	isc_region_t tbsreg;
216 	EVP_PKEY *pkey = key->keydata.pkey;
217 	EVP_MD_CTX *ctx = EVP_MD_CTX_new();
218 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
219 	unsigned int siglen = 0;
220 
221 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
222 		key->key_alg == DST_ALG_ED448);
223 
224 	if (ctx == NULL) {
225 		return (ISC_R_NOMEMORY);
226 	}
227 
228 #if HAVE_OPENSSL_ED25519
229 	if (key->key_alg == DST_ALG_ED25519) {
230 		siglen = DNS_SIG_ED25519SIZE;
231 	}
232 #endif /* if HAVE_OPENSSL_ED25519 */
233 #if HAVE_OPENSSL_ED448
234 	if (key->key_alg == DST_ALG_ED448) {
235 		siglen = DNS_SIG_ED448SIZE;
236 	}
237 #endif /* if HAVE_OPENSSL_ED448 */
238 	if (siglen == 0) {
239 		return (ISC_R_NOTIMPLEMENTED);
240 	}
241 
242 	if (sig->length != siglen) {
243 		return (DST_R_VERIFYFAILURE);
244 	}
245 
246 	isc_buffer_usedregion(buf, &tbsreg);
247 
248 	if (EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey) != 1) {
249 		DST_RET(dst__openssl_toresult3(
250 			dctx->category, "EVP_DigestVerifyInit", ISC_R_FAILURE));
251 	}
252 
253 	status = EVP_DigestVerify(ctx, sig->base, siglen, tbsreg.base,
254 				  tbsreg.length);
255 
256 	switch (status) {
257 	case 1:
258 		ret = ISC_R_SUCCESS;
259 		break;
260 	case 0:
261 		ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
262 		break;
263 	default:
264 		ret = dst__openssl_toresult3(dctx->category, "EVP_DigestVerify",
265 					     DST_R_VERIFYFAILURE);
266 		break;
267 	}
268 
269 err:
270 	EVP_MD_CTX_free(ctx);
271 	isc_buffer_free(&buf);
272 	dctx->ctxdata.generic = NULL;
273 
274 	return (ret);
275 }
276 
277 static bool
278 openssleddsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
279 	int status;
280 	EVP_PKEY *pkey1 = key1->keydata.pkey;
281 	EVP_PKEY *pkey2 = key2->keydata.pkey;
282 
283 	if (pkey1 == NULL && pkey2 == NULL) {
284 		return (true);
285 	} else if (pkey1 == NULL || pkey2 == NULL) {
286 		return (false);
287 	}
288 
289 	status = EVP_PKEY_cmp(pkey1, pkey2);
290 	if (status == 1) {
291 		return (true);
292 	}
293 	return (false);
294 }
295 
296 static isc_result_t
297 openssleddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
298 	isc_result_t ret;
299 	EVP_PKEY *pkey = NULL;
300 	EVP_PKEY_CTX *ctx = NULL;
301 	int nid = 0, status;
302 
303 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
304 		key->key_alg == DST_ALG_ED448);
305 	UNUSED(unused);
306 	UNUSED(callback);
307 
308 #if HAVE_OPENSSL_ED25519
309 	if (key->key_alg == DST_ALG_ED25519) {
310 		nid = NID_ED25519;
311 		key->key_size = DNS_KEY_ED25519SIZE * 8;
312 	}
313 #endif /* if HAVE_OPENSSL_ED25519 */
314 #if HAVE_OPENSSL_ED448
315 	if (key->key_alg == DST_ALG_ED448) {
316 		nid = NID_ED448;
317 		key->key_size = DNS_KEY_ED448SIZE * 8;
318 	}
319 #endif /* if HAVE_OPENSSL_ED448 */
320 	if (nid == 0) {
321 		return (ISC_R_NOTIMPLEMENTED);
322 	}
323 
324 	ctx = EVP_PKEY_CTX_new_id(nid, NULL);
325 	if (ctx == NULL) {
326 		return (dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
327 					       DST_R_OPENSSLFAILURE));
328 	}
329 
330 	status = EVP_PKEY_keygen_init(ctx);
331 	if (status != 1) {
332 		DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
333 					       DST_R_OPENSSLFAILURE));
334 	}
335 
336 	status = EVP_PKEY_keygen(ctx, &pkey);
337 	if (status != 1) {
338 		DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
339 					       DST_R_OPENSSLFAILURE));
340 	}
341 
342 	key->keydata.pkey = pkey;
343 	ret = ISC_R_SUCCESS;
344 
345 err:
346 	EVP_PKEY_CTX_free(ctx);
347 	return (ret);
348 }
349 
350 static bool
351 openssleddsa_isprivate(const dst_key_t *key) {
352 	EVP_PKEY *pkey = key->keydata.pkey;
353 	size_t len;
354 
355 	if (pkey == NULL) {
356 		return (false);
357 	}
358 
359 	if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) == 1 && len > 0) {
360 		return (true);
361 	}
362 	/* can check if first error is EC_R_INVALID_PRIVATE_KEY */
363 	while (ERR_get_error() != 0) {
364 		/**/
365 	}
366 
367 	return (false);
368 }
369 
370 static void
371 openssleddsa_destroy(dst_key_t *key) {
372 	EVP_PKEY *pkey = key->keydata.pkey;
373 
374 	EVP_PKEY_free(pkey);
375 	key->keydata.pkey = NULL;
376 }
377 
378 static isc_result_t
379 openssleddsa_todns(const dst_key_t *key, isc_buffer_t *data) {
380 	EVP_PKEY *pkey = key->keydata.pkey;
381 	isc_region_t r;
382 	size_t len;
383 
384 	REQUIRE(pkey != NULL);
385 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
386 		key->key_alg == DST_ALG_ED448);
387 
388 	if (key->key_alg == DST_ALG_ED25519) {
389 		len = DNS_KEY_ED25519SIZE;
390 	} else {
391 		len = DNS_KEY_ED448SIZE;
392 	}
393 
394 	isc_buffer_availableregion(data, &r);
395 	if (r.length < len) {
396 		return (ISC_R_NOSPACE);
397 	}
398 
399 	if (EVP_PKEY_get_raw_public_key(pkey, r.base, &len) != 1)
400 		return (dst__openssl_toresult(ISC_R_FAILURE));
401 
402 	isc_buffer_add(data, len);
403 	return (ISC_R_SUCCESS);
404 }
405 
406 static isc_result_t
407 openssleddsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
408 	isc_result_t ret;
409 	isc_region_t r;
410 	size_t len;
411 	EVP_PKEY *pkey;
412 
413 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
414 		key->key_alg == DST_ALG_ED448);
415 
416 	isc_buffer_remainingregion(data, &r);
417 	if (r.length == 0) {
418 		return (ISC_R_SUCCESS);
419 	}
420 
421 	len = r.length;
422 	ret = raw_key_to_ossl(key->key_alg, 0, r.base, &len, &pkey);
423 	if (ret != ISC_R_SUCCESS)
424 		return ret;
425 
426 	isc_buffer_forward(data, len);
427 	key->keydata.pkey = pkey;
428 	key->key_size = len * 8;
429 	return (ISC_R_SUCCESS);
430 }
431 
432 static isc_result_t
433 openssleddsa_tofile(const dst_key_t *key, const char *directory) {
434 	isc_result_t ret;
435 	dst_private_t priv;
436 	unsigned char *buf = NULL;
437 	size_t len;
438 	int i;
439 
440 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
441 		key->key_alg == DST_ALG_ED448);
442 
443 	if (key->keydata.pkey == NULL) {
444 		return (DST_R_NULLKEY);
445 	}
446 
447 	if (key->external) {
448 		priv.nelements = 0;
449 		return (dst__privstruct_writefile(key, &priv, directory));
450 	}
451 
452 	i = 0;
453 
454 	if (openssleddsa_isprivate(key)) {
455 		if (key->key_alg == DST_ALG_ED25519) {
456 			len = DNS_KEY_ED25519SIZE;
457 		} else {
458 			len = DNS_KEY_ED448SIZE;
459 		}
460 		buf = isc_mem_get(key->mctx, len);
461 		if (EVP_PKEY_get_raw_private_key(key->keydata.pkey, buf,
462 						 &len) != 1)
463 			DST_RET(dst__openssl_toresult(ISC_R_FAILURE));
464 		priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY;
465 		priv.elements[i].length = len;
466 		priv.elements[i].data = buf;
467 		i++;
468 	}
469 	if (key->engine != NULL) {
470 		priv.elements[i].tag = TAG_EDDSA_ENGINE;
471 		priv.elements[i].length = (unsigned short)strlen(key->engine) +
472 					  1;
473 		priv.elements[i].data = (unsigned char *)key->engine;
474 		i++;
475 	}
476 	if (key->label != NULL) {
477 		priv.elements[i].tag = TAG_EDDSA_LABEL;
478 		priv.elements[i].length = (unsigned short)strlen(key->label) +
479 					  1;
480 		priv.elements[i].data = (unsigned char *)key->label;
481 		i++;
482 	}
483 
484 	priv.nelements = i;
485 	ret = dst__privstruct_writefile(key, &priv, directory);
486 
487 err:
488 	if (buf != NULL) {
489 		isc_mem_put(key->mctx, buf, len);
490 	}
491 	return (ret);
492 }
493 
494 static isc_result_t
495 eddsa_check(EVP_PKEY *pkey, EVP_PKEY *pubpkey) {
496 	if (pubpkey == NULL) {
497 		return (ISC_R_SUCCESS);
498 	}
499 	if (EVP_PKEY_cmp(pkey, pubpkey) == 1) {
500 		return (ISC_R_SUCCESS);
501 	}
502 	return (ISC_R_FAILURE);
503 }
504 
505 static isc_result_t
506 openssleddsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
507 	dst_private_t priv;
508 	isc_result_t ret;
509 	int i, privkey_index = -1;
510 	const char *engine = NULL, *label = NULL;
511 	EVP_PKEY *pkey = NULL, *pubpkey = NULL;
512 	size_t len;
513 	isc_mem_t *mctx = key->mctx;
514 
515 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
516 		key->key_alg == DST_ALG_ED448);
517 
518 	/* read private key file */
519 	ret = dst__privstruct_parse(key, DST_ALG_ED25519, lexer, mctx, &priv);
520 	if (ret != ISC_R_SUCCESS) {
521 		goto err;
522 	}
523 
524 	if (key->external) {
525 		if (priv.nelements != 0) {
526 			DST_RET(DST_R_INVALIDPRIVATEKEY);
527 		}
528 		if (pub == NULL) {
529 			DST_RET(DST_R_INVALIDPRIVATEKEY);
530 		}
531 		key->keydata.pkey = pub->keydata.pkey;
532 		pub->keydata.pkey = NULL;
533 		dst__privstruct_free(&priv, mctx);
534 		isc_safe_memwipe(&priv, sizeof(priv));
535 		return (ISC_R_SUCCESS);
536 	}
537 
538 	if (pub != NULL) {
539 		pubpkey = pub->keydata.pkey;
540 	}
541 
542 	for (i = 0; i < priv.nelements; i++) {
543 		switch (priv.elements[i].tag) {
544 		case TAG_EDDSA_ENGINE:
545 			engine = (char *)priv.elements[i].data;
546 			break;
547 		case TAG_EDDSA_LABEL:
548 			label = (char *)priv.elements[i].data;
549 			break;
550 		case TAG_EDDSA_PRIVATEKEY:
551 			privkey_index = i;
552 			break;
553 		default:
554 			break;
555 		}
556 	}
557 
558 	if (label != NULL) {
559 		ret = openssleddsa_fromlabel(key, engine, label, NULL);
560 		if (ret != ISC_R_SUCCESS) {
561 			goto err;
562 		}
563 		if (eddsa_check(key->keydata.pkey, pubpkey) != ISC_R_SUCCESS) {
564 			DST_RET(DST_R_INVALIDPRIVATEKEY);
565 		}
566 		DST_RET(ISC_R_SUCCESS);
567 	}
568 
569 	if (privkey_index < 0) {
570 		DST_RET(DST_R_INVALIDPRIVATEKEY);
571 	}
572 
573 	len = priv.elements[privkey_index].length;
574 	ret = raw_key_to_ossl(key->key_alg, 1,
575 			      priv.elements[privkey_index].data, &len, &pkey);
576 	if (ret != ISC_R_SUCCESS) {
577 		goto err;
578 	}
579 	if (eddsa_check(pkey, pubpkey) != ISC_R_SUCCESS) {
580 		EVP_PKEY_free(pkey);
581 		DST_RET(DST_R_INVALIDPRIVATEKEY);
582 	}
583 	key->keydata.pkey = pkey;
584 	key->key_size = len * 8;
585 	ret = ISC_R_SUCCESS;
586 
587 err:
588 	dst__privstruct_free(&priv, mctx);
589 	isc_safe_memwipe(&priv, sizeof(priv));
590 	return (ret);
591 }
592 
593 static isc_result_t
594 openssleddsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
595 		       const char *pin) {
596 #if !defined(OPENSSL_NO_ENGINE)
597 	isc_result_t ret;
598 	ENGINE *e;
599 	EVP_PKEY *pkey = NULL, *pubpkey = NULL;
600 	int baseid = EVP_PKEY_NONE;
601 
602 	UNUSED(pin);
603 
604 	REQUIRE(key->key_alg == DST_ALG_ED25519 ||
605 		key->key_alg == DST_ALG_ED448);
606 
607 #if HAVE_OPENSSL_ED25519
608 	if (key->key_alg == DST_ALG_ED25519) {
609 		baseid = EVP_PKEY_ED25519;
610 	}
611 #endif /* if HAVE_OPENSSL_ED25519 */
612 #if HAVE_OPENSSL_ED448
613 	if (key->key_alg == DST_ALG_ED448) {
614 		baseid = EVP_PKEY_ED448;
615 	}
616 #endif /* if HAVE_OPENSSL_ED448 */
617 	if (baseid == EVP_PKEY_NONE) {
618 		return (ISC_R_NOTIMPLEMENTED);
619 	}
620 
621 	if (engine == NULL) {
622 		return (DST_R_NOENGINE);
623 	}
624 	e = dst__openssl_getengine(engine);
625 	if (e == NULL) {
626 		return (DST_R_NOENGINE);
627 	}
628 	pkey = ENGINE_load_private_key(e, label, NULL, NULL);
629 	if (pkey == NULL) {
630 		return (dst__openssl_toresult2("ENGINE_load_private_key",
631 					       ISC_R_NOTFOUND));
632 	}
633 	if (EVP_PKEY_base_id(pkey) != baseid) {
634 		DST_RET(DST_R_INVALIDPRIVATEKEY);
635 	}
636 
637 	pubpkey = ENGINE_load_public_key(e, label, NULL, NULL);
638 	if (eddsa_check(pkey, pubpkey) != ISC_R_SUCCESS) {
639 		DST_RET(DST_R_INVALIDPRIVATEKEY);
640 	}
641 
642 	key->engine = isc_mem_strdup(key->mctx, engine);
643 	key->label = isc_mem_strdup(key->mctx, label);
644 	key->key_size = EVP_PKEY_bits(pkey);
645 	key->keydata.pkey = pkey;
646 	pkey = NULL;
647 	ret = ISC_R_SUCCESS;
648 
649 err:
650 	if (pubpkey != NULL) {
651 		EVP_PKEY_free(pubpkey);
652 	}
653 	if (pkey != NULL) {
654 		EVP_PKEY_free(pkey);
655 	}
656 	return (ret);
657 #else  /* if !defined(OPENSSL_NO_ENGINE) */
658 	UNUSED(key);
659 	UNUSED(engine);
660 	UNUSED(label);
661 	UNUSED(pin);
662 	return (DST_R_NOENGINE);
663 #endif /* if !defined(OPENSSL_NO_ENGINE) */
664 }
665 
666 static dst_func_t openssleddsa_functions = {
667 	openssleddsa_createctx,
668 	NULL, /*%< createctx2 */
669 	openssleddsa_destroyctx,
670 	openssleddsa_adddata,
671 	openssleddsa_sign,
672 	openssleddsa_verify,
673 	NULL, /*%< verify2 */
674 	NULL, /*%< computesecret */
675 	openssleddsa_compare,
676 	NULL, /*%< paramcompare */
677 	openssleddsa_generate,
678 	openssleddsa_isprivate,
679 	openssleddsa_destroy,
680 	openssleddsa_todns,
681 	openssleddsa_fromdns,
682 	openssleddsa_tofile,
683 	openssleddsa_parse,
684 	NULL, /*%< cleanup */
685 	openssleddsa_fromlabel,
686 	NULL, /*%< dump */
687 	NULL, /*%< restore */
688 };
689 
690 isc_result_t
691 dst__openssleddsa_init(dst_func_t **funcp) {
692 	REQUIRE(funcp != NULL);
693 	if (*funcp == NULL) {
694 		*funcp = &openssleddsa_functions;
695 	}
696 	return (ISC_R_SUCCESS);
697 }
698 
699 #endif /* HAVE_OPENSSL_ED25519 || HAVE_OPENSSL_ED448 */
700 
701 #endif /* !USE_PKCS11 */
702 
703 /*! \file */
704