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