pkcs11gost_link.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /* $Id$ */
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  * RU CryptoPro GOST keys:
00047  *  mechanisms:
00048  *    CKM_GOSTR3411
00049  *    CKM_GOSTR3410_WITH_GOSTR3411
00050  *    CKM_GOSTR3410_KEY_PAIR_GEN
00051  *  domain parameters:
00052  *    CKA_GOSTR3410_PARAMS (fixed BER OID 1.2.643.2.2.35.1)
00053  *    CKA_GOSTR3411_PARAMS (fixed BER OID 1.2.643.2.2.30.1)
00054  *    CKA_GOST28147_PARAMS (optional, don't use)
00055  *  public keys:
00056  *    object class CKO_PUBLIC_KEY
00057  *    key type CKK_GOSTR3410
00058  *    attribute CKA_VALUE (point Q)
00059  *    attribute CKA_GOSTR3410_PARAMS
00060  *    attribute CKA_GOSTR3411_PARAMS
00061  *    attribute CKA_GOST28147_PARAMS
00062  *  private keys:
00063  *    object class CKO_PRIVATE_KEY
00064  *    key type CKK_GOSTR3410
00065  *    attribute CKA_VALUE (big int d)
00066  *    attribute CKA_GOSTR3410_PARAMS
00067  *    attribute CKA_GOSTR3411_PARAMS
00068  *    attribute CKA_GOST28147_PARAMS
00069  *  point format: <x> <y> (little endian)
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 /* HASH methods */
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 /* DST methods */
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         /* read private key file */
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, /*%< createctx2 */
00915         pkcs11gost_destroyctx,
00916         pkcs11gost_adddata,
00917         pkcs11gost_sign,
00918         pkcs11gost_verify,
00919         NULL, /*%< verify2 */
00920         NULL, /*%< computesecret */
00921         pkcs11gost_compare,
00922         NULL, /*%< paramcompare */
00923         pkcs11gost_generate,
00924         pkcs11gost_isprivate,
00925         pkcs11gost_destroy,
00926         pkcs11gost_todns,
00927         pkcs11gost_fromdns,
00928         pkcs11gost_tofile,
00929         pkcs11gost_parse,
00930         NULL, /*%< cleanup */
00931         NULL, /*%< fromlabel */
00932         NULL, /*%< dump */
00933         NULL, /*%< restore */
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 /* PKCS11CRYPTO && HAVE_PKCS11_GOST */
00945 
00946 #include <isc/util.h>
00947 
00948 EMPTY_TRANSLATION_UNIT
00949 
00950 #endif /* PKCS11CRYPTO && HAVE_PKCS11_GOST */
00951 /*! \file */

Generated on Tue Apr 28 17:40:59 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha