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