00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_GOST)
00022
00023 #include <isc/entropy.h>
00024 #include <isc/mem.h>
00025 #include <isc/sha2.h>
00026 #include <isc/string.h>
00027 #include <isc/util.h>
00028
00029 #include <dns/keyvalues.h>
00030 #include <dns/log.h>
00031 #include <dst/result.h>
00032
00033 #include "dst_internal.h"
00034 #include "dst_parse.h"
00035 #include "dst_pkcs11.h"
00036 #include "dst_gost.h"
00037
00038 #include <pk11/pk11.h>
00039 #include <pk11/internal.h>
00040 #define WANT_GOST_PARAMS
00041 #include <pk11/constants.h>
00042
00043 #include <pkcs11/pkcs11.h>
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 #define CKA_VALUE2 CKA_PRIVATE_EXPONENT
00073
00074 #define ISC_GOST_SIGNATURELENGTH 64
00075 #define ISC_GOST_PUBKEYLENGTH 64
00076 #define ISC_GOST_KEYSIZE 256
00077
00078
00079
00080 isc_result_t
00081 isc_gost_init(isc_gost_t *ctx) {
00082 CK_RV rv;
00083 CK_MECHANISM mech = { CKM_GOSTR3411, NULL, 0 };
00084 int ret = ISC_R_SUCCESS;
00085
00086 ret = pk11_get_session(ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
00087 ISC_FALSE, NULL, 0);
00088 if (ret != ISC_R_SUCCESS)
00089 return (ret);
00090 PK11_CALL(pkcs_C_DigestInit, (ctx->session, &mech), ISC_R_FAILURE);
00091 return (ret);
00092 }
00093
00094 void
00095 isc_gost_invalidate(isc_gost_t *ctx) {
00096 CK_BYTE garbage[ISC_GOST_DIGESTLENGTH];
00097 CK_ULONG len = ISC_GOST_DIGESTLENGTH;
00098
00099 if (ctx->handle == NULL)
00100 return;
00101 (void) pkcs_C_DigestFinal(ctx->session, garbage, &len);
00102 memset(garbage, 0, sizeof(garbage));
00103 pk11_return_session(ctx);
00104 }
00105
00106 isc_result_t
00107 isc_gost_update(isc_gost_t *ctx, const unsigned char *buf, unsigned int len) {
00108 CK_RV rv;
00109 CK_BYTE_PTR pPart;
00110 int ret = ISC_R_SUCCESS;
00111
00112 DE_CONST(buf, pPart);
00113 PK11_CALL(pkcs_C_DigestUpdate,
00114 (ctx->session, pPart, (CK_ULONG) len),
00115 ISC_R_FAILURE);
00116 return (ret);
00117 }
00118
00119 isc_result_t
00120 isc_gost_final(isc_gost_t *ctx, unsigned char *digest) {
00121 CK_RV rv;
00122 CK_ULONG len = ISC_GOST_DIGESTLENGTH;
00123 int ret = ISC_R_SUCCESS;
00124
00125 PK11_CALL(pkcs_C_DigestFinal,
00126 (ctx->session, (CK_BYTE_PTR) digest, &len),
00127 ISC_R_FAILURE);
00128 pk11_return_session(ctx);
00129 return (ret);
00130 }
00131
00132
00133
00134 static CK_BBOOL truevalue = TRUE;
00135 static CK_BBOOL falsevalue = FALSE;
00136
00137 #define DST_RET(a) {ret = a; goto err;}
00138
00139 static isc_result_t pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data);
00140 static void pkcs11gost_destroy(dst_key_t *key);
00141
00142 static isc_result_t
00143 pkcs11gost_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
00144 CK_RV rv;
00145 CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 };
00146 CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
00147 CK_KEY_TYPE keyType = CKK_GOSTR3410;
00148 CK_ATTRIBUTE keyTemplate[] =
00149 {
00150 { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
00151 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
00152 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00153 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00154 { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00155 { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
00156 { CKA_VALUE, NULL, 0 },
00157 { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
00158 (CK_ULONG) sizeof(pk11_gost_a_paramset) },
00159 { CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
00160 (CK_ULONG) sizeof(pk11_gost_paramset) }
00161 };
00162 CK_ATTRIBUTE *attr;
00163 pk11_object_t *gost;
00164 pk11_context_t *pk11_ctx;
00165 isc_result_t ret;
00166 unsigned int i;
00167
00168 pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
00169 sizeof(*pk11_ctx));
00170 if (pk11_ctx == NULL)
00171 return (ISC_R_NOMEMORY);
00172 ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
00173 ISC_FALSE, NULL, pk11_get_best_token(OP_GOST));
00174 if (ret != ISC_R_SUCCESS)
00175 goto err;
00176
00177 gost = key->keydata.pkey;
00178 if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) {
00179 pk11_ctx->ontoken = gost->ontoken;
00180 pk11_ctx->object = gost->object;
00181 goto token_key;
00182 }
00183
00184 for (attr = pk11_attribute_first(gost);
00185 attr != NULL;
00186 attr = pk11_attribute_next(gost, attr))
00187 switch (attr->type) {
00188 case CKA_VALUE2:
00189 INSIST(keyTemplate[6].type == CKA_VALUE);
00190 keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
00191 attr->ulValueLen);
00192 if (keyTemplate[6].pValue == NULL)
00193 DST_RET(ISC_R_NOMEMORY);
00194 memmove(keyTemplate[6].pValue, attr->pValue,
00195 attr->ulValueLen);
00196 keyTemplate[6].ulValueLen = attr->ulValueLen;
00197 break;
00198 }
00199 pk11_ctx->object = CK_INVALID_HANDLE;
00200 pk11_ctx->ontoken = ISC_FALSE;
00201 PK11_RET(pkcs_C_CreateObject,
00202 (pk11_ctx->session,
00203 keyTemplate, (CK_ULONG) 9,
00204 &pk11_ctx->object),
00205 ISC_R_FAILURE);
00206
00207 token_key:
00208
00209 PK11_RET(pkcs_C_SignInit,
00210 (pk11_ctx->session, &mech, pk11_ctx->object),
00211 ISC_R_FAILURE);
00212
00213 dctx->ctxdata.pk11_ctx = pk11_ctx;
00214
00215 for (i = 6; i <= 6; i++)
00216 if (keyTemplate[i].pValue != NULL) {
00217 memset(keyTemplate[i].pValue, 0,
00218 keyTemplate[i].ulValueLen);
00219 isc_mem_put(dctx->mctx,
00220 keyTemplate[i].pValue,
00221 keyTemplate[i].ulValueLen);
00222 }
00223
00224 return (ISC_R_SUCCESS);
00225
00226 err:
00227 if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
00228 (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object);
00229 for (i = 6; i <= 6; i++)
00230 if (keyTemplate[i].pValue != NULL) {
00231 memset(keyTemplate[i].pValue, 0,
00232 keyTemplate[i].ulValueLen);
00233 isc_mem_put(dctx->mctx,
00234 keyTemplate[i].pValue,
00235 keyTemplate[i].ulValueLen);
00236 }
00237 pk11_return_session(pk11_ctx);
00238 memset(pk11_ctx, 0, sizeof(*pk11_ctx));
00239 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
00240
00241 return (ret);
00242 }
00243
00244 static isc_result_t
00245 pkcs11gost_createctx_verify(dst_key_t *key, dst_context_t *dctx) {
00246 CK_RV rv;
00247 CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 };
00248 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
00249 CK_KEY_TYPE keyType = CKK_GOSTR3410;
00250 CK_ATTRIBUTE keyTemplate[] =
00251 {
00252 { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
00253 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
00254 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00255 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00256 { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
00257 { CKA_VALUE, NULL, 0 },
00258 { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
00259 (CK_ULONG) sizeof(pk11_gost_a_paramset) },
00260 { CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
00261 (CK_ULONG) sizeof(pk11_gost_paramset) }
00262 };
00263 CK_ATTRIBUTE *attr;
00264 pk11_object_t *gost;
00265 pk11_context_t *pk11_ctx;
00266 isc_result_t ret;
00267 unsigned int i;
00268
00269 pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
00270 sizeof(*pk11_ctx));
00271 if (pk11_ctx == NULL)
00272 return (ISC_R_NOMEMORY);
00273 ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
00274 ISC_FALSE, NULL, pk11_get_best_token(OP_GOST));
00275 if (ret != ISC_R_SUCCESS)
00276 goto err;
00277
00278 gost = key->keydata.pkey;
00279 if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) {
00280 pk11_ctx->ontoken = gost->ontoken;
00281 pk11_ctx->object = gost->object;
00282 goto token_key;
00283 }
00284
00285 for (attr = pk11_attribute_first(gost);
00286 attr != NULL;
00287 attr = pk11_attribute_next(gost, attr))
00288 switch (attr->type) {
00289 case CKA_VALUE:
00290 INSIST(keyTemplate[5].type == attr->type);
00291 keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
00292 attr->ulValueLen);
00293 if (keyTemplate[5].pValue == NULL)
00294 DST_RET(ISC_R_NOMEMORY);
00295 memmove(keyTemplate[5].pValue, attr->pValue,
00296 attr->ulValueLen);
00297 keyTemplate[5].ulValueLen = attr->ulValueLen;
00298 break;
00299 }
00300 pk11_ctx->object = CK_INVALID_HANDLE;
00301 pk11_ctx->ontoken = ISC_FALSE;
00302 PK11_RET(pkcs_C_CreateObject,
00303 (pk11_ctx->session,
00304 keyTemplate, (CK_ULONG) 8,
00305 &pk11_ctx->object),
00306 ISC_R_FAILURE);
00307
00308 token_key:
00309
00310 PK11_RET(pkcs_C_VerifyInit,
00311 (pk11_ctx->session, &mech, pk11_ctx->object),
00312 ISC_R_FAILURE);
00313
00314 dctx->ctxdata.pk11_ctx = pk11_ctx;
00315
00316 for (i = 5; i <= 5; i++)
00317 if (keyTemplate[i].pValue != NULL) {
00318 memset(keyTemplate[i].pValue, 0,
00319 keyTemplate[i].ulValueLen);
00320 isc_mem_put(dctx->mctx,
00321 keyTemplate[i].pValue,
00322 keyTemplate[i].ulValueLen);
00323 }
00324
00325 return (ISC_R_SUCCESS);
00326
00327 err:
00328 if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
00329 (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object);
00330 for (i = 5; i <= 5; i++)
00331 if (keyTemplate[i].pValue != NULL) {
00332 memset(keyTemplate[i].pValue, 0,
00333 keyTemplate[i].ulValueLen);
00334 isc_mem_put(dctx->mctx,
00335 keyTemplate[i].pValue,
00336 keyTemplate[i].ulValueLen);
00337 }
00338 pk11_return_session(pk11_ctx);
00339 memset(pk11_ctx, 0, sizeof(*pk11_ctx));
00340 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
00341
00342 return (ret);
00343 }
00344
00345 static isc_result_t
00346 pkcs11gost_createctx(dst_key_t *key, dst_context_t *dctx) {
00347 if (dctx->use == DO_SIGN)
00348 return (pkcs11gost_createctx_sign(key, dctx));
00349 else
00350 return (pkcs11gost_createctx_verify(key, dctx));
00351 }
00352
00353 static void
00354 pkcs11gost_destroyctx(dst_context_t *dctx) {
00355 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
00356
00357 if (pk11_ctx != NULL) {
00358 if (!pk11_ctx->ontoken &&
00359 (pk11_ctx->object != CK_INVALID_HANDLE))
00360 (void) pkcs_C_DestroyObject(pk11_ctx->session,
00361 pk11_ctx->object);
00362 pk11_return_session(pk11_ctx);
00363 memset(pk11_ctx, 0, sizeof(*pk11_ctx));
00364 isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
00365 dctx->ctxdata.pk11_ctx = NULL;
00366 }
00367 }
00368
00369 static isc_result_t
00370 pkcs11gost_adddata(dst_context_t *dctx, const isc_region_t *data) {
00371 CK_RV rv;
00372 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
00373 isc_result_t ret = ISC_R_SUCCESS;
00374
00375 if (dctx->use == DO_SIGN)
00376 PK11_CALL(pkcs_C_SignUpdate,
00377 (pk11_ctx->session,
00378 (CK_BYTE_PTR) data->base,
00379 (CK_ULONG) data->length),
00380 ISC_R_FAILURE);
00381 else
00382 PK11_CALL(pkcs_C_VerifyUpdate,
00383 (pk11_ctx->session,
00384 (CK_BYTE_PTR) data->base,
00385 (CK_ULONG) data->length),
00386 ISC_R_FAILURE);
00387 return (ret);
00388 }
00389
00390 static isc_result_t
00391 pkcs11gost_sign(dst_context_t *dctx, isc_buffer_t *sig) {
00392 CK_RV rv;
00393 CK_ULONG siglen = ISC_GOST_SIGNATURELENGTH;
00394 isc_region_t r;
00395 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
00396 isc_result_t ret = ISC_R_SUCCESS;
00397
00398 isc_buffer_availableregion(sig, &r);
00399 if (r.length < ISC_GOST_SIGNATURELENGTH)
00400 return (ISC_R_NOSPACE);
00401
00402 PK11_RET(pkcs_C_SignFinal,
00403 (pk11_ctx->session, (CK_BYTE_PTR) r.base, &siglen),
00404 DST_R_SIGNFAILURE);
00405 if (siglen != ISC_GOST_SIGNATURELENGTH)
00406 return (DST_R_SIGNFAILURE);
00407
00408 isc_buffer_add(sig, ISC_GOST_SIGNATURELENGTH);
00409
00410 err:
00411 return (ret);
00412 }
00413
00414 static isc_result_t
00415 pkcs11gost_verify(dst_context_t *dctx, const isc_region_t *sig) {
00416 CK_RV rv;
00417 pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
00418 isc_result_t ret = ISC_R_SUCCESS;
00419
00420 PK11_CALL(pkcs_C_VerifyFinal,
00421 (pk11_ctx->session,
00422 (CK_BYTE_PTR) sig->base,
00423 (CK_ULONG) sig->length),
00424 DST_R_VERIFYFAILURE);
00425 return (ret);
00426 }
00427
00428 static isc_boolean_t
00429 pkcs11gost_compare(const dst_key_t *key1, const dst_key_t *key2) {
00430 pk11_object_t *gost1, *gost2;
00431 CK_ATTRIBUTE *attr1, *attr2;
00432
00433 gost1 = key1->keydata.pkey;
00434 gost2 = key2->keydata.pkey;
00435
00436 if ((gost1 == NULL) && (gost2 == NULL))
00437 return (ISC_TRUE);
00438 else if ((gost1 == NULL) || (gost2 == NULL))
00439 return (ISC_FALSE);
00440
00441 attr1 = pk11_attribute_bytype(gost1, CKA_VALUE);
00442 attr2 = pk11_attribute_bytype(gost2, CKA_VALUE);
00443 if ((attr1 == NULL) && (attr2 == NULL))
00444 return (ISC_TRUE);
00445 else if ((attr1 == NULL) || (attr2 == NULL) ||
00446 (attr1->ulValueLen != attr2->ulValueLen) ||
00447 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
00448 return (ISC_FALSE);
00449
00450 attr1 = pk11_attribute_bytype(gost1, CKA_VALUE2);
00451 attr2 = pk11_attribute_bytype(gost2, CKA_VALUE2);
00452 if (((attr1 != NULL) || (attr2 != NULL)) &&
00453 ((attr1 == NULL) || (attr2 == NULL) ||
00454 (attr1->ulValueLen != attr2->ulValueLen) ||
00455 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)))
00456 return (ISC_FALSE);
00457
00458 if (!gost1->ontoken && !gost2->ontoken)
00459 return (ISC_TRUE);
00460 else if (gost1->ontoken || gost2->ontoken ||
00461 (gost1->object != gost2->object))
00462 return (ISC_FALSE);
00463
00464 return (ISC_TRUE);
00465 }
00466
00467 static isc_result_t
00468 pkcs11gost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
00469 CK_RV rv;
00470 CK_MECHANISM mech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL, 0 };
00471 CK_KEY_TYPE keyType = CKK_GOSTR3410;
00472 CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
00473 CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
00474 CK_ATTRIBUTE pubTemplate[] =
00475 {
00476 { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
00477 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
00478 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00479 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00480 { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
00481 { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
00482 (CK_ULONG) sizeof(pk11_gost_a_paramset) },
00483 { CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
00484 (CK_ULONG) sizeof(pk11_gost_paramset) }
00485 };
00486 CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
00487 CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
00488 CK_ATTRIBUTE privTemplate[] =
00489 {
00490 { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
00491 { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
00492 { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00493 { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00494 { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
00495 { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
00496 { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
00497 };
00498 CK_ATTRIBUTE *attr;
00499 pk11_object_t *gost;
00500 pk11_context_t *pk11_ctx;
00501 isc_result_t ret;
00502
00503 UNUSED(unused);
00504 UNUSED(callback);
00505
00506 pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
00507 sizeof(*pk11_ctx));
00508 if (pk11_ctx == NULL)
00509 return (ISC_R_NOMEMORY);
00510 ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
00511 ISC_FALSE, NULL, pk11_get_best_token(OP_GOST));
00512 if (ret != ISC_R_SUCCESS)
00513 goto err;
00514
00515 PK11_RET(pkcs_C_GenerateKeyPair,
00516 (pk11_ctx->session, &mech,
00517 pubTemplate, (CK_ULONG) 7,
00518 privTemplate, (CK_ULONG) 7,
00519 &pub, &priv),
00520 DST_R_CRYPTOFAILURE);
00521
00522 gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost));
00523 if (gost == NULL)
00524 DST_RET(ISC_R_NOMEMORY);
00525 memset(gost, 0, sizeof(*gost));
00526 key->keydata.pkey = gost;
00527 key->key_size = ISC_GOST_KEYSIZE;
00528 gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx,
00529 sizeof(*attr) * 2);
00530 if (gost->repr == NULL)
00531 DST_RET(ISC_R_NOMEMORY);
00532 memset(gost->repr, 0, sizeof(*attr) * 2);
00533 gost->attrcnt = 2;
00534
00535 attr = gost->repr;
00536 attr[0].type = CKA_VALUE;
00537 attr[1].type = CKA_VALUE2;
00538
00539 attr = gost->repr;
00540 PK11_RET(pkcs_C_GetAttributeValue,
00541 (pk11_ctx->session, pub, attr, 1),
00542 DST_R_CRYPTOFAILURE);
00543 attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
00544 if (attr->pValue == NULL)
00545 DST_RET(ISC_R_NOMEMORY);
00546 memset(attr->pValue, 0, attr->ulValueLen);
00547 PK11_RET(pkcs_C_GetAttributeValue,
00548 (pk11_ctx->session, pub, attr, 1),
00549 DST_R_CRYPTOFAILURE);
00550
00551 attr++;
00552 attr->type = CKA_VALUE;
00553 PK11_RET(pkcs_C_GetAttributeValue,
00554 (pk11_ctx->session, priv, attr, 1),
00555 DST_R_CRYPTOFAILURE);
00556 attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
00557 if (attr->pValue == NULL)
00558 DST_RET(ISC_R_NOMEMORY);
00559 memset(attr->pValue, 0, attr->ulValueLen);
00560 PK11_RET(pkcs_C_GetAttributeValue,
00561 (pk11_ctx->session, priv, attr, 1),
00562 DST_R_CRYPTOFAILURE);
00563 attr->type = CKA_VALUE2;
00564
00565 (void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
00566 (void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
00567 pk11_return_session(pk11_ctx);
00568 memset(pk11_ctx, 0, sizeof(*pk11_ctx));
00569 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
00570
00571 return (ISC_R_SUCCESS);
00572
00573 err:
00574 pkcs11gost_destroy(key);
00575 if (priv != CK_INVALID_HANDLE)
00576 (void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
00577 if (pub != CK_INVALID_HANDLE)
00578 (void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
00579 pk11_return_session(pk11_ctx);
00580 memset(pk11_ctx, 0, sizeof(*pk11_ctx));
00581 isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
00582
00583 return (ret);
00584 }
00585
00586 static isc_boolean_t
00587 pkcs11gost_isprivate(const dst_key_t *key) {
00588 pk11_object_t *gost = key->keydata.pkey;
00589 CK_ATTRIBUTE *attr;
00590
00591 if (gost == NULL)
00592 return (ISC_FALSE);
00593 attr = pk11_attribute_bytype(gost, CKA_VALUE2);
00594 return (ISC_TF((attr != NULL) || gost->ontoken));
00595 }
00596
00597 static void
00598 pkcs11gost_destroy(dst_key_t *key) {
00599 pk11_object_t *gost = key->keydata.pkey;
00600 CK_ATTRIBUTE *attr;
00601
00602 if (gost == NULL)
00603 return;
00604
00605 INSIST((gost->object == CK_INVALID_HANDLE) || gost->ontoken);
00606
00607 for (attr = pk11_attribute_first(gost);
00608 attr != NULL;
00609 attr = pk11_attribute_next(gost, attr))
00610 switch (attr->type) {
00611 case CKA_VALUE:
00612 case CKA_VALUE2:
00613 if (attr->pValue != NULL) {
00614 memset(attr->pValue, 0, attr->ulValueLen);
00615 isc_mem_put(key->mctx,
00616 attr->pValue,
00617 attr->ulValueLen);
00618 }
00619 break;
00620 }
00621 if (gost->repr != NULL) {
00622 memset(gost->repr, 0, gost->attrcnt * sizeof(*attr));
00623 isc_mem_put(key->mctx,
00624 gost->repr,
00625 gost->attrcnt * sizeof(*attr));
00626 }
00627 memset(gost, 0, sizeof(*gost));
00628 isc_mem_put(key->mctx, gost, sizeof(*gost));
00629 key->keydata.pkey = NULL;
00630 }
00631
00632 static isc_result_t
00633 pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data) {
00634 pk11_object_t *gost;
00635 isc_region_t r;
00636 CK_ATTRIBUTE *attr;
00637
00638 REQUIRE(key->keydata.pkey != NULL);
00639
00640 gost = key->keydata.pkey;
00641 attr = pk11_attribute_bytype(gost, CKA_VALUE);
00642 if ((attr == NULL) || (attr->ulValueLen != ISC_GOST_PUBKEYLENGTH))
00643 return (ISC_R_FAILURE);
00644
00645 isc_buffer_availableregion(data, &r);
00646 if (r.length < ISC_GOST_PUBKEYLENGTH)
00647 return (ISC_R_NOSPACE);
00648 memmove(r.base, (CK_BYTE_PTR) attr->pValue, ISC_GOST_PUBKEYLENGTH);
00649 isc_buffer_add(data, ISC_GOST_PUBKEYLENGTH);
00650
00651 return (ISC_R_SUCCESS);
00652 }
00653
00654 static isc_result_t
00655 pkcs11gost_fromdns(dst_key_t *key, isc_buffer_t *data) {
00656 pk11_object_t *gost;
00657 isc_region_t r;
00658 CK_ATTRIBUTE *attr;
00659
00660 isc_buffer_remainingregion(data, &r);
00661 if (r.length == 0)
00662 return (ISC_R_SUCCESS);
00663 if (r.length != ISC_GOST_PUBKEYLENGTH)
00664 return (DST_R_INVALIDPUBLICKEY);
00665
00666 gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost));
00667 if (gost == NULL)
00668 return (ISC_R_NOMEMORY);
00669 memset(gost, 0, sizeof(*gost));
00670 gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr));
00671 if (gost->repr == NULL)
00672 goto nomemory;
00673 gost->attrcnt = 1;
00674
00675 attr = gost->repr;
00676 attr->type = CKA_VALUE;
00677 attr->pValue = isc_mem_get(key->mctx, ISC_GOST_PUBKEYLENGTH);
00678 if (attr->pValue == NULL)
00679 goto nomemory;
00680 memmove((CK_BYTE_PTR) attr->pValue, r.base, ISC_GOST_PUBKEYLENGTH);
00681 attr->ulValueLen = ISC_GOST_PUBKEYLENGTH;
00682
00683 isc_buffer_forward(data, ISC_GOST_PUBKEYLENGTH);
00684 key->keydata.pkey = gost;
00685 key->key_size = ISC_GOST_KEYSIZE;
00686 return (ISC_R_SUCCESS);
00687
00688 nomemory:
00689 for (attr = pk11_attribute_first(gost);
00690 attr != NULL;
00691 attr = pk11_attribute_next(gost, attr))
00692 switch (attr->type) {
00693 case CKA_VALUE:
00694 if (attr->pValue != NULL) {
00695 memset(attr->pValue, 0, attr->ulValueLen);
00696 isc_mem_put(key->mctx,
00697 attr->pValue,
00698 attr->ulValueLen);
00699 }
00700 break;
00701 }
00702 if (gost->repr != NULL) {
00703 memset(gost->repr, 0, gost->attrcnt * sizeof(*attr));
00704 isc_mem_put(key->mctx,
00705 gost->repr,
00706 gost->attrcnt * sizeof(*attr));
00707 }
00708 memset(gost, 0, sizeof(*gost));
00709 isc_mem_put(key->mctx, gost, sizeof(*gost));
00710 return (ISC_R_NOMEMORY);
00711 }
00712
00713 static unsigned char gost_private_der[39] = {
00714 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
00715 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
00716 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
00717 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
00718 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20
00719 };
00720
00721 #ifdef PREFER_GOSTASN1
00722
00723 static isc_result_t
00724 pkcs11gost_tofile(const dst_key_t *key, const char *directory) {
00725 isc_result_t ret;
00726 pk11_object_t *gost;
00727 dst_private_t priv;
00728 unsigned char *buf = NULL;
00729 unsigned int i = 0;
00730 CK_ATTRIBUTE *attr;
00731 int adj;
00732
00733 if (key->keydata.pkey == NULL)
00734 return (DST_R_NULLKEY);
00735
00736 if (key->external) {
00737 priv.nelements = 0;
00738 return (dst__privstruct_writefile(key, &priv, directory));
00739 }
00740
00741 gost = key->keydata.pkey;
00742 attr = pk11_attribute_bytype(gost, CKA_VALUE2);
00743 if (attr != NULL) {
00744 buf = isc_mem_get(key->mctx, attr->ulValueLen + 39);
00745 if (buf == NULL)
00746 return (ISC_R_NOMEMORY);
00747 priv.elements[i].tag = TAG_GOST_PRIVASN1;
00748 priv.elements[i].length =
00749 (unsigned short) attr->ulValueLen + 39;
00750 memmove(buf, gost_private_der, 39);
00751 memmove(buf + 39, attr->pValue, attr->ulValueLen);
00752 adj = (int) attr->ulValueLen - 32;
00753 if (adj != 0) {
00754 buf[1] += adj;
00755 buf[36] += adj;
00756 buf[38] += adj;
00757 }
00758 priv.elements[i].data = buf;
00759 i++;
00760 } else
00761 return (DST_R_CRYPTOFAILURE);
00762
00763 priv.nelements = i;
00764 ret = dst__privstruct_writefile(key, &priv, directory);
00765
00766 if (buf != NULL) {
00767 memset(buf, 0, attr->ulValueLen);
00768 isc_mem_put(key->mctx, buf, attr->ulValueLen);
00769 }
00770 return (ret);
00771 }
00772
00773 #else
00774
00775 static isc_result_t
00776 pkcs11gost_tofile(const dst_key_t *key, const char *directory) {
00777 isc_result_t ret;
00778 pk11_object_t *gost;
00779 dst_private_t priv;
00780 unsigned char *buf = NULL;
00781 unsigned int i = 0;
00782 CK_ATTRIBUTE *attr;
00783
00784 if (key->keydata.pkey == NULL)
00785 return (DST_R_NULLKEY);
00786
00787 if (key->external) {
00788 priv.nelements = 0;
00789 return (dst__privstruct_writefile(key, &priv, directory));
00790 }
00791
00792 gost = key->keydata.pkey;
00793 attr = pk11_attribute_bytype(gost, CKA_VALUE2);
00794 if (attr != NULL) {
00795 buf = isc_mem_get(key->mctx, attr->ulValueLen);
00796 if (buf == NULL)
00797 return (ISC_R_NOMEMORY);
00798 priv.elements[i].tag = TAG_GOST_PRIVRAW;
00799 priv.elements[i].length = (unsigned short) attr->ulValueLen;
00800 memmove(buf, attr->pValue, attr->ulValueLen);
00801 priv.elements[i].data = buf;
00802 i++;
00803 } else
00804 return (DST_R_CRYPTOFAILURE);
00805
00806 priv.nelements = i;
00807 ret = dst__privstruct_writefile(key, &priv, directory);
00808
00809 if (buf != NULL) {
00810 memset(buf, 0, attr->ulValueLen);
00811 isc_mem_put(key->mctx, buf, attr->ulValueLen);
00812 }
00813 return (ret);
00814 }
00815 #endif
00816
00817 static isc_result_t
00818 pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
00819 dst_private_t priv;
00820 isc_result_t ret;
00821 pk11_object_t *gost = NULL;
00822 CK_ATTRIBUTE *attr, *pattr;
00823 isc_mem_t *mctx = key->mctx;
00824
00825 if ((pub == NULL) || (pub->keydata.pkey == NULL))
00826 DST_RET(DST_R_INVALIDPRIVATEKEY);
00827
00828
00829 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
00830 if (ret != ISC_R_SUCCESS)
00831 return (ret);
00832
00833 if (key->external) {
00834 if (priv.nelements != 0)
00835 DST_RET(DST_R_INVALIDPRIVATEKEY);
00836
00837 key->keydata.pkey = pub->keydata.pkey;
00838 pub->keydata.pkey = NULL;
00839 key->key_size = pub->key_size;
00840
00841 dst__privstruct_free(&priv, mctx);
00842 memset(&priv, 0, sizeof(priv));
00843
00844 return (ISC_R_SUCCESS);
00845 }
00846
00847 if (priv.elements[0].tag == TAG_GOST_PRIVASN1) {
00848 int adj = (int) priv.elements[0].length - (39 + 32);
00849 unsigned char buf[39];
00850
00851 if ((adj > 0) || (adj < -31))
00852 DST_RET(DST_R_INVALIDPRIVATEKEY);
00853 memmove(buf, gost_private_der, 39);
00854 if (adj != 0) {
00855 buf[1] += adj;
00856 buf[36] += adj;
00857 buf[38] += adj;
00858 }
00859 if (memcmp(priv.elements[0].data, buf, 39) != 0)
00860 DST_RET(DST_R_INVALIDPRIVATEKEY);
00861 priv.elements[0].tag = TAG_GOST_PRIVRAW;
00862 priv.elements[0].length -= 39;
00863 memmove(priv.elements[0].data,
00864 priv.elements[0].data + 39,
00865 32 + adj);
00866 }
00867
00868 gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost));
00869 if (gost == NULL)
00870 DST_RET(ISC_R_NOMEMORY);
00871 memset(gost, 0, sizeof(*gost));
00872 key->keydata.pkey = gost;
00873 key->key_size = ISC_GOST_KEYSIZE;
00874
00875 gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx,
00876 sizeof(*attr) * 2);
00877 if (gost->repr == NULL)
00878 DST_RET(ISC_R_NOMEMORY);
00879 memset(gost->repr, 0, sizeof(*attr) * 2);
00880 gost->attrcnt = 2;
00881
00882 attr = gost->repr;
00883 attr->type = CKA_VALUE;
00884 pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE);
00885 INSIST(pattr != NULL);
00886 attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
00887 if (attr->pValue == NULL)
00888 DST_RET(ISC_R_NOMEMORY);
00889 memmove(attr->pValue, pattr->pValue, pattr->ulValueLen);
00890 attr->ulValueLen = pattr->ulValueLen;
00891
00892 attr++;
00893 attr->type = CKA_VALUE2;
00894 attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length);
00895 if (attr->pValue == NULL)
00896 DST_RET(ISC_R_NOMEMORY);
00897 memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length);
00898 attr->ulValueLen = priv.elements[0].length;
00899
00900 dst__privstruct_free(&priv, mctx);
00901 memset(&priv, 0, sizeof(priv));
00902
00903 return (ISC_R_SUCCESS);
00904
00905 err:
00906 pkcs11gost_destroy(key);
00907 dst__privstruct_free(&priv, mctx);
00908 memset(&priv, 0, sizeof(priv));
00909 return (ret);
00910 }
00911
00912 static dst_func_t pkcs11gost_functions = {
00913 pkcs11gost_createctx,
00914 NULL,
00915 pkcs11gost_destroyctx,
00916 pkcs11gost_adddata,
00917 pkcs11gost_sign,
00918 pkcs11gost_verify,
00919 NULL,
00920 NULL,
00921 pkcs11gost_compare,
00922 NULL,
00923 pkcs11gost_generate,
00924 pkcs11gost_isprivate,
00925 pkcs11gost_destroy,
00926 pkcs11gost_todns,
00927 pkcs11gost_fromdns,
00928 pkcs11gost_tofile,
00929 pkcs11gost_parse,
00930 NULL,
00931 NULL,
00932 NULL,
00933 NULL,
00934 };
00935
00936 isc_result_t
00937 dst__pkcs11gost_init(dst_func_t **funcp) {
00938 REQUIRE(funcp != NULL);
00939 if (*funcp == NULL)
00940 *funcp = &pkcs11gost_functions;
00941 return (ISC_R_SUCCESS);
00942 }
00943
00944 #else
00945
00946 #include <isc/util.h>
00947
00948 EMPTY_TRANSLATION_UNIT
00949
00950 #endif
00951