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