xref: /netbsd-src/external/mpl/bind/dist/lib/dns/openssleddsa_link.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: openssleddsa_link.c,v 1.11 2025/01/26 16:25:23 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 /*! \file */
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 
27 #include <isc/mem.h>
28 #include <isc/result.h>
29 #include <isc/safe.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
32 
33 #include <dns/keyvalues.h>
34 
35 #include "dst_internal.h"
36 #include "dst_openssl.h"
37 #include "dst_parse.h"
38 #include "openssl_shim.h"
39 
40 #define DST_RET(a)        \
41 	{                 \
42 		ret = a;  \
43 		goto err; \
44 	}
45 
46 #if HAVE_OPENSSL_ED25519
47 #ifndef NID_ED25519
48 #error "Ed25519 group is not known (NID_ED25519)"
49 #endif /* ifndef NID_ED25519 */
50 #endif /* HAVE_OPENSSL_ED25519 */
51 
52 #if HAVE_OPENSSL_ED448
53 #ifndef NID_ED448
54 #error "Ed448 group is not known (NID_ED448)"
55 #endif /* ifndef NID_ED448 */
56 #endif /* HAVE_OPENSSL_ED448 */
57 
58 typedef struct eddsa_alginfo {
59 	int pkey_type, nid;
60 	unsigned int key_size, sig_size;
61 } eddsa_alginfo_t;
62 
63 static const eddsa_alginfo_t *
64 openssleddsa_alg_info(unsigned int key_alg) {
65 #if HAVE_OPENSSL_ED25519
66 	if (key_alg == DST_ALG_ED25519) {
67 		static const eddsa_alginfo_t ed25519_alginfo = {
68 			.pkey_type = EVP_PKEY_ED25519,
69 			.nid = NID_ED25519,
70 			.key_size = DNS_KEY_ED25519SIZE,
71 			.sig_size = DNS_SIG_ED25519SIZE,
72 		};
73 		return &ed25519_alginfo;
74 	}
75 #endif /* HAVE_OPENSSL_ED25519 */
76 #if HAVE_OPENSSL_ED448
77 	if (key_alg == DST_ALG_ED448) {
78 		static const eddsa_alginfo_t ed448_alginfo = {
79 			.pkey_type = EVP_PKEY_ED448,
80 			.nid = NID_ED448,
81 			.key_size = DNS_KEY_ED448SIZE,
82 			.sig_size = DNS_SIG_ED448SIZE,
83 		};
84 		return &ed448_alginfo;
85 	}
86 #endif /* HAVE_OPENSSL_ED448 */
87 	return NULL;
88 }
89 
90 static isc_result_t
91 raw_key_to_ossl(const eddsa_alginfo_t *alginfo, int private,
92 		const unsigned char *key, size_t *key_len, EVP_PKEY **pkey) {
93 	isc_result_t ret;
94 	int pkey_type = alginfo->pkey_type;
95 	size_t len = alginfo->key_size;
96 
97 	ret = (private ? DST_R_INVALIDPRIVATEKEY : DST_R_INVALIDPUBLICKEY);
98 	if (*key_len < len) {
99 		return ret;
100 	}
101 
102 	if (private) {
103 		*pkey = EVP_PKEY_new_raw_private_key(pkey_type, NULL, key, len);
104 	} else {
105 		*pkey = EVP_PKEY_new_raw_public_key(pkey_type, NULL, key, len);
106 	}
107 	if (*pkey == NULL) {
108 		return dst__openssl_toresult(ret);
109 	}
110 
111 	*key_len = len;
112 	return ISC_R_SUCCESS;
113 }
114 
115 static isc_result_t
116 openssleddsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
117 		       const char *pin);
118 
119 static isc_result_t
120 openssleddsa_createctx(dst_key_t *key, dst_context_t *dctx) {
121 	isc_buffer_t *buf = NULL;
122 	const eddsa_alginfo_t *alginfo =
123 		openssleddsa_alg_info(dctx->key->key_alg);
124 
125 	UNUSED(key);
126 	REQUIRE(alginfo != NULL);
127 
128 	isc_buffer_allocate(dctx->mctx, &buf, 64);
129 	dctx->ctxdata.generic = buf;
130 
131 	return ISC_R_SUCCESS;
132 }
133 
134 static void
135 openssleddsa_destroyctx(dst_context_t *dctx) {
136 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
137 	const eddsa_alginfo_t *alginfo =
138 		openssleddsa_alg_info(dctx->key->key_alg);
139 
140 	REQUIRE(alginfo != NULL);
141 	if (buf != NULL) {
142 		isc_buffer_free(&buf);
143 	}
144 	dctx->ctxdata.generic = NULL;
145 }
146 
147 static isc_result_t
148 openssleddsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
149 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
150 	isc_buffer_t *nbuf = NULL;
151 	isc_region_t r;
152 	unsigned int length;
153 	isc_result_t result;
154 	const eddsa_alginfo_t *alginfo =
155 		openssleddsa_alg_info(dctx->key->key_alg);
156 
157 	REQUIRE(alginfo != NULL);
158 
159 	result = isc_buffer_copyregion(buf, data);
160 	if (result == ISC_R_SUCCESS) {
161 		return ISC_R_SUCCESS;
162 	}
163 
164 	length = isc_buffer_length(buf) + data->length + 64;
165 	isc_buffer_allocate(dctx->mctx, &nbuf, length);
166 	isc_buffer_usedregion(buf, &r);
167 	(void)isc_buffer_copyregion(nbuf, &r);
168 	(void)isc_buffer_copyregion(nbuf, data);
169 	isc_buffer_free(&buf);
170 	dctx->ctxdata.generic = nbuf;
171 
172 	return ISC_R_SUCCESS;
173 }
174 
175 static isc_result_t
176 openssleddsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
177 	isc_result_t ret;
178 	dst_key_t *key = dctx->key;
179 	isc_region_t tbsreg;
180 	isc_region_t sigreg;
181 	EVP_PKEY *pkey = key->keydata.pkeypair.priv;
182 	EVP_MD_CTX *ctx = EVP_MD_CTX_new();
183 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
184 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
185 	size_t siglen;
186 
187 	REQUIRE(alginfo != NULL);
188 
189 	if (ctx == NULL) {
190 		return ISC_R_NOMEMORY;
191 	}
192 
193 	siglen = alginfo->sig_size;
194 	isc_buffer_availableregion(sig, &sigreg);
195 	if (sigreg.length < (unsigned int)siglen) {
196 		DST_RET(ISC_R_NOSPACE);
197 	}
198 
199 	isc_buffer_usedregion(buf, &tbsreg);
200 
201 	if (EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey) != 1) {
202 		DST_RET(dst__openssl_toresult3(
203 			dctx->category, "EVP_DigestSignInit", ISC_R_FAILURE));
204 	}
205 	if (EVP_DigestSign(ctx, sigreg.base, &siglen, tbsreg.base,
206 			   tbsreg.length) != 1)
207 	{
208 		DST_RET(dst__openssl_toresult3(dctx->category, "EVP_DigestSign",
209 					       DST_R_SIGNFAILURE));
210 	}
211 	isc_buffer_add(sig, (unsigned int)siglen);
212 	ret = ISC_R_SUCCESS;
213 
214 err:
215 	EVP_MD_CTX_free(ctx);
216 	isc_buffer_free(&buf);
217 	dctx->ctxdata.generic = NULL;
218 
219 	return ret;
220 }
221 
222 static isc_result_t
223 openssleddsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
224 	isc_result_t ret;
225 	dst_key_t *key = dctx->key;
226 	int status;
227 	isc_region_t tbsreg;
228 	EVP_PKEY *pkey = key->keydata.pkeypair.pub;
229 	EVP_MD_CTX *ctx = EVP_MD_CTX_new();
230 	isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic;
231 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
232 
233 	REQUIRE(alginfo != NULL);
234 
235 	if (ctx == NULL) {
236 		return dst__openssl_toresult(ISC_R_NOMEMORY);
237 	}
238 
239 	if (sig->length != alginfo->sig_size) {
240 		DST_RET(DST_R_VERIFYFAILURE);
241 	}
242 
243 	isc_buffer_usedregion(buf, &tbsreg);
244 
245 	if (EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey) != 1) {
246 		DST_RET(dst__openssl_toresult3(
247 			dctx->category, "EVP_DigestVerifyInit", ISC_R_FAILURE));
248 	}
249 
250 	status = EVP_DigestVerify(ctx, sig->base, sig->length, tbsreg.base,
251 				  tbsreg.length);
252 
253 	switch (status) {
254 	case 1:
255 		ret = ISC_R_SUCCESS;
256 		break;
257 	case 0:
258 		ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
259 		break;
260 	default:
261 		ret = dst__openssl_toresult3(dctx->category, "EVP_DigestVerify",
262 					     DST_R_VERIFYFAILURE);
263 		break;
264 	}
265 
266 err:
267 	EVP_MD_CTX_free(ctx);
268 	isc_buffer_free(&buf);
269 	dctx->ctxdata.generic = NULL;
270 
271 	return ret;
272 }
273 
274 static isc_result_t
275 openssleddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
276 	isc_result_t ret;
277 	EVP_PKEY *pkey = NULL;
278 	EVP_PKEY_CTX *ctx = NULL;
279 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
280 	int status;
281 
282 	REQUIRE(alginfo != NULL);
283 	UNUSED(unused);
284 	UNUSED(callback);
285 
286 	ctx = EVP_PKEY_CTX_new_id(alginfo->nid, NULL);
287 	if (ctx == NULL) {
288 		return dst__openssl_toresult2("EVP_PKEY_CTX_new_id",
289 					      DST_R_OPENSSLFAILURE);
290 	}
291 
292 	status = EVP_PKEY_keygen_init(ctx);
293 	if (status != 1) {
294 		DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
295 					       DST_R_OPENSSLFAILURE));
296 	}
297 
298 	status = EVP_PKEY_keygen(ctx, &pkey);
299 	if (status != 1) {
300 		DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
301 					       DST_R_OPENSSLFAILURE));
302 	}
303 
304 	key->key_size = alginfo->key_size * 8;
305 	key->keydata.pkeypair.priv = pkey;
306 	key->keydata.pkeypair.pub = pkey;
307 	ret = ISC_R_SUCCESS;
308 
309 err:
310 	EVP_PKEY_CTX_free(ctx);
311 	return ret;
312 }
313 
314 static isc_result_t
315 openssleddsa_todns(const dst_key_t *key, isc_buffer_t *data) {
316 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
317 	EVP_PKEY *pkey = key->keydata.pkeypair.pub;
318 	isc_region_t r;
319 	size_t len;
320 
321 	REQUIRE(pkey != NULL);
322 	REQUIRE(alginfo != NULL);
323 
324 	len = alginfo->key_size;
325 	isc_buffer_availableregion(data, &r);
326 	if (r.length < len) {
327 		return ISC_R_NOSPACE;
328 	}
329 
330 	if (EVP_PKEY_get_raw_public_key(pkey, r.base, &len) != 1) {
331 		return dst__openssl_toresult(ISC_R_FAILURE);
332 	}
333 
334 	isc_buffer_add(data, len);
335 	return ISC_R_SUCCESS;
336 }
337 
338 static isc_result_t
339 openssleddsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
340 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
341 	isc_result_t ret;
342 	isc_region_t r;
343 	size_t len;
344 	EVP_PKEY *pkey = NULL;
345 
346 	REQUIRE(alginfo != NULL);
347 
348 	isc_buffer_remainingregion(data, &r);
349 	if (r.length == 0) {
350 		return ISC_R_SUCCESS;
351 	}
352 
353 	len = r.length;
354 	ret = raw_key_to_ossl(alginfo, 0, r.base, &len, &pkey);
355 	if (ret != ISC_R_SUCCESS) {
356 		return ret;
357 	}
358 
359 	isc_buffer_forward(data, len);
360 	key->keydata.pkeypair.pub = pkey;
361 	key->key_size = len * 8;
362 	return ISC_R_SUCCESS;
363 }
364 
365 static isc_result_t
366 openssleddsa_tofile(const dst_key_t *key, const char *directory) {
367 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
368 	isc_result_t ret;
369 	dst_private_t priv;
370 	unsigned char *buf = NULL;
371 	size_t len;
372 	int i;
373 
374 	REQUIRE(alginfo != NULL);
375 
376 	if (key->keydata.pkeypair.pub == NULL) {
377 		return DST_R_NULLKEY;
378 	}
379 
380 	if (key->external) {
381 		priv.nelements = 0;
382 		return dst__privstruct_writefile(key, &priv, directory);
383 	}
384 
385 	i = 0;
386 
387 	if (dst__openssl_keypair_isprivate(key)) {
388 		len = alginfo->key_size;
389 		buf = isc_mem_get(key->mctx, len);
390 		if (EVP_PKEY_get_raw_private_key(key->keydata.pkeypair.priv,
391 						 buf, &len) != 1)
392 		{
393 			DST_RET(dst__openssl_toresult(ISC_R_FAILURE));
394 		}
395 		priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY;
396 		priv.elements[i].length = len;
397 		priv.elements[i].data = buf;
398 		i++;
399 	}
400 	if (key->engine != NULL) {
401 		priv.elements[i].tag = TAG_EDDSA_ENGINE;
402 		priv.elements[i].length = (unsigned short)strlen(key->engine) +
403 					  1;
404 		priv.elements[i].data = (unsigned char *)key->engine;
405 		i++;
406 	}
407 	if (key->label != NULL) {
408 		priv.elements[i].tag = TAG_EDDSA_LABEL;
409 		priv.elements[i].length = (unsigned short)strlen(key->label) +
410 					  1;
411 		priv.elements[i].data = (unsigned char *)key->label;
412 		i++;
413 	}
414 
415 	priv.nelements = i;
416 	ret = dst__privstruct_writefile(key, &priv, directory);
417 
418 err:
419 	if (buf != NULL) {
420 		isc_mem_put(key->mctx, buf, len);
421 	}
422 	return ret;
423 }
424 
425 static isc_result_t
426 openssleddsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
427 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
428 	dst_private_t priv;
429 	isc_result_t ret;
430 	int i, privkey_index = -1;
431 	const char *engine = NULL, *label = NULL;
432 	EVP_PKEY *pkey = NULL;
433 	size_t len;
434 	isc_mem_t *mctx = key->mctx;
435 
436 	REQUIRE(alginfo != NULL);
437 
438 	/* read private key file */
439 	ret = dst__privstruct_parse(key, DST_ALG_ED25519, lexer, mctx, &priv);
440 	if (ret != ISC_R_SUCCESS) {
441 		goto err;
442 	}
443 
444 	if (key->external) {
445 		if (priv.nelements != 0) {
446 			DST_RET(DST_R_INVALIDPRIVATEKEY);
447 		}
448 		if (pub == NULL) {
449 			DST_RET(DST_R_INVALIDPRIVATEKEY);
450 		}
451 		key->keydata.pkeypair.priv = pub->keydata.pkeypair.priv;
452 		key->keydata.pkeypair.pub = pub->keydata.pkeypair.pub;
453 		pub->keydata.pkeypair.priv = NULL;
454 		pub->keydata.pkeypair.pub = NULL;
455 		DST_RET(ISC_R_SUCCESS);
456 	}
457 
458 	for (i = 0; i < priv.nelements; i++) {
459 		switch (priv.elements[i].tag) {
460 		case TAG_EDDSA_ENGINE:
461 			engine = (char *)priv.elements[i].data;
462 			break;
463 		case TAG_EDDSA_LABEL:
464 			label = (char *)priv.elements[i].data;
465 			break;
466 		case TAG_EDDSA_PRIVATEKEY:
467 			privkey_index = i;
468 			break;
469 		default:
470 			break;
471 		}
472 	}
473 
474 	if (label != NULL) {
475 		ret = openssleddsa_fromlabel(key, engine, label, NULL);
476 		if (ret != ISC_R_SUCCESS) {
477 			goto err;
478 		}
479 		/* Check that the public component matches if given */
480 		if (pub != NULL && EVP_PKEY_eq(key->keydata.pkeypair.pub,
481 					       pub->keydata.pkeypair.pub) != 1)
482 		{
483 			DST_RET(DST_R_INVALIDPRIVATEKEY);
484 		}
485 		DST_RET(ISC_R_SUCCESS);
486 	}
487 
488 	if (privkey_index < 0) {
489 		DST_RET(DST_R_INVALIDPRIVATEKEY);
490 	}
491 
492 	len = priv.elements[privkey_index].length;
493 	ret = raw_key_to_ossl(alginfo, 1, priv.elements[privkey_index].data,
494 			      &len, &pkey);
495 	if (ret != ISC_R_SUCCESS) {
496 		goto err;
497 	}
498 	/* Check that the public component matches if given */
499 	if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) {
500 		DST_RET(DST_R_INVALIDPRIVATEKEY);
501 	}
502 
503 	key->keydata.pkeypair.priv = pkey;
504 	key->keydata.pkeypair.pub = pkey;
505 	key->key_size = len * 8;
506 	pkey = NULL;
507 	ret = ISC_R_SUCCESS;
508 
509 err:
510 	EVP_PKEY_free(pkey);
511 	dst__privstruct_free(&priv, mctx);
512 	isc_safe_memwipe(&priv, sizeof(priv));
513 	return ret;
514 }
515 
516 static isc_result_t
517 openssleddsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
518 		       const char *pin) {
519 	const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg);
520 	EVP_PKEY *privpkey = NULL, *pubpkey = NULL;
521 	isc_result_t ret;
522 
523 	REQUIRE(alginfo != NULL);
524 	UNUSED(pin);
525 
526 	ret = dst__openssl_fromlabel(alginfo->pkey_type, engine, label, pin,
527 				     &pubpkey, &privpkey);
528 	if (ret != ISC_R_SUCCESS) {
529 		goto err;
530 	}
531 
532 	if (engine != NULL) {
533 		key->engine = isc_mem_strdup(key->mctx, engine);
534 	}
535 	key->label = isc_mem_strdup(key->mctx, label);
536 	key->key_size = EVP_PKEY_bits(privpkey);
537 	key->keydata.pkeypair.priv = privpkey;
538 	key->keydata.pkeypair.pub = pubpkey;
539 	privpkey = NULL;
540 	pubpkey = NULL;
541 
542 err:
543 	EVP_PKEY_free(privpkey);
544 	EVP_PKEY_free(pubpkey);
545 	return ret;
546 }
547 
548 static dst_func_t openssleddsa_functions = {
549 	openssleddsa_createctx,
550 	NULL, /*%< createctx2 */
551 	openssleddsa_destroyctx,
552 	openssleddsa_adddata,
553 	openssleddsa_sign,
554 	openssleddsa_verify,
555 	NULL, /*%< verify2 */
556 	NULL, /*%< computesecret */
557 	dst__openssl_keypair_compare,
558 	NULL, /*%< paramcompare */
559 	openssleddsa_generate,
560 	dst__openssl_keypair_isprivate,
561 	dst__openssl_keypair_destroy,
562 	openssleddsa_todns,
563 	openssleddsa_fromdns,
564 	openssleddsa_tofile,
565 	openssleddsa_parse,
566 	NULL, /*%< cleanup */
567 	openssleddsa_fromlabel,
568 	NULL, /*%< dump */
569 	NULL, /*%< restore */
570 };
571 
572 /*
573  * The test vectors below where generated by util/gen-eddsa-vectors.c
574  */
575 #if HAVE_OPENSSL_ED448
576 static unsigned char ed448_pub[] =
577 	"\x0a\x19\x36\xf0\x4c\x2d\xc1\xfe\xbe\xdc\xfa\xf6\xeb\xd2\x8f\x3b\x04"
578 	"\x14\x2e\x88\xc6\xb5\xdc\xe8\x2a\xc6\xb9\x7c\xa8\x22\xe8\x36\xfb\x06"
579 	"\x55\xa3\x3c\xdb\x9d\x68\x59\x7e\xa9\x5f\x93\x96\x87\x83\x28\xce\xdd"
580 	"\x12\xc9\xb8\x78\x02\x80";
581 static unsigned char ed448_sig[] =
582 	"\x7e\xec\x4e\x11\xd9\x79\x89\xd2\xe2\x85\x7a\x1c\xd7\x36\xe8\x24\x1f"
583 	"\x90\xa0\x9c\x84\xfb\x51\xcd\xdc\xfd\x05\xcd\x8c\x08\x51\x05\x18\xc8"
584 	"\x85\xb2\x28\x00\xea\xfe\x10\x46\xad\x52\xe6\xe9\x62\x35\x3b\x2a\x14"
585 	"\x8b\xe7\xf0\x66\x5f\x00\x66\x3c\xa1\x4d\x03\x95\xcc\x73\xfc\xf2\x40"
586 	"\x4b\x67\x85\x5b\x9f\xa9\x87\xb6\xbb\xa3\x9d\x73\x9f\xcb\x4e\x2c\xd2"
587 	"\x46\xc7\x84\xd3\x7d\x94\x32\x30\x27\xb0\xa7\xf6\x6d\xf4\x77\xe8\xf5"
588 	"\xb4\xee\x3f\x0e\x2b\x35\xdd\x5a\x35\xfe\x35\x00";
589 #endif
590 
591 #if HAVE_OPENSSL_ED25519
592 static unsigned char ed25519_pub[] =
593 	"\x66\x5c\x21\x59\xe3\xa0\x6e\xa3\x7d\x82\x7c\xf1\xe7\xa3\xdd\xaf\xd1"
594 	"\x6d\x92\x81\xfb\x09\x0c\x7c\xfe\x6d\xf8\x87\x24\x7e\x6e\x25";
595 static unsigned char ed25519_sig[] =
596 	"\x26\x70\x5c\xc1\x85\xb6\x5e\x65\xe5\xa7\xd5\x85\x63\xc9\x1d\x45\x56"
597 	"\x38\xa3\x9c\xa3\x42\x4d\xc8\x89\xff\x84\xea\x2c\xa8\x8b\xfa\x2f\xab"
598 	"\x75\x7c\x68\x95\xfd\xdf\x62\x60\x4e\x4d\x10\xf8\x3c\xae\xcf\x18\x93"
599 	"\x90\x05\xa4\x54\x38\x45\x2f\x81\x71\x1e\x0f\x46\x04";
600 #endif
601 
602 static isc_result_t
603 check_algorithm(unsigned char algorithm) {
604 	EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create();
605 	EVP_PKEY *pkey = NULL;
606 	const eddsa_alginfo_t *alginfo = NULL;
607 	const unsigned char *key = NULL;
608 	const unsigned char *sig = NULL;
609 	const unsigned char test[] = "test";
610 	isc_result_t ret = ISC_R_SUCCESS;
611 	size_t key_len, sig_len;
612 
613 	if (evp_md_ctx == NULL) {
614 		DST_RET(ISC_R_NOMEMORY);
615 	}
616 
617 	switch (algorithm) {
618 #if HAVE_OPENSSL_ED448
619 	case DST_ALG_ED448:
620 		sig = ed448_sig;
621 		sig_len = sizeof(ed448_sig) - 1;
622 		key = ed448_pub;
623 		key_len = sizeof(ed448_pub) - 1;
624 		alginfo = openssleddsa_alg_info(algorithm);
625 		break;
626 #endif
627 #if HAVE_OPENSSL_ED25519
628 	case DST_ALG_ED25519:
629 		sig = ed25519_sig;
630 		sig_len = sizeof(ed25519_sig) - 1;
631 		key = ed25519_pub;
632 		key_len = sizeof(ed25519_pub) - 1;
633 		alginfo = openssleddsa_alg_info(algorithm);
634 		break;
635 #endif
636 	default:
637 		DST_RET(ISC_R_NOTIMPLEMENTED);
638 	}
639 
640 	INSIST(alginfo != NULL);
641 	ret = raw_key_to_ossl(alginfo, 0, key, &key_len, &pkey);
642 	if (ret != ISC_R_SUCCESS) {
643 		goto err;
644 	}
645 
646 	/*
647 	 * Check that we can verify the signature.
648 	 */
649 	if (EVP_DigestVerifyInit(evp_md_ctx, NULL, NULL, NULL, pkey) != 1 ||
650 	    EVP_DigestVerify(evp_md_ctx, sig, sig_len, test,
651 			     sizeof(test) - 1) != 1)
652 	{
653 		DST_RET(ISC_R_NOTIMPLEMENTED);
654 	}
655 
656 err:
657 	if (pkey != NULL) {
658 		EVP_PKEY_free(pkey);
659 	}
660 	if (evp_md_ctx != NULL) {
661 		EVP_MD_CTX_destroy(evp_md_ctx);
662 	}
663 	ERR_clear_error();
664 	return ret;
665 }
666 
667 isc_result_t
668 dst__openssleddsa_init(dst_func_t **funcp, unsigned char algorithm) {
669 	REQUIRE(funcp != NULL);
670 
671 	if (*funcp == NULL) {
672 		if (check_algorithm(algorithm) == ISC_R_SUCCESS) {
673 			*funcp = &openssleddsa_functions;
674 		}
675 	}
676 	return ISC_R_SUCCESS;
677 }
678 
679 #endif /* HAVE_OPENSSL_ED25519 || HAVE_OPENSSL_ED448 */
680