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