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