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