"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/pkcs11gost_link.c" (7 Sep 2020, 26039 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pkcs11gost_link.c" see the Fossies "Dox" file reference documentation.

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