1 /* $NetBSD: pkcs11eddsa_link.c,v 1.1 2024/02/18 20:57:33 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 USE_PKCS11 19 20 #include <stdbool.h> 21 22 #include <isc/mem.h> 23 #include <isc/safe.h> 24 #include <isc/string.h> 25 #include <isc/util.h> 26 27 #include <pk11/constants.h> 28 #include <pk11/internal.h> 29 #include <pk11/pk11.h> 30 #include <pkcs11/pkcs11.h> 31 32 #include <dns/keyvalues.h> 33 34 #include <dst/result.h> 35 36 #include "dst_internal.h" 37 #include "dst_parse.h" 38 #include "dst_pkcs11.h" 39 40 /* 41 * FIPS 186-3 EDDSA keys: 42 * mechanisms: 43 * CKM_EDDSA, 44 * CKM_EC_EDWARDS_KEY_PAIR_GEN 45 * domain parameters: 46 * CKA_EC_PARAMS (choice with OID namedCurve) 47 * public keys: 48 * object class CKO_PUBLIC_KEY 49 * key type CKK_EC_EDWARDS 50 * attribute CKA_EC_PARAMS (choice with OID namedCurve) 51 * attribute CKA_EC_POINT (big int A) 52 * private keys: 53 * object class CKO_PRIVATE_KEY 54 * key type CKK_EC_EDWARDS 55 * attribute CKA_EC_PARAMS (choice with OID namedCurve) 56 * attribute CKA_VALUE (big int k) 57 * point format: 0x04 (octet-string) <size> <A> 58 */ 59 60 #define TAG_OCTECT_STRING 0x04 61 62 #define DST_RET(a) \ 63 { \ 64 ret = a; \ 65 goto err; \ 66 } 67 68 static CK_BBOOL truevalue = TRUE; 69 static CK_BBOOL falsevalue = FALSE; 70 71 static void 72 pkcs11eddsa_destroy(dst_key_t *key); 73 74 static isc_result_t 75 pkcs11eddsa_createctx(dst_key_t *key, dst_context_t *dctx) { 76 isc_buffer_t *buf = NULL; 77 78 UNUSED(key); 79 REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 || 80 dctx->key->key_alg == DST_ALG_ED448); 81 82 isc_buffer_allocate(dctx->mctx, &buf, 16); 83 isc_buffer_setautorealloc(buf, true); 84 dctx->ctxdata.generic = buf; 85 86 return (ISC_R_SUCCESS); 87 } 88 89 static void 90 pkcs11eddsa_destroyctx(dst_context_t *dctx) { 91 isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; 92 93 REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 || 94 dctx->key->key_alg == DST_ALG_ED448); 95 if (buf != NULL) { 96 isc_buffer_free(&buf); 97 } 98 dctx->ctxdata.generic = NULL; 99 } 100 101 static isc_result_t 102 pkcs11eddsa_adddata(dst_context_t *dctx, const isc_region_t *data) { 103 isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; 104 isc_result_t result; 105 106 REQUIRE(dctx->key->key_alg == DST_ALG_ED25519 || 107 dctx->key->key_alg == DST_ALG_ED448); 108 109 result = isc_buffer_copyregion(buf, data); 110 INSIST(result == ISC_R_SUCCESS); 111 112 return (result); 113 } 114 115 static isc_result_t 116 pkcs11eddsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { 117 isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; 118 CK_RV rv; 119 CK_MECHANISM mech = { CKM_EDDSA, NULL, 0 }; 120 CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; 121 CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; 122 CK_KEY_TYPE keyType = CKK_EC_EDWARDS; 123 CK_ATTRIBUTE keyTemplate[] = { 124 { CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) }, 125 { CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) }, 126 { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 127 { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 128 { CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) }, 129 { CKA_EC_PARAMS, NULL, 0 }, 130 { CKA_VALUE, NULL, 0 } 131 }; 132 CK_ATTRIBUTE *attr; 133 CK_ULONG siglen; 134 CK_SLOT_ID slotid; 135 pk11_context_t *pk11_ctx; 136 dst_key_t *key = dctx->key; 137 pk11_object_t *ec = key->keydata.pkey; 138 isc_region_t t; 139 isc_region_t r; 140 isc_result_t ret = ISC_R_SUCCESS; 141 unsigned int i; 142 143 REQUIRE(key->key_alg == DST_ALG_ED25519 || 144 key->key_alg == DST_ALG_ED448); 145 REQUIRE(ec != NULL); 146 147 switch (key->key_alg) { 148 case DST_ALG_ED25519: 149 siglen = DNS_SIG_ED25519SIZE; 150 break; 151 case DST_ALG_ED448: 152 siglen = DNS_SIG_ED448SIZE; 153 break; 154 default: 155 UNREACHABLE(); 156 } 157 158 pk11_ctx = isc_mem_get(dctx->mctx, sizeof(*pk11_ctx)); 159 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 160 if (ec->ontoken && (dctx->use == DO_SIGN)) { 161 slotid = ec->slot; 162 } else { 163 slotid = pk11_get_best_token(OP_EDDSA); 164 } 165 ret = pk11_get_session(pk11_ctx, OP_EDDSA, true, false, ec->reqlogon, 166 NULL, slotid); 167 if (ret != ISC_R_SUCCESS) { 168 goto err; 169 } 170 171 isc_buffer_availableregion(sig, &r); 172 if (r.length < siglen) { 173 DST_RET(ISC_R_NOSPACE); 174 } 175 176 if (ec->ontoken && (ec->object != CK_INVALID_HANDLE)) { 177 pk11_ctx->ontoken = ec->ontoken; 178 pk11_ctx->object = ec->object; 179 goto token_key; 180 } 181 182 for (attr = pk11_attribute_first(ec); attr != NULL; 183 attr = pk11_attribute_next(ec, attr)) 184 { 185 switch (attr->type) { 186 case CKA_EC_PARAMS: 187 INSIST(keyTemplate[5].type == attr->type); 188 keyTemplate[5].pValue = isc_mem_get(dctx->mctx, 189 attr->ulValueLen); 190 memmove(keyTemplate[5].pValue, attr->pValue, 191 attr->ulValueLen); 192 keyTemplate[5].ulValueLen = attr->ulValueLen; 193 break; 194 case CKA_VALUE: 195 INSIST(keyTemplate[6].type == attr->type); 196 keyTemplate[6].pValue = isc_mem_get(dctx->mctx, 197 attr->ulValueLen); 198 memmove(keyTemplate[6].pValue, attr->pValue, 199 attr->ulValueLen); 200 keyTemplate[6].ulValueLen = attr->ulValueLen; 201 break; 202 } 203 } 204 pk11_ctx->object = CK_INVALID_HANDLE; 205 pk11_ctx->ontoken = false; 206 PK11_RET(pkcs_C_CreateObject, 207 (pk11_ctx->session, keyTemplate, (CK_ULONG)7, &hKey), 208 ISC_R_FAILURE); 209 210 token_key: 211 212 PK11_RET(pkcs_C_SignInit, 213 (pk11_ctx->session, &mech, 214 pk11_ctx->ontoken ? pk11_ctx->object : hKey), 215 ISC_R_FAILURE); 216 217 isc_buffer_usedregion(buf, &t); 218 219 PK11_RET(pkcs_C_Sign, 220 (pk11_ctx->session, (CK_BYTE_PTR)t.base, (CK_ULONG)t.length, 221 (CK_BYTE_PTR)r.base, &siglen), 222 DST_R_SIGNFAILURE); 223 224 isc_buffer_add(sig, (unsigned int)siglen); 225 226 err: 227 228 if (hKey != CK_INVALID_HANDLE) { 229 (void)pkcs_C_DestroyObject(pk11_ctx->session, hKey); 230 } 231 for (i = 5; i <= 6; i++) { 232 if (keyTemplate[i].pValue != NULL) { 233 { 234 memset(keyTemplate[i].pValue, 0, 235 keyTemplate[i].ulValueLen); 236 isc_mem_put(dctx->mctx, keyTemplate[i].pValue, 237 keyTemplate[i].ulValueLen); 238 } 239 } 240 } 241 pk11_return_session(pk11_ctx); 242 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 243 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); 244 isc_buffer_free(&buf); 245 dctx->ctxdata.generic = NULL; 246 247 return (ret); 248 } 249 250 static isc_result_t 251 pkcs11eddsa_verify(dst_context_t *dctx, const isc_region_t *sig) { 252 isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; 253 CK_RV rv; 254 CK_MECHANISM mech = { CKM_EDDSA, NULL, 0 }; 255 CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; 256 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; 257 CK_KEY_TYPE keyType = CKK_EC_EDWARDS; 258 CK_ATTRIBUTE keyTemplate[] = { 259 { CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) }, 260 { CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) }, 261 { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 262 { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 263 { CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) }, 264 { CKA_EC_PARAMS, NULL, 0 }, 265 { CKA_EC_POINT, NULL, 0 } 266 }; 267 CK_ATTRIBUTE *attr; 268 CK_SLOT_ID slotid; 269 pk11_context_t *pk11_ctx; 270 dst_key_t *key = dctx->key; 271 pk11_object_t *ec = key->keydata.pkey; 272 isc_region_t t; 273 isc_result_t ret = ISC_R_SUCCESS; 274 unsigned int i; 275 276 REQUIRE(key->key_alg == DST_ALG_ED25519 || 277 key->key_alg == DST_ALG_ED448); 278 REQUIRE(ec != NULL); 279 280 pk11_ctx = isc_mem_get(dctx->mctx, sizeof(*pk11_ctx)); 281 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 282 if (ec->ontoken && (dctx->use == DO_SIGN)) { 283 slotid = ec->slot; 284 } else { 285 slotid = pk11_get_best_token(OP_EDDSA); 286 } 287 ret = pk11_get_session(pk11_ctx, OP_EDDSA, true, false, ec->reqlogon, 288 NULL, slotid); 289 if (ret != ISC_R_SUCCESS) { 290 goto err; 291 } 292 293 for (attr = pk11_attribute_first(ec); attr != NULL; 294 attr = pk11_attribute_next(ec, attr)) 295 { 296 switch (attr->type) { 297 case CKA_EC_PARAMS: 298 INSIST(keyTemplate[5].type == attr->type); 299 keyTemplate[5].pValue = isc_mem_get(dctx->mctx, 300 attr->ulValueLen); 301 memmove(keyTemplate[5].pValue, attr->pValue, 302 attr->ulValueLen); 303 keyTemplate[5].ulValueLen = attr->ulValueLen; 304 break; 305 case CKA_EC_POINT: 306 INSIST(keyTemplate[6].type == attr->type); 307 keyTemplate[6].pValue = isc_mem_get(dctx->mctx, 308 attr->ulValueLen); 309 memmove(keyTemplate[6].pValue, attr->pValue, 310 attr->ulValueLen); 311 keyTemplate[6].ulValueLen = attr->ulValueLen; 312 break; 313 } 314 } 315 pk11_ctx->object = CK_INVALID_HANDLE; 316 pk11_ctx->ontoken = false; 317 PK11_RET(pkcs_C_CreateObject, 318 (pk11_ctx->session, keyTemplate, (CK_ULONG)7, &hKey), 319 ISC_R_FAILURE); 320 321 PK11_RET(pkcs_C_VerifyInit, (pk11_ctx->session, &mech, hKey), 322 ISC_R_FAILURE); 323 324 isc_buffer_usedregion(buf, &t); 325 326 PK11_RET(pkcs_C_Verify, 327 (pk11_ctx->session, (CK_BYTE_PTR)t.base, (CK_ULONG)t.length, 328 (CK_BYTE_PTR)sig->base, (CK_ULONG)sig->length), 329 DST_R_VERIFYFAILURE); 330 331 err: 332 333 if (hKey != CK_INVALID_HANDLE) { 334 (void)pkcs_C_DestroyObject(pk11_ctx->session, hKey); 335 } 336 for (i = 5; i <= 6; i++) { 337 if (keyTemplate[i].pValue != NULL) { 338 { 339 memset(keyTemplate[i].pValue, 0, 340 keyTemplate[i].ulValueLen); 341 isc_mem_put(dctx->mctx, keyTemplate[i].pValue, 342 keyTemplate[i].ulValueLen); 343 } 344 } 345 } 346 pk11_return_session(pk11_ctx); 347 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 348 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); 349 isc_buffer_free(&buf); 350 dctx->ctxdata.generic = NULL; 351 352 return (ret); 353 } 354 355 static bool 356 pkcs11eddsa_compare(const dst_key_t *key1, const dst_key_t *key2) { 357 pk11_object_t *ec1, *ec2; 358 CK_ATTRIBUTE *attr1, *attr2; 359 360 ec1 = key1->keydata.pkey; 361 ec2 = key2->keydata.pkey; 362 363 if ((ec1 == NULL) && (ec2 == NULL)) { 364 return (true); 365 } else if ((ec1 == NULL) || (ec2 == NULL)) { 366 return (false); 367 } 368 369 attr1 = pk11_attribute_bytype(ec1, CKA_EC_PARAMS); 370 attr2 = pk11_attribute_bytype(ec2, CKA_EC_PARAMS); 371 if ((attr1 == NULL) && (attr2 == NULL)) { 372 return (true); 373 } else if ((attr1 == NULL) || (attr2 == NULL) || 374 (attr1->ulValueLen != attr2->ulValueLen) || 375 !isc_safe_memequal(attr1->pValue, attr2->pValue, 376 attr1->ulValueLen)) 377 { 378 return (false); 379 } 380 381 attr1 = pk11_attribute_bytype(ec1, CKA_EC_POINT); 382 attr2 = pk11_attribute_bytype(ec2, CKA_EC_POINT); 383 if ((attr1 == NULL) && (attr2 == NULL)) { 384 return (true); 385 } else if ((attr1 == NULL) || (attr2 == NULL) || 386 (attr1->ulValueLen != attr2->ulValueLen) || 387 !isc_safe_memequal(attr1->pValue, attr2->pValue, 388 attr1->ulValueLen)) 389 { 390 return (false); 391 } 392 393 attr1 = pk11_attribute_bytype(ec1, CKA_VALUE); 394 attr2 = pk11_attribute_bytype(ec2, CKA_VALUE); 395 if (((attr1 != NULL) || (attr2 != NULL)) && 396 ((attr1 == NULL) || (attr2 == NULL) || 397 (attr1->ulValueLen != attr2->ulValueLen) || 398 !isc_safe_memequal(attr1->pValue, attr2->pValue, 399 attr1->ulValueLen))) 400 { 401 return (false); 402 } 403 404 if (!ec1->ontoken && !ec2->ontoken) { 405 return (true); 406 } else if (ec1->ontoken || ec2->ontoken || (ec1->object != ec2->object)) 407 { 408 return (false); 409 } 410 411 return (true); 412 } 413 414 #define SETCURVE() \ 415 switch (key->key_alg) { \ 416 case DST_ALG_ED25519: \ 417 attr->pValue = isc_mem_get(key->mctx, \ 418 sizeof(PK11_ECX_ED25519)); \ 419 memmove(attr->pValue, PK11_ECX_ED25519, \ 420 sizeof(PK11_ECX_ED25519)); \ 421 attr->ulValueLen = sizeof(PK11_ECX_ED25519); \ 422 break; \ 423 case DST_ALG_ED448: \ 424 attr->pValue = isc_mem_get(key->mctx, sizeof(PK11_ECX_ED448)); \ 425 memmove(attr->pValue, PK11_ECX_ED448, sizeof(PK11_ECX_ED448)); \ 426 attr->ulValueLen = sizeof(PK11_ECX_ED448); \ 427 break; \ 428 default: \ 429 UNREACHABLE(); \ 430 } 431 432 #define FREECURVE() \ 433 if (attr->pValue != NULL) { \ 434 memset(attr->pValue, 0, attr->ulValueLen); \ 435 isc_mem_put(key->mctx, attr->pValue, attr->ulValueLen); \ 436 attr->pValue = NULL; \ 437 } 438 439 static isc_result_t 440 pkcs11eddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { 441 CK_RV rv; 442 CK_MECHANISM mech = { CKM_EC_EDWARDS_KEY_PAIR_GEN, NULL, 0 }; 443 CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; 444 CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; 445 CK_KEY_TYPE keyType = CKK_EC_EDWARDS; 446 CK_ATTRIBUTE pubTemplate[] = { 447 { CKA_CLASS, &pubClass, (CK_ULONG)sizeof(pubClass) }, 448 { CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) }, 449 { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 450 { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 451 { CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) }, 452 { CKA_EC_PARAMS, NULL, 0 } 453 }; 454 CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; 455 CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY; 456 CK_ATTRIBUTE privTemplate[] = { 457 { CKA_CLASS, &privClass, (CK_ULONG)sizeof(privClass) }, 458 { CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) }, 459 { CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 460 { CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 461 { CKA_SENSITIVE, &falsevalue, (CK_ULONG)sizeof(falsevalue) }, 462 { CKA_EXTRACTABLE, &truevalue, (CK_ULONG)sizeof(truevalue) }, 463 { CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) } 464 }; 465 CK_ATTRIBUTE *attr; 466 pk11_object_t *ec; 467 pk11_context_t *pk11_ctx; 468 isc_result_t ret; 469 470 REQUIRE(key->key_alg == DST_ALG_ED25519 || 471 key->key_alg == DST_ALG_ED448); 472 UNUSED(unused); 473 UNUSED(callback); 474 475 pk11_ctx = isc_mem_get(key->mctx, sizeof(*pk11_ctx)); 476 ret = pk11_get_session(pk11_ctx, OP_EDDSA, true, false, false, NULL, 477 pk11_get_best_token(OP_EDDSA)); 478 if (ret != ISC_R_SUCCESS) { 479 goto err; 480 } 481 482 ec = isc_mem_get(key->mctx, sizeof(*ec)); 483 memset(ec, 0, sizeof(*ec)); 484 key->keydata.pkey = ec; 485 ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 3); 486 memset(ec->repr, 0, sizeof(*attr) * 3); 487 ec->attrcnt = 3; 488 489 attr = ec->repr; 490 attr[0].type = CKA_EC_PARAMS; 491 attr[1].type = CKA_EC_POINT; 492 attr[2].type = CKA_VALUE; 493 494 attr = &pubTemplate[5]; 495 SETCURVE(); 496 497 PK11_RET(pkcs_C_GenerateKeyPair, 498 (pk11_ctx->session, &mech, pubTemplate, (CK_ULONG)6, 499 privTemplate, (CK_ULONG)7, &pub, &priv), 500 DST_R_CRYPTOFAILURE); 501 502 attr = &pubTemplate[5]; 503 FREECURVE(); 504 505 attr = ec->repr; 506 SETCURVE(); 507 508 attr++; 509 PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, pub, attr, 1), 510 DST_R_CRYPTOFAILURE); 511 attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); 512 memset(attr->pValue, 0, attr->ulValueLen); 513 PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, pub, attr, 1), 514 DST_R_CRYPTOFAILURE); 515 516 attr++; 517 PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, priv, attr, 1), 518 DST_R_CRYPTOFAILURE); 519 attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); 520 memset(attr->pValue, 0, attr->ulValueLen); 521 PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, priv, attr, 1), 522 DST_R_CRYPTOFAILURE); 523 524 (void)pkcs_C_DestroyObject(pk11_ctx->session, priv); 525 (void)pkcs_C_DestroyObject(pk11_ctx->session, pub); 526 pk11_return_session(pk11_ctx); 527 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 528 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 529 530 switch (key->key_alg) { 531 case DST_ALG_ED25519: 532 key->key_size = DNS_KEY_ED25519SIZE * 8; 533 break; 534 case DST_ALG_ED448: 535 key->key_size = DNS_KEY_ED448SIZE * 8; 536 break; 537 default: 538 UNREACHABLE(); 539 } 540 541 return (ISC_R_SUCCESS); 542 543 err: 544 pkcs11eddsa_destroy(key); 545 if (priv != CK_INVALID_HANDLE) { 546 (void)pkcs_C_DestroyObject(pk11_ctx->session, priv); 547 } 548 if (pub != CK_INVALID_HANDLE) { 549 (void)pkcs_C_DestroyObject(pk11_ctx->session, pub); 550 } 551 pk11_return_session(pk11_ctx); 552 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 553 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 554 555 return (ret); 556 } 557 558 static bool 559 pkcs11eddsa_isprivate(const dst_key_t *key) { 560 pk11_object_t *ec = key->keydata.pkey; 561 CK_ATTRIBUTE *attr; 562 563 if (ec == NULL) { 564 return (false); 565 } 566 attr = pk11_attribute_bytype(ec, CKA_VALUE); 567 return (attr != NULL || ec->ontoken); 568 } 569 570 static void 571 pkcs11eddsa_destroy(dst_key_t *key) { 572 pk11_object_t *ec = key->keydata.pkey; 573 CK_ATTRIBUTE *attr; 574 575 if (ec == NULL) { 576 return; 577 } 578 579 INSIST((ec->object == CK_INVALID_HANDLE) || ec->ontoken); 580 581 for (attr = pk11_attribute_first(ec); attr != NULL; 582 attr = pk11_attribute_next(ec, attr)) 583 { 584 switch (attr->type) { 585 case CKA_LABEL: 586 case CKA_ID: 587 case CKA_EC_PARAMS: 588 case CKA_EC_POINT: 589 case CKA_VALUE: 590 FREECURVE(); 591 break; 592 } 593 } 594 if (ec->repr != NULL) { 595 memset(ec->repr, 0, ec->attrcnt * sizeof(*attr)); 596 isc_mem_put(key->mctx, ec->repr, ec->attrcnt * sizeof(*attr)); 597 } 598 memset(ec, 0, sizeof(*ec)); 599 isc_mem_put(key->mctx, ec, sizeof(*ec)); 600 key->keydata.pkey = NULL; 601 } 602 603 static isc_result_t 604 pkcs11eddsa_todns(const dst_key_t *key, isc_buffer_t *data) { 605 pk11_object_t *ec; 606 isc_region_t r; 607 unsigned int len; 608 CK_ATTRIBUTE *attr; 609 610 REQUIRE(key->keydata.pkey != NULL); 611 612 switch (key->key_alg) { 613 case DST_ALG_ED25519: 614 len = DNS_KEY_ED25519SIZE; 615 break; 616 case DST_ALG_ED448: 617 len = DNS_KEY_ED448SIZE; 618 break; 619 default: 620 UNREACHABLE(); 621 } 622 623 ec = key->keydata.pkey; 624 attr = pk11_attribute_bytype(ec, CKA_EC_POINT); 625 if ((attr == NULL) || (attr->ulValueLen != len + 2) || 626 (((CK_BYTE_PTR)attr->pValue)[0] != TAG_OCTECT_STRING) || 627 (((CK_BYTE_PTR)attr->pValue)[1] != len)) 628 { 629 return (ISC_R_FAILURE); 630 } 631 632 isc_buffer_availableregion(data, &r); 633 if (r.length < len) { 634 return (ISC_R_NOSPACE); 635 } 636 memmove(r.base, (CK_BYTE_PTR)attr->pValue + 2, len); 637 isc_buffer_add(data, len); 638 639 return (ISC_R_SUCCESS); 640 } 641 642 static isc_result_t 643 pkcs11eddsa_fromdns(dst_key_t *key, isc_buffer_t *data) { 644 pk11_object_t *ec; 645 isc_region_t r; 646 unsigned int len; 647 CK_ATTRIBUTE *attr; 648 649 REQUIRE(key->key_alg == DST_ALG_ED25519 || 650 key->key_alg == DST_ALG_ED448); 651 652 switch (key->key_alg) { 653 case DST_ALG_ED25519: 654 len = DNS_KEY_ED25519SIZE; 655 break; 656 case DST_ALG_ED448: 657 len = DNS_KEY_ED448SIZE; 658 break; 659 default: 660 UNREACHABLE(); 661 } 662 663 isc_buffer_remainingregion(data, &r); 664 if (r.length == 0) { 665 return (ISC_R_SUCCESS); 666 } 667 if (r.length != len) { 668 return (DST_R_INVALIDPUBLICKEY); 669 } 670 671 ec = isc_mem_get(key->mctx, sizeof(*ec)); 672 memset(ec, 0, sizeof(*ec)); 673 ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 2); 674 ec->attrcnt = 2; 675 676 attr = ec->repr; 677 attr->type = CKA_EC_PARAMS; 678 SETCURVE(); 679 680 attr++; 681 attr->type = CKA_EC_POINT; 682 attr->pValue = isc_mem_get(key->mctx, len + 2); 683 ((CK_BYTE_PTR)attr->pValue)[0] = TAG_OCTECT_STRING; 684 ((CK_BYTE_PTR)attr->pValue)[1] = len; 685 memmove((CK_BYTE_PTR)attr->pValue + 2, r.base, len); 686 attr->ulValueLen = len + 2; 687 688 isc_buffer_forward(data, len); 689 key->keydata.pkey = ec; 690 key->key_size = len * 8; 691 692 return (ISC_R_SUCCESS); 693 } 694 695 static isc_result_t 696 pkcs11eddsa_tofile(const dst_key_t *key, const char *directory) { 697 isc_result_t ret; 698 pk11_object_t *ec; 699 dst_private_t priv; 700 unsigned char *buf = NULL; 701 unsigned int i = 0; 702 CK_ATTRIBUTE *attr; 703 704 if (key->keydata.pkey == NULL) { 705 return (DST_R_NULLKEY); 706 } 707 708 if (key->external) { 709 priv.nelements = 0; 710 return (dst__privstruct_writefile(key, &priv, directory)); 711 } 712 713 ec = key->keydata.pkey; 714 attr = pk11_attribute_bytype(ec, CKA_VALUE); 715 if (attr != NULL) { 716 buf = isc_mem_get(key->mctx, attr->ulValueLen); 717 priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY; 718 priv.elements[i].length = (unsigned short)attr->ulValueLen; 719 memmove(buf, attr->pValue, attr->ulValueLen); 720 priv.elements[i].data = buf; 721 i++; 722 } 723 724 if (key->engine != NULL) { 725 priv.elements[i].tag = TAG_EDDSA_ENGINE; 726 priv.elements[i].length = strlen(key->engine) + 1; 727 priv.elements[i].data = (unsigned char *)key->engine; 728 i++; 729 } 730 731 if (key->label != NULL) { 732 priv.elements[i].tag = TAG_EDDSA_LABEL; 733 priv.elements[i].length = strlen(key->label) + 1; 734 priv.elements[i].data = (unsigned char *)key->label; 735 i++; 736 } 737 738 priv.nelements = i; 739 ret = dst__privstruct_writefile(key, &priv, directory); 740 741 if (buf != NULL) { 742 memset(buf, 0, attr->ulValueLen); 743 isc_mem_put(key->mctx, buf, attr->ulValueLen); 744 } 745 return (ret); 746 } 747 748 static isc_result_t 749 pkcs11eddsa_fetch(dst_key_t *key, const char *engine, const char *label, 750 dst_key_t *pub) { 751 CK_RV rv; 752 CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; 753 CK_KEY_TYPE keyType = CKK_EC_EDWARDS; 754 CK_ATTRIBUTE searchTemplate[] = { 755 { CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) }, 756 { CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) }, 757 { CKA_TOKEN, &truevalue, (CK_ULONG)sizeof(truevalue) }, 758 { CKA_LABEL, NULL, 0 } 759 }; 760 CK_ULONG cnt; 761 CK_ATTRIBUTE *attr; 762 CK_ATTRIBUTE *pubattr; 763 pk11_object_t *ec; 764 pk11_object_t *pubec; 765 pk11_context_t *pk11_ctx = NULL; 766 isc_result_t ret; 767 768 if (label == NULL) { 769 return (DST_R_NOENGINE); 770 } 771 772 ec = key->keydata.pkey; 773 pubec = pub->keydata.pkey; 774 775 ec->object = CK_INVALID_HANDLE; 776 ec->ontoken = true; 777 ec->reqlogon = true; 778 ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 2); 779 memset(ec->repr, 0, sizeof(*attr) * 2); 780 ec->attrcnt = 2; 781 attr = ec->repr; 782 783 attr->type = CKA_EC_PARAMS; 784 pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS); 785 INSIST(pubattr != NULL); 786 attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); 787 memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen); 788 attr->ulValueLen = pubattr->ulValueLen; 789 attr++; 790 791 attr->type = CKA_EC_POINT; 792 pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT); 793 INSIST(pubattr != NULL); 794 attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); 795 memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen); 796 attr->ulValueLen = pubattr->ulValueLen; 797 798 ret = pk11_parse_uri(ec, label, key->mctx, OP_EDDSA); 799 if (ret != ISC_R_SUCCESS) { 800 goto err; 801 } 802 803 pk11_ctx = isc_mem_get(key->mctx, sizeof(*pk11_ctx)); 804 ret = pk11_get_session(pk11_ctx, OP_EDDSA, true, false, ec->reqlogon, 805 NULL, ec->slot); 806 if (ret != ISC_R_SUCCESS) { 807 goto err; 808 } 809 810 attr = pk11_attribute_bytype(ec, CKA_LABEL); 811 if (attr == NULL) { 812 attr = pk11_attribute_bytype(ec, CKA_ID); 813 INSIST(attr != NULL); 814 searchTemplate[3].type = CKA_ID; 815 } 816 searchTemplate[3].pValue = attr->pValue; 817 searchTemplate[3].ulValueLen = attr->ulValueLen; 818 819 PK11_RET(pkcs_C_FindObjectsInit, 820 (pk11_ctx->session, searchTemplate, (CK_ULONG)4), 821 DST_R_CRYPTOFAILURE); 822 PK11_RET(pkcs_C_FindObjects, 823 (pk11_ctx->session, &ec->object, (CK_ULONG)1, &cnt), 824 DST_R_CRYPTOFAILURE); 825 (void)pkcs_C_FindObjectsFinal(pk11_ctx->session); 826 if (cnt == 0) { 827 DST_RET(ISC_R_NOTFOUND); 828 } 829 if (cnt > 1) { 830 DST_RET(ISC_R_EXISTS); 831 } 832 833 if (engine != NULL) { 834 key->engine = isc_mem_strdup(key->mctx, engine); 835 } 836 837 key->label = isc_mem_strdup(key->mctx, label); 838 839 pk11_return_session(pk11_ctx); 840 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 841 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 842 return (ISC_R_SUCCESS); 843 844 err: 845 if (pk11_ctx != NULL) { 846 pk11_return_session(pk11_ctx); 847 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 848 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 849 } 850 return (ret); 851 } 852 853 static isc_result_t 854 pkcs11eddsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 855 dst_private_t priv; 856 isc_result_t ret; 857 pk11_object_t *ec = NULL; 858 CK_ATTRIBUTE *attr, *pattr; 859 isc_mem_t *mctx = key->mctx; 860 unsigned int i; 861 const char *engine = NULL, *label = NULL; 862 863 REQUIRE(key->key_alg == DST_ALG_ED25519 || 864 key->key_alg == DST_ALG_ED448); 865 866 if ((pub == NULL) || (pub->keydata.pkey == NULL)) { 867 DST_RET(DST_R_INVALIDPRIVATEKEY); 868 } 869 870 /* read private key file */ 871 ret = dst__privstruct_parse(key, DST_ALG_ED25519, lexer, mctx, &priv); 872 if (ret != ISC_R_SUCCESS) { 873 return (ret); 874 } 875 876 if (key->external) { 877 if (priv.nelements != 0) { 878 DST_RET(DST_R_INVALIDPRIVATEKEY); 879 } 880 881 key->keydata.pkey = pub->keydata.pkey; 882 pub->keydata.pkey = NULL; 883 key->key_size = pub->key_size; 884 885 dst__privstruct_free(&priv, mctx); 886 memset(&priv, 0, sizeof(priv)); 887 888 return (ISC_R_SUCCESS); 889 } 890 891 for (i = 0; i < priv.nelements; i++) { 892 switch (priv.elements[i].tag) { 893 case TAG_EDDSA_ENGINE: 894 engine = (char *)priv.elements[i].data; 895 break; 896 case TAG_EDDSA_LABEL: 897 label = (char *)priv.elements[i].data; 898 break; 899 default: 900 break; 901 } 902 } 903 ec = isc_mem_get(key->mctx, sizeof(*ec)); 904 memset(ec, 0, sizeof(*ec)); 905 key->keydata.pkey = ec; 906 907 /* Is this key is stored in a HSM? See if we can fetch it. */ 908 if ((label != NULL) || (engine != NULL)) { 909 ret = pkcs11eddsa_fetch(key, engine, label, pub); 910 if (ret != ISC_R_SUCCESS) { 911 goto err; 912 } 913 dst__privstruct_free(&priv, mctx); 914 memset(&priv, 0, sizeof(priv)); 915 return (ret); 916 } 917 918 ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 3); 919 memset(ec->repr, 0, sizeof(*attr) * 3); 920 ec->attrcnt = 3; 921 922 attr = ec->repr; 923 attr->type = CKA_EC_PARAMS; 924 pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_PARAMS); 925 INSIST(pattr != NULL); 926 attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); 927 memmove(attr->pValue, pattr->pValue, pattr->ulValueLen); 928 attr->ulValueLen = pattr->ulValueLen; 929 930 attr++; 931 attr->type = CKA_EC_POINT; 932 pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_POINT); 933 INSIST(pattr != NULL); 934 attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); 935 memmove(attr->pValue, pattr->pValue, pattr->ulValueLen); 936 attr->ulValueLen = pattr->ulValueLen; 937 938 attr++; 939 attr->type = CKA_VALUE; 940 attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length); 941 memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length); 942 attr->ulValueLen = priv.elements[0].length; 943 944 dst__privstruct_free(&priv, mctx); 945 memset(&priv, 0, sizeof(priv)); 946 switch (key->key_alg) { 947 case DST_ALG_ED25519: 948 key->key_size = DNS_KEY_ED25519SIZE * 8; 949 break; 950 case DST_ALG_ED448: 951 key->key_size = DNS_KEY_ED448SIZE * 8; 952 break; 953 default: 954 UNREACHABLE(); 955 } 956 957 return (ISC_R_SUCCESS); 958 959 err: 960 pkcs11eddsa_destroy(key); 961 dst__privstruct_free(&priv, mctx); 962 memset(&priv, 0, sizeof(priv)); 963 return (ret); 964 } 965 966 static isc_result_t 967 pkcs11eddsa_fromlabel(dst_key_t *key, const char *engine, const char *label, 968 const char *pin) { 969 CK_RV rv; 970 CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; 971 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; 972 CK_KEY_TYPE keyType = CKK_EC_EDWARDS; 973 CK_ATTRIBUTE searchTemplate[] = { 974 { CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) }, 975 { CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) }, 976 { CKA_TOKEN, &truevalue, (CK_ULONG)sizeof(truevalue) }, 977 { CKA_LABEL, NULL, 0 } 978 }; 979 CK_ULONG cnt; 980 CK_ATTRIBUTE *attr; 981 pk11_object_t *ec; 982 pk11_context_t *pk11_ctx = NULL; 983 isc_result_t ret; 984 unsigned int i; 985 986 UNUSED(pin); 987 988 ec = isc_mem_get(key->mctx, sizeof(*ec)); 989 memset(ec, 0, sizeof(*ec)); 990 ec->object = CK_INVALID_HANDLE; 991 ec->ontoken = true; 992 ec->reqlogon = true; 993 key->keydata.pkey = ec; 994 995 ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 2); 996 memset(ec->repr, 0, sizeof(*attr) * 2); 997 ec->attrcnt = 2; 998 attr = ec->repr; 999 attr[0].type = CKA_EC_PARAMS; 1000 attr[1].type = CKA_EC_POINT; 1001 1002 ret = pk11_parse_uri(ec, label, key->mctx, OP_EDDSA); 1003 if (ret != ISC_R_SUCCESS) { 1004 goto err; 1005 } 1006 1007 pk11_ctx = isc_mem_get(key->mctx, sizeof(*pk11_ctx)); 1008 ret = pk11_get_session(pk11_ctx, OP_EDDSA, true, false, ec->reqlogon, 1009 NULL, ec->slot); 1010 if (ret != ISC_R_SUCCESS) { 1011 goto err; 1012 } 1013 1014 attr = pk11_attribute_bytype(ec, CKA_LABEL); 1015 if (attr == NULL) { 1016 attr = pk11_attribute_bytype(ec, CKA_ID); 1017 INSIST(attr != NULL); 1018 searchTemplate[3].type = CKA_ID; 1019 } 1020 searchTemplate[3].pValue = attr->pValue; 1021 searchTemplate[3].ulValueLen = attr->ulValueLen; 1022 1023 PK11_RET(pkcs_C_FindObjectsInit, 1024 (pk11_ctx->session, searchTemplate, (CK_ULONG)4), 1025 DST_R_CRYPTOFAILURE); 1026 PK11_RET(pkcs_C_FindObjects, 1027 (pk11_ctx->session, &hKey, (CK_ULONG)1, &cnt), 1028 DST_R_CRYPTOFAILURE); 1029 (void)pkcs_C_FindObjectsFinal(pk11_ctx->session); 1030 if (cnt == 0) { 1031 DST_RET(ISC_R_NOTFOUND); 1032 } 1033 if (cnt > 1) { 1034 DST_RET(ISC_R_EXISTS); 1035 } 1036 1037 attr = ec->repr; 1038 PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, hKey, attr, 2), 1039 DST_R_CRYPTOFAILURE); 1040 for (i = 0; i <= 1; i++) { 1041 attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); 1042 memset(attr[i].pValue, 0, attr[i].ulValueLen); 1043 } 1044 PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, hKey, attr, 2), 1045 DST_R_CRYPTOFAILURE); 1046 1047 keyClass = CKO_PRIVATE_KEY; 1048 PK11_RET(pkcs_C_FindObjectsInit, 1049 (pk11_ctx->session, searchTemplate, (CK_ULONG)4), 1050 DST_R_CRYPTOFAILURE); 1051 PK11_RET(pkcs_C_FindObjects, 1052 (pk11_ctx->session, &ec->object, (CK_ULONG)1, &cnt), 1053 DST_R_CRYPTOFAILURE); 1054 (void)pkcs_C_FindObjectsFinal(pk11_ctx->session); 1055 if (cnt == 0) { 1056 DST_RET(ISC_R_NOTFOUND); 1057 } 1058 if (cnt > 1) { 1059 DST_RET(ISC_R_EXISTS); 1060 } 1061 1062 if (engine != NULL) { 1063 key->engine = isc_mem_strdup(key->mctx, engine); 1064 } 1065 1066 key->label = isc_mem_strdup(key->mctx, label); 1067 switch (key->key_alg) { 1068 case DST_ALG_ED25519: 1069 key->key_size = DNS_KEY_ED25519SIZE * 8; 1070 break; 1071 case DST_ALG_ED448: 1072 key->key_size = DNS_KEY_ED448SIZE * 8; 1073 break; 1074 default: 1075 UNREACHABLE(); 1076 } 1077 1078 pk11_return_session(pk11_ctx); 1079 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 1080 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 1081 return (ISC_R_SUCCESS); 1082 1083 err: 1084 pkcs11eddsa_destroy(key); 1085 if (pk11_ctx != NULL) { 1086 pk11_return_session(pk11_ctx); 1087 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 1088 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 1089 } 1090 return (ret); 1091 } 1092 1093 static dst_func_t pkcs11eddsa_functions = { 1094 pkcs11eddsa_createctx, 1095 NULL, /*%< createctx2 */ 1096 pkcs11eddsa_destroyctx, 1097 pkcs11eddsa_adddata, 1098 pkcs11eddsa_sign, 1099 pkcs11eddsa_verify, 1100 NULL, /*%< verify2 */ 1101 NULL, /*%< computesecret */ 1102 pkcs11eddsa_compare, 1103 NULL, /*%< paramcompare */ 1104 pkcs11eddsa_generate, 1105 pkcs11eddsa_isprivate, 1106 pkcs11eddsa_destroy, 1107 pkcs11eddsa_todns, 1108 pkcs11eddsa_fromdns, 1109 pkcs11eddsa_tofile, 1110 pkcs11eddsa_parse, 1111 NULL, /*%< cleanup */ 1112 pkcs11eddsa_fromlabel, 1113 NULL, /*%< dump */ 1114 NULL, /*%< restore */ 1115 }; 1116 1117 isc_result_t 1118 dst__pkcs11eddsa_init(dst_func_t **funcp) { 1119 REQUIRE(funcp != NULL); 1120 if (*funcp == NULL) { 1121 *funcp = &pkcs11eddsa_functions; 1122 } 1123 return (ISC_R_SUCCESS); 1124 } 1125 1126 #endif /* USE_PKCS11 */ 1127