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