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