1/* 2 * Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <config.h> 18 19#ifdef HAVE_OPENSSL_ECDSA 20 21#if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384) 22#error "ECDSA without EVP for SHA2?" 23#endif 24 25#include <isc/entropy.h> 26#include <isc/mem.h> 27#include <isc/sha2.h> 28#include <isc/string.h> 29#include <isc/util.h> 30 31#include <dns/keyvalues.h> 32#include <dst/result.h> 33 34#include "dst_internal.h" 35#include "dst_openssl.h" 36#include "dst_parse.h" 37 38#include <openssl/err.h> 39#include <openssl/objects.h> 40#include <openssl/ecdsa.h> 41#include <openssl/bn.h> 42 43#ifndef NID_X9_62_prime256v1 44#error "P-256 group is not known (NID_X9_62_prime256v1)" 45#endif 46#ifndef NID_secp384r1 47#error "P-384 group is not known (NID_secp384r1)" 48#endif 49 50#define DST_RET(a) {ret = a; goto err;} 51 52static isc_result_t opensslecdsa_todns(const dst_key_t *key, 53 isc_buffer_t *data); 54 55static isc_result_t 56opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { 57 EVP_MD_CTX *evp_md_ctx; 58 const EVP_MD *type = NULL; 59 60 UNUSED(key); 61 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || 62 dctx->key->key_alg == DST_ALG_ECDSA384); 63 64 evp_md_ctx = EVP_MD_CTX_create(); 65 if (evp_md_ctx == NULL) 66 return (ISC_R_NOMEMORY); 67 if (dctx->key->key_alg == DST_ALG_ECDSA256) 68 type = EVP_sha256(); 69 else 70 type = EVP_sha384(); 71 72 if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) { 73 EVP_MD_CTX_destroy(evp_md_ctx); 74 return (dst__openssl_toresult3(dctx->category, 75 "EVP_DigestInit_ex", 76 ISC_R_FAILURE)); 77 } 78 79 dctx->ctxdata.evp_md_ctx = evp_md_ctx; 80 81 return (ISC_R_SUCCESS); 82} 83 84static void 85opensslecdsa_destroyctx(dst_context_t *dctx) { 86 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 87 88 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || 89 dctx->key->key_alg == DST_ALG_ECDSA384); 90 91 if (evp_md_ctx != NULL) { 92 EVP_MD_CTX_destroy(evp_md_ctx); 93 dctx->ctxdata.evp_md_ctx = NULL; 94 } 95} 96 97static isc_result_t 98opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) { 99 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 100 101 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || 102 dctx->key->key_alg == DST_ALG_ECDSA384); 103 104 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) 105 return (dst__openssl_toresult3(dctx->category, 106 "EVP_DigestUpdate", 107 ISC_R_FAILURE)); 108 109 return (ISC_R_SUCCESS); 110} 111 112static int 113BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) { 114 int bytes = size - BN_num_bytes(bn); 115 116 while (bytes-- > 0) 117 *buf++ = 0; 118 BN_bn2bin(bn, buf); 119 return (size); 120} 121 122static isc_result_t 123opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { 124 isc_result_t ret; 125 dst_key_t *key = dctx->key; 126 isc_region_t r; 127 ECDSA_SIG *ecdsasig; 128 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 129 EVP_PKEY *pkey = key->keydata.pkey; 130 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey); 131 unsigned int dgstlen, siglen; 132 unsigned char digest[EVP_MAX_MD_SIZE]; 133 134 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 135 key->key_alg == DST_ALG_ECDSA384); 136 137 if (eckey == NULL) 138 return (ISC_R_FAILURE); 139 140 if (key->key_alg == DST_ALG_ECDSA256) 141 siglen = DNS_SIG_ECDSA256SIZE; 142 else 143 siglen = DNS_SIG_ECDSA384SIZE; 144 145 isc_buffer_availableregion(sig, &r); 146 if (r.length < siglen) 147 DST_RET(ISC_R_NOSPACE); 148 149 if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen)) 150 DST_RET(dst__openssl_toresult3(dctx->category, 151 "EVP_DigestFinal", 152 ISC_R_FAILURE)); 153 154 ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey); 155 if (ecdsasig == NULL) 156 DST_RET(dst__openssl_toresult3(dctx->category, 157 "ECDSA_do_sign", 158 DST_R_SIGNFAILURE)); 159 BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2); 160 isc_region_consume(&r, siglen / 2); 161 BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2); 162 isc_region_consume(&r, siglen / 2); 163 ECDSA_SIG_free(ecdsasig); 164 isc_buffer_add(sig, siglen); 165 ret = ISC_R_SUCCESS; 166 167 err: 168 if (eckey != NULL) 169 EC_KEY_free(eckey); 170 return (ret); 171} 172 173static isc_result_t 174opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) { 175 isc_result_t ret; 176 dst_key_t *key = dctx->key; 177 int status; 178 unsigned char *cp = sig->base; 179 ECDSA_SIG *ecdsasig = NULL; 180 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 181 EVP_PKEY *pkey = key->keydata.pkey; 182 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey); 183 unsigned int dgstlen, siglen; 184 unsigned char digest[EVP_MAX_MD_SIZE]; 185 186 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 187 key->key_alg == DST_ALG_ECDSA384); 188 189 if (eckey == NULL) 190 return (ISC_R_FAILURE); 191 192 if (key->key_alg == DST_ALG_ECDSA256) 193 siglen = DNS_SIG_ECDSA256SIZE; 194 else 195 siglen = DNS_SIG_ECDSA384SIZE; 196 197 if (sig->length != siglen) 198 return (DST_R_VERIFYFAILURE); 199 200 if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen)) 201 DST_RET (dst__openssl_toresult3(dctx->category, 202 "EVP_DigestFinal_ex", 203 ISC_R_FAILURE)); 204 205 ecdsasig = ECDSA_SIG_new(); 206 if (ecdsasig == NULL) 207 DST_RET (ISC_R_NOMEMORY); 208 if (ecdsasig->r != NULL) 209 BN_free(ecdsasig->r); 210 ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL); 211 cp += siglen / 2; 212 if (ecdsasig->s != NULL) 213 BN_free(ecdsasig->s); 214 ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL); 215 /* cp += siglen / 2; */ 216 217 status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey); 218 switch (status) { 219 case 1: 220 ret = ISC_R_SUCCESS; 221 break; 222 case 0: 223 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE); 224 break; 225 default: 226 ret = dst__openssl_toresult3(dctx->category, 227 "ECDSA_do_verify", 228 DST_R_VERIFYFAILURE); 229 break; 230 } 231 232 err: 233 if (ecdsasig != NULL) 234 ECDSA_SIG_free(ecdsasig); 235 if (eckey != NULL) 236 EC_KEY_free(eckey); 237 return (ret); 238} 239 240static isc_boolean_t 241opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) { 242 isc_boolean_t ret; 243 int status; 244 EVP_PKEY *pkey1 = key1->keydata.pkey; 245 EVP_PKEY *pkey2 = key2->keydata.pkey; 246 EC_KEY *eckey1 = NULL; 247 EC_KEY *eckey2 = NULL; 248 const BIGNUM *priv1, *priv2; 249 250 if (pkey1 == NULL && pkey2 == NULL) 251 return (ISC_TRUE); 252 else if (pkey1 == NULL || pkey2 == NULL) 253 return (ISC_FALSE); 254 255 eckey1 = EVP_PKEY_get1_EC_KEY(pkey1); 256 eckey2 = EVP_PKEY_get1_EC_KEY(pkey2); 257 if (eckey1 == NULL && eckey2 == NULL) { 258 DST_RET (ISC_TRUE); 259 } else if (eckey1 == NULL || eckey2 == NULL) 260 DST_RET (ISC_FALSE); 261 262 status = EVP_PKEY_cmp(pkey1, pkey2); 263 if (status != 1) 264 DST_RET (ISC_FALSE); 265 266 priv1 = EC_KEY_get0_private_key(eckey1); 267 priv2 = EC_KEY_get0_private_key(eckey2); 268 if (priv1 != NULL || priv2 != NULL) { 269 if (priv1 == NULL || priv2 == NULL) 270 DST_RET (ISC_FALSE); 271 if (BN_cmp(priv1, priv2) != 0) 272 DST_RET (ISC_FALSE); 273 } 274 ret = ISC_TRUE; 275 276 err: 277 if (eckey1 != NULL) 278 EC_KEY_free(eckey1); 279 if (eckey2 != NULL) 280 EC_KEY_free(eckey2); 281 return (ret); 282} 283 284static isc_result_t 285opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { 286 isc_result_t ret; 287 EVP_PKEY *pkey; 288 EC_KEY *eckey = NULL; 289 int group_nid; 290 291 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 292 key->key_alg == DST_ALG_ECDSA384); 293 UNUSED(unused); 294 UNUSED(callback); 295 296 if (key->key_alg == DST_ALG_ECDSA256) 297 group_nid = NID_X9_62_prime256v1; 298 else 299 group_nid = NID_secp384r1; 300 301 eckey = EC_KEY_new_by_curve_name(group_nid); 302 if (eckey == NULL) 303 return (dst__openssl_toresult2("EC_KEY_new_by_curve_name", 304 DST_R_OPENSSLFAILURE)); 305 306 if (EC_KEY_generate_key(eckey) != 1) 307 DST_RET (dst__openssl_toresult2("EC_KEY_generate_key", 308 DST_R_OPENSSLFAILURE)); 309 310 pkey = EVP_PKEY_new(); 311 if (pkey == NULL) 312 DST_RET (ISC_R_NOMEMORY); 313 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 314 EVP_PKEY_free(pkey); 315 DST_RET (ISC_R_FAILURE); 316 } 317 key->keydata.pkey = pkey; 318 ret = ISC_R_SUCCESS; 319 320 err: 321 if (eckey != NULL) 322 EC_KEY_free(eckey); 323 return (ret); 324} 325 326static isc_boolean_t 327opensslecdsa_isprivate(const dst_key_t *key) { 328 isc_boolean_t ret; 329 EVP_PKEY *pkey = key->keydata.pkey; 330 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey); 331 332 ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL); 333 if (eckey != NULL) 334 EC_KEY_free(eckey); 335 return (ret); 336} 337 338static void 339opensslecdsa_destroy(dst_key_t *key) { 340 EVP_PKEY *pkey = key->keydata.pkey; 341 342 EVP_PKEY_free(pkey); 343 key->keydata.pkey = NULL; 344} 345 346static isc_result_t 347opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { 348 isc_result_t ret; 349 EVP_PKEY *pkey; 350 EC_KEY *eckey = NULL; 351 isc_region_t r; 352 int len; 353 unsigned char *cp; 354 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1]; 355 356 REQUIRE(key->keydata.pkey != NULL); 357 358 pkey = key->keydata.pkey; 359 eckey = EVP_PKEY_get1_EC_KEY(pkey); 360 if (eckey == NULL) 361 return (dst__openssl_toresult(ISC_R_FAILURE)); 362 len = i2o_ECPublicKey(eckey, NULL); 363 /* skip form */ 364 len--; 365 366 isc_buffer_availableregion(data, &r); 367 if (r.length < (unsigned int) len) 368 DST_RET (ISC_R_NOSPACE); 369 cp = buf; 370 if (!i2o_ECPublicKey(eckey, &cp)) 371 DST_RET (dst__openssl_toresult(ISC_R_FAILURE)); 372 memmove(r.base, buf + 1, len); 373 isc_buffer_add(data, len); 374 ret = ISC_R_SUCCESS; 375 376 err: 377 if (eckey != NULL) 378 EC_KEY_free(eckey); 379 return (ret); 380} 381 382static isc_result_t 383opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { 384 isc_result_t ret; 385 EVP_PKEY *pkey; 386 EC_KEY *eckey = NULL; 387 isc_region_t r; 388 int group_nid; 389 unsigned int len; 390 const unsigned char *cp; 391 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1]; 392 393 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 394 key->key_alg == DST_ALG_ECDSA384); 395 396 if (key->key_alg == DST_ALG_ECDSA256) { 397 len = DNS_KEY_ECDSA256SIZE; 398 group_nid = NID_X9_62_prime256v1; 399 } else { 400 len = DNS_KEY_ECDSA384SIZE; 401 group_nid = NID_secp384r1; 402 } 403 404 isc_buffer_remainingregion(data, &r); 405 if (r.length == 0) 406 return (ISC_R_SUCCESS); 407 if (r.length < len) 408 return (DST_R_INVALIDPUBLICKEY); 409 410 eckey = EC_KEY_new_by_curve_name(group_nid); 411 if (eckey == NULL) 412 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 413 414 buf[0] = POINT_CONVERSION_UNCOMPRESSED; 415 memmove(buf + 1, r.base, len); 416 cp = buf; 417 if (o2i_ECPublicKey(&eckey, 418 (const unsigned char **) &cp, 419 (long) len + 1) == NULL) 420 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); 421 if (EC_KEY_check_key(eckey) != 1) 422 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); 423 424 pkey = EVP_PKEY_new(); 425 if (pkey == NULL) 426 DST_RET (ISC_R_NOMEMORY); 427 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 428 EVP_PKEY_free(pkey); 429 DST_RET (dst__openssl_toresult(ISC_R_FAILURE)); 430 } 431 432 isc_buffer_forward(data, len); 433 key->keydata.pkey = pkey; 434 ret = ISC_R_SUCCESS; 435 436 err: 437 if (eckey != NULL) 438 EC_KEY_free(eckey); 439 return (ret); 440} 441 442static isc_result_t 443opensslecdsa_tofile(const dst_key_t *key, const char *directory) { 444 isc_result_t ret; 445 EVP_PKEY *pkey; 446 EC_KEY *eckey = NULL; 447 const BIGNUM *privkey; 448 dst_private_t priv; 449 unsigned char *buf = NULL; 450 451 if (key->keydata.pkey == NULL) 452 return (DST_R_NULLKEY); 453 454 if (key->external) { 455 priv.nelements = 0; 456 return (dst__privstruct_writefile(key, &priv, directory)); 457 } 458 459 pkey = key->keydata.pkey; 460 eckey = EVP_PKEY_get1_EC_KEY(pkey); 461 if (eckey == NULL) 462 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 463 privkey = EC_KEY_get0_private_key(eckey); 464 if (privkey == NULL) 465 DST_RET (ISC_R_FAILURE); 466 467 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey)); 468 if (buf == NULL) 469 DST_RET (ISC_R_NOMEMORY); 470 471 priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY; 472 priv.elements[0].length = BN_num_bytes(privkey); 473 BN_bn2bin(privkey, buf); 474 priv.elements[0].data = buf; 475 priv.nelements = ECDSA_NTAGS; 476 ret = dst__privstruct_writefile(key, &priv, directory); 477 478 err: 479 if (eckey != NULL) 480 EC_KEY_free(eckey); 481 if (buf != NULL) 482 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey)); 483 return (ret); 484} 485 486static isc_result_t 487ecdsa_check(EC_KEY *eckey, dst_key_t *pub) 488{ 489 isc_result_t ret = ISC_R_FAILURE; 490 EVP_PKEY *pkey; 491 EC_KEY *pubeckey = NULL; 492 const EC_POINT *pubkey; 493 494 if (pub == NULL) 495 return (ISC_R_SUCCESS); 496 pkey = pub->keydata.pkey; 497 if (pkey == NULL) 498 return (ISC_R_SUCCESS); 499 pubeckey = EVP_PKEY_get1_EC_KEY(pkey); 500 if (pubeckey == NULL) 501 return (ISC_R_SUCCESS); 502 pubkey = EC_KEY_get0_public_key(pubeckey); 503 if (pubkey == NULL) 504 DST_RET (ISC_R_SUCCESS); 505 if (EC_KEY_set_public_key(eckey, pubkey) != 1) 506 DST_RET (ISC_R_SUCCESS); 507 if (EC_KEY_check_key(eckey) == 1) 508 DST_RET (ISC_R_SUCCESS); 509 510 err: 511 if (pubeckey != NULL) 512 EC_KEY_free(pubeckey); 513 return (ret); 514} 515 516static isc_result_t 517opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 518 dst_private_t priv; 519 isc_result_t ret; 520 EVP_PKEY *pkey, *pubpkey; 521 EC_KEY *eckey = NULL, *pubeckey = NULL; 522 const EC_POINT *pubkey; 523 BIGNUM *privkey; 524 int group_nid; 525 isc_mem_t *mctx = key->mctx; 526 527 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 528 key->key_alg == DST_ALG_ECDSA384); 529 530 if (key->key_alg == DST_ALG_ECDSA256) 531 group_nid = NID_X9_62_prime256v1; 532 else 533 group_nid = NID_secp384r1; 534 535 eckey = EC_KEY_new_by_curve_name(group_nid); 536 if (eckey == NULL) 537 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 538 539 /* read private key file */ 540 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); 541 if (ret != ISC_R_SUCCESS) 542 goto err; 543 544 if (key->external) { 545 /* 546 * Copy the public key to this new key. 547 */ 548 if (pub == NULL) 549 DST_RET(DST_R_INVALIDPRIVATEKEY); 550 pubpkey = pub->keydata.pkey; 551 pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey); 552 if (pubeckey == NULL) 553 DST_RET(DST_R_INVALIDPRIVATEKEY); 554 pubkey = EC_KEY_get0_public_key(pubeckey); 555 if (pubkey == NULL) 556 DST_RET(DST_R_INVALIDPRIVATEKEY); 557 if (EC_KEY_set_public_key(eckey, pubkey) != 1) 558 DST_RET(DST_R_INVALIDPRIVATEKEY); 559 if (EC_KEY_check_key(eckey) != 1) 560 DST_RET(DST_R_INVALIDPRIVATEKEY); 561 } else { 562 privkey = BN_bin2bn(priv.elements[0].data, 563 priv.elements[0].length, NULL); 564 if (privkey == NULL) 565 DST_RET(ISC_R_NOMEMORY); 566 if (!EC_KEY_set_private_key(eckey, privkey)) 567 DST_RET(ISC_R_NOMEMORY); 568 if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) 569 DST_RET(DST_R_INVALIDPRIVATEKEY); 570 dst__privstruct_free(&priv, mctx); 571 memset(&priv, 0, sizeof(priv)); 572 } 573 574 pkey = EVP_PKEY_new(); 575 if (pkey == NULL) 576 DST_RET (ISC_R_NOMEMORY); 577 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 578 EVP_PKEY_free(pkey); 579 DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 580 } 581 key->keydata.pkey = pkey; 582 ret = ISC_R_SUCCESS; 583 584 err: 585 if (eckey != NULL) 586 EC_KEY_free(eckey); 587 if (pubeckey != NULL) 588 EC_KEY_free(pubeckey); 589 dst__privstruct_free(&priv, mctx); 590 memset(&priv, 0, sizeof(priv)); 591 return (ret); 592} 593 594static dst_func_t opensslecdsa_functions = { 595 opensslecdsa_createctx, 596 opensslecdsa_destroyctx, 597 opensslecdsa_adddata, 598 opensslecdsa_sign, 599 opensslecdsa_verify, 600 NULL, /*%< verify2 */ 601 NULL, /*%< computesecret */ 602 opensslecdsa_compare, 603 NULL, /*%< paramcompare */ 604 opensslecdsa_generate, 605 opensslecdsa_isprivate, 606 opensslecdsa_destroy, 607 opensslecdsa_todns, 608 opensslecdsa_fromdns, 609 opensslecdsa_tofile, 610 opensslecdsa_parse, 611 NULL, /*%< cleanup */ 612 NULL, /*%< fromlabel */ 613 NULL, /*%< dump */ 614 NULL, /*%< restore */ 615}; 616 617isc_result_t 618dst__opensslecdsa_init(dst_func_t **funcp) { 619 REQUIRE(funcp != NULL); 620 if (*funcp == NULL) 621 *funcp = &opensslecdsa_functions; 622 return (ISC_R_SUCCESS); 623} 624 625#else /* HAVE_OPENSSL_ECDSA */ 626 627#include <isc/util.h> 628 629EMPTY_TRANSLATION_UNIT 630 631#endif /* HAVE_OPENSSL_ECDSA */ 632/*! \file */ 633