xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/isc/pk11.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
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