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