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 /*! \file */
13 
14 #if USE_PKCS11
15 
16 #include <stdbool.h>
17 
18 #include <isc/mem.h>
19 #include <isc/safe.h>
20 #include <isc/string.h>
21 #include <isc/util.h>
22 
23 #include <pk11/constants.h>
24 #include <pk11/internal.h>
25 #include <pk11/pk11.h>
26 #include <pkcs11/pkcs11.h>
27 
28 #include <dns/keyvalues.h>
29 
30 #include <dst/result.h>
31 
32 #include "dst_internal.h"
33 #include "dst_parse.h"
34 #include "dst_pkcs11.h"
35 
36 /*
37  * FIPS 186-3 ECDSA keys:
38  *  mechanisms:
39  *    CKM_ECDSA,
40  *    CKM_EC_KEY_PAIR_GEN
41  *  domain parameters:
42  *    CKA_EC_PARAMS (choice with OID namedCurve)
43  *  public keys:
44  *    object class CKO_PUBLIC_KEY
45  *    key type CKK_EC
46  *    attribute CKA_EC_PARAMS (choice with OID namedCurve)
47  *    attribute CKA_EC_POINT (point Q)
48  *  private keys:
49  *    object class CKO_PRIVATE_KEY
50  *    key type CKK_EC
51  *    attribute CKA_EC_PARAMS (choice with OID namedCurve)
52  *    attribute CKA_VALUE (big int d)
53  *  point format: 0x04 (octet-string) <2*size+1> 0x4 (uncompressed) <x> <y>
54  */
55 
56 #define TAG_OCTECT_STRING 0x04
57 #define UNCOMPRESSED	  0x04
58 
59 #define DST_RET(a)        \
60 	{                 \
61 		ret = a;  \
62 		goto err; \
63 	}
64 
65 static CK_BBOOL truevalue = TRUE;
66 static CK_BBOOL falsevalue = FALSE;
67 
68 static void
69 pkcs11ecdsa_destroy(dst_key_t *key);
70 
71 static isc_result_t
pkcs11ecdsa_createctx(dst_key_t * key,dst_context_t * dctx)72 pkcs11ecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
73 	CK_RV rv;
74 	CK_MECHANISM mech = { 0, NULL, 0 };
75 	CK_SLOT_ID slotid;
76 	pk11_context_t *pk11_ctx;
77 	pk11_object_t *ec = key->keydata.pkey;
78 	isc_result_t ret;
79 
80 	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
81 		dctx->key->key_alg == DST_ALG_ECDSA384);
82 	REQUIRE(ec != NULL);
83 
84 	if (dctx->key->key_alg == DST_ALG_ECDSA256) {
85 		mech.mechanism = CKM_SHA256;
86 	} else {
87 		mech.mechanism = CKM_SHA384;
88 	}
89 
90 	pk11_ctx = isc_mem_get(dctx->mctx, sizeof(*pk11_ctx));
91 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
92 	if (ec->ontoken && (dctx->use == DO_SIGN)) {
93 		slotid = ec->slot;
94 	} else {
95 		slotid = pk11_get_best_token(OP_ECDSA);
96 	}
97 	ret = pk11_get_session(pk11_ctx, OP_ECDSA, true, false, ec->reqlogon,
98 			       NULL, slotid);
99 	if (ret != ISC_R_SUCCESS) {
100 		goto err;
101 	}
102 
103 	PK11_RET(pkcs_C_DigestInit, (pk11_ctx->session, &mech), ISC_R_FAILURE);
104 	dctx->ctxdata.pk11_ctx = pk11_ctx;
105 	return (ISC_R_SUCCESS);
106 
107 err:
108 	pk11_return_session(pk11_ctx);
109 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
110 	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
111 
112 	return (ret);
113 }
114 
115 static void
pkcs11ecdsa_destroyctx(dst_context_t * dctx)116 pkcs11ecdsa_destroyctx(dst_context_t *dctx) {
117 	CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
118 	CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
119 	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
120 
121 	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
122 		dctx->key->key_alg == DST_ALG_ECDSA384);
123 
124 	if (pk11_ctx != NULL) {
125 		(void)pkcs_C_DigestFinal(pk11_ctx->session, garbage, &len);
126 		memset(garbage, 0, sizeof(garbage));
127 		pk11_return_session(pk11_ctx);
128 		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
129 		isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
130 		dctx->ctxdata.pk11_ctx = NULL;
131 	}
132 }
133 
134 static isc_result_t
pkcs11ecdsa_adddata(dst_context_t * dctx,const isc_region_t * data)135 pkcs11ecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
136 	CK_RV rv;
137 	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
138 	isc_result_t ret = ISC_R_SUCCESS;
139 
140 	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
141 		dctx->key->key_alg == DST_ALG_ECDSA384);
142 
143 	PK11_CALL(pkcs_C_DigestUpdate,
144 		  (pk11_ctx->session, (CK_BYTE_PTR)data->base,
145 		   (CK_ULONG)data->length),
146 		  ISC_R_FAILURE);
147 
148 	return (ret);
149 }
150 
151 static isc_result_t
pkcs11ecdsa_sign(dst_context_t * dctx,isc_buffer_t * sig)152 pkcs11ecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
153 	CK_RV rv;
154 	CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 };
155 	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
156 	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
157 	CK_KEY_TYPE keyType = CKK_EC;
158 	CK_ATTRIBUTE keyTemplate[] = {
159 		{ CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) },
160 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) },
161 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
162 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
163 		{ CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) },
164 		{ CKA_EC_PARAMS, NULL, 0 },
165 		{ CKA_VALUE, NULL, 0 }
166 	};
167 	CK_ATTRIBUTE *attr;
168 	CK_BYTE digest[ISC_SHA384_DIGESTLENGTH];
169 	CK_ULONG dgstlen;
170 	CK_ULONG siglen;
171 	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
172 	dst_key_t *key = dctx->key;
173 	pk11_object_t *ec = key->keydata.pkey;
174 	isc_region_t r;
175 	isc_result_t ret = ISC_R_SUCCESS;
176 	unsigned int i;
177 
178 	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
179 		key->key_alg == DST_ALG_ECDSA384);
180 	REQUIRE(ec != NULL);
181 
182 	switch (key->key_alg) {
183 	case DST_ALG_ECDSA256:
184 		dgstlen = ISC_SHA256_DIGESTLENGTH;
185 		siglen = DNS_SIG_ECDSA256SIZE;
186 		break;
187 	case DST_ALG_ECDSA384:
188 		siglen = DNS_SIG_ECDSA384SIZE;
189 		dgstlen = ISC_SHA384_DIGESTLENGTH;
190 		break;
191 	default:
192 		INSIST(0);
193 		ISC_UNREACHABLE();
194 	}
195 
196 	PK11_RET(pkcs_C_DigestFinal, (pk11_ctx->session, digest, &dgstlen),
197 		 ISC_R_FAILURE);
198 
199 	isc_buffer_availableregion(sig, &r);
200 	if (r.length < siglen) {
201 		DST_RET(ISC_R_NOSPACE);
202 	}
203 
204 	if (ec->ontoken && (ec->object != CK_INVALID_HANDLE)) {
205 		pk11_ctx->ontoken = ec->ontoken;
206 		pk11_ctx->object = ec->object;
207 		goto token_key;
208 	}
209 
210 	for (attr = pk11_attribute_first(ec); attr != NULL;
211 	     attr = pk11_attribute_next(ec, attr))
212 		switch (attr->type) {
213 		case CKA_EC_PARAMS:
214 			INSIST(keyTemplate[5].type == attr->type);
215 			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
216 							    attr->ulValueLen);
217 			memmove(keyTemplate[5].pValue, attr->pValue,
218 				attr->ulValueLen);
219 			keyTemplate[5].ulValueLen = attr->ulValueLen;
220 			break;
221 		case CKA_VALUE:
222 			INSIST(keyTemplate[6].type == attr->type);
223 			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
224 							    attr->ulValueLen);
225 			memmove(keyTemplate[6].pValue, attr->pValue,
226 				attr->ulValueLen);
227 			keyTemplate[6].ulValueLen = attr->ulValueLen;
228 			break;
229 		}
230 	pk11_ctx->object = CK_INVALID_HANDLE;
231 	pk11_ctx->ontoken = false;
232 	PK11_RET(pkcs_C_CreateObject,
233 		 (pk11_ctx->session, keyTemplate, (CK_ULONG)7, &hKey),
234 		 ISC_R_FAILURE);
235 
236 token_key:
237 
238 	PK11_RET(pkcs_C_SignInit,
239 		 (pk11_ctx->session, &mech,
240 		  pk11_ctx->ontoken ? pk11_ctx->object : hKey),
241 		 ISC_R_FAILURE);
242 
243 	PK11_RET(pkcs_C_Sign,
244 		 (pk11_ctx->session, digest, dgstlen, (CK_BYTE_PTR)r.base,
245 		  &siglen),
246 		 DST_R_SIGNFAILURE);
247 
248 	isc_buffer_add(sig, (unsigned int)siglen);
249 
250 err:
251 
252 	if (hKey != CK_INVALID_HANDLE) {
253 		(void)pkcs_C_DestroyObject(pk11_ctx->session, hKey);
254 	}
255 	for (i = 5; i <= 6; i++) {
256 		if (keyTemplate[i].pValue != NULL) {
257 			{
258 				memset(keyTemplate[i].pValue, 0,
259 				       keyTemplate[i].ulValueLen);
260 				isc_mem_put(dctx->mctx, keyTemplate[i].pValue,
261 					    keyTemplate[i].ulValueLen);
262 			}
263 		}
264 	}
265 	pk11_return_session(pk11_ctx);
266 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
267 	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
268 	dctx->ctxdata.pk11_ctx = NULL;
269 
270 	return (ret);
271 }
272 
273 static isc_result_t
pkcs11ecdsa_verify(dst_context_t * dctx,const isc_region_t * sig)274 pkcs11ecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
275 	CK_RV rv;
276 	CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 };
277 	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
278 	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
279 	CK_KEY_TYPE keyType = CKK_EC;
280 	CK_ATTRIBUTE keyTemplate[] = {
281 		{ CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) },
282 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) },
283 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
284 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
285 		{ CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) },
286 		{ CKA_EC_PARAMS, NULL, 0 },
287 		{ CKA_EC_POINT, NULL, 0 }
288 	};
289 	CK_ATTRIBUTE *attr;
290 	CK_BYTE digest[ISC_SHA384_DIGESTLENGTH];
291 	CK_ULONG dgstlen;
292 	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
293 	dst_key_t *key = dctx->key;
294 	pk11_object_t *ec = key->keydata.pkey;
295 	isc_result_t ret = ISC_R_SUCCESS;
296 	unsigned int i;
297 
298 	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
299 		key->key_alg == DST_ALG_ECDSA384);
300 	REQUIRE(ec != NULL);
301 
302 	switch (key->key_alg) {
303 	case DST_ALG_ECDSA256:
304 		dgstlen = ISC_SHA256_DIGESTLENGTH;
305 		break;
306 	case DST_ALG_ECDSA384:
307 		dgstlen = ISC_SHA384_DIGESTLENGTH;
308 		break;
309 	default:
310 		INSIST(0);
311 		ISC_UNREACHABLE();
312 	}
313 
314 	PK11_RET(pkcs_C_DigestFinal, (pk11_ctx->session, digest, &dgstlen),
315 		 ISC_R_FAILURE);
316 
317 	for (attr = pk11_attribute_first(ec); attr != NULL;
318 	     attr = pk11_attribute_next(ec, attr))
319 		switch (attr->type) {
320 		case CKA_EC_PARAMS:
321 			INSIST(keyTemplate[5].type == attr->type);
322 			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
323 							    attr->ulValueLen);
324 			memmove(keyTemplate[5].pValue, attr->pValue,
325 				attr->ulValueLen);
326 			keyTemplate[5].ulValueLen = attr->ulValueLen;
327 			break;
328 		case CKA_EC_POINT:
329 			INSIST(keyTemplate[6].type == attr->type);
330 			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
331 							    attr->ulValueLen);
332 			memmove(keyTemplate[6].pValue, attr->pValue,
333 				attr->ulValueLen);
334 			keyTemplate[6].ulValueLen = attr->ulValueLen;
335 			break;
336 		}
337 	pk11_ctx->object = CK_INVALID_HANDLE;
338 	pk11_ctx->ontoken = false;
339 	PK11_RET(pkcs_C_CreateObject,
340 		 (pk11_ctx->session, keyTemplate, (CK_ULONG)7, &hKey),
341 		 ISC_R_FAILURE);
342 
343 	PK11_RET(pkcs_C_VerifyInit, (pk11_ctx->session, &mech, hKey),
344 		 ISC_R_FAILURE);
345 
346 	PK11_RET(pkcs_C_Verify,
347 		 (pk11_ctx->session, digest, dgstlen, (CK_BYTE_PTR)sig->base,
348 		  (CK_ULONG)sig->length),
349 		 DST_R_VERIFYFAILURE);
350 
351 err:
352 
353 	if (hKey != CK_INVALID_HANDLE) {
354 		(void)pkcs_C_DestroyObject(pk11_ctx->session, hKey);
355 	}
356 	for (i = 5; i <= 6; i++) {
357 		if (keyTemplate[i].pValue != NULL) {
358 			{
359 				memset(keyTemplate[i].pValue, 0,
360 				       keyTemplate[i].ulValueLen);
361 				isc_mem_put(dctx->mctx, keyTemplate[i].pValue,
362 					    keyTemplate[i].ulValueLen);
363 			}
364 		}
365 	}
366 	pk11_return_session(pk11_ctx);
367 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
368 	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
369 	dctx->ctxdata.pk11_ctx = NULL;
370 
371 	return (ret);
372 }
373 
374 static bool
pkcs11ecdsa_compare(const dst_key_t * key1,const dst_key_t * key2)375 pkcs11ecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
376 	pk11_object_t *ec1, *ec2;
377 	CK_ATTRIBUTE *attr1, *attr2;
378 
379 	ec1 = key1->keydata.pkey;
380 	ec2 = key2->keydata.pkey;
381 
382 	if ((ec1 == NULL) && (ec2 == NULL)) {
383 		return (true);
384 	} else if ((ec1 == NULL) || (ec2 == NULL)) {
385 		return (false);
386 	}
387 
388 	attr1 = pk11_attribute_bytype(ec1, CKA_EC_PARAMS);
389 	attr2 = pk11_attribute_bytype(ec2, CKA_EC_PARAMS);
390 	if ((attr1 == NULL) && (attr2 == NULL)) {
391 		return (true);
392 	} else if ((attr1 == NULL) || (attr2 == NULL) ||
393 		   (attr1->ulValueLen != attr2->ulValueLen) ||
394 		   !isc_safe_memequal(attr1->pValue, attr2->pValue,
395 				      attr1->ulValueLen))
396 	{
397 		return (false);
398 	}
399 
400 	attr1 = pk11_attribute_bytype(ec1, CKA_EC_POINT);
401 	attr2 = pk11_attribute_bytype(ec2, CKA_EC_POINT);
402 	if ((attr1 == NULL) && (attr2 == NULL)) {
403 		return (true);
404 	} else if ((attr1 == NULL) || (attr2 == NULL) ||
405 		   (attr1->ulValueLen != attr2->ulValueLen) ||
406 		   !isc_safe_memequal(attr1->pValue, attr2->pValue,
407 				      attr1->ulValueLen))
408 	{
409 		return (false);
410 	}
411 
412 	attr1 = pk11_attribute_bytype(ec1, CKA_VALUE);
413 	attr2 = pk11_attribute_bytype(ec2, CKA_VALUE);
414 	if (((attr1 != NULL) || (attr2 != NULL)) &&
415 	    ((attr1 == NULL) || (attr2 == NULL) ||
416 	     (attr1->ulValueLen != attr2->ulValueLen) ||
417 	     !isc_safe_memequal(attr1->pValue, attr2->pValue,
418 				attr1->ulValueLen)))
419 	{
420 		return (false);
421 	}
422 
423 	if (!ec1->ontoken && !ec2->ontoken) {
424 		return (true);
425 	} else if (ec1->ontoken || ec2->ontoken || (ec1->object != ec2->object))
426 	{
427 		return (false);
428 	}
429 
430 	return (true);
431 }
432 
433 #define SETCURVE()                                                       \
434 	switch (key->key_alg) {                                          \
435 	case DST_ALG_ECDSA256:                                           \
436 		attr->pValue = isc_mem_get(key->mctx,                    \
437 					   sizeof(PK11_ECC_PRIME256V1)); \
438 		memmove(attr->pValue, PK11_ECC_PRIME256V1,               \
439 			sizeof(PK11_ECC_PRIME256V1));                    \
440 		attr->ulValueLen = sizeof(PK11_ECC_PRIME256V1);          \
441 		break;                                                   \
442 	case DST_ALG_ECDSA384:                                           \
443 		attr->pValue = isc_mem_get(key->mctx,                    \
444 					   sizeof(PK11_ECC_SECP384R1));  \
445 		memmove(attr->pValue, PK11_ECC_SECP384R1,                \
446 			sizeof(PK11_ECC_SECP384R1));                     \
447 		attr->ulValueLen = sizeof(PK11_ECC_SECP384R1);           \
448 		break;                                                   \
449 	default:                                                         \
450 		INSIST(0);                                               \
451 		ISC_UNREACHABLE();                                       \
452 	}
453 
454 #define FREECURVE()                                                     \
455 	if (attr->pValue != NULL) {                                     \
456 		memset(attr->pValue, 0, attr->ulValueLen);              \
457 		isc_mem_put(key->mctx, attr->pValue, attr->ulValueLen); \
458 		attr->pValue = NULL;                                    \
459 	}
460 
461 static isc_result_t
pkcs11ecdsa_generate(dst_key_t * key,int unused,void (* callback)(int))462 pkcs11ecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
463 	CK_RV rv;
464 	CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 };
465 	CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
466 	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
467 	CK_KEY_TYPE keyType = CKK_EC;
468 	CK_ATTRIBUTE pubTemplate[] = {
469 		{ CKA_CLASS, &pubClass, (CK_ULONG)sizeof(pubClass) },
470 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) },
471 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
472 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
473 		{ CKA_VERIFY, &truevalue, (CK_ULONG)sizeof(truevalue) },
474 		{ CKA_EC_PARAMS, NULL, 0 }
475 	};
476 	CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
477 	CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
478 	CK_ATTRIBUTE privTemplate[] = {
479 		{ CKA_CLASS, &privClass, (CK_ULONG)sizeof(privClass) },
480 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) },
481 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
482 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
483 		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
484 		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG)sizeof(truevalue) },
485 		{ CKA_SIGN, &truevalue, (CK_ULONG)sizeof(truevalue) }
486 	};
487 	CK_ATTRIBUTE *attr;
488 	pk11_object_t *ec;
489 	pk11_context_t *pk11_ctx;
490 	isc_result_t ret;
491 
492 	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
493 		key->key_alg == DST_ALG_ECDSA384);
494 	UNUSED(unused);
495 	UNUSED(callback);
496 
497 	pk11_ctx = isc_mem_get(key->mctx, sizeof(*pk11_ctx));
498 	ret = pk11_get_session(pk11_ctx, OP_ECDSA, true, false, false, NULL,
499 			       pk11_get_best_token(OP_ECDSA));
500 	if (ret != ISC_R_SUCCESS) {
501 		goto err;
502 	}
503 
504 	ec = isc_mem_get(key->mctx, sizeof(*ec));
505 	memset(ec, 0, sizeof(*ec));
506 	key->keydata.pkey = ec;
507 	ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 3);
508 	memset(ec->repr, 0, sizeof(*attr) * 3);
509 	ec->attrcnt = 3;
510 
511 	attr = ec->repr;
512 	attr[0].type = CKA_EC_PARAMS;
513 	attr[1].type = CKA_EC_POINT;
514 	attr[2].type = CKA_VALUE;
515 
516 	attr = &pubTemplate[5];
517 	SETCURVE();
518 
519 	PK11_RET(pkcs_C_GenerateKeyPair,
520 		 (pk11_ctx->session, &mech, pubTemplate, (CK_ULONG)6,
521 		  privTemplate, (CK_ULONG)7, &pub, &priv),
522 		 DST_R_CRYPTOFAILURE);
523 
524 	attr = &pubTemplate[5];
525 	FREECURVE();
526 
527 	attr = ec->repr;
528 	SETCURVE();
529 
530 	attr++;
531 	PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, pub, attr, 1),
532 		 DST_R_CRYPTOFAILURE);
533 	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
534 	memset(attr->pValue, 0, attr->ulValueLen);
535 	PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, pub, attr, 1),
536 		 DST_R_CRYPTOFAILURE);
537 
538 	attr++;
539 	PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, priv, attr, 1),
540 		 DST_R_CRYPTOFAILURE);
541 	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
542 	memset(attr->pValue, 0, attr->ulValueLen);
543 	PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, priv, attr, 1),
544 		 DST_R_CRYPTOFAILURE);
545 
546 	(void)pkcs_C_DestroyObject(pk11_ctx->session, priv);
547 	(void)pkcs_C_DestroyObject(pk11_ctx->session, pub);
548 	pk11_return_session(pk11_ctx);
549 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
550 	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
551 
552 	switch (key->key_alg) {
553 	case DST_ALG_ECDSA256:
554 		key->key_size = DNS_KEY_ECDSA256SIZE * 4;
555 		break;
556 	case DST_ALG_ECDSA384:
557 		key->key_size = DNS_KEY_ECDSA384SIZE * 4;
558 		break;
559 	default:
560 		INSIST(0);
561 		ISC_UNREACHABLE();
562 	}
563 
564 	return (ISC_R_SUCCESS);
565 
566 err:
567 	pkcs11ecdsa_destroy(key);
568 	if (priv != CK_INVALID_HANDLE) {
569 		(void)pkcs_C_DestroyObject(pk11_ctx->session, priv);
570 	}
571 	if (pub != CK_INVALID_HANDLE) {
572 		(void)pkcs_C_DestroyObject(pk11_ctx->session, pub);
573 	}
574 	pk11_return_session(pk11_ctx);
575 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
576 	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
577 
578 	return (ret);
579 }
580 
581 static bool
pkcs11ecdsa_isprivate(const dst_key_t * key)582 pkcs11ecdsa_isprivate(const dst_key_t *key) {
583 	pk11_object_t *ec = key->keydata.pkey;
584 	CK_ATTRIBUTE *attr;
585 
586 	if (ec == NULL) {
587 		return (false);
588 	}
589 	attr = pk11_attribute_bytype(ec, CKA_VALUE);
590 	return (attr != NULL || ec->ontoken);
591 }
592 
593 static void
pkcs11ecdsa_destroy(dst_key_t * key)594 pkcs11ecdsa_destroy(dst_key_t *key) {
595 	pk11_object_t *ec = key->keydata.pkey;
596 	CK_ATTRIBUTE *attr;
597 
598 	if (ec == NULL) {
599 		return;
600 	}
601 
602 	INSIST((ec->object == CK_INVALID_HANDLE) || ec->ontoken);
603 
604 	for (attr = pk11_attribute_first(ec); attr != NULL;
605 	     attr = pk11_attribute_next(ec, attr))
606 		switch (attr->type) {
607 		case CKA_LABEL:
608 		case CKA_ID:
609 		case CKA_EC_PARAMS:
610 		case CKA_EC_POINT:
611 		case CKA_VALUE:
612 			FREECURVE();
613 			break;
614 		}
615 	if (ec->repr != NULL) {
616 		memset(ec->repr, 0, ec->attrcnt * sizeof(*attr));
617 		isc_mem_put(key->mctx, ec->repr, ec->attrcnt * sizeof(*attr));
618 	}
619 	memset(ec, 0, sizeof(*ec));
620 	isc_mem_put(key->mctx, ec, sizeof(*ec));
621 	key->keydata.pkey = NULL;
622 }
623 
624 static isc_result_t
pkcs11ecdsa_todns(const dst_key_t * key,isc_buffer_t * data)625 pkcs11ecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
626 	pk11_object_t *ec;
627 	isc_region_t r;
628 	unsigned int len;
629 	CK_ATTRIBUTE *attr;
630 
631 	REQUIRE(key->keydata.pkey != NULL);
632 
633 	switch (key->key_alg) {
634 	case DST_ALG_ECDSA256:
635 		len = DNS_KEY_ECDSA256SIZE;
636 		break;
637 	case DST_ALG_ECDSA384:
638 		len = DNS_KEY_ECDSA384SIZE;
639 		break;
640 	default:
641 		INSIST(0);
642 		ISC_UNREACHABLE();
643 	}
644 
645 	ec = key->keydata.pkey;
646 	attr = pk11_attribute_bytype(ec, CKA_EC_POINT);
647 	if ((attr == NULL) || (attr->ulValueLen != len + 3) ||
648 	    (((CK_BYTE_PTR)attr->pValue)[0] != TAG_OCTECT_STRING) ||
649 	    (((CK_BYTE_PTR)attr->pValue)[1] != len + 1) ||
650 	    (((CK_BYTE_PTR)attr->pValue)[2] != UNCOMPRESSED))
651 	{
652 		return (ISC_R_FAILURE);
653 	}
654 
655 	isc_buffer_availableregion(data, &r);
656 	if (r.length < len) {
657 		return (ISC_R_NOSPACE);
658 	}
659 	memmove(r.base, (CK_BYTE_PTR)attr->pValue + 3, len);
660 	isc_buffer_add(data, len);
661 
662 	return (ISC_R_SUCCESS);
663 }
664 
665 static isc_result_t
pkcs11ecdsa_fromdns(dst_key_t * key,isc_buffer_t * data)666 pkcs11ecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
667 	pk11_object_t *ec;
668 	isc_region_t r;
669 	unsigned int len;
670 	CK_ATTRIBUTE *attr;
671 
672 	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
673 		key->key_alg == DST_ALG_ECDSA384);
674 
675 	switch (key->key_alg) {
676 	case DST_ALG_ECDSA256:
677 		len = DNS_KEY_ECDSA256SIZE;
678 		break;
679 	case DST_ALG_ECDSA384:
680 		len = DNS_KEY_ECDSA384SIZE;
681 		break;
682 	default:
683 		INSIST(0);
684 		ISC_UNREACHABLE();
685 	}
686 
687 	isc_buffer_remainingregion(data, &r);
688 	if (r.length == 0) {
689 		return (ISC_R_SUCCESS);
690 	}
691 	if (r.length != len) {
692 		return (DST_R_INVALIDPUBLICKEY);
693 	}
694 
695 	ec = isc_mem_get(key->mctx, sizeof(*ec));
696 	memset(ec, 0, sizeof(*ec));
697 	ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 2);
698 	ec->attrcnt = 2;
699 
700 	attr = ec->repr;
701 	attr->type = CKA_EC_PARAMS;
702 	SETCURVE();
703 
704 	attr++;
705 	attr->type = CKA_EC_POINT;
706 	attr->pValue = isc_mem_get(key->mctx, len + 3);
707 	((CK_BYTE_PTR)attr->pValue)[0] = TAG_OCTECT_STRING;
708 	((CK_BYTE_PTR)attr->pValue)[1] = len + 1;
709 	((CK_BYTE_PTR)attr->pValue)[2] = UNCOMPRESSED;
710 	memmove((CK_BYTE_PTR)attr->pValue + 3, r.base, len);
711 	attr->ulValueLen = len + 3;
712 
713 	isc_buffer_forward(data, len);
714 	key->keydata.pkey = ec;
715 	key->key_size = len * 4;
716 
717 	return (ISC_R_SUCCESS);
718 }
719 
720 static isc_result_t
pkcs11ecdsa_tofile(const dst_key_t * key,const char * directory)721 pkcs11ecdsa_tofile(const dst_key_t *key, const char *directory) {
722 	isc_result_t ret;
723 	pk11_object_t *ec;
724 	dst_private_t priv;
725 	unsigned char *buf = NULL;
726 	unsigned int i = 0;
727 	CK_ATTRIBUTE *attr;
728 
729 	if (key->keydata.pkey == NULL) {
730 		return (DST_R_NULLKEY);
731 	}
732 
733 	if (key->external) {
734 		priv.nelements = 0;
735 		return (dst__privstruct_writefile(key, &priv, directory));
736 	}
737 
738 	ec = key->keydata.pkey;
739 	attr = pk11_attribute_bytype(ec, CKA_VALUE);
740 	if (attr != NULL) {
741 		buf = isc_mem_get(key->mctx, attr->ulValueLen);
742 		priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY;
743 		priv.elements[i].length = (unsigned short)attr->ulValueLen;
744 		memmove(buf, attr->pValue, attr->ulValueLen);
745 		priv.elements[i].data = buf;
746 		i++;
747 	}
748 
749 	if (key->engine != NULL) {
750 		priv.elements[i].tag = TAG_ECDSA_ENGINE;
751 		priv.elements[i].length = strlen(key->engine) + 1;
752 		priv.elements[i].data = (unsigned char *)key->engine;
753 		i++;
754 	}
755 
756 	if (key->label != NULL) {
757 		priv.elements[i].tag = TAG_ECDSA_LABEL;
758 		priv.elements[i].length = strlen(key->label) + 1;
759 		priv.elements[i].data = (unsigned char *)key->label;
760 		i++;
761 	}
762 
763 	priv.nelements = i;
764 	ret = dst__privstruct_writefile(key, &priv, directory);
765 
766 	if (buf != NULL) {
767 		memset(buf, 0, attr->ulValueLen);
768 		isc_mem_put(key->mctx, buf, attr->ulValueLen);
769 	}
770 	return (ret);
771 }
772 
773 static isc_result_t
pkcs11ecdsa_fetch(dst_key_t * key,const char * engine,const char * label,dst_key_t * pub)774 pkcs11ecdsa_fetch(dst_key_t *key, const char *engine, const char *label,
775 		  dst_key_t *pub) {
776 	CK_RV rv;
777 	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
778 	CK_KEY_TYPE keyType = CKK_EC;
779 	CK_ATTRIBUTE searchTemplate[] = {
780 		{ CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) },
781 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) },
782 		{ CKA_TOKEN, &truevalue, (CK_ULONG)sizeof(truevalue) },
783 		{ CKA_LABEL, NULL, 0 }
784 	};
785 	CK_ULONG cnt;
786 	CK_ATTRIBUTE *attr;
787 	CK_ATTRIBUTE *pubattr;
788 	pk11_object_t *ec;
789 	pk11_object_t *pubec;
790 	pk11_context_t *pk11_ctx = NULL;
791 	isc_result_t ret;
792 
793 	if (label == NULL) {
794 		return (DST_R_NOENGINE);
795 	}
796 
797 	ec = key->keydata.pkey;
798 	pubec = pub->keydata.pkey;
799 
800 	ec->object = CK_INVALID_HANDLE;
801 	ec->ontoken = true;
802 	ec->reqlogon = true;
803 	ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 2);
804 	memset(ec->repr, 0, sizeof(*attr) * 2);
805 	ec->attrcnt = 2;
806 	attr = ec->repr;
807 
808 	attr->type = CKA_EC_PARAMS;
809 	pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS);
810 	INSIST(pubattr != NULL);
811 	attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
812 	memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
813 	attr->ulValueLen = pubattr->ulValueLen;
814 	attr++;
815 
816 	attr->type = CKA_EC_POINT;
817 	pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT);
818 	INSIST(pubattr != NULL);
819 	attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
820 	memmove(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
821 	attr->ulValueLen = pubattr->ulValueLen;
822 
823 	ret = pk11_parse_uri(ec, label, key->mctx, OP_ECDSA);
824 	if (ret != ISC_R_SUCCESS) {
825 		goto err;
826 	}
827 
828 	pk11_ctx = isc_mem_get(key->mctx, sizeof(*pk11_ctx));
829 	ret = pk11_get_session(pk11_ctx, OP_ECDSA, true, false, ec->reqlogon,
830 			       NULL, ec->slot);
831 	if (ret != ISC_R_SUCCESS) {
832 		goto err;
833 	}
834 
835 	attr = pk11_attribute_bytype(ec, CKA_LABEL);
836 	if (attr == NULL) {
837 		attr = pk11_attribute_bytype(ec, CKA_ID);
838 		INSIST(attr != NULL);
839 		searchTemplate[3].type = CKA_ID;
840 	}
841 	searchTemplate[3].pValue = attr->pValue;
842 	searchTemplate[3].ulValueLen = attr->ulValueLen;
843 
844 	PK11_RET(pkcs_C_FindObjectsInit,
845 		 (pk11_ctx->session, searchTemplate, (CK_ULONG)4),
846 		 DST_R_CRYPTOFAILURE);
847 	PK11_RET(pkcs_C_FindObjects,
848 		 (pk11_ctx->session, &ec->object, (CK_ULONG)1, &cnt),
849 		 DST_R_CRYPTOFAILURE);
850 	(void)pkcs_C_FindObjectsFinal(pk11_ctx->session);
851 	if (cnt == 0) {
852 		DST_RET(ISC_R_NOTFOUND);
853 	}
854 	if (cnt > 1) {
855 		DST_RET(ISC_R_EXISTS);
856 	}
857 
858 	if (engine != NULL) {
859 		key->engine = isc_mem_strdup(key->mctx, engine);
860 	}
861 
862 	key->label = isc_mem_strdup(key->mctx, label);
863 
864 	pk11_return_session(pk11_ctx);
865 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
866 	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
867 	return (ISC_R_SUCCESS);
868 
869 err:
870 	if (pk11_ctx != NULL) {
871 		pk11_return_session(pk11_ctx);
872 		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
873 		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
874 	}
875 	return (ret);
876 }
877 
878 static isc_result_t
pkcs11ecdsa_parse(dst_key_t * key,isc_lex_t * lexer,dst_key_t * pub)879 pkcs11ecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
880 	dst_private_t priv;
881 	isc_result_t ret;
882 	pk11_object_t *ec = NULL;
883 	CK_ATTRIBUTE *attr, *pattr;
884 	isc_mem_t *mctx = key->mctx;
885 	unsigned int i;
886 	const char *engine = NULL, *label = NULL;
887 
888 	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
889 		key->key_alg == DST_ALG_ECDSA384);
890 
891 	if ((pub == NULL) || (pub->keydata.pkey == NULL)) {
892 		DST_RET(DST_R_INVALIDPRIVATEKEY);
893 	}
894 
895 	/* read private key file */
896 	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
897 	if (ret != ISC_R_SUCCESS) {
898 		return (ret);
899 	}
900 
901 	if (key->external) {
902 		if (priv.nelements != 0) {
903 			DST_RET(DST_R_INVALIDPRIVATEKEY);
904 		}
905 
906 		key->keydata.pkey = pub->keydata.pkey;
907 		pub->keydata.pkey = NULL;
908 		key->key_size = pub->key_size;
909 
910 		dst__privstruct_free(&priv, mctx);
911 		memset(&priv, 0, sizeof(priv));
912 
913 		return (ISC_R_SUCCESS);
914 	}
915 
916 	for (i = 0; i < priv.nelements; i++) {
917 		switch (priv.elements[i].tag) {
918 		case TAG_ECDSA_ENGINE:
919 			engine = (char *)priv.elements[i].data;
920 			break;
921 		case TAG_ECDSA_LABEL:
922 			label = (char *)priv.elements[i].data;
923 			break;
924 		default:
925 			break;
926 		}
927 	}
928 	ec = isc_mem_get(key->mctx, sizeof(*ec));
929 	memset(ec, 0, sizeof(*ec));
930 	key->keydata.pkey = ec;
931 
932 	/* Is this key is stored in a HSM? See if we can fetch it. */
933 	if ((label != NULL) || (engine != NULL)) {
934 		ret = pkcs11ecdsa_fetch(key, engine, label, pub);
935 		if (ret != ISC_R_SUCCESS) {
936 			goto err;
937 		}
938 		dst__privstruct_free(&priv, mctx);
939 		memset(&priv, 0, sizeof(priv));
940 		return (ret);
941 	}
942 
943 	ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 3);
944 	memset(ec->repr, 0, sizeof(*attr) * 3);
945 	ec->attrcnt = 3;
946 
947 	attr = ec->repr;
948 	attr->type = CKA_EC_PARAMS;
949 	pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_PARAMS);
950 	INSIST(pattr != NULL);
951 	attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
952 	memmove(attr->pValue, pattr->pValue, pattr->ulValueLen);
953 	attr->ulValueLen = pattr->ulValueLen;
954 
955 	attr++;
956 	attr->type = CKA_EC_POINT;
957 	pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_POINT);
958 	INSIST(pattr != NULL);
959 	attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
960 	memmove(attr->pValue, pattr->pValue, pattr->ulValueLen);
961 	attr->ulValueLen = pattr->ulValueLen;
962 
963 	attr++;
964 	attr->type = CKA_VALUE;
965 	attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length);
966 	memmove(attr->pValue, priv.elements[0].data, priv.elements[0].length);
967 	attr->ulValueLen = priv.elements[0].length;
968 
969 	dst__privstruct_free(&priv, mctx);
970 	memset(&priv, 0, sizeof(priv));
971 	switch (key->key_alg) {
972 	case DST_ALG_ECDSA256:
973 		key->key_size = DNS_KEY_ECDSA256SIZE * 4;
974 		break;
975 	case DST_ALG_ECDSA384:
976 		key->key_size = DNS_KEY_ECDSA384SIZE * 4;
977 		break;
978 	default:
979 		INSIST(0);
980 		ISC_UNREACHABLE();
981 	}
982 
983 	return (ISC_R_SUCCESS);
984 
985 err:
986 	pkcs11ecdsa_destroy(key);
987 	dst__privstruct_free(&priv, mctx);
988 	memset(&priv, 0, sizeof(priv));
989 	return (ret);
990 }
991 
992 static isc_result_t
pkcs11ecdsa_fromlabel(dst_key_t * key,const char * engine,const char * label,const char * pin)993 pkcs11ecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
994 		      const char *pin) {
995 	CK_RV rv;
996 	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
997 	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
998 	CK_KEY_TYPE keyType = CKK_EC;
999 	CK_ATTRIBUTE searchTemplate[] = {
1000 		{ CKA_CLASS, &keyClass, (CK_ULONG)sizeof(keyClass) },
1001 		{ CKA_KEY_TYPE, &keyType, (CK_ULONG)sizeof(keyType) },
1002 		{ CKA_TOKEN, &truevalue, (CK_ULONG)sizeof(truevalue) },
1003 		{ CKA_LABEL, NULL, 0 }
1004 	};
1005 	CK_ULONG cnt;
1006 	CK_ATTRIBUTE *attr;
1007 	pk11_object_t *ec;
1008 	pk11_context_t *pk11_ctx = NULL;
1009 	isc_result_t ret;
1010 	unsigned int i;
1011 
1012 	UNUSED(pin);
1013 
1014 	ec = isc_mem_get(key->mctx, sizeof(*ec));
1015 	memset(ec, 0, sizeof(*ec));
1016 	ec->object = CK_INVALID_HANDLE;
1017 	ec->ontoken = true;
1018 	ec->reqlogon = true;
1019 	key->keydata.pkey = ec;
1020 
1021 	ec->repr = isc_mem_get(key->mctx, sizeof(*attr) * 2);
1022 	memset(ec->repr, 0, sizeof(*attr) * 2);
1023 	ec->attrcnt = 2;
1024 	attr = ec->repr;
1025 	attr[0].type = CKA_EC_PARAMS;
1026 	attr[1].type = CKA_EC_POINT;
1027 
1028 	ret = pk11_parse_uri(ec, label, key->mctx, OP_ECDSA);
1029 	if (ret != ISC_R_SUCCESS) {
1030 		goto err;
1031 	}
1032 
1033 	pk11_ctx = isc_mem_get(key->mctx, sizeof(*pk11_ctx));
1034 	ret = pk11_get_session(pk11_ctx, OP_ECDSA, true, false, ec->reqlogon,
1035 			       NULL, ec->slot);
1036 	if (ret != ISC_R_SUCCESS) {
1037 		goto err;
1038 	}
1039 
1040 	attr = pk11_attribute_bytype(ec, CKA_LABEL);
1041 	if (attr == NULL) {
1042 		attr = pk11_attribute_bytype(ec, CKA_ID);
1043 		INSIST(attr != NULL);
1044 		searchTemplate[3].type = CKA_ID;
1045 	}
1046 	searchTemplate[3].pValue = attr->pValue;
1047 	searchTemplate[3].ulValueLen = attr->ulValueLen;
1048 
1049 	PK11_RET(pkcs_C_FindObjectsInit,
1050 		 (pk11_ctx->session, searchTemplate, (CK_ULONG)4),
1051 		 DST_R_CRYPTOFAILURE);
1052 	PK11_RET(pkcs_C_FindObjects,
1053 		 (pk11_ctx->session, &hKey, (CK_ULONG)1, &cnt),
1054 		 DST_R_CRYPTOFAILURE);
1055 	(void)pkcs_C_FindObjectsFinal(pk11_ctx->session);
1056 	if (cnt == 0) {
1057 		DST_RET(ISC_R_NOTFOUND);
1058 	}
1059 	if (cnt > 1) {
1060 		DST_RET(ISC_R_EXISTS);
1061 	}
1062 
1063 	attr = ec->repr;
1064 	PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, hKey, attr, 2),
1065 		 DST_R_CRYPTOFAILURE);
1066 	for (i = 0; i <= 1; i++) {
1067 		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
1068 		memset(attr[i].pValue, 0, attr[i].ulValueLen);
1069 	}
1070 	PK11_RET(pkcs_C_GetAttributeValue, (pk11_ctx->session, hKey, attr, 2),
1071 		 DST_R_CRYPTOFAILURE);
1072 
1073 	keyClass = CKO_PRIVATE_KEY;
1074 	PK11_RET(pkcs_C_FindObjectsInit,
1075 		 (pk11_ctx->session, searchTemplate, (CK_ULONG)4),
1076 		 DST_R_CRYPTOFAILURE);
1077 	PK11_RET(pkcs_C_FindObjects,
1078 		 (pk11_ctx->session, &ec->object, (CK_ULONG)1, &cnt),
1079 		 DST_R_CRYPTOFAILURE);
1080 	(void)pkcs_C_FindObjectsFinal(pk11_ctx->session);
1081 	if (cnt == 0) {
1082 		DST_RET(ISC_R_NOTFOUND);
1083 	}
1084 	if (cnt > 1) {
1085 		DST_RET(ISC_R_EXISTS);
1086 	}
1087 
1088 	if (engine != NULL) {
1089 		key->engine = isc_mem_strdup(key->mctx, engine);
1090 	}
1091 
1092 	key->label = isc_mem_strdup(key->mctx, label);
1093 	switch (key->key_alg) {
1094 	case DST_ALG_ECDSA256:
1095 		key->key_size = DNS_KEY_ECDSA256SIZE * 4;
1096 		break;
1097 	case DST_ALG_ECDSA384:
1098 		key->key_size = DNS_KEY_ECDSA384SIZE * 4;
1099 		break;
1100 	default:
1101 		INSIST(0);
1102 		ISC_UNREACHABLE();
1103 	}
1104 
1105 	pk11_return_session(pk11_ctx);
1106 	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
1107 	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
1108 	return (ISC_R_SUCCESS);
1109 
1110 err:
1111 	pkcs11ecdsa_destroy(key);
1112 	if (pk11_ctx != NULL) {
1113 		pk11_return_session(pk11_ctx);
1114 		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
1115 		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
1116 	}
1117 	return (ret);
1118 }
1119 
1120 static dst_func_t pkcs11ecdsa_functions = {
1121 	pkcs11ecdsa_createctx,
1122 	NULL, /*%< createctx2 */
1123 	pkcs11ecdsa_destroyctx,
1124 	pkcs11ecdsa_adddata,
1125 	pkcs11ecdsa_sign,
1126 	pkcs11ecdsa_verify,
1127 	NULL, /*%< verify2 */
1128 	NULL, /*%< computesecret */
1129 	pkcs11ecdsa_compare,
1130 	NULL, /*%< paramcompare */
1131 	pkcs11ecdsa_generate,
1132 	pkcs11ecdsa_isprivate,
1133 	pkcs11ecdsa_destroy,
1134 	pkcs11ecdsa_todns,
1135 	pkcs11ecdsa_fromdns,
1136 	pkcs11ecdsa_tofile,
1137 	pkcs11ecdsa_parse,
1138 	NULL, /*%< cleanup */
1139 	pkcs11ecdsa_fromlabel,
1140 	NULL, /*%< dump */
1141 	NULL, /*%< restore */
1142 };
1143 
1144 isc_result_t
dst__pkcs11ecdsa_init(dst_func_t ** funcp)1145 dst__pkcs11ecdsa_init(dst_func_t **funcp) {
1146 	REQUIRE(funcp != NULL);
1147 	if (*funcp == NULL) {
1148 		*funcp = &pkcs11ecdsa_functions;
1149 	}
1150 	return (ISC_R_SUCCESS);
1151 }
1152 
1153 #endif /* USE_PKCS11 */
1154