1 /* $NetBSD: pkcs11gost_link.c,v 1.1.1.5 2015/07/08 15:38:01 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Id */ 20 21 #include <config.h> 22 23 #if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_GOST) 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 <dns/log.h> 33 #include <dst/result.h> 34 35 #include "dst_internal.h" 36 #include "dst_parse.h" 37 #include "dst_pkcs11.h" 38 #include "dst_gost.h" 39 40 #include <pk11/pk11.h> 41 #include <pk11/internal.h> 42 #define WANT_GOST_PARAMS 43 #include <pk11/constants.h> 44 45 #include <pkcs11/pkcs11.h> 46 47 /* 48 * RU CryptoPro GOST keys: 49 * mechanisms: 50 * CKM_GOSTR3411 51 * CKM_GOSTR3410_WITH_GOSTR3411 52 * CKM_GOSTR3410_KEY_PAIR_GEN 53 * domain parameters: 54 * CKA_GOSTR3410_PARAMS (fixed BER OID 1.2.643.2.2.35.1) 55 * CKA_GOSTR3411_PARAMS (fixed BER OID 1.2.643.2.2.30.1) 56 * CKA_GOST28147_PARAMS (optional, don't use) 57 * public keys: 58 * object class CKO_PUBLIC_KEY 59 * key type CKK_GOSTR3410 60 * attribute CKA_VALUE (point Q) 61 * attribute CKA_GOSTR3410_PARAMS 62 * attribute CKA_GOSTR3411_PARAMS 63 * attribute CKA_GOST28147_PARAMS 64 * private keys: 65 * object class CKO_PRIVATE_KEY 66 * key type CKK_GOSTR3410 67 * attribute CKA_VALUE (big int d) 68 * attribute CKA_GOSTR3410_PARAMS 69 * attribute CKA_GOSTR3411_PARAMS 70 * attribute CKA_GOST28147_PARAMS 71 * point format: <x> <y> (little endian) 72 */ 73 74 #define CKA_VALUE2 CKA_PRIVATE_EXPONENT 75 76 #define ISC_GOST_SIGNATURELENGTH 64 77 #define ISC_GOST_PUBKEYLENGTH 64 78 #define ISC_GOST_KEYSIZE 256 79 80 /* HASH methods */ 81 82 isc_result_t 83 isc_gost_init(isc_gost_t *ctx) { 84 CK_RV rv; 85 CK_MECHANISM mech = { CKM_GOSTR3411, NULL, 0 }; 86 int ret = ISC_R_SUCCESS; 87 88 ret = pk11_get_session(ctx, OP_GOST, ISC_TRUE, ISC_FALSE, 89 ISC_FALSE, NULL, 0); 90 if (ret != ISC_R_SUCCESS) 91 return (ret); 92 PK11_CALL(pkcs_C_DigestInit, (ctx->session, &mech), ISC_R_FAILURE); 93 return (ret); 94 } 95 96 void 97 isc_gost_invalidate(isc_gost_t *ctx) { 98 CK_BYTE garbage[ISC_GOST_DIGESTLENGTH]; 99 CK_ULONG len = ISC_GOST_DIGESTLENGTH; 100 101 if (ctx->handle == NULL) 102 return; 103 (void) pkcs_C_DigestFinal(ctx->session, garbage, &len); 104 memset(garbage, 0, sizeof(garbage)); 105 pk11_return_session(ctx); 106 } 107 108 isc_result_t 109 isc_gost_update(isc_gost_t *ctx, const unsigned char *buf, unsigned int len) { 110 CK_RV rv; 111 CK_BYTE_PTR pPart; 112 int ret = ISC_R_SUCCESS; 113 114 DE_CONST(buf, pPart); 115 PK11_CALL(pkcs_C_DigestUpdate, 116 (ctx->session, pPart, (CK_ULONG) len), 117 ISC_R_FAILURE); 118 return (ret); 119 } 120 121 isc_result_t 122 isc_gost_final(isc_gost_t *ctx, unsigned char *digest) { 123 CK_RV rv; 124 CK_ULONG len = ISC_GOST_DIGESTLENGTH; 125 int ret = ISC_R_SUCCESS; 126 127 PK11_CALL(pkcs_C_DigestFinal, 128 (ctx->session, (CK_BYTE_PTR) digest, &len), 129 ISC_R_FAILURE); 130 pk11_return_session(ctx); 131 return (ret); 132 } 133 134 /* DST methods */ 135 136 static CK_BBOOL truevalue = TRUE; 137 static CK_BBOOL falsevalue = FALSE; 138 139 #define DST_RET(a) {ret = a; goto err;} 140 141 static isc_result_t pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data); 142 static void pkcs11gost_destroy(dst_key_t *key); 143 144 static isc_result_t 145 pkcs11gost_createctx_sign(dst_key_t *key, dst_context_t *dctx) { 146 CK_RV rv; 147 CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 }; 148 CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; 149 CK_KEY_TYPE keyType = CKK_GOSTR3410; 150 CK_ATTRIBUTE keyTemplate[] = 151 { 152 { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, 153 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, 154 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 155 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 156 { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 157 { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, 158 { CKA_VALUE, NULL, 0 }, 159 { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, 160 (CK_ULONG) sizeof(pk11_gost_a_paramset) }, 161 { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, 162 (CK_ULONG) sizeof(pk11_gost_paramset) } 163 }; 164 CK_ATTRIBUTE *attr; 165 pk11_object_t *gost; 166 pk11_context_t *pk11_ctx; 167 isc_result_t ret; 168 unsigned int i; 169 170 pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, 171 sizeof(*pk11_ctx)); 172 if (pk11_ctx == NULL) 173 return (ISC_R_NOMEMORY); 174 ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE, 175 ISC_FALSE, NULL, pk11_get_best_token(OP_GOST)); 176 if (ret != ISC_R_SUCCESS) 177 goto err; 178 179 gost = key->keydata.pkey; 180 if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) { 181 pk11_ctx->ontoken = gost->ontoken; 182 pk11_ctx->object = gost->object; 183 goto token_key; 184 } 185 186 for (attr = pk11_attribute_first(gost); 187 attr != NULL; 188 attr = pk11_attribute_next(gost, attr)) 189 switch (attr->type) { 190 case CKA_VALUE2: 191 INSIST(keyTemplate[6].type == CKA_VALUE); 192 keyTemplate[6].pValue = isc_mem_get(dctx->mctx, 193 attr->ulValueLen); 194 if (keyTemplate[6].pValue == NULL) 195 DST_RET(ISC_R_NOMEMORY); 196 memmove(keyTemplate[6].pValue, attr->pValue, 197 attr->ulValueLen); 198 keyTemplate[6].ulValueLen = attr->ulValueLen; 199 break; 200 } 201 pk11_ctx->object = CK_INVALID_HANDLE; 202 pk11_ctx->ontoken = ISC_FALSE; 203 PK11_RET(pkcs_C_CreateObject, 204 (pk11_ctx->session, 205 keyTemplate, (CK_ULONG) 9, 206 &pk11_ctx->object), 207 ISC_R_FAILURE); 208 209 token_key: 210 211 PK11_RET(pkcs_C_SignInit, 212 (pk11_ctx->session, &mech, pk11_ctx->object), 213 ISC_R_FAILURE); 214 215 dctx->ctxdata.pk11_ctx = pk11_ctx; 216 217 for (i = 6; i <= 6; i++) 218 if (keyTemplate[i].pValue != NULL) { 219 memset(keyTemplate[i].pValue, 0, 220 keyTemplate[i].ulValueLen); 221 isc_mem_put(dctx->mctx, 222 keyTemplate[i].pValue, 223 keyTemplate[i].ulValueLen); 224 } 225 226 return (ISC_R_SUCCESS); 227 228 err: 229 if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) 230 (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object); 231 for (i = 6; i <= 6; i++) 232 if (keyTemplate[i].pValue != NULL) { 233 memset(keyTemplate[i].pValue, 0, 234 keyTemplate[i].ulValueLen); 235 isc_mem_put(dctx->mctx, 236 keyTemplate[i].pValue, 237 keyTemplate[i].ulValueLen); 238 } 239 pk11_return_session(pk11_ctx); 240 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 241 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); 242 243 return (ret); 244 } 245 246 static isc_result_t 247 pkcs11gost_createctx_verify(dst_key_t *key, dst_context_t *dctx) { 248 CK_RV rv; 249 CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 }; 250 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; 251 CK_KEY_TYPE keyType = CKK_GOSTR3410; 252 CK_ATTRIBUTE keyTemplate[] = 253 { 254 { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, 255 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, 256 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 257 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 258 { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, 259 { CKA_VALUE, NULL, 0 }, 260 { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, 261 (CK_ULONG) sizeof(pk11_gost_a_paramset) }, 262 { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, 263 (CK_ULONG) sizeof(pk11_gost_paramset) } 264 }; 265 CK_ATTRIBUTE *attr; 266 pk11_object_t *gost; 267 pk11_context_t *pk11_ctx; 268 isc_result_t ret; 269 unsigned int i; 270 271 pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, 272 sizeof(*pk11_ctx)); 273 if (pk11_ctx == NULL) 274 return (ISC_R_NOMEMORY); 275 ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE, 276 ISC_FALSE, NULL, pk11_get_best_token(OP_GOST)); 277 if (ret != ISC_R_SUCCESS) 278 goto err; 279 280 gost = key->keydata.pkey; 281 if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) { 282 pk11_ctx->ontoken = gost->ontoken; 283 pk11_ctx->object = gost->object; 284 goto token_key; 285 } 286 287 for (attr = pk11_attribute_first(gost); 288 attr != NULL; 289 attr = pk11_attribute_next(gost, attr)) 290 switch (attr->type) { 291 case CKA_VALUE: 292 INSIST(keyTemplate[5].type == attr->type); 293 keyTemplate[5].pValue = isc_mem_get(dctx->mctx, 294 attr->ulValueLen); 295 if (keyTemplate[5].pValue == NULL) 296 DST_RET(ISC_R_NOMEMORY); 297 memmove(keyTemplate[5].pValue, attr->pValue, 298 attr->ulValueLen); 299 keyTemplate[5].ulValueLen = attr->ulValueLen; 300 break; 301 } 302 pk11_ctx->object = CK_INVALID_HANDLE; 303 pk11_ctx->ontoken = ISC_FALSE; 304 PK11_RET(pkcs_C_CreateObject, 305 (pk11_ctx->session, 306 keyTemplate, (CK_ULONG) 8, 307 &pk11_ctx->object), 308 ISC_R_FAILURE); 309 310 token_key: 311 312 PK11_RET(pkcs_C_VerifyInit, 313 (pk11_ctx->session, &mech, pk11_ctx->object), 314 ISC_R_FAILURE); 315 316 dctx->ctxdata.pk11_ctx = pk11_ctx; 317 318 for (i = 5; i <= 5; i++) 319 if (keyTemplate[i].pValue != NULL) { 320 memset(keyTemplate[i].pValue, 0, 321 keyTemplate[i].ulValueLen); 322 isc_mem_put(dctx->mctx, 323 keyTemplate[i].pValue, 324 keyTemplate[i].ulValueLen); 325 } 326 327 return (ISC_R_SUCCESS); 328 329 err: 330 if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) 331 (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object); 332 for (i = 5; i <= 5; i++) 333 if (keyTemplate[i].pValue != NULL) { 334 memset(keyTemplate[i].pValue, 0, 335 keyTemplate[i].ulValueLen); 336 isc_mem_put(dctx->mctx, 337 keyTemplate[i].pValue, 338 keyTemplate[i].ulValueLen); 339 } 340 pk11_return_session(pk11_ctx); 341 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 342 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); 343 344 return (ret); 345 } 346 347 static isc_result_t 348 pkcs11gost_createctx(dst_key_t *key, dst_context_t *dctx) { 349 if (dctx->use == DO_SIGN) 350 return (pkcs11gost_createctx_sign(key, dctx)); 351 else 352 return (pkcs11gost_createctx_verify(key, dctx)); 353 } 354 355 static void 356 pkcs11gost_destroyctx(dst_context_t *dctx) { 357 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; 358 359 if (pk11_ctx != NULL) { 360 if (!pk11_ctx->ontoken && 361 (pk11_ctx->object != CK_INVALID_HANDLE)) 362 (void) pkcs_C_DestroyObject(pk11_ctx->session, 363 pk11_ctx->object); 364 pk11_return_session(pk11_ctx); 365 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 366 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); 367 dctx->ctxdata.pk11_ctx = NULL; 368 } 369 } 370 371 static isc_result_t 372 pkcs11gost_adddata(dst_context_t *dctx, const isc_region_t *data) { 373 CK_RV rv; 374 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; 375 isc_result_t ret = ISC_R_SUCCESS; 376 377 if (dctx->use == DO_SIGN) 378 PK11_CALL(pkcs_C_SignUpdate, 379 (pk11_ctx->session, 380 (CK_BYTE_PTR) data->base, 381 (CK_ULONG) data->length), 382 ISC_R_FAILURE); 383 else 384 PK11_CALL(pkcs_C_VerifyUpdate, 385 (pk11_ctx->session, 386 (CK_BYTE_PTR) data->base, 387 (CK_ULONG) data->length), 388 ISC_R_FAILURE); 389 return (ret); 390 } 391 392 static isc_result_t 393 pkcs11gost_sign(dst_context_t *dctx, isc_buffer_t *sig) { 394 CK_RV rv; 395 CK_ULONG siglen = ISC_GOST_SIGNATURELENGTH; 396 isc_region_t r; 397 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; 398 isc_result_t ret = ISC_R_SUCCESS; 399 400 isc_buffer_availableregion(sig, &r); 401 if (r.length < ISC_GOST_SIGNATURELENGTH) 402 return (ISC_R_NOSPACE); 403 404 PK11_RET(pkcs_C_SignFinal, 405 (pk11_ctx->session, (CK_BYTE_PTR) r.base, &siglen), 406 DST_R_SIGNFAILURE); 407 if (siglen != ISC_GOST_SIGNATURELENGTH) 408 return (DST_R_SIGNFAILURE); 409 410 isc_buffer_add(sig, ISC_GOST_SIGNATURELENGTH); 411 412 err: 413 return (ret); 414 } 415 416 static isc_result_t 417 pkcs11gost_verify(dst_context_t *dctx, const isc_region_t *sig) { 418 CK_RV rv; 419 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; 420 isc_result_t ret = ISC_R_SUCCESS; 421 422 PK11_CALL(pkcs_C_VerifyFinal, 423 (pk11_ctx->session, 424 (CK_BYTE_PTR) sig->base, 425 (CK_ULONG) sig->length), 426 DST_R_VERIFYFAILURE); 427 return (ret); 428 } 429 430 static isc_boolean_t 431 pkcs11gost_compare(const dst_key_t *key1, const dst_key_t *key2) { 432 pk11_object_t *gost1, *gost2; 433 CK_ATTRIBUTE *attr1, *attr2; 434 435 gost1 = key1->keydata.pkey; 436 gost2 = key2->keydata.pkey; 437 438 if ((gost1 == NULL) && (gost2 == NULL)) 439 return (ISC_TRUE); 440 else if ((gost1 == NULL) || (gost2 == NULL)) 441 return (ISC_FALSE); 442 443 attr1 = pk11_attribute_bytype(gost1, CKA_VALUE); 444 attr2 = pk11_attribute_bytype(gost2, CKA_VALUE); 445 if ((attr1 == NULL) && (attr2 == NULL)) 446 return (ISC_TRUE); 447 else if ((attr1 == NULL) || (attr2 == NULL) || 448 (attr1->ulValueLen != attr2->ulValueLen) || 449 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) 450 return (ISC_FALSE); 451 452 attr1 = pk11_attribute_bytype(gost1, CKA_VALUE2); 453 attr2 = pk11_attribute_bytype(gost2, CKA_VALUE2); 454 if (((attr1 != NULL) || (attr2 != NULL)) && 455 ((attr1 == NULL) || (attr2 == NULL) || 456 (attr1->ulValueLen != attr2->ulValueLen) || 457 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) 458 return (ISC_FALSE); 459 460 if (!gost1->ontoken && !gost2->ontoken) 461 return (ISC_TRUE); 462 else if (gost1->ontoken || gost2->ontoken || 463 (gost1->object != gost2->object)) 464 return (ISC_FALSE); 465 466 return (ISC_TRUE); 467 } 468 469 static isc_result_t 470 pkcs11gost_generate(dst_key_t *key, int unused, void (*callback)(int)) { 471 CK_RV rv; 472 CK_MECHANISM mech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL, 0 }; 473 CK_KEY_TYPE keyType = CKK_GOSTR3410; 474 CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; 475 CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; 476 CK_ATTRIBUTE pubTemplate[] = 477 { 478 { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, 479 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, 480 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 481 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 482 { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, 483 { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, 484 (CK_ULONG) sizeof(pk11_gost_a_paramset) }, 485 { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, 486 (CK_ULONG) sizeof(pk11_gost_paramset) } 487 }; 488 CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; 489 CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY; 490 CK_ATTRIBUTE privTemplate[] = 491 { 492 { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, 493 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, 494 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 495 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 496 { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, 497 { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, 498 { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, 499 }; 500 CK_ATTRIBUTE *attr; 501 pk11_object_t *gost; 502 pk11_context_t *pk11_ctx; 503 isc_result_t ret; 504 505 UNUSED(unused); 506 UNUSED(callback); 507 508 pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, 509 sizeof(*pk11_ctx)); 510 if (pk11_ctx == NULL) 511 return (ISC_R_NOMEMORY); 512 ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE, 513 ISC_FALSE, NULL, pk11_get_best_token(OP_GOST)); 514 if (ret != ISC_R_SUCCESS) 515 goto err; 516 517 PK11_RET(pkcs_C_GenerateKeyPair, 518 (pk11_ctx->session, &mech, 519 pubTemplate, (CK_ULONG) 7, 520 privTemplate, (CK_ULONG) 7, 521 &pub, &priv), 522 DST_R_CRYPTOFAILURE); 523 524 gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); 525 if (gost == NULL) 526 DST_RET(ISC_R_NOMEMORY); 527 memset(gost, 0, sizeof(*gost)); 528 key->keydata.pkey = gost; 529 key->key_size = ISC_GOST_KEYSIZE; 530 gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, 531 sizeof(*attr) * 2); 532 if (gost->repr == NULL) 533 DST_RET(ISC_R_NOMEMORY); 534 memset(gost->repr, 0, sizeof(*attr) * 2); 535 gost->attrcnt = 2; 536 537 attr = gost->repr; 538 attr[0].type = CKA_VALUE; 539 attr[1].type = CKA_VALUE2; 540 541 attr = gost->repr; 542 PK11_RET(pkcs_C_GetAttributeValue, 543 (pk11_ctx->session, pub, attr, 1), 544 DST_R_CRYPTOFAILURE); 545 attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); 546 if (attr->pValue == NULL) 547 DST_RET(ISC_R_NOMEMORY); 548 memset(attr->pValue, 0, attr->ulValueLen); 549 PK11_RET(pkcs_C_GetAttributeValue, 550 (pk11_ctx->session, pub, attr, 1), 551 DST_R_CRYPTOFAILURE); 552 553 attr++; 554 attr->type = CKA_VALUE; 555 PK11_RET(pkcs_C_GetAttributeValue, 556 (pk11_ctx->session, priv, attr, 1), 557 DST_R_CRYPTOFAILURE); 558 attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); 559 if (attr->pValue == NULL) 560 DST_RET(ISC_R_NOMEMORY); 561 memset(attr->pValue, 0, attr->ulValueLen); 562 PK11_RET(pkcs_C_GetAttributeValue, 563 (pk11_ctx->session, priv, attr, 1), 564 DST_R_CRYPTOFAILURE); 565 attr->type = CKA_VALUE2; 566 567 (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); 568 (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); 569 pk11_return_session(pk11_ctx); 570 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 571 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 572 573 return (ISC_R_SUCCESS); 574 575 err: 576 pkcs11gost_destroy(key); 577 if (priv != CK_INVALID_HANDLE) 578 (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); 579 if (pub != CK_INVALID_HANDLE) 580 (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); 581 pk11_return_session(pk11_ctx); 582 memset(pk11_ctx, 0, sizeof(*pk11_ctx)); 583 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); 584 585 return (ret); 586 } 587 588 static isc_boolean_t 589 pkcs11gost_isprivate(const dst_key_t *key) { 590 pk11_object_t *gost = key->keydata.pkey; 591 CK_ATTRIBUTE *attr; 592 593 if (gost == NULL) 594 return (ISC_FALSE); 595 attr = pk11_attribute_bytype(gost, CKA_VALUE2); 596 return (ISC_TF((attr != NULL) || gost->ontoken)); 597 } 598 599 static void 600 pkcs11gost_destroy(dst_key_t *key) { 601 pk11_object_t *gost = key->keydata.pkey; 602 CK_ATTRIBUTE *attr; 603 604 if (gost == NULL) 605 return; 606 607 INSIST((gost->object == CK_INVALID_HANDLE) || gost->ontoken); 608 609 for (attr = pk11_attribute_first(gost); 610 attr != NULL; 611 attr = pk11_attribute_next(gost, attr)) 612 switch (attr->type) { 613 case CKA_VALUE: 614 case CKA_VALUE2: 615 if (attr->pValue != NULL) { 616 memset(attr->pValue, 0, attr->ulValueLen); 617 isc_mem_put(key->mctx, 618 attr->pValue, 619 attr->ulValueLen); 620 } 621 break; 622 } 623 if (gost->repr != NULL) { 624 memset(gost->repr, 0, gost->attrcnt * sizeof(*attr)); 625 isc_mem_put(key->mctx, 626 gost->repr, 627 gost->attrcnt * sizeof(*attr)); 628 } 629 memset(gost, 0, sizeof(*gost)); 630 isc_mem_put(key->mctx, gost, sizeof(*gost)); 631 key->keydata.pkey = NULL; 632 } 633 634 static isc_result_t 635 pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data) { 636 pk11_object_t *gost; 637 isc_region_t r; 638 CK_ATTRIBUTE *attr; 639 640 REQUIRE(key->keydata.pkey != NULL); 641 642 gost = key->keydata.pkey; 643 attr = pk11_attribute_bytype(gost, CKA_VALUE); 644 if ((attr == NULL) || (attr->ulValueLen != ISC_GOST_PUBKEYLENGTH)) 645 return (ISC_R_FAILURE); 646 647 isc_buffer_availableregion(data, &r); 648 if (r.length < ISC_GOST_PUBKEYLENGTH) 649 return (ISC_R_NOSPACE); 650 memmove(r.base, (CK_BYTE_PTR) attr->pValue, ISC_GOST_PUBKEYLENGTH); 651 isc_buffer_add(data, ISC_GOST_PUBKEYLENGTH); 652 653 return (ISC_R_SUCCESS); 654 } 655 656 static isc_result_t 657 pkcs11gost_fromdns(dst_key_t *key, isc_buffer_t *data) { 658 pk11_object_t *gost; 659 isc_region_t r; 660 CK_ATTRIBUTE *attr; 661 662 isc_buffer_remainingregion(data, &r); 663 if (r.length == 0) 664 return (ISC_R_SUCCESS); 665 if (r.length != ISC_GOST_PUBKEYLENGTH) 666 return (DST_R_INVALIDPUBLICKEY); 667 668 gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); 669 if (gost == NULL) 670 return (ISC_R_NOMEMORY); 671 memset(gost, 0, sizeof(*gost)); 672 gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr)); 673 if (gost->repr == NULL) 674 goto nomemory; 675 gost->attrcnt = 1; 676 677 attr = gost->repr; 678 attr->type = CKA_VALUE; 679 attr->pValue = isc_mem_get(key->mctx, ISC_GOST_PUBKEYLENGTH); 680 if (attr->pValue == NULL) 681 goto nomemory; 682 memmove((CK_BYTE_PTR) attr->pValue, r.base, ISC_GOST_PUBKEYLENGTH); 683 attr->ulValueLen = ISC_GOST_PUBKEYLENGTH; 684 685 isc_buffer_forward(data, ISC_GOST_PUBKEYLENGTH); 686 key->keydata.pkey = gost; 687 key->key_size = ISC_GOST_KEYSIZE; 688 return (ISC_R_SUCCESS); 689 690 nomemory: 691 for (attr = pk11_attribute_first(gost); 692 attr != NULL; 693 attr = pk11_attribute_next(gost, attr)) 694 switch (attr->type) { 695 case CKA_VALUE: 696 if (attr->pValue != NULL) { 697 memset(attr->pValue, 0, attr->ulValueLen); 698 isc_mem_put(key->mctx, 699 attr->pValue, 700 attr->ulValueLen); 701 } 702 break; 703 } 704 if (gost->repr != NULL) { 705 memset(gost->repr, 0, gost->attrcnt * sizeof(*attr)); 706 isc_mem_put(key->mctx, 707 gost->repr, 708 gost->attrcnt * sizeof(*attr)); 709 } 710 memset(gost, 0, sizeof(*gost)); 711 isc_mem_put(key->mctx, gost, sizeof(*gost)); 712 return (ISC_R_NOMEMORY); 713 } 714 715 static unsigned char gost_private_der[39] = { 716 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, 717 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, 718 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 719 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 720 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20 721 }; 722 723 #ifdef PREFER_GOSTASN1 724 725 static isc_result_t 726 pkcs11gost_tofile(const dst_key_t *key, const char *directory) { 727 isc_result_t ret; 728 pk11_object_t *gost; 729 dst_private_t priv; 730 unsigned char *buf = NULL; 731 unsigned int i = 0; 732 CK_ATTRIBUTE *attr; 733 int adj; 734 735 if (key->keydata.pkey == NULL) 736 return (DST_R_NULLKEY); 737 738 if (key->external) { 739 priv.nelements = 0; 740 return (dst__privstruct_writefile(key, &priv, directory)); 741 } 742 743 gost = key->keydata.pkey; 744 attr = pk11_attribute_bytype(gost, CKA_VALUE2); 745 if (attr != NULL) { 746 buf = isc_mem_get(key->mctx, attr->ulValueLen + 39); 747 if (buf == NULL) 748 return (ISC_R_NOMEMORY); 749 priv.elements[i].tag = TAG_GOST_PRIVASN1; 750 priv.elements[i].length = 751 (unsigned short) attr->ulValueLen + 39; 752 memmove(buf, gost_private_der, 39); 753 memmove(buf + 39, attr->pValue, attr->ulValueLen); 754 adj = (int) attr->ulValueLen - 32; 755 if (adj != 0) { 756 buf[1] += adj; 757 buf[36] += adj; 758 buf[38] += adj; 759 } 760 priv.elements[i].data = buf; 761 i++; 762 } else 763 return (DST_R_CRYPTOFAILURE); 764 765 priv.nelements = i; 766 ret = dst__privstruct_writefile(key, &priv, directory); 767 768 if (buf != NULL) { 769 memset(buf, 0, attr->ulValueLen); 770 isc_mem_put(key->mctx, buf, attr->ulValueLen); 771 } 772 return (ret); 773 } 774 775 #else 776 777 static isc_result_t 778 pkcs11gost_tofile(const dst_key_t *key, const char *directory) { 779 isc_result_t ret; 780 pk11_object_t *gost; 781 dst_private_t priv; 782 unsigned char *buf = NULL; 783 unsigned int i = 0; 784 CK_ATTRIBUTE *attr; 785 786 if (key->keydata.pkey == NULL) 787 return (DST_R_NULLKEY); 788 789 if (key->external) { 790 priv.nelements = 0; 791 return (dst__privstruct_writefile(key, &priv, directory)); 792 } 793 794 gost = key->keydata.pkey; 795 attr = pk11_attribute_bytype(gost, CKA_VALUE2); 796 if (attr != NULL) { 797 buf = isc_mem_get(key->mctx, attr->ulValueLen); 798 if (buf == NULL) 799 return (ISC_R_NOMEMORY); 800 priv.elements[i].tag = TAG_GOST_PRIVRAW; 801 priv.elements[i].length = (unsigned short) attr->ulValueLen; 802 memmove(buf, attr->pValue, attr->ulValueLen); 803 priv.elements[i].data = buf; 804 i++; 805 } else 806 return (DST_R_CRYPTOFAILURE); 807 808 priv.nelements = i; 809 ret = dst__privstruct_writefile(key, &priv, directory); 810 811 if (buf != NULL) { 812 memset(buf, 0, attr->ulValueLen); 813 isc_mem_put(key->mctx, buf, attr->ulValueLen); 814 } 815 return (ret); 816 } 817 #endif 818 819 static isc_result_t 820 pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 821 dst_private_t priv; 822 isc_result_t ret; 823 pk11_object_t *gost = NULL; 824 CK_ATTRIBUTE *attr, *pattr; 825 isc_mem_t *mctx = key->mctx; 826 827 if ((pub == NULL) || (pub->keydata.pkey == NULL)) 828 DST_RET(DST_R_INVALIDPRIVATEKEY); 829 830 /* read private key file */ 831 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); 832 if (ret != ISC_R_SUCCESS) 833 return (ret); 834 835 if (key->external) { 836 if (priv.nelements != 0) 837 DST_RET(DST_R_INVALIDPRIVATEKEY); 838 839 key->keydata.pkey = pub->keydata.pkey; 840 pub->keydata.pkey = NULL; 841 key->key_size = pub->key_size; 842 843 dst__privstruct_free(&priv, mctx); 844 memset(&priv, 0, sizeof(priv)); 845 846 return (ISC_R_SUCCESS); 847 } 848 849 if (priv.elements[0].tag == TAG_GOST_PRIVASN1) { 850 int adj = (int) priv.elements[0].length - (39 + 32); 851 unsigned char buf[39]; 852 853 if ((adj > 0) || (adj < -31)) 854 DST_RET(DST_R_INVALIDPRIVATEKEY); 855 memmove(buf, gost_private_der, 39); 856 if (adj != 0) { 857 buf[1] += adj; 858 buf[36] += adj; 859 buf[38] += adj; 860 } 861 if (memcmp(priv.elements[0].data, buf, 39) != 0) 862 DST_RET(DST_R_INVALIDPRIVATEKEY); 863 priv.elements[0].tag = TAG_GOST_PRIVRAW; 864 priv.elements[0].length -= 39; 865 memmove(priv.elements[0].data, 866 priv.elements[0].data + 39, 867 32 + adj); 868 } 869 870 gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); 871 if (gost == NULL) 872 DST_RET(ISC_R_NOMEMORY); 873 memset(gost, 0, sizeof(*gost)); 874 key->keydata.pkey = gost; 875 key->key_size = ISC_GOST_KEYSIZE; 876 877 gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, 878 sizeof(*attr) * 2); 879 if (gost->repr == NULL) 880 DST_RET(ISC_R_NOMEMORY); 881 memset(gost->repr, 0, sizeof(*attr) * 2); 882 gost->attrcnt = 2; 883 884 attr = gost->repr; 885 attr->type = CKA_VALUE; 886 pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE); 887 INSIST(pattr != NULL); 888 attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); 889 if (attr->pValue == NULL) 890 DST_RET(ISC_R_NOMEMORY); 891 memmove(attr->pValue, pattr->pValue, pattr->ulValueLen); 892 attr->ulValueLen = pattr->ulValueLen; 893 894 attr++; 895 attr->type = CKA_VALUE2; 896 attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length); 897 if (attr->pValue == NULL) 898 DST_RET(ISC_R_NOMEMORY); 899 memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length); 900 attr->ulValueLen = priv.elements[0].length; 901 902 dst__privstruct_free(&priv, mctx); 903 memset(&priv, 0, sizeof(priv)); 904 905 return (ISC_R_SUCCESS); 906 907 err: 908 pkcs11gost_destroy(key); 909 dst__privstruct_free(&priv, mctx); 910 memset(&priv, 0, sizeof(priv)); 911 return (ret); 912 } 913 914 static dst_func_t pkcs11gost_functions = { 915 pkcs11gost_createctx, 916 NULL, /*%< createctx2 */ 917 pkcs11gost_destroyctx, 918 pkcs11gost_adddata, 919 pkcs11gost_sign, 920 pkcs11gost_verify, 921 NULL, /*%< verify2 */ 922 NULL, /*%< computesecret */ 923 pkcs11gost_compare, 924 NULL, /*%< paramcompare */ 925 pkcs11gost_generate, 926 pkcs11gost_isprivate, 927 pkcs11gost_destroy, 928 pkcs11gost_todns, 929 pkcs11gost_fromdns, 930 pkcs11gost_tofile, 931 pkcs11gost_parse, 932 NULL, /*%< cleanup */ 933 NULL, /*%< fromlabel */ 934 NULL, /*%< dump */ 935 NULL, /*%< restore */ 936 }; 937 938 isc_result_t 939 dst__pkcs11gost_init(dst_func_t **funcp) { 940 REQUIRE(funcp != NULL); 941 if (*funcp == NULL) 942 *funcp = &pkcs11gost_functions; 943 return (ISC_R_SUCCESS); 944 } 945 946 #else /* PKCS11CRYPTO && HAVE_PKCS11_GOST */ 947 948 #include <isc/util.h> 949 950 EMPTY_TRANSLATION_UNIT 951 952 #endif /* PKCS11CRYPTO && HAVE_PKCS11_GOST */ 953 /*! \file */ 954