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