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