1 /*
2  * slot.c: reader, smart card and slot related management functions
3  *
4  * Copyright (C) 2002  Timo Teräs <timo.teras@iki.fi>
5  * Copyright (C) 2009 Martin Paljak <martin@martinpaljak.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #include "config.h"
23 #include "libopensc/opensc.h"
24 
25 #include <string.h>
26 #include <stdlib.h>
27 
28 #include "sc-pkcs11.h"
29 
30 /* Print virtual_slots list. Called by DEBUG_VSS(S, C) */
_debug_virtual_slots(sc_pkcs11_slot_t * p)31 void _debug_virtual_slots(sc_pkcs11_slot_t *p)
32 {
33 	int i, vs_size;
34 	sc_pkcs11_slot_t * slot;
35 
36 	vs_size = list_size(&virtual_slots);
37 	_sc_debug(context, 10,
38 			"VSS size:%d", vs_size);
39 	_sc_debug(context, 10,
40 			"VSS  [i] id   flags LU events nsessions slot_info.flags reader p11card description");
41 	for (i = 0; i < vs_size; i++) {
42 		slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
43 		if (slot) {
44 			_sc_debug(context, 10,
45 				"VSS %s[%d] 0x%2.2lx 0x%4.4x %d  %d  %d %4.4lx  %p %p %.64s",
46 				((slot == p) ? "*" : " "),
47 				i, slot->id, slot->flags, slot->login_user, slot->events, slot->nsessions,
48 				slot->slot_info.flags,
49 				slot->reader, slot->p11card,
50 				slot->slot_info.slotDescription);
51 		}
52 	}
53 	_sc_debug(context, 10, "VSS END");
54 }
55 
56 static struct sc_pkcs11_framework_ops *frameworks[] = {
57 	&framework_pkcs15,
58 #ifdef USE_PKCS15_INIT
59 	/* This should be the last framework, because it
60 	 * will assume the card is blank and try to initialize it */
61 	&framework_pkcs15init,
62 #endif
63 	NULL
64 };
65 
reader_reclaim_slot(sc_reader_t * reader)66 static struct sc_pkcs11_slot * reader_reclaim_slot(sc_reader_t *reader)
67 {
68 	unsigned int i;
69 	CK_UTF8CHAR slotDescription[64];
70 	CK_UTF8CHAR manufacturerID[32];
71 
72 	strcpy_bp(slotDescription, reader->name, 64);
73 	strcpy_bp(manufacturerID, reader->vendor, 32);
74 
75 	/* Locate a slot related to the reader */
76 	for (i = 0; i<list_size(&virtual_slots); i++) {
77 		sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
78 		if (slot->reader == NULL && reader != NULL
79 				&& 0 == memcmp(slot->slot_info.slotDescription, slotDescription, 64)
80 				&& 0 == memcmp(slot->slot_info.manufacturerID, manufacturerID, 32)
81 				&& slot->slot_info.hardwareVersion.major == reader->version_major
82 				&& slot->slot_info.hardwareVersion.minor == reader->version_minor) {
83 			return slot;
84 		}
85 	}
86 	return NULL;
87 }
88 
init_slot_info(CK_SLOT_INFO_PTR pInfo,sc_reader_t * reader)89 void init_slot_info(CK_SLOT_INFO_PTR pInfo, sc_reader_t *reader)
90 {
91 	if (reader) {
92 		strcpy_bp(pInfo->slotDescription, reader->name, 64);
93 		strcpy_bp(pInfo->manufacturerID, reader->vendor, 32);
94 		pInfo->hardwareVersion.major = reader->version_major;
95 		pInfo->hardwareVersion.minor = reader->version_minor;
96 	} else {
97 		strcpy_bp(pInfo->slotDescription, "Virtual hotplug slot", 64);
98 		strcpy_bp(pInfo->manufacturerID, OPENSC_VS_FF_COMPANY_NAME, 32);
99 		pInfo->hardwareVersion.major = OPENSC_VERSION_MAJOR;
100 		pInfo->hardwareVersion.minor = OPENSC_VERSION_MINOR;
101 	}
102 	pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT;
103 	pInfo->firmwareVersion.major = 0;
104 	pInfo->firmwareVersion.minor = 0;
105 }
106 
107 /* simclist helpers to locate interesting objects by ID */
object_list_seeker(const void * el,const void * key)108 static int object_list_seeker(const void *el, const void *key)
109 {
110 	const struct sc_pkcs11_object *object = (struct sc_pkcs11_object *)el;
111 
112 	if ((el == NULL) || (key == NULL))
113 		return 0;
114 	if (object->handle == *(CK_OBJECT_HANDLE*)key)
115 		return 1;
116 	return 0;
117 }
118 
create_slot(sc_reader_t * reader)119 CK_RV create_slot(sc_reader_t *reader)
120 {
121 	/* find unused slots previously allocated for the same reader */
122 	struct sc_pkcs11_slot *slot = reader_reclaim_slot(reader);
123 
124 	/* create a new slot if no empty slot is available */
125 	if (!slot) {
126 		sc_log(context, "Creating new slot");
127 		if (list_size(&virtual_slots) >= sc_pkcs11_conf.max_virtual_slots)
128 			return CKR_FUNCTION_FAILED;
129 
130 		slot = (struct sc_pkcs11_slot *)calloc(1, sizeof(struct sc_pkcs11_slot));
131 		if (!slot)
132 			return CKR_HOST_MEMORY;
133 
134 		list_append(&virtual_slots, slot);
135 		if (0 != list_init(&slot->objects)) {
136 			return CKR_HOST_MEMORY;
137 		}
138 		list_attributes_seeker(&slot->objects, object_list_seeker);
139 
140 		if (0 != list_init(&slot->logins)) {
141 			return CKR_HOST_MEMORY;
142 		}
143 	} else {
144 		DEBUG_VSS(slot, "Reusing this old slot");
145 
146 		/* reuse the old list of logins/objects since they should be empty */
147 		list_t logins = slot->logins;
148 		list_t objects = slot->objects;
149 
150 		memset(slot, 0, sizeof *slot);
151 
152 		slot->logins = logins;
153 		slot->objects = objects;
154 	}
155 
156 	slot->login_user = -1;
157 	slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot);
158 	init_slot_info(&slot->slot_info, reader);
159 	slot->reader = reader;
160 
161 	DEBUG_VSS(slot, "Finished initializing this slot");
162 
163 	return CKR_OK;
164 }
165 
sc_pkcs11_card_free(struct sc_pkcs11_card * p11card)166 void sc_pkcs11_card_free(struct sc_pkcs11_card *p11card)
167 {
168 	if (p11card) {
169 		size_t i;
170 		if (p11card->framework && p11card->framework->unbind)
171 			p11card->framework->unbind(p11card);
172 		sc_disconnect_card(p11card->card);
173 		for (i=0; i < p11card->nmechanisms; ++i) {
174 			if (p11card->mechanisms[i]->free_mech_data) {
175 				p11card->mechanisms[i]->free_mech_data(p11card->mechanisms[i]->mech_data);
176 			}
177 			free(p11card->mechanisms[i]);
178 		}
179 		free(p11card->mechanisms);
180 		free(p11card);
181 	}
182 }
183 
card_removed(sc_reader_t * reader)184 CK_RV card_removed(sc_reader_t * reader)
185 {
186 	unsigned int i;
187 	struct sc_pkcs11_card *p11card = NULL;
188 	/* Mark all slots as "token not present" */
189 	sc_log(context, "%s: card removed", reader->name);
190 
191 
192 	for (i=0; i < list_size(&virtual_slots); i++) {
193 		sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
194 		if (slot->reader == reader) {
195 			/* Save the "card" object */
196 			if (slot->p11card)
197 				p11card = slot->p11card;
198 			slot_token_removed(slot->id);
199 		}
200 	}
201 
202 	sc_pkcs11_card_free(p11card);
203 
204 	return CKR_OK;
205 }
206 
207 
card_detect(sc_reader_t * reader)208 CK_RV card_detect(sc_reader_t *reader)
209 {
210 	struct sc_pkcs11_card *p11card = NULL;
211 	int free_p11card = 0;
212 	int rc;
213 	CK_RV rv;
214 	unsigned int i;
215 	int j;
216 
217 	sc_log(context, "%s: Detecting smart card", reader->name);
218 	/* Check if someone inserted a card */
219 again:
220 	rc = sc_detect_card_presence(reader);
221 	if (rc < 0) {
222 		sc_log(context, "%s: failed, %s", reader->name, sc_strerror(rc));
223 		return sc_to_cryptoki_error(rc, NULL);
224 	}
225 	if (rc == 0) {
226 		sc_log(context, "%s: card absent", reader->name);
227 		card_removed(reader);	/* Release all resources */
228 		return CKR_TOKEN_NOT_PRESENT;
229 	}
230 
231 	/* If the card was changed, disconnect the current one */
232 	if (rc & SC_READER_CARD_CHANGED) {
233 		sc_log(context, "%s: Card changed", reader->name);
234 		/* The following should never happen - but if it
235 		 * does we'll be stuck in an endless loop.
236 		 * So better be fussy.
237 		if (!retry--)
238 			return CKR_TOKEN_NOT_PRESENT; */
239 		card_removed(reader);
240 		goto again;
241 	}
242 
243 	/* Locate a slot related to the reader */
244 	for (i=0; i<list_size(&virtual_slots); i++) {
245 		sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
246 		if (slot->reader == reader) {
247 			p11card = slot->p11card;
248 			break;
249 		}
250 	}
251 
252 	/* Detect the card if it's not known already */
253 	if (p11card == NULL) {
254 		sc_log(context, "%s: First seen the card ", reader->name);
255 		p11card = (struct sc_pkcs11_card *)calloc(1, sizeof(struct sc_pkcs11_card));
256 		if (!p11card)
257 			return CKR_HOST_MEMORY;
258 		free_p11card = 1;
259 		p11card->reader = reader;
260 	}
261 
262 	if (p11card->card == NULL) {
263 		sc_log(context, "%s: Connecting ... ", reader->name);
264 		rc = sc_connect_card(reader, &p11card->card);
265 		if (rc != SC_SUCCESS) {
266 			sc_log(context, "%s: SC connect card error %i", reader->name, rc);
267 			rv = sc_to_cryptoki_error(rc, NULL);
268 			goto fail;
269 		}
270 
271 		/* escape commands are only guaranteed to be working with a card
272 		 * inserted. That's why by now, after sc_connect_card() the reader's
273 		 * metadata may have changed. We re-initialize the metadata for every
274 		 * slot of this reader here. */
275 		if (reader->flags & SC_READER_ENABLE_ESCAPE) {
276 			for (i = 0; i<list_size(&virtual_slots); i++) {
277 				sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
278 				if (slot->reader == reader)
279 					init_slot_info(&slot->slot_info, reader);
280 			}
281 		}
282 
283 		sc_log(context, "%s: Connected SC card %p", reader->name, p11card->card);
284 	}
285 
286 	/* Detect the framework */
287 	if (p11card->framework == NULL) {
288 		struct sc_app_info *app_generic = sc_pkcs15_get_application_by_type(p11card->card, "generic");
289 
290 		sc_log(context, "%s: Detecting Framework. %i on-card applications", reader->name, p11card->card->app_count);
291 		sc_log(context, "%s: generic application %s", reader->name, app_generic ? app_generic->label : "<none>");
292 
293 		for (i = 0; frameworks[i]; i++)
294 			if (frameworks[i]->bind != NULL)
295 				break;
296 		/*TODO: only first framework is used: pkcs15init framework is not reachable here */
297 		if (frameworks[i] == NULL) {
298 			rv = CKR_GENERAL_ERROR;
299 			goto fail;
300 		}
301 
302 		p11card->framework = frameworks[i];
303 
304 		/* Initialize framework */
305 		sc_log(context, "%s: Detected framework %d. Creating tokens.", reader->name, i);
306 		/* Bind 'generic' application or (emulated?) card without applications */
307 		if (app_generic || !p11card->card->app_count)   {
308 			scconf_block *conf_block = NULL;
309 			int enable_InitToken = 0;
310 
311 			conf_block = sc_match_atr_block(p11card->card->ctx, NULL,
312 				&p11card->reader->atr);
313 			if (!conf_block) /* check default block */
314 				conf_block = sc_get_conf_block(context,
315 					"framework", "pkcs15", 1);
316 
317 			enable_InitToken = scconf_get_bool(conf_block,
318 				"pkcs11_enable_InitToken", 0);
319 
320 			sc_log(context, "%s: Try to bind 'generic' token.", reader->name);
321 			rv = frameworks[i]->bind(p11card, app_generic);
322 			if (rv == CKR_TOKEN_NOT_RECOGNIZED && enable_InitToken)   {
323 				sc_log(context, "%s: 'InitToken' enabled -- accept non-binded card", reader->name);
324 				rv = CKR_OK;
325 			}
326 			if (rv != CKR_OK)   {
327 				sc_log(context,
328 				       "%s: cannot bind 'generic' token: rv 0x%lX",
329 				       reader->name, rv);
330 				goto fail;
331 			}
332 
333 			sc_log(context, "%s: Creating 'generic' token.", reader->name);
334 			rv = frameworks[i]->create_tokens(p11card, app_generic);
335 			if (rv != CKR_OK)   {
336 				sc_log(context,
337 				       "%s: create 'generic' token error 0x%lX",
338 				       reader->name, rv);
339 				goto fail;
340 			}
341 			/* p11card is now bound to some slot */
342 			free_p11card = 0;
343 		}
344 
345 		/* Now bind the rest of applications that are not 'generic' */
346 		for (j = 0; j < p11card->card->app_count; j++)   {
347 			struct sc_app_info *app_info = p11card->card->app[j];
348 			char *app_name = app_info ? app_info->label : "<anonymous>";
349 
350 			if (app_generic && app_generic == p11card->card->app[j])
351 				continue;
352 
353 			sc_log(context, "%s: Binding %s token.", reader->name, app_name);
354 			rv = frameworks[i]->bind(p11card, app_info);
355 			if (rv != CKR_OK)   {
356 				sc_log(context, "%s: bind %s token error Ox%lX",
357 				       reader->name, app_name, rv);
358 				continue;
359 			}
360 
361 			sc_log(context, "%s: Creating %s token.", reader->name, app_name);
362 			rv = frameworks[i]->create_tokens(p11card, app_info);
363 			if (rv != CKR_OK)   {
364 				sc_log(context,
365 				       "%s: create %s token error 0x%lX",
366 				       reader->name, app_name, rv);
367 				goto fail;
368 			}
369 			/* p11card is now bound to some slot */
370 			free_p11card = 0;
371 		}
372 	}
373 
374 	sc_log(context, "%s: Detection ended", reader->name);
375 	rv = CKR_OK;
376 
377 fail:
378 	if (free_p11card) {
379 		sc_pkcs11_card_free(p11card);
380 	}
381 
382 	return rv;
383 }
384 
385 
386 CK_RV
card_detect_all(void)387 card_detect_all(void)
388 {
389 	unsigned int i, j;
390 
391 	sc_log(context, "Detect all cards");
392 	/* Detect cards in all initialized readers */
393 	for (i=0; i< sc_ctx_get_reader_count(context); i++) {
394 		sc_reader_t *reader = sc_ctx_get_reader(context, i);
395 
396 		if (reader->flags & SC_READER_REMOVED) {
397 			card_removed(reader);
398 			/* do not remove slots related to this reader which would be
399 			 * possible according to PKCS#11 2.20 and later, because NSS can't
400 			 * handle a shrinking slot list
401 			 * https://bugzilla.mozilla.org/show_bug.cgi?id=1613632 */
402 
403 			/* Instead, remove the relation between reader and slot */
404 			for (j = 0; j<list_size(&virtual_slots); j++) {
405 				sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
406 				if (slot->reader == reader) {
407 					slot->reader = NULL;
408 				}
409 			}
410 		} else {
411 			/* Locate a slot related to the reader */
412 			int found = 0;
413 			for (j = 0; j<list_size(&virtual_slots); j++) {
414 				sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, j);
415 				if (slot->reader == reader) {
416 					found = 1;
417 					break;
418 				}
419 			}
420 			if (!found) {
421 				for (j = 0; j < sc_pkcs11_conf.slots_per_card; j++) {
422 					CK_RV rv = create_slot(reader);
423 					if (rv != CKR_OK)
424 						return rv;
425 				}
426 			}
427 			card_detect(reader);
428 		}
429 	}
430 	sc_log(context, "All cards detected");
431 	return CKR_OK;
432 }
433 
434 /* Allocates an existing slot to a card */
slot_allocate(struct sc_pkcs11_slot ** slot,struct sc_pkcs11_card * p11card)435 CK_RV slot_allocate(struct sc_pkcs11_slot ** slot, struct sc_pkcs11_card * p11card)
436 {
437 	unsigned int i;
438 	struct sc_pkcs11_slot *tmp_slot = NULL;
439 
440 	/* Locate a free slot for this reader */
441 	for (i=0; i< list_size(&virtual_slots); i++) {
442 		tmp_slot = (struct sc_pkcs11_slot *)list_get_at(&virtual_slots, i);
443 		if (tmp_slot->reader == p11card->reader && tmp_slot->p11card == NULL)
444 			break;
445 	}
446 	if (!tmp_slot || (i == list_size(&virtual_slots)))
447 		return CKR_FUNCTION_FAILED;
448 	sc_log(context, "Allocated slot 0x%lx for card in reader %s", tmp_slot->id, p11card->reader->name);
449 	tmp_slot->p11card = p11card;
450 	tmp_slot->events = SC_EVENT_CARD_INSERTED;
451 	*slot = tmp_slot;
452 	return CKR_OK;
453 }
454 
slot_get_slot(CK_SLOT_ID id,struct sc_pkcs11_slot ** slot)455 CK_RV slot_get_slot(CK_SLOT_ID id, struct sc_pkcs11_slot ** slot)
456 {
457 	if (context == NULL)
458 		return CKR_CRYPTOKI_NOT_INITIALIZED;
459 
460 	*slot = list_seek(&virtual_slots, &id);	/* FIXME: check for null? */
461 	if (!*slot)
462 		return CKR_SLOT_ID_INVALID;
463 	return CKR_OK;
464 }
465 
slot_get_token(CK_SLOT_ID id,struct sc_pkcs11_slot ** slot)466 CK_RV slot_get_token(CK_SLOT_ID id, struct sc_pkcs11_slot ** slot)
467 {
468 	CK_RV rv;
469 
470 	sc_log(context, "Slot(id=0x%lX): get token", id);
471 	rv = slot_get_slot(id, slot);
472 	if (rv != CKR_OK)
473 		return rv;
474 
475 	if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT)) {
476 		if ((*slot)->reader == NULL)
477 			return CKR_TOKEN_NOT_PRESENT;
478 		sc_log(context, "Slot(id=0x%lX): get token: now detect card", id);
479 		rv = card_detect((*slot)->reader);
480 		if (rv != CKR_OK)
481 			return rv;
482 	}
483 
484 	if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT)) {
485 		sc_log(context, "card detected, but slot not presenting token");
486 		return CKR_TOKEN_NOT_PRESENT;
487 	}
488 	sc_log(context, "Slot-get-token returns OK");
489 	return CKR_OK;
490 }
491 
slot_token_removed(CK_SLOT_ID id)492 CK_RV slot_token_removed(CK_SLOT_ID id)
493 {
494 	CK_RV rv;
495 	int token_was_present;
496 	struct sc_pkcs11_slot *slot;
497 	struct sc_pkcs11_object *object;
498 
499 	sc_log(context, "slot_token_removed(0x%lx)", id);
500 	rv = slot_get_slot(id, &slot);
501 	if (rv != CKR_OK)
502 		return rv;
503 
504 	token_was_present = (slot->slot_info.flags & CKF_TOKEN_PRESENT);
505 
506 	/* Terminate active sessions */
507 	sc_pkcs11_close_all_sessions(id);
508 
509 	while ((object = list_fetch(&slot->objects))) {
510 		if (object->ops->release)
511 			object->ops->release(object);
512 	}
513 
514 	/* Release framework stuff */
515 	if (slot->p11card != NULL) {
516 		if (slot->fw_data != NULL && slot->p11card->framework != NULL
517 				&& slot->p11card->framework->release_token != NULL) {
518 			slot->p11card->framework->release_token(slot->p11card, slot->fw_data);
519 			slot->fw_data = NULL;
520 		}
521 		slot->p11card = NULL;
522 	}
523 
524 	/* Reset relevant slot properties */
525 	slot->slot_info.flags &= ~CKF_TOKEN_PRESENT;
526 	slot->login_user = -1;
527 	pop_all_login_states(slot);
528 
529 	if (token_was_present)
530 		slot->events = SC_EVENT_CARD_REMOVED;
531 
532 	memset(&slot->token_info, 0, sizeof slot->token_info);
533 
534 	return CKR_OK;
535 }
536 
537 /* Called from C_WaitForSlotEvent */
slot_find_changed(CK_SLOT_ID_PTR idp,int mask)538 CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask)
539 {
540 	unsigned int i;
541 	LOG_FUNC_CALLED(context);
542 
543 	card_detect_all();
544 	for (i=0; i<list_size(&virtual_slots); i++) {
545 		sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
546 		sc_log(context, "slot 0x%lx token: %lu events: 0x%02X",
547 		       slot->id, (slot->slot_info.flags & CKF_TOKEN_PRESENT),
548 		       slot->events);
549 		if ((slot->events & SC_EVENT_CARD_INSERTED)
550 				&& !(slot->slot_info.flags & CKF_TOKEN_PRESENT)) {
551 			/* If a token has not been initialized, clear the inserted event */
552 			slot->events &= ~SC_EVENT_CARD_INSERTED;
553 		}
554 		sc_log(context, "mask: 0x%02X events: 0x%02X result: %d", mask, slot->events, (slot->events & mask));
555 
556 		if (slot->events & mask) {
557 			slot->events &= ~mask;
558 			*idp = slot->id;
559 			LOG_FUNC_RETURN(context, CKR_OK);
560 		}
561 	}
562 	LOG_FUNC_RETURN(context, CKR_NO_EVENT);
563 }
564