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