1 /* $NetBSD: pk11.c,v 1.1 2024/02/18 20:57:49 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 #include <errno.h>
17 #include <inttypes.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <isc/log.h>
24 #include <isc/mem.h>
25 #include <isc/once.h>
26 #include <isc/platform.h>
27 #include <isc/print.h>
28 #include <isc/stdio.h>
29 #include <isc/strerr.h>
30 #include <isc/string.h>
31 #include <isc/thread.h>
32 #include <isc/util.h>
33
34 #include <pk11/internal.h>
35 #include <pk11/pk11.h>
36 #include <pk11/result.h>
37 #include <pk11/site.h>
38 #include <pkcs11/pkcs11.h>
39
40 #include <dst/result.h>
41
42 /* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */
43 #ifndef PINLEN
44 #define PINLEN 256
45 #endif /* ifndef PINLEN */
46
47 #ifndef PK11_NO_LOGERR
48 #define PK11_NO_LOGERR 1
49 #endif /* ifndef PK11_NO_LOGERR */
50
51 LIBISC_EXTERNAL_DATA bool pk11_verbose_init = false;
52
53 static isc_once_t once = ISC_ONCE_INIT;
54 static isc_mem_t *pk11_mctx = NULL;
55 static int32_t allocsize = 0;
56 static bool initialized = false;
57
58 typedef struct pk11_session pk11_session_t;
59 typedef struct pk11_token pk11_token_t;
60 typedef ISC_LIST(pk11_session_t) pk11_sessionlist_t;
61
62 struct pk11_session {
63 unsigned int magic;
64 CK_SESSION_HANDLE session;
65 ISC_LINK(pk11_session_t) link;
66 pk11_token_t *token;
67 };
68
69 struct pk11_token {
70 unsigned int magic;
71 unsigned int operations;
72 ISC_LINK(pk11_token_t) link;
73 CK_SLOT_ID slotid;
74 pk11_sessionlist_t sessions;
75 bool logged;
76 char name[32];
77 char manuf[32];
78 char model[16];
79 char serial[16];
80 char pin[PINLEN + 1];
81 };
82 static ISC_LIST(pk11_token_t) tokens;
83
84 static pk11_token_t *best_rsa_token;
85 static pk11_token_t *best_ecdsa_token;
86 static pk11_token_t *best_eddsa_token;
87
88 static isc_result_t
89 free_all_sessions(void);
90 static isc_result_t
91 free_session_list(pk11_sessionlist_t *slist);
92 static isc_result_t
93 setup_session(pk11_session_t *sp, pk11_token_t *token, bool rw);
94 static void
95 scan_slots(void);
96 static isc_result_t
97 token_login(pk11_session_t *sp);
98 static char *
99 percent_decode(char *x, size_t *len);
100 static bool
101 pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny);
102 static CK_ATTRIBUTE *
103 push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len);
104
105 static isc_mutex_t alloclock;
106 static isc_mutex_t sessionlock;
107
108 static pk11_sessionlist_t actives;
109
110 static CK_C_INITIALIZE_ARGS pk11_init_args = {
111 NULL_PTR, /* CreateMutex */
112 NULL_PTR, /* DestroyMutex */
113 NULL_PTR, /* LockMutex */
114 NULL_PTR, /* UnlockMutex */
115 CKF_OS_LOCKING_OK, /* flags */
116 NULL_PTR, /* pReserved */
117 };
118
119 #ifndef PK11_LIB_LOCATION
120 #define PK11_LIB_LOCATION "unknown_provider"
121 #endif /* ifndef PK11_LIB_LOCATION */
122
123 #ifndef WIN32
124 static const char *lib_name = PK11_LIB_LOCATION;
125 #else /* ifndef WIN32 */
126 static const char *lib_name = PK11_LIB_LOCATION ".dll";
127 #endif /* ifndef WIN32 */
128
129 void
pk11_set_lib_name(const char * name)130 pk11_set_lib_name(const char *name) {
131 lib_name = name;
132 }
133
134 const char *
pk11_get_lib_name(void)135 pk11_get_lib_name(void) {
136 return (lib_name);
137 }
138
139 static void
initialize(void)140 initialize(void) {
141 char *pk11_provider;
142
143 isc_mutex_init(&alloclock);
144 isc_mutex_init(&sessionlock);
145
146 pk11_provider = getenv("PKCS11_PROVIDER");
147 if (pk11_provider != NULL) {
148 lib_name = pk11_provider;
149 }
150 }
151
152 void *
pk11_mem_get(size_t size)153 pk11_mem_get(size_t size) {
154 void *ptr;
155
156 LOCK(&alloclock);
157 if (pk11_mctx != NULL) {
158 ptr = isc_mem_get(pk11_mctx, size);
159 } else {
160 ptr = malloc(size);
161 if (ptr == NULL && size != 0) {
162 char strbuf[ISC_STRERRORSIZE];
163 strerror_r(errno, strbuf, sizeof(strbuf));
164 isc_error_fatal(__FILE__, __LINE__, "malloc failed: %s",
165 strbuf);
166 }
167 }
168 UNLOCK(&alloclock);
169
170 if (ptr != NULL) {
171 memset(ptr, 0, size);
172 }
173 return (ptr);
174 }
175
176 void
pk11_mem_put(void * ptr,size_t size)177 pk11_mem_put(void *ptr, size_t size) {
178 if (ptr != NULL) {
179 memset(ptr, 0, size);
180 }
181 LOCK(&alloclock);
182 if (pk11_mctx != NULL) {
183 isc_mem_put(pk11_mctx, ptr, size);
184 } else {
185 if (ptr != NULL) {
186 allocsize -= (int)size;
187 }
188 free(ptr);
189 }
190 UNLOCK(&alloclock);
191 }
192
193 isc_result_t
pk11_initialize(isc_mem_t * mctx,const char * engine)194 pk11_initialize(isc_mem_t *mctx, const char *engine) {
195 isc_result_t result = ISC_R_SUCCESS;
196 CK_RV rv;
197
198 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
199
200 LOCK(&sessionlock);
201 LOCK(&alloclock);
202 if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0)) {
203 isc_mem_attach(mctx, &pk11_mctx);
204 }
205 UNLOCK(&alloclock);
206 if (initialized) {
207 goto unlock;
208 } else {
209 initialized = true;
210 }
211
212 ISC_LIST_INIT(tokens);
213 ISC_LIST_INIT(actives);
214
215 if (engine != NULL) {
216 lib_name = engine;
217 }
218
219 /* Initialize the CRYPTOKI library */
220 rv = pkcs_C_Initialize((CK_VOID_PTR)&pk11_init_args);
221
222 if (rv == 0xfe) {
223 result = PK11_R_NOPROVIDER;
224 fprintf(stderr, "Can't load PKCS#11 provider: %s\n",
225 pk11_get_load_error_message());
226 goto unlock;
227 }
228 if (rv != CKR_OK) {
229 result = PK11_R_INITFAILED;
230 goto unlock;
231 }
232
233 scan_slots();
234 unlock:
235 UNLOCK(&sessionlock);
236 return (result);
237 }
238
239 isc_result_t
pk11_finalize(void)240 pk11_finalize(void) {
241 pk11_token_t *token, *next;
242 isc_result_t ret;
243
244 ret = free_all_sessions();
245 (void)pkcs_C_Finalize(NULL_PTR);
246 token = ISC_LIST_HEAD(tokens);
247 while (token != NULL) {
248 next = ISC_LIST_NEXT(token, link);
249 ISC_LIST_UNLINK(tokens, token, link);
250 if (token == best_rsa_token) {
251 best_rsa_token = NULL;
252 }
253 if (token == best_ecdsa_token) {
254 best_ecdsa_token = NULL;
255 }
256 if (token == best_eddsa_token) {
257 best_eddsa_token = NULL;
258 }
259 pk11_mem_put(token, sizeof(*token));
260 token = next;
261 }
262 if (pk11_mctx != NULL) {
263 isc_mem_detach(&pk11_mctx);
264 }
265 initialized = false;
266 return (ret);
267 }
268
269 isc_result_t
pk11_get_session(pk11_context_t * ctx,pk11_optype_t optype,bool need_services,bool rw,bool logon,const char * pin,CK_SLOT_ID slot)270 pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype, bool need_services,
271 bool rw, bool logon, const char *pin, CK_SLOT_ID slot) {
272 pk11_token_t *token = NULL;
273 pk11_sessionlist_t *freelist;
274 pk11_session_t *sp;
275 isc_result_t ret;
276 UNUSED(need_services);
277
278 memset(ctx, 0, sizeof(pk11_context_t));
279 ctx->handle = NULL;
280 ctx->session = CK_INVALID_HANDLE;
281
282 ret = pk11_initialize(NULL, NULL);
283 if (ret != ISC_R_SUCCESS) {
284 return (ret);
285 }
286
287 LOCK(&sessionlock);
288 /* wait for initialization to finish */
289 UNLOCK(&sessionlock);
290
291 switch (optype) {
292 case OP_ANY:
293 for (token = ISC_LIST_HEAD(tokens); token != NULL;
294 token = ISC_LIST_NEXT(token, link))
295 {
296 if (token->slotid == slot) {
297 break;
298 }
299 }
300 break;
301 default:
302 for (token = ISC_LIST_HEAD(tokens); token != NULL;
303 token = ISC_LIST_NEXT(token, link))
304 {
305 if (token->slotid == slot) {
306 break;
307 }
308 }
309 break;
310 }
311 if (token == NULL) {
312 return (ISC_R_NOTFOUND);
313 }
314
315 /* Override the token's PIN */
316 if (logon && pin != NULL && *pin != '\0') {
317 if (strlen(pin) > PINLEN) {
318 return (ISC_R_RANGE);
319 }
320 /*
321 * We want to zero out the old pin before
322 * overwriting with a new one.
323 */
324 memset(token->pin, 0, sizeof(token->pin));
325 strlcpy(token->pin, pin, sizeof(token->pin));
326 }
327
328 freelist = &token->sessions;
329
330 LOCK(&sessionlock);
331 sp = ISC_LIST_HEAD(*freelist);
332 if (sp != NULL) {
333 ISC_LIST_UNLINK(*freelist, sp, link);
334 ISC_LIST_APPEND(actives, sp, link);
335 UNLOCK(&sessionlock);
336 if (logon) {
337 ret = token_login(sp);
338 }
339 ctx->handle = sp;
340 ctx->session = sp->session;
341 return (ret);
342 }
343 UNLOCK(&sessionlock);
344
345 sp = pk11_mem_get(sizeof(*sp));
346 sp->magic = SES_MAGIC;
347 sp->token = token;
348 sp->session = CK_INVALID_HANDLE;
349 ISC_LINK_INIT(sp, link);
350 ret = setup_session(sp, token, rw);
351 if ((ret == ISC_R_SUCCESS) && logon) {
352 ret = token_login(sp);
353 }
354 LOCK(&sessionlock);
355 ISC_LIST_APPEND(actives, sp, link);
356 UNLOCK(&sessionlock);
357 ctx->handle = sp;
358 ctx->session = sp->session;
359 return (ret);
360 }
361
362 void
pk11_return_session(pk11_context_t * ctx)363 pk11_return_session(pk11_context_t *ctx) {
364 pk11_session_t *sp = (pk11_session_t *)ctx->handle;
365
366 if (sp == NULL) {
367 return;
368 }
369 ctx->handle = NULL;
370 ctx->session = CK_INVALID_HANDLE;
371
372 LOCK(&sessionlock);
373 ISC_LIST_UNLINK(actives, sp, link);
374 UNLOCK(&sessionlock);
375 if (sp->session == CK_INVALID_HANDLE) {
376 pk11_mem_put(sp, sizeof(*sp));
377 return;
378 }
379
380 LOCK(&sessionlock);
381 ISC_LIST_APPEND(sp->token->sessions, sp, link);
382 UNLOCK(&sessionlock);
383 }
384
385 static isc_result_t
free_all_sessions(void)386 free_all_sessions(void) {
387 pk11_token_t *token;
388 isc_result_t ret = ISC_R_SUCCESS;
389 isc_result_t oret;
390
391 for (token = ISC_LIST_HEAD(tokens); token != NULL;
392 token = ISC_LIST_NEXT(token, link))
393 {
394 oret = free_session_list(&token->sessions);
395 if (oret != ISC_R_SUCCESS) {
396 ret = oret;
397 }
398 }
399 if (!ISC_LIST_EMPTY(actives)) {
400 ret = ISC_R_ADDRINUSE;
401 oret = free_session_list(&actives);
402 if (oret != ISC_R_SUCCESS) {
403 ret = oret;
404 }
405 }
406 return (ret);
407 }
408
409 static isc_result_t
free_session_list(pk11_sessionlist_t * slist)410 free_session_list(pk11_sessionlist_t *slist) {
411 pk11_session_t *sp;
412 CK_RV rv;
413 isc_result_t ret;
414
415 ret = ISC_R_SUCCESS;
416 LOCK(&sessionlock);
417 while (!ISC_LIST_EMPTY(*slist)) {
418 sp = ISC_LIST_HEAD(*slist);
419 ISC_LIST_UNLINK(*slist, sp, link);
420 UNLOCK(&sessionlock);
421 if (sp->session != CK_INVALID_HANDLE) {
422 rv = pkcs_C_CloseSession(sp->session);
423 if (rv != CKR_OK) {
424 ret = DST_R_CRYPTOFAILURE;
425 }
426 }
427 LOCK(&sessionlock);
428 pk11_mem_put(sp, sizeof(*sp));
429 }
430 UNLOCK(&sessionlock);
431
432 return (ret);
433 }
434
435 static isc_result_t
setup_session(pk11_session_t * sp,pk11_token_t * token,bool rw)436 setup_session(pk11_session_t *sp, pk11_token_t *token, bool rw) {
437 CK_RV rv;
438 CK_FLAGS flags = CKF_SERIAL_SESSION;
439
440 if (rw) {
441 flags += CKF_RW_SESSION;
442 }
443
444 rv = pkcs_C_OpenSession(token->slotid, flags, NULL_PTR, NULL_PTR,
445 &sp->session);
446 if (rv != CKR_OK) {
447 return (DST_R_CRYPTOFAILURE);
448 }
449 return (ISC_R_SUCCESS);
450 }
451
452 static isc_result_t
token_login(pk11_session_t * sp)453 token_login(pk11_session_t *sp) {
454 CK_RV rv;
455 pk11_token_t *token = sp->token;
456 isc_result_t ret = ISC_R_SUCCESS;
457
458 LOCK(&sessionlock);
459 if (!token->logged) {
460 rv = pkcs_C_Login(sp->session, CKU_USER,
461 (CK_UTF8CHAR_PTR)token->pin,
462 (CK_ULONG)strlen(token->pin));
463 if (rv != CKR_OK) {
464 #if PK11_NO_LOGERR
465 pk11_error_fatalcheck(__FILE__, __LINE__,
466 "pkcs_C_Login", rv);
467 #else /* if PK11_NO_LOGERR */
468 ret = ISC_R_NOPERM;
469 #endif /* if PK11_NO_LOGERR */
470 } else {
471 token->logged = true;
472 }
473 }
474 UNLOCK(&sessionlock);
475 return (ret);
476 }
477
478 #define PK11_TRACE(fmt) \
479 if (pk11_verbose_init) \
480 fprintf(stderr, fmt)
481 #define PK11_TRACE1(fmt, arg) \
482 if (pk11_verbose_init) \
483 fprintf(stderr, fmt, arg)
484 #define PK11_TRACE2(fmt, arg1, arg2) \
485 if (pk11_verbose_init) \
486 fprintf(stderr, fmt, arg1, arg2)
487 #define PK11_TRACEM(mech) \
488 if (pk11_verbose_init) \
489 fprintf(stderr, #mech ": 0x%lx\n", rv)
490
491 static void
scan_slots(void)492 scan_slots(void) {
493 CK_MECHANISM_INFO mechInfo;
494 CK_TOKEN_INFO tokenInfo;
495 CK_RV rv;
496 CK_SLOT_ID slot;
497 CK_SLOT_ID_PTR slotList;
498 CK_ULONG slotCount;
499 pk11_token_t *token;
500 unsigned int i;
501 bool bad;
502
503 slotCount = 0;
504 PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
505 PK11_TRACE1("slotCount=%lu\n", slotCount);
506 /* it's not an error if we didn't find any providers */
507 if (slotCount == 0) {
508 return;
509 }
510 slotList = pk11_mem_get(sizeof(CK_SLOT_ID) * slotCount);
511 PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
512
513 for (i = 0; i < slotCount; i++) {
514 slot = slotList[i];
515 PK11_TRACE2("slot#%u=0x%lx\n", i, slot);
516
517 rv = pkcs_C_GetTokenInfo(slot, &tokenInfo);
518 if (rv != CKR_OK) {
519 continue;
520 }
521 token = pk11_mem_get(sizeof(*token));
522 token->magic = TOK_MAGIC;
523 token->slotid = slot;
524 ISC_LINK_INIT(token, link);
525 ISC_LIST_INIT(token->sessions);
526 memmove(token->name, tokenInfo.label, 32);
527 memmove(token->manuf, tokenInfo.manufacturerID, 32);
528 memmove(token->model, tokenInfo.model, 16);
529 memmove(token->serial, tokenInfo.serialNumber, 16);
530 ISC_LIST_APPEND(tokens, token, link);
531
532 /* Check for RSA support */
533 bad = false;
534 rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
535 &mechInfo);
536 if ((rv != CKR_OK) ||
537 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
538 {
539 bad = true;
540 PK11_TRACEM(CKM_RSA_PKCS_KEY_PAIR_GEN);
541 }
542 rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_RSA_PKCS, &mechInfo);
543 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
544 ((mechInfo.flags & CKF_VERIFY) == 0))
545 {
546 bad = true;
547 PK11_TRACEM(CKM_MD5_RSA_PKCS);
548 }
549 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
550 &mechInfo);
551 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
552 ((mechInfo.flags & CKF_VERIFY) == 0))
553 {
554 bad = true;
555 PK11_TRACEM(CKM_SHA1_RSA_PKCS);
556 }
557 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS,
558 &mechInfo);
559 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
560 ((mechInfo.flags & CKF_VERIFY) == 0))
561 {
562 bad = true;
563 PK11_TRACEM(CKM_SHA256_RSA_PKCS);
564 }
565 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS,
566 &mechInfo);
567 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
568 ((mechInfo.flags & CKF_VERIFY) == 0))
569 {
570 bad = true;
571 PK11_TRACEM(CKM_SHA512_RSA_PKCS);
572 }
573 rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS, &mechInfo);
574 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
575 ((mechInfo.flags & CKF_VERIFY) == 0))
576 {
577 bad = true;
578 PK11_TRACEM(CKM_RSA_PKCS);
579 }
580 if (!bad) {
581 token->operations |= 1 << OP_RSA;
582 if (best_rsa_token == NULL) {
583 best_rsa_token = token;
584 }
585 }
586
587 /* Check for ECDSA support */
588 bad = false;
589 rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN,
590 &mechInfo);
591 if ((rv != CKR_OK) ||
592 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
593 {
594 bad = true;
595 PK11_TRACEM(CKM_EC_KEY_PAIR_GEN);
596 }
597 rv = pkcs_C_GetMechanismInfo(slot, CKM_ECDSA, &mechInfo);
598 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
599 ((mechInfo.flags & CKF_VERIFY) == 0))
600 {
601 bad = true;
602 PK11_TRACEM(CKM_ECDSA);
603 }
604 if (!bad) {
605 token->operations |= 1 << OP_ECDSA;
606 if (best_ecdsa_token == NULL) {
607 best_ecdsa_token = token;
608 }
609 }
610
611 /* Check for EDDSA support */
612 bad = false;
613 rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_EDWARDS_KEY_PAIR_GEN,
614 &mechInfo);
615 if ((rv != CKR_OK) ||
616 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
617 {
618 bad = true;
619 PK11_TRACEM(CKM_EC_EDWARDS_KEY_PAIR_GEN);
620 }
621 rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA, &mechInfo);
622 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) ||
623 ((mechInfo.flags & CKF_VERIFY) == 0))
624 {
625 bad = true;
626 PK11_TRACEM(CKM_EDDSA);
627 }
628 if (!bad) {
629 token->operations |= 1 << OP_EDDSA;
630 if (best_eddsa_token == NULL) {
631 best_eddsa_token = token;
632 }
633 }
634 }
635
636 if (slotList != NULL) {
637 pk11_mem_put(slotList, sizeof(CK_SLOT_ID) * slotCount);
638 }
639 }
640
641 CK_SLOT_ID
pk11_get_best_token(pk11_optype_t optype)642 pk11_get_best_token(pk11_optype_t optype) {
643 pk11_token_t *token = NULL;
644
645 switch (optype) {
646 case OP_RSA:
647 token = best_rsa_token;
648 break;
649 case OP_ECDSA:
650 token = best_ecdsa_token;
651 break;
652 case OP_EDDSA:
653 token = best_eddsa_token;
654 break;
655 default:
656 break;
657 }
658 if (token == NULL) {
659 return (0);
660 }
661 return (token->slotid);
662 }
663
664 isc_result_t
pk11_numbits(CK_BYTE_PTR data,unsigned int bytecnt,unsigned int * bits)665 pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits) {
666 unsigned int bitcnt, i;
667 CK_BYTE top;
668
669 if (bytecnt == 0) {
670 *bits = 0;
671 return (ISC_R_SUCCESS);
672 }
673 bitcnt = bytecnt * 8;
674 for (i = 0; i < bytecnt; i++) {
675 top = data[i];
676 if (top == 0) {
677 bitcnt -= 8;
678 continue;
679 }
680 if (top & 0x80) {
681 *bits = bitcnt;
682 return (ISC_R_SUCCESS);
683 }
684 if (top & 0x40) {
685 *bits = bitcnt - 1;
686 return (ISC_R_SUCCESS);
687 }
688 if (top & 0x20) {
689 *bits = bitcnt - 2;
690 return (ISC_R_SUCCESS);
691 }
692 if (top & 0x10) {
693 *bits = bitcnt - 3;
694 return (ISC_R_SUCCESS);
695 }
696 if (top & 0x08) {
697 *bits = bitcnt - 4;
698 return (ISC_R_SUCCESS);
699 }
700 if (top & 0x04) {
701 *bits = bitcnt - 5;
702 return (ISC_R_SUCCESS);
703 }
704 if (top & 0x02) {
705 *bits = bitcnt - 6;
706 return (ISC_R_SUCCESS);
707 }
708 if (top & 0x01) {
709 *bits = bitcnt - 7;
710 return (ISC_R_SUCCESS);
711 }
712 break;
713 }
714 return (ISC_R_RANGE);
715 }
716
717 CK_ATTRIBUTE *
pk11_attribute_first(const pk11_object_t * obj)718 pk11_attribute_first(const pk11_object_t *obj) {
719 return (obj->repr);
720 }
721
722 CK_ATTRIBUTE *
pk11_attribute_next(const pk11_object_t * obj,CK_ATTRIBUTE * attr)723 pk11_attribute_next(const pk11_object_t *obj, CK_ATTRIBUTE *attr) {
724 CK_ATTRIBUTE *next;
725
726 next = attr + 1;
727 if ((next - obj->repr) >= obj->attrcnt) {
728 return (NULL);
729 }
730 return (next);
731 }
732
733 CK_ATTRIBUTE *
pk11_attribute_bytype(const pk11_object_t * obj,CK_ATTRIBUTE_TYPE type)734 pk11_attribute_bytype(const pk11_object_t *obj, CK_ATTRIBUTE_TYPE type) {
735 CK_ATTRIBUTE *attr;
736
737 for (attr = pk11_attribute_first(obj); attr != NULL;
738 attr = pk11_attribute_next(obj, attr))
739 {
740 if (attr->type == type) {
741 return (attr);
742 }
743 }
744 return (NULL);
745 }
746
747 static char *
percent_decode(char * x,size_t * len)748 percent_decode(char *x, size_t *len) {
749 char *p, *c;
750 unsigned char v = 0;
751
752 INSIST(len != NULL);
753
754 for (p = c = x; p[0] != '\0'; p++, c++) {
755 switch (p[0]) {
756 case '%':
757 switch (p[1]) {
758 case '0':
759 case '1':
760 case '2':
761 case '3':
762 case '4':
763 case '5':
764 case '6':
765 case '7':
766 case '8':
767 case '9':
768 v = (p[1] - '0') << 4;
769 break;
770 case 'A':
771 case 'B':
772 case 'C':
773 case 'D':
774 case 'E':
775 case 'F':
776 v = (p[1] - 'A' + 10) << 4;
777 break;
778 case 'a':
779 case 'b':
780 case 'c':
781 case 'd':
782 case 'e':
783 case 'f':
784 v = (p[1] - 'a' + 10) << 4;
785 break;
786 default:
787 return (NULL);
788 }
789 switch (p[2]) {
790 case '0':
791 case '1':
792 case '2':
793 case '3':
794 case '4':
795 case '5':
796 case '6':
797 case '7':
798 case '8':
799 case '9':
800 v |= (p[2] - '0') & 0x0f;
801 break;
802 case 'A':
803 case 'B':
804 case 'C':
805 case 'D':
806 case 'E':
807 case 'F':
808 v = (p[2] - 'A' + 10) & 0x0f;
809 break;
810 case 'a':
811 case 'b':
812 case 'c':
813 case 'd':
814 case 'e':
815 case 'f':
816 v = (p[2] - 'a' + 10) & 0x0f;
817 break;
818 default:
819 return (NULL);
820 }
821 p += 2;
822 *c = (char)v;
823 (*len)++;
824 break;
825 default:
826 *c = *p;
827 (*len)++;
828 }
829 }
830 return (x);
831 }
832
833 static bool
pk11strcmp(const char * x,size_t lenx,const char * y,size_t leny)834 pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny) {
835 char buf[32];
836
837 INSIST((leny == 32) || (leny == 16));
838
839 memset(buf, ' ', 32);
840 if (lenx > leny) {
841 lenx = leny;
842 }
843 memmove(buf, x, lenx);
844 return (memcmp(buf, y, leny) == 0);
845 }
846
847 static CK_ATTRIBUTE *
push_attribute(pk11_object_t * obj,isc_mem_t * mctx,size_t len)848 push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len) {
849 CK_ATTRIBUTE *old = obj->repr;
850 CK_ATTRIBUTE *attr;
851 CK_BYTE cnt = obj->attrcnt;
852
853 REQUIRE(old != NULL || cnt == 0);
854
855 obj->repr = isc_mem_get(mctx, (cnt + 1) * sizeof(*attr));
856 memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
857 if (old != NULL) {
858 memmove(obj->repr, old, cnt * sizeof(*attr));
859 }
860 attr = obj->repr + cnt;
861 attr->ulValueLen = (CK_ULONG)len;
862 attr->pValue = isc_mem_get(mctx, len);
863 memset(attr->pValue, 0, len);
864 if (old != NULL) {
865 memset(old, 0, cnt * sizeof(*attr));
866 isc_mem_put(mctx, old, cnt * sizeof(*attr));
867 }
868 obj->attrcnt++;
869 return (attr);
870 }
871
872 #define DST_RET(a) \
873 { \
874 ret = a; \
875 goto err; \
876 }
877
878 isc_result_t
pk11_parse_uri(pk11_object_t * obj,const char * label,isc_mem_t * mctx,pk11_optype_t optype)879 pk11_parse_uri(pk11_object_t *obj, const char *label, isc_mem_t *mctx,
880 pk11_optype_t optype) {
881 CK_ATTRIBUTE *attr;
882 pk11_token_t *token = NULL;
883 char *uri, *p, *a, *na, *v;
884 size_t len, l;
885 FILE *stream = NULL;
886 char pin[PINLEN + 1];
887 bool gotpin = false;
888 isc_result_t ret;
889
890 /* get values to work on */
891 len = strlen(label) + 1;
892 uri = isc_mem_get(mctx, len);
893 memmove(uri, label, len);
894
895 /* get the URI scheme */
896 p = strchr(uri, ':');
897 if (p == NULL) {
898 DST_RET(PK11_R_NOPROVIDER);
899 }
900 *p++ = '\0';
901 if (strcmp(uri, "pkcs11") != 0) {
902 DST_RET(PK11_R_NOPROVIDER);
903 }
904
905 /* get attributes */
906 for (na = p; na != NULL;) {
907 a = na;
908 p = strchr(a, ';');
909 if (p == NULL) {
910 /* last attribute */
911 na = NULL;
912 } else {
913 *p++ = '\0';
914 na = p;
915 }
916 p = strchr(a, '=');
917 if (p != NULL) {
918 *p++ = '\0';
919 v = p;
920 } else {
921 v = a;
922 }
923 l = 0;
924 v = percent_decode(v, &l);
925 if (v == NULL) {
926 DST_RET(PK11_R_NOPROVIDER);
927 }
928 if ((a == v) || (strcmp(a, "object") == 0)) {
929 /* object: CKA_LABEL */
930 attr = pk11_attribute_bytype(obj, CKA_LABEL);
931 if (attr != NULL) {
932 DST_RET(PK11_R_NOPROVIDER);
933 }
934 attr = push_attribute(obj, mctx, l);
935 if (attr == NULL) {
936 DST_RET(ISC_R_NOMEMORY);
937 }
938 attr->type = CKA_LABEL;
939 memmove(attr->pValue, v, l);
940 } else if (strcmp(a, "token") == 0) {
941 /* token: CK_TOKEN_INFO label */
942 if (token == NULL) {
943 for (token = ISC_LIST_HEAD(tokens);
944 token != NULL;
945 token = ISC_LIST_NEXT(token, link))
946 {
947 if (pk11strcmp(v, l, token->name, 32)) {
948 break;
949 }
950 }
951 }
952 } else if (strcmp(a, "manufacturer") == 0) {
953 /* manufacturer: CK_TOKEN_INFO manufacturerID */
954 if (token == NULL) {
955 for (token = ISC_LIST_HEAD(tokens);
956 token != NULL;
957 token = ISC_LIST_NEXT(token, link))
958 {
959 if (pk11strcmp(v, l, token->manuf, 32))
960 {
961 break;
962 }
963 }
964 }
965 } else if (strcmp(a, "serial") == 0) {
966 /* serial: CK_TOKEN_INFO serialNumber */
967 if (token == NULL) {
968 for (token = ISC_LIST_HEAD(tokens);
969 token != NULL;
970 token = ISC_LIST_NEXT(token, link))
971 {
972 if (pk11strcmp(v, l, token->serial, 16))
973 {
974 break;
975 }
976 }
977 }
978 } else if (strcmp(a, "model") == 0) {
979 /* model: CK_TOKEN_INFO model */
980 if (token == NULL) {
981 for (token = ISC_LIST_HEAD(tokens);
982 token != NULL;
983 token = ISC_LIST_NEXT(token, link))
984 {
985 if (pk11strcmp(v, l, token->model, 16))
986 {
987 break;
988 }
989 }
990 }
991 } else if (strcmp(a, "library-manufacturer") == 0) {
992 /* ignored */
993 } else if (strcmp(a, "library-description") == 0) {
994 /* ignored */
995 } else if (strcmp(a, "library-version") == 0) {
996 /* ignored */
997 } else if (strcmp(a, "object-type") == 0) {
998 /* object-type: CKA_CLASS */
999 /* only private makes sense */
1000 if (strcmp(v, "private") != 0) {
1001 DST_RET(PK11_R_NOPROVIDER);
1002 }
1003 } else if (strcmp(a, "id") == 0) {
1004 /* id: CKA_ID */
1005 attr = pk11_attribute_bytype(obj, CKA_ID);
1006 if (attr != NULL) {
1007 DST_RET(PK11_R_NOPROVIDER);
1008 }
1009 attr = push_attribute(obj, mctx, l);
1010 if (attr == NULL) {
1011 DST_RET(ISC_R_NOMEMORY);
1012 }
1013 attr->type = CKA_ID;
1014 memmove(attr->pValue, v, l);
1015 } else if (strcmp(a, "pin-source") == 0) {
1016 /* pin-source: PIN */
1017 ret = isc_stdio_open(v, "r", &stream);
1018 if (ret != ISC_R_SUCCESS) {
1019 goto err;
1020 }
1021 memset(pin, 0, PINLEN + 1);
1022 ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l);
1023 if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF)) {
1024 goto err;
1025 }
1026 if (l > PINLEN) {
1027 DST_RET(ISC_R_RANGE);
1028 }
1029 ret = isc_stdio_close(stream);
1030 stream = NULL;
1031 if (ret != ISC_R_SUCCESS) {
1032 goto err;
1033 }
1034 gotpin = true;
1035 } else {
1036 DST_RET(PK11_R_NOPROVIDER);
1037 }
1038 }
1039
1040 if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) &&
1041 (pk11_attribute_bytype(obj, CKA_ID) == NULL))
1042 {
1043 DST_RET(ISC_R_NOTFOUND);
1044 }
1045
1046 if (token == NULL) {
1047 if (optype == OP_RSA) {
1048 token = best_rsa_token;
1049 } else if (optype == OP_ECDSA) {
1050 token = best_ecdsa_token;
1051 } else if (optype == OP_EDDSA) {
1052 token = best_eddsa_token;
1053 }
1054 }
1055 if (token == NULL) {
1056 DST_RET(ISC_R_NOTFOUND);
1057 }
1058 obj->slot = token->slotid;
1059 if (gotpin) {
1060 memmove(token->pin, pin, PINLEN + 1);
1061 obj->reqlogon = true;
1062 }
1063
1064 ret = ISC_R_SUCCESS;
1065
1066 err:
1067 if (stream != NULL) {
1068 (void)isc_stdio_close(stream);
1069 }
1070 isc_mem_put(mctx, uri, len);
1071 return (ret);
1072 }
1073
1074 void
pk11_error_fatalcheck(const char * file,int line,const char * funcname,CK_RV rv)1075 pk11_error_fatalcheck(const char *file, int line, const char *funcname,
1076 CK_RV rv) {
1077 isc_error_fatal(file, line, "%s: Error = 0x%.8lX\n", funcname, rv);
1078 }
1079
1080 void
pk11_dump_tokens(void)1081 pk11_dump_tokens(void) {
1082 pk11_token_t *token;
1083 bool first;
1084
1085 printf("DEFAULTS\n");
1086 printf("\tbest_rsa_token=%p\n", best_rsa_token);
1087 printf("\tbest_ecdsa_token=%p\n", best_ecdsa_token);
1088 printf("\tbest_eddsa_token=%p\n", best_eddsa_token);
1089
1090 for (token = ISC_LIST_HEAD(tokens); token != NULL;
1091 token = ISC_LIST_NEXT(token, link))
1092 {
1093 printf("\nTOKEN\n");
1094 printf("\taddress=%p\n", token);
1095 printf("\tslotID=%lu\n", token->slotid);
1096 printf("\tlabel=%.32s\n", token->name);
1097 printf("\tmanufacturerID=%.32s\n", token->manuf);
1098 printf("\tmodel=%.16s\n", token->model);
1099 printf("\tserialNumber=%.16s\n", token->serial);
1100 printf("\tsupported operations=0x%x (", token->operations);
1101 first = true;
1102 if (token->operations & (1 << OP_RSA)) {
1103 first = false;
1104 printf("RSA");
1105 }
1106 if (token->operations & (1 << OP_ECDSA)) {
1107 if (!first) {
1108 printf(",");
1109 }
1110 printf("EC");
1111 }
1112 printf(")\n");
1113 }
1114 }
1115