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