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