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