root / libcacard / vcard_emul_nss.c @ 02021812
History | View | Annotate | Download (37.1 kB)
1 |
/*
|
---|---|
2 |
* This is the actual card emulator.
|
3 |
*
|
4 |
* These functions can be implemented in different ways on different platforms
|
5 |
* using the underlying system primitives. For Linux it uses NSS, though direct
|
6 |
* to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
|
7 |
* used. On Windows CAPI could be used.
|
8 |
*
|
9 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
10 |
* See the COPYING.LIB file in the top-level directory.
|
11 |
*/
|
12 |
|
13 |
/*
|
14 |
* NSS headers
|
15 |
*/
|
16 |
|
17 |
/* avoid including prototypes.h that redefines uint32 */
|
18 |
#define NO_NSPR_10_SUPPORT
|
19 |
|
20 |
#include <nss.h> |
21 |
#include <pk11pub.h> |
22 |
#include <cert.h> |
23 |
#include <key.h> |
24 |
#include <secmod.h> |
25 |
#include <prthread.h> |
26 |
#include <secerr.h> |
27 |
|
28 |
#include "qemu-common.h" |
29 |
|
30 |
#include "vcard.h" |
31 |
#include "card_7816t.h" |
32 |
#include "vcard_emul.h" |
33 |
#include "vreader.h" |
34 |
#include "vevent.h" |
35 |
|
36 |
typedef enum { |
37 |
VCardEmulUnknown = -1,
|
38 |
VCardEmulFalse = 0,
|
39 |
VCardEmulTrue = 1
|
40 |
} VCardEmulTriState; |
41 |
|
42 |
struct VCardKeyStruct {
|
43 |
CERTCertificate *cert; |
44 |
PK11SlotInfo *slot; |
45 |
SECKEYPrivateKey *key; |
46 |
VCardEmulTriState failedX509; |
47 |
}; |
48 |
|
49 |
|
50 |
typedef struct VirtualReaderOptionsStruct VirtualReaderOptions; |
51 |
|
52 |
struct VReaderEmulStruct {
|
53 |
PK11SlotInfo *slot; |
54 |
VCardEmulType default_type; |
55 |
char *type_params;
|
56 |
PRBool present; |
57 |
int series;
|
58 |
VCard *saved_vcard; |
59 |
}; |
60 |
|
61 |
/*
|
62 |
* NSS Specific options
|
63 |
*/
|
64 |
struct VirtualReaderOptionsStruct {
|
65 |
char *name;
|
66 |
char *vname;
|
67 |
VCardEmulType card_type; |
68 |
char *type_params;
|
69 |
char **cert_name;
|
70 |
int cert_count;
|
71 |
}; |
72 |
|
73 |
struct VCardEmulOptionsStruct {
|
74 |
void *nss_db;
|
75 |
VirtualReaderOptions *vreader; |
76 |
int vreader_count;
|
77 |
VCardEmulType hw_card_type; |
78 |
const char *hw_type_params; |
79 |
PRBool use_hw; |
80 |
}; |
81 |
|
82 |
static int nss_emul_init; |
83 |
|
84 |
/* if we have more that just the slot, define
|
85 |
* VCardEmulStruct here */
|
86 |
|
87 |
/*
|
88 |
* allocate the set of arrays for certs, cert_len, key
|
89 |
*/
|
90 |
static PRBool
|
91 |
vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp, |
92 |
VCardKey ***keysp, int cert_count)
|
93 |
{ |
94 |
*certsp = NULL;
|
95 |
*cert_lenp = NULL;
|
96 |
*keysp = NULL;
|
97 |
*certsp = (unsigned char **)g_malloc(sizeof(unsigned char *)*cert_count); |
98 |
*cert_lenp = (int *)g_malloc(sizeof(int)*cert_count); |
99 |
*keysp = (VCardKey **)g_malloc(sizeof(VCardKey *)*cert_count);
|
100 |
return PR_TRUE;
|
101 |
} |
102 |
|
103 |
/*
|
104 |
* Emulator specific card information
|
105 |
*/
|
106 |
typedef struct CardEmulCardStruct CardEmulPrivate; |
107 |
|
108 |
static VCardEmul *
|
109 |
vcard_emul_new_card(PK11SlotInfo *slot) |
110 |
{ |
111 |
PK11_ReferenceSlot(slot); |
112 |
/* currently we don't need anything other than the slot */
|
113 |
return (VCardEmul *)slot;
|
114 |
} |
115 |
|
116 |
static void |
117 |
vcard_emul_delete_card(VCardEmul *vcard_emul) |
118 |
{ |
119 |
PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul; |
120 |
if (slot == NULL) { |
121 |
return;
|
122 |
} |
123 |
PK11_FreeSlot(slot); |
124 |
} |
125 |
|
126 |
static PK11SlotInfo *
|
127 |
vcard_emul_card_get_slot(VCard *card) |
128 |
{ |
129 |
/* note, the card is holding the reference, no need to get another one */
|
130 |
return (PK11SlotInfo *)vcard_get_private(card);
|
131 |
} |
132 |
|
133 |
|
134 |
/*
|
135 |
* key functions
|
136 |
*/
|
137 |
/* private constructure */
|
138 |
static VCardKey *
|
139 |
vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert) |
140 |
{ |
141 |
VCardKey *key; |
142 |
|
143 |
key = (VCardKey *)g_malloc(sizeof(VCardKey));
|
144 |
key->slot = PK11_ReferenceSlot(slot); |
145 |
key->cert = CERT_DupCertificate(cert); |
146 |
/* NOTE: if we aren't logged into the token, this could return NULL */
|
147 |
/* NOTE: the cert is a temp cert, not necessarily the cert in the token,
|
148 |
* use the DER version of this function */
|
149 |
key->key = PK11_FindKeyByDERCert(slot, cert, NULL);
|
150 |
key->failedX509 = VCardEmulUnknown; |
151 |
return key;
|
152 |
} |
153 |
|
154 |
/* destructor */
|
155 |
void
|
156 |
vcard_emul_delete_key(VCardKey *key) |
157 |
{ |
158 |
if (!nss_emul_init || (key == NULL)) { |
159 |
return;
|
160 |
} |
161 |
if (key->key) {
|
162 |
SECKEY_DestroyPrivateKey(key->key); |
163 |
key->key = NULL;
|
164 |
} |
165 |
if (key->cert) {
|
166 |
CERT_DestroyCertificate(key->cert); |
167 |
} |
168 |
if (key->slot) {
|
169 |
PK11_FreeSlot(key->slot); |
170 |
} |
171 |
return;
|
172 |
} |
173 |
|
174 |
/*
|
175 |
* grab the nss key from a VCardKey. If it doesn't exist, try to look it up
|
176 |
*/
|
177 |
static SECKEYPrivateKey *
|
178 |
vcard_emul_get_nss_key(VCardKey *key) |
179 |
{ |
180 |
if (key->key) {
|
181 |
return key->key;
|
182 |
} |
183 |
/* NOTE: if we aren't logged into the token, this could return NULL */
|
184 |
key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
|
185 |
return key->key;
|
186 |
} |
187 |
|
188 |
/*
|
189 |
* Map NSS errors to 7816 errors
|
190 |
*/
|
191 |
static vcard_7816_status_t
|
192 |
vcard_emul_map_error(int error)
|
193 |
{ |
194 |
switch (error) {
|
195 |
case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
|
196 |
return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
|
197 |
case SEC_ERROR_BAD_DATA:
|
198 |
case SEC_ERROR_OUTPUT_LEN:
|
199 |
case SEC_ERROR_INPUT_LEN:
|
200 |
case SEC_ERROR_INVALID_ARGS:
|
201 |
case SEC_ERROR_INVALID_ALGORITHM:
|
202 |
case SEC_ERROR_NO_KEY:
|
203 |
case SEC_ERROR_INVALID_KEY:
|
204 |
case SEC_ERROR_DECRYPTION_DISALLOWED:
|
205 |
return VCARD7816_STATUS_ERROR_DATA_INVALID;
|
206 |
case SEC_ERROR_NO_MEMORY:
|
207 |
return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
|
208 |
} |
209 |
return VCARD7816_STATUS_EXC_ERROR_CHANGE;
|
210 |
} |
211 |
|
212 |
/* RSA sign/decrypt with the key, signature happens 'in place' */
|
213 |
vcard_7816_status_t |
214 |
vcard_emul_rsa_op(VCard *card, VCardKey *key, |
215 |
unsigned char *buffer, int buffer_size) |
216 |
{ |
217 |
SECKEYPrivateKey *priv_key; |
218 |
unsigned signature_len;
|
219 |
PK11SlotInfo *slot; |
220 |
SECStatus rv; |
221 |
unsigned char buf[2048]; |
222 |
unsigned char *bp = NULL; |
223 |
int pad_len;
|
224 |
vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS; |
225 |
|
226 |
if ((!nss_emul_init) || (key == NULL)) { |
227 |
/* couldn't get the key, indicate that we aren't logged in */
|
228 |
return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
|
229 |
} |
230 |
priv_key = vcard_emul_get_nss_key(key); |
231 |
if (priv_key == NULL) { |
232 |
/* couldn't get the key, indicate that we aren't logged in */
|
233 |
return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
|
234 |
} |
235 |
slot = vcard_emul_card_get_slot(card); |
236 |
|
237 |
/*
|
238 |
* this is only true of the rsa signature
|
239 |
*/
|
240 |
signature_len = PK11_SignatureLen(priv_key); |
241 |
if (buffer_size != signature_len) {
|
242 |
return VCARD7816_STATUS_ERROR_DATA_INVALID;
|
243 |
} |
244 |
/* be able to handle larger keys if necessariy */
|
245 |
bp = &buf[0];
|
246 |
if (sizeof(buf) < signature_len) { |
247 |
bp = g_malloc(signature_len); |
248 |
} |
249 |
|
250 |
/*
|
251 |
* do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then
|
252 |
* choke when they try to do the actual operations. Try to detect
|
253 |
* those cases and treat them as if the token didn't claim support for
|
254 |
* X_509.
|
255 |
*/
|
256 |
if (key->failedX509 != VCardEmulTrue
|
257 |
&& PK11_DoesMechanism(slot, CKM_RSA_X_509)) { |
258 |
rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len, |
259 |
buffer, buffer_size); |
260 |
if (rv == SECSuccess) {
|
261 |
assert(buffer_size == signature_len); |
262 |
memcpy(buffer, bp, signature_len); |
263 |
key->failedX509 = VCardEmulFalse; |
264 |
goto cleanup;
|
265 |
} |
266 |
/*
|
267 |
* we've had a successful X509 operation, this failure must be
|
268 |
* somethine else
|
269 |
*/
|
270 |
if (key->failedX509 == VCardEmulFalse) {
|
271 |
ret = vcard_emul_map_error(PORT_GetError()); |
272 |
goto cleanup;
|
273 |
} |
274 |
/*
|
275 |
* key->failedX509 must be Unknown at this point, try the
|
276 |
* non-x_509 case
|
277 |
*/
|
278 |
} |
279 |
/* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */
|
280 |
/* is this a PKCS #1 formatted signature? */
|
281 |
if ((buffer[0] == 0) && (buffer[1] == 1)) { |
282 |
int i;
|
283 |
|
284 |
for (i = 2; i < buffer_size; i++) { |
285 |
/* rsa signature pad */
|
286 |
if (buffer[i] != 0xff) { |
287 |
break;
|
288 |
} |
289 |
} |
290 |
if ((i < buffer_size) && (buffer[i] == 0)) { |
291 |
/* yes, we have a properly formated PKCS #1 signature */
|
292 |
/*
|
293 |
* NOTE: even if we accidentally got an encrypt buffer, which
|
294 |
* through shear luck started with 00, 01, ff, 00, it won't matter
|
295 |
* because the resulting Sign operation will effectively decrypt
|
296 |
* the real buffer.
|
297 |
*/
|
298 |
SECItem signature; |
299 |
SECItem hash; |
300 |
|
301 |
i++; |
302 |
hash.data = &buffer[i]; |
303 |
hash.len = buffer_size - i; |
304 |
signature.data = bp; |
305 |
signature.len = signature_len; |
306 |
rv = PK11_Sign(priv_key, &signature, &hash); |
307 |
if (rv != SECSuccess) {
|
308 |
ret = vcard_emul_map_error(PORT_GetError()); |
309 |
goto cleanup;
|
310 |
} |
311 |
assert(buffer_size == signature.len); |
312 |
memcpy(buffer, bp, signature.len); |
313 |
/*
|
314 |
* we got here because either the X509 attempt failed, or the
|
315 |
* token couldn't do the X509 operation, in either case stay
|
316 |
* with the PKCS version for future operations on this key
|
317 |
*/
|
318 |
key->failedX509 = VCardEmulTrue; |
319 |
goto cleanup;
|
320 |
} |
321 |
} |
322 |
pad_len = buffer_size - signature_len; |
323 |
assert(pad_len < 4);
|
324 |
/*
|
325 |
* OK now we've decrypted the payload, package it up in PKCS #1 for the
|
326 |
* upper layer.
|
327 |
*/
|
328 |
buffer[0] = 0; |
329 |
buffer[1] = 2; /* RSA_encrypt */ |
330 |
pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */ |
331 |
/*
|
332 |
* padding for PKCS #1 encrypted data is a string of random bytes. The
|
333 |
* random butes protect against potential decryption attacks against RSA.
|
334 |
* Since PrivDecrypt has already stripped those bytes, we can't reconstruct
|
335 |
* them. This shouldn't matter to the upper level code which should just
|
336 |
* strip this code out anyway, so We'll pad with a constant 3.
|
337 |
*/
|
338 |
memset(&buffer[2], 0x03, pad_len); |
339 |
pad_len += 2; /* index to the end of the pad */ |
340 |
buffer[pad_len] = 0;
|
341 |
pad_len++; /* index to the start of the data */
|
342 |
memcpy(&buffer[pad_len], bp, signature_len); |
343 |
/*
|
344 |
* we got here because either the X509 attempt failed, or the
|
345 |
* token couldn't do the X509 operation, in either case stay
|
346 |
* with the PKCS version for future operations on this key
|
347 |
*/
|
348 |
key->failedX509 = VCardEmulTrue; |
349 |
cleanup:
|
350 |
if (bp != buf) {
|
351 |
g_free(bp); |
352 |
} |
353 |
return ret;
|
354 |
} |
355 |
|
356 |
/*
|
357 |
* Login functions
|
358 |
*/
|
359 |
/* return the number of login attempts still possible on the card. if unknown,
|
360 |
* return -1 */
|
361 |
int
|
362 |
vcard_emul_get_login_count(VCard *card) |
363 |
{ |
364 |
return -1; |
365 |
} |
366 |
|
367 |
/* login into the card, return the 7816 status word (sw2 || sw1) */
|
368 |
vcard_7816_status_t |
369 |
vcard_emul_login(VCard *card, unsigned char *pin, int pin_len) |
370 |
{ |
371 |
PK11SlotInfo *slot; |
372 |
unsigned char *pin_string = NULL; |
373 |
int i;
|
374 |
SECStatus rv; |
375 |
|
376 |
if (!nss_emul_init) {
|
377 |
return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
|
378 |
} |
379 |
slot = vcard_emul_card_get_slot(card); |
380 |
/* We depend on the PKCS #11 module internal login state here because we
|
381 |
* create a separate process to handle each guest instance. If we needed
|
382 |
* to handle multiple guests from one process, then we would need to keep
|
383 |
* a lot of extra state in our card structure
|
384 |
* */
|
385 |
pin_string = g_malloc(pin_len+1);
|
386 |
memcpy(pin_string, pin, pin_len); |
387 |
pin_string[pin_len] = 0;
|
388 |
|
389 |
/* handle CAC expanded pins correctly */
|
390 |
for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) { |
391 |
pin_string[i] = 0;
|
392 |
} |
393 |
|
394 |
rv = PK11_Authenticate(slot, PR_FALSE, pin_string); |
395 |
memset(pin_string, 0, pin_len); /* don't let the pin hang around in memory |
396 |
to be snooped */
|
397 |
g_free(pin_string); |
398 |
if (rv == SECSuccess) {
|
399 |
return VCARD7816_STATUS_SUCCESS;
|
400 |
} |
401 |
/* map the error from port get error */
|
402 |
return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
|
403 |
} |
404 |
|
405 |
void
|
406 |
vcard_emul_reset(VCard *card, VCardPower power) |
407 |
{ |
408 |
PK11SlotInfo *slot; |
409 |
|
410 |
if (!nss_emul_init) {
|
411 |
return;
|
412 |
} |
413 |
|
414 |
/*
|
415 |
* if we reset the card (either power on or power off), we lose our login
|
416 |
* state
|
417 |
*/
|
418 |
/* TODO: we may also need to send insertion/removal events? */
|
419 |
slot = vcard_emul_card_get_slot(card); |
420 |
PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
|
421 |
return;
|
422 |
} |
423 |
|
424 |
|
425 |
static VReader *
|
426 |
vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot) |
427 |
{ |
428 |
VReaderList *reader_list = vreader_get_reader_list(); |
429 |
VReaderListEntry *current_entry = NULL;
|
430 |
|
431 |
if (reader_list == NULL) { |
432 |
return NULL; |
433 |
} |
434 |
for (current_entry = vreader_list_get_first(reader_list); current_entry;
|
435 |
current_entry = vreader_list_get_next(current_entry)) { |
436 |
VReader *reader = vreader_list_get_reader(current_entry); |
437 |
VReaderEmul *reader_emul = vreader_get_private(reader); |
438 |
if (reader_emul->slot == slot) {
|
439 |
return reader;
|
440 |
} |
441 |
vreader_free(reader); |
442 |
} |
443 |
|
444 |
return NULL; |
445 |
} |
446 |
|
447 |
/*
|
448 |
* create a new reader emul
|
449 |
*/
|
450 |
static VReaderEmul *
|
451 |
vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params) |
452 |
{ |
453 |
VReaderEmul *new_reader_emul; |
454 |
|
455 |
new_reader_emul = (VReaderEmul *)g_malloc(sizeof(VReaderEmul));
|
456 |
|
457 |
new_reader_emul->slot = PK11_ReferenceSlot(slot); |
458 |
new_reader_emul->default_type = type; |
459 |
new_reader_emul->type_params = strdup(params); |
460 |
new_reader_emul->present = PR_FALSE; |
461 |
new_reader_emul->series = 0;
|
462 |
new_reader_emul->saved_vcard = NULL;
|
463 |
return new_reader_emul;
|
464 |
} |
465 |
|
466 |
static void |
467 |
vreader_emul_delete(VReaderEmul *vreader_emul) |
468 |
{ |
469 |
if (vreader_emul == NULL) { |
470 |
return;
|
471 |
} |
472 |
if (vreader_emul->slot) {
|
473 |
PK11_FreeSlot(vreader_emul->slot); |
474 |
} |
475 |
if (vreader_emul->type_params) {
|
476 |
g_free(vreader_emul->type_params); |
477 |
} |
478 |
g_free(vreader_emul); |
479 |
} |
480 |
|
481 |
/*
|
482 |
* TODO: move this to emulater non-specific file
|
483 |
*/
|
484 |
static VCardEmulType
|
485 |
vcard_emul_get_type(VReader *vreader) |
486 |
{ |
487 |
VReaderEmul *vreader_emul; |
488 |
|
489 |
vreader_emul = vreader_get_private(vreader); |
490 |
if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
|
491 |
return vreader_emul->default_type;
|
492 |
} |
493 |
|
494 |
return vcard_emul_type_select(vreader);
|
495 |
} |
496 |
/*
|
497 |
* TODO: move this to emulater non-specific file
|
498 |
*/
|
499 |
static const char * |
500 |
vcard_emul_get_type_params(VReader *vreader) |
501 |
{ |
502 |
VReaderEmul *vreader_emul; |
503 |
|
504 |
vreader_emul = vreader_get_private(vreader); |
505 |
if (vreader_emul && vreader_emul->type_params) {
|
506 |
return vreader_emul->type_params;
|
507 |
} |
508 |
|
509 |
return ""; |
510 |
} |
511 |
|
512 |
/* pull the slot out of the reader private data */
|
513 |
static PK11SlotInfo *
|
514 |
vcard_emul_reader_get_slot(VReader *vreader) |
515 |
{ |
516 |
VReaderEmul *vreader_emul = vreader_get_private(vreader); |
517 |
if (vreader_emul == NULL) { |
518 |
return NULL; |
519 |
} |
520 |
return vreader_emul->slot;
|
521 |
} |
522 |
|
523 |
/*
|
524 |
* Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate
|
525 |
* historical bytes for any software emulated card. The remaining bytes can be
|
526 |
* used to indicate the actual emulator
|
527 |
*/
|
528 |
static const unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }; |
529 |
|
530 |
void
|
531 |
vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) |
532 |
{ |
533 |
int len = MIN(sizeof(nss_atr), *atr_len); |
534 |
assert(atr != NULL);
|
535 |
|
536 |
memcpy(atr, nss_atr, len); |
537 |
*atr_len = len; |
538 |
return;
|
539 |
} |
540 |
|
541 |
/*
|
542 |
* create a new card from certs and keys
|
543 |
*/
|
544 |
static VCard *
|
545 |
vcard_emul_make_card(VReader *reader, |
546 |
unsigned char * const *certs, int *cert_len, |
547 |
VCardKey *keys[], int cert_count)
|
548 |
{ |
549 |
VCardEmul *vcard_emul; |
550 |
VCard *vcard; |
551 |
PK11SlotInfo *slot; |
552 |
VCardEmulType type; |
553 |
const char *params; |
554 |
|
555 |
type = vcard_emul_get_type(reader); |
556 |
|
557 |
/* ignore the inserted card */
|
558 |
if (type == VCARD_EMUL_NONE) {
|
559 |
return NULL; |
560 |
} |
561 |
slot = vcard_emul_reader_get_slot(reader); |
562 |
if (slot == NULL) { |
563 |
return NULL; |
564 |
} |
565 |
|
566 |
params = vcard_emul_get_type_params(reader); |
567 |
/* params these can be NULL */
|
568 |
|
569 |
vcard_emul = vcard_emul_new_card(slot); |
570 |
if (vcard_emul == NULL) { |
571 |
return NULL; |
572 |
} |
573 |
vcard = vcard_new(vcard_emul, vcard_emul_delete_card); |
574 |
if (vcard == NULL) { |
575 |
vcard_emul_delete_card(vcard_emul); |
576 |
return NULL; |
577 |
} |
578 |
vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count); |
579 |
return vcard;
|
580 |
} |
581 |
|
582 |
|
583 |
/*
|
584 |
* 'clone' a physical card as a virtual card
|
585 |
*/
|
586 |
static VCard *
|
587 |
vcard_emul_mirror_card(VReader *vreader) |
588 |
{ |
589 |
/*
|
590 |
* lookup certs using the C_FindObjects. The Stan Cert handle won't give
|
591 |
* us the real certs until we log in.
|
592 |
*/
|
593 |
PK11GenericObject *firstObj, *thisObj; |
594 |
int cert_count;
|
595 |
unsigned char **certs; |
596 |
int *cert_len;
|
597 |
VCardKey **keys; |
598 |
PK11SlotInfo *slot; |
599 |
PRBool ret; |
600 |
VCard *card; |
601 |
|
602 |
slot = vcard_emul_reader_get_slot(vreader); |
603 |
if (slot == NULL) { |
604 |
return NULL; |
605 |
} |
606 |
|
607 |
firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE); |
608 |
if (firstObj == NULL) { |
609 |
return NULL; |
610 |
} |
611 |
|
612 |
/* count the certs */
|
613 |
cert_count = 0;
|
614 |
for (thisObj = firstObj; thisObj;
|
615 |
thisObj = PK11_GetNextGenericObject(thisObj)) { |
616 |
cert_count++; |
617 |
} |
618 |
|
619 |
if (cert_count == 0) { |
620 |
PK11_DestroyGenericObjects(firstObj); |
621 |
return NULL; |
622 |
} |
623 |
|
624 |
/* allocate the arrays */
|
625 |
ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count); |
626 |
if (ret == PR_FALSE) {
|
627 |
return NULL; |
628 |
} |
629 |
|
630 |
/* fill in the arrays */
|
631 |
cert_count = 0;
|
632 |
for (thisObj = firstObj; thisObj;
|
633 |
thisObj = PK11_GetNextGenericObject(thisObj)) { |
634 |
SECItem derCert; |
635 |
CERTCertificate *cert; |
636 |
SECStatus rv; |
637 |
|
638 |
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, |
639 |
CKA_VALUE, &derCert); |
640 |
if (rv != SECSuccess) {
|
641 |
continue;
|
642 |
} |
643 |
/* create floating temp cert. This gives us a cert structure even if
|
644 |
* the token isn't logged in */
|
645 |
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, |
646 |
NULL, PR_FALSE, PR_TRUE);
|
647 |
SECITEM_FreeItem(&derCert, PR_FALSE); |
648 |
if (cert == NULL) { |
649 |
continue;
|
650 |
} |
651 |
|
652 |
certs[cert_count] = cert->derCert.data; |
653 |
cert_len[cert_count] = cert->derCert.len; |
654 |
keys[cert_count] = vcard_emul_make_key(slot, cert); |
655 |
cert_count++; |
656 |
CERT_DestroyCertificate(cert); /* key obj still has a reference */
|
657 |
} |
658 |
|
659 |
/* now create the card */
|
660 |
card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); |
661 |
g_free(certs); |
662 |
g_free(cert_len); |
663 |
g_free(keys); |
664 |
|
665 |
return card;
|
666 |
} |
667 |
|
668 |
static VCardEmulType default_card_type = VCARD_EMUL_NONE;
|
669 |
static const char *default_type_params = ""; |
670 |
|
671 |
/*
|
672 |
* This thread looks for card and reader insertions and puts events on the
|
673 |
* event queue
|
674 |
*/
|
675 |
static void |
676 |
vcard_emul_event_thread(void *arg)
|
677 |
{ |
678 |
PK11SlotInfo *slot; |
679 |
VReader *vreader; |
680 |
VReaderEmul *vreader_emul; |
681 |
VCard *vcard; |
682 |
SECMODModule *module = (SECMODModule *)arg; |
683 |
|
684 |
do {
|
685 |
slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500); |
686 |
if (slot == NULL) { |
687 |
break;
|
688 |
} |
689 |
vreader = vcard_emul_find_vreader_from_slot(slot); |
690 |
if (vreader == NULL) { |
691 |
/* new vreader */
|
692 |
vreader_emul = vreader_emul_new(slot, default_card_type, |
693 |
default_type_params); |
694 |
vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, |
695 |
vreader_emul_delete); |
696 |
PK11_FreeSlot(slot); |
697 |
slot = NULL;
|
698 |
vreader_add_reader(vreader); |
699 |
vreader_free(vreader); |
700 |
continue;
|
701 |
} |
702 |
/* card remove/insert */
|
703 |
vreader_emul = vreader_get_private(vreader); |
704 |
if (PK11_IsPresent(slot)) {
|
705 |
int series = PK11_GetSlotSeries(slot);
|
706 |
if (series != vreader_emul->series) {
|
707 |
if (vreader_emul->present) {
|
708 |
vreader_insert_card(vreader, NULL);
|
709 |
} |
710 |
vcard = vcard_emul_mirror_card(vreader); |
711 |
vreader_insert_card(vreader, vcard); |
712 |
vcard_free(vcard); |
713 |
} |
714 |
vreader_emul->series = series; |
715 |
vreader_emul->present = 1;
|
716 |
vreader_free(vreader); |
717 |
PK11_FreeSlot(slot); |
718 |
continue;
|
719 |
} |
720 |
if (vreader_emul->present) {
|
721 |
vreader_insert_card(vreader, NULL);
|
722 |
} |
723 |
vreader_emul->series = 0;
|
724 |
vreader_emul->present = 0;
|
725 |
PK11_FreeSlot(slot); |
726 |
vreader_free(vreader); |
727 |
} while (1); |
728 |
} |
729 |
|
730 |
/* if the card is inserted when we start up, make sure our state is correct */
|
731 |
static void |
732 |
vcard_emul_init_series(VReader *vreader, VCard *vcard) |
733 |
{ |
734 |
VReaderEmul *vreader_emul = vreader_get_private(vreader); |
735 |
PK11SlotInfo *slot = vreader_emul->slot; |
736 |
|
737 |
vreader_emul->present = PK11_IsPresent(slot); |
738 |
vreader_emul->series = PK11_GetSlotSeries(slot); |
739 |
if (vreader_emul->present == 0) { |
740 |
vreader_insert_card(vreader, NULL);
|
741 |
} |
742 |
} |
743 |
|
744 |
/*
|
745 |
* each module has a separate wait call, create a thread for each module that
|
746 |
* we are using.
|
747 |
*/
|
748 |
static void |
749 |
vcard_emul_new_event_thread(SECMODModule *module) |
750 |
{ |
751 |
PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread, |
752 |
module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD, |
753 |
PR_UNJOINABLE_THREAD, 0);
|
754 |
} |
755 |
|
756 |
static const VCardEmulOptions default_options = { |
757 |
.nss_db = NULL,
|
758 |
.vreader = NULL,
|
759 |
.vreader_count = 0,
|
760 |
.hw_card_type = VCARD_EMUL_CAC, |
761 |
.hw_type_params = "",
|
762 |
.use_hw = PR_TRUE |
763 |
}; |
764 |
|
765 |
|
766 |
/*
|
767 |
* NSS needs the app to supply a password prompt. In our case the only time
|
768 |
* the password is supplied is as part of the Login APDU. The actual password
|
769 |
* is passed in the pw_arg in that case. In all other cases pw_arg should be
|
770 |
* NULL.
|
771 |
*/
|
772 |
static char * |
773 |
vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg)
|
774 |
{ |
775 |
/* if it didn't work the first time, don't keep trying */
|
776 |
if (retries) {
|
777 |
return NULL; |
778 |
} |
779 |
/* we are looking up a password when we don't have one in hand */
|
780 |
if (pw_arg == NULL) { |
781 |
return NULL; |
782 |
} |
783 |
/* TODO: we really should verify that were are using the right slot */
|
784 |
return PORT_Strdup(pw_arg);
|
785 |
} |
786 |
|
787 |
/* Force a card removal even if the card is not physically removed */
|
788 |
VCardEmulError |
789 |
vcard_emul_force_card_remove(VReader *vreader) |
790 |
{ |
791 |
if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
|
792 |
return VCARD_EMUL_FAIL; /* card is already removed */ |
793 |
} |
794 |
|
795 |
/* OK, remove it */
|
796 |
vreader_insert_card(vreader, NULL);
|
797 |
return VCARD_EMUL_OK;
|
798 |
} |
799 |
|
800 |
/* Re-insert of a card that has been removed by force removal */
|
801 |
VCardEmulError |
802 |
vcard_emul_force_card_insert(VReader *vreader) |
803 |
{ |
804 |
VReaderEmul *vreader_emul; |
805 |
VCard *vcard; |
806 |
|
807 |
if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
|
808 |
return VCARD_EMUL_FAIL; /* card is already removed */ |
809 |
} |
810 |
vreader_emul = vreader_get_private(vreader); |
811 |
|
812 |
/* if it's a softcard, get the saved vcard from the reader emul structure */
|
813 |
if (vreader_emul->saved_vcard) {
|
814 |
vcard = vcard_reference(vreader_emul->saved_vcard); |
815 |
} else {
|
816 |
/* it must be a physical card, rebuild it */
|
817 |
if (!PK11_IsPresent(vreader_emul->slot)) {
|
818 |
/* physical card has been removed, not way to reinsert it */
|
819 |
return VCARD_EMUL_FAIL;
|
820 |
} |
821 |
vcard = vcard_emul_mirror_card(vreader); |
822 |
} |
823 |
vreader_insert_card(vreader, vcard); |
824 |
vcard_free(vcard); |
825 |
|
826 |
return VCARD_EMUL_OK;
|
827 |
} |
828 |
|
829 |
|
830 |
static PRBool
|
831 |
module_has_removable_hw_slots(SECMODModule *mod) |
832 |
{ |
833 |
int i;
|
834 |
PRBool ret = PR_FALSE; |
835 |
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); |
836 |
|
837 |
if (!moduleLock) {
|
838 |
PORT_SetError(SEC_ERROR_NOT_INITIALIZED); |
839 |
return ret;
|
840 |
} |
841 |
SECMOD_GetReadLock(moduleLock); |
842 |
for (i = 0; i < mod->slotCount; i++) { |
843 |
PK11SlotInfo *slot = mod->slots[i]; |
844 |
if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) {
|
845 |
ret = PR_TRUE; |
846 |
break;
|
847 |
} |
848 |
} |
849 |
SECMOD_ReleaseReadLock(moduleLock); |
850 |
return ret;
|
851 |
} |
852 |
|
853 |
/* Previously we returned FAIL if no readers found. This makes
|
854 |
* no sense when using hardware, since there may be no readers connected
|
855 |
* at the time vcard_emul_init is called, but they will be properly
|
856 |
* recognized later. So Instead return FAIL only if no_hw==1 and no
|
857 |
* vcards can be created (indicates error with certificates provided
|
858 |
* or db), or if any other higher level error (NSS error, missing coolkey). */
|
859 |
static int vcard_emul_init_called; |
860 |
|
861 |
VCardEmulError |
862 |
vcard_emul_init(const VCardEmulOptions *options)
|
863 |
{ |
864 |
SECStatus rv; |
865 |
PRBool ret, has_readers = PR_FALSE, need_coolkey_module; |
866 |
VReader *vreader; |
867 |
VReaderEmul *vreader_emul; |
868 |
SECMODListLock *module_lock; |
869 |
SECMODModuleList *module_list; |
870 |
SECMODModuleList *mlp; |
871 |
int i;
|
872 |
|
873 |
if (vcard_emul_init_called) {
|
874 |
return VCARD_EMUL_INIT_ALREADY_INITED;
|
875 |
} |
876 |
vcard_emul_init_called = 1;
|
877 |
vreader_init(); |
878 |
vevent_queue_init(); |
879 |
|
880 |
if (options == NULL) { |
881 |
options = &default_options; |
882 |
} |
883 |
|
884 |
/* first initialize NSS */
|
885 |
if (options->nss_db) {
|
886 |
rv = NSS_Init(options->nss_db); |
887 |
} else {
|
888 |
rv = NSS_Init("sql:/etc/pki/nssdb");
|
889 |
} |
890 |
if (rv != SECSuccess) {
|
891 |
return VCARD_EMUL_FAIL;
|
892 |
} |
893 |
/* Set password callback function */
|
894 |
PK11_SetPasswordFunc(vcard_emul_get_password); |
895 |
|
896 |
/* set up soft cards emulated by software certs rather than physical cards
|
897 |
* */
|
898 |
for (i = 0; i < options->vreader_count; i++) { |
899 |
int j;
|
900 |
int cert_count;
|
901 |
unsigned char **certs; |
902 |
int *cert_len;
|
903 |
VCardKey **keys; |
904 |
PK11SlotInfo *slot; |
905 |
|
906 |
slot = PK11_FindSlotByName(options->vreader[i].name); |
907 |
if (slot == NULL) { |
908 |
continue;
|
909 |
} |
910 |
vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, |
911 |
options->vreader[i].type_params); |
912 |
vreader = vreader_new(options->vreader[i].vname, vreader_emul, |
913 |
vreader_emul_delete); |
914 |
vreader_add_reader(vreader); |
915 |
cert_count = options->vreader[i].cert_count; |
916 |
|
917 |
ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, |
918 |
options->vreader[i].cert_count); |
919 |
if (ret == PR_FALSE) {
|
920 |
continue;
|
921 |
} |
922 |
cert_count = 0;
|
923 |
for (j = 0; j < options->vreader[i].cert_count; j++) { |
924 |
/* we should have a better way of identifying certs than by
|
925 |
* nickname here */
|
926 |
CERTCertificate *cert = PK11_FindCertFromNickname( |
927 |
options->vreader[i].cert_name[j], |
928 |
NULL);
|
929 |
if (cert == NULL) { |
930 |
continue;
|
931 |
} |
932 |
certs[cert_count] = cert->derCert.data; |
933 |
cert_len[cert_count] = cert->derCert.len; |
934 |
keys[cert_count] = vcard_emul_make_key(slot, cert); |
935 |
/* this is safe because the key is still holding a cert reference */
|
936 |
CERT_DestroyCertificate(cert); |
937 |
cert_count++; |
938 |
} |
939 |
if (cert_count) {
|
940 |
VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, |
941 |
keys, cert_count); |
942 |
vreader_insert_card(vreader, vcard); |
943 |
vcard_emul_init_series(vreader, vcard); |
944 |
/* allow insertion and removal of soft cards */
|
945 |
vreader_emul->saved_vcard = vcard_reference(vcard); |
946 |
vcard_free(vcard); |
947 |
vreader_free(vreader); |
948 |
has_readers = PR_TRUE; |
949 |
} |
950 |
g_free(certs); |
951 |
g_free(cert_len); |
952 |
g_free(keys); |
953 |
} |
954 |
|
955 |
/* if we aren't suppose to use hw, skip looking up hardware tokens */
|
956 |
if (!options->use_hw) {
|
957 |
nss_emul_init = has_readers; |
958 |
return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
|
959 |
} |
960 |
|
961 |
/* make sure we have some PKCS #11 module loaded */
|
962 |
module_lock = SECMOD_GetDefaultModuleListLock(); |
963 |
module_list = SECMOD_GetDefaultModuleList(); |
964 |
need_coolkey_module = !has_readers; |
965 |
SECMOD_GetReadLock(module_lock); |
966 |
for (mlp = module_list; mlp; mlp = mlp->next) {
|
967 |
SECMODModule *module = mlp->module; |
968 |
if (module_has_removable_hw_slots(module)) {
|
969 |
need_coolkey_module = PR_FALSE; |
970 |
break;
|
971 |
} |
972 |
} |
973 |
SECMOD_ReleaseReadLock(module_lock); |
974 |
|
975 |
if (need_coolkey_module) {
|
976 |
SECMODModule *module; |
977 |
module = SECMOD_LoadUserModule( |
978 |
(char *)"library=libcoolkeypk11.so name=Coolkey", |
979 |
NULL, PR_FALSE);
|
980 |
if (module == NULL) { |
981 |
return VCARD_EMUL_FAIL;
|
982 |
} |
983 |
SECMOD_DestroyModule(module); /* free our reference, Module will still
|
984 |
* be on the list.
|
985 |
* until we destroy it */
|
986 |
} |
987 |
|
988 |
/* now examine all the slots, finding which should be readers */
|
989 |
/* We should control this with options. For now we mirror out any
|
990 |
* removable hardware slot */
|
991 |
default_card_type = options->hw_card_type; |
992 |
default_type_params = strdup(options->hw_type_params); |
993 |
|
994 |
SECMOD_GetReadLock(module_lock); |
995 |
for (mlp = module_list; mlp; mlp = mlp->next) {
|
996 |
SECMODModule *module = mlp->module; |
997 |
PRBool has_emul_slots = PR_FALSE; |
998 |
|
999 |
if (module == NULL) { |
1000 |
continue;
|
1001 |
} |
1002 |
|
1003 |
for (i = 0; i < module->slotCount; i++) { |
1004 |
PK11SlotInfo *slot = module->slots[i]; |
1005 |
|
1006 |
/* only map removable HW slots */
|
1007 |
if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { |
1008 |
continue;
|
1009 |
} |
1010 |
vreader_emul = vreader_emul_new(slot, options->hw_card_type, |
1011 |
options->hw_type_params); |
1012 |
vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, |
1013 |
vreader_emul_delete); |
1014 |
vreader_add_reader(vreader); |
1015 |
|
1016 |
has_readers = PR_TRUE; |
1017 |
has_emul_slots = PR_TRUE; |
1018 |
|
1019 |
if (PK11_IsPresent(slot)) {
|
1020 |
VCard *vcard; |
1021 |
vcard = vcard_emul_mirror_card(vreader); |
1022 |
vreader_insert_card(vreader, vcard); |
1023 |
vcard_emul_init_series(vreader, vcard); |
1024 |
vcard_free(vcard); |
1025 |
} |
1026 |
} |
1027 |
if (has_emul_slots) {
|
1028 |
vcard_emul_new_event_thread(module); |
1029 |
} |
1030 |
} |
1031 |
SECMOD_ReleaseReadLock(module_lock); |
1032 |
nss_emul_init = has_readers; |
1033 |
|
1034 |
return VCARD_EMUL_OK;
|
1035 |
} |
1036 |
|
1037 |
/* Recreate card insert events for all readers (user should
|
1038 |
* deduce implied reader insert. perhaps do a reader insert as well?)
|
1039 |
*/
|
1040 |
void
|
1041 |
vcard_emul_replay_insertion_events(void)
|
1042 |
{ |
1043 |
VReaderListEntry *current_entry; |
1044 |
VReaderListEntry *next_entry = NULL;
|
1045 |
VReaderList *list = vreader_get_reader_list(); |
1046 |
|
1047 |
for (current_entry = vreader_list_get_first(list); current_entry;
|
1048 |
current_entry = next_entry) { |
1049 |
VReader *vreader = vreader_list_get_reader(current_entry); |
1050 |
next_entry = vreader_list_get_next(current_entry); |
1051 |
vreader_queue_card_event(vreader); |
1052 |
} |
1053 |
} |
1054 |
|
1055 |
/*
|
1056 |
* Silly little functions to help parsing our argument string
|
1057 |
*/
|
1058 |
static int |
1059 |
count_tokens(const char *str, char token, char token_end) |
1060 |
{ |
1061 |
int count = 0; |
1062 |
|
1063 |
for (; *str; str++) {
|
1064 |
if (*str == token) {
|
1065 |
count++; |
1066 |
} |
1067 |
if (*str == token_end) {
|
1068 |
break;
|
1069 |
} |
1070 |
} |
1071 |
return count;
|
1072 |
} |
1073 |
|
1074 |
static const char * |
1075 |
strip(const char *str) |
1076 |
{ |
1077 |
for (; *str && isspace(*str); str++) {
|
1078 |
} |
1079 |
return str;
|
1080 |
} |
1081 |
|
1082 |
static const char * |
1083 |
find_blank(const char *str) |
1084 |
{ |
1085 |
for (; *str && !isspace(*str); str++) {
|
1086 |
} |
1087 |
return str;
|
1088 |
} |
1089 |
|
1090 |
|
1091 |
/*
|
1092 |
* We really want to use some existing argument parsing library here. That
|
1093 |
* would give us a consistent look */
|
1094 |
static VCardEmulOptions options;
|
1095 |
#define READER_STEP 4 |
1096 |
|
1097 |
/* Expects "args" to be at the beginning of a token (ie right after the ','
|
1098 |
* ending the previous token), and puts the next token start in "token",
|
1099 |
* and its length in "token_length". "token" will not be nul-terminated.
|
1100 |
* After calling the macro, "args" will be advanced to the beginning of
|
1101 |
* the next token.
|
1102 |
* This macro may call continue or break.
|
1103 |
*/
|
1104 |
#define NEXT_TOKEN(token) \
|
1105 |
(token) = args; \ |
1106 |
args = strpbrk(args, ",)"); \
|
1107 |
if (*args == 0) { \ |
1108 |
break; \
|
1109 |
} \ |
1110 |
if (*args == ')') { \ |
1111 |
args++; \ |
1112 |
continue; \
|
1113 |
} \ |
1114 |
(token##_length) = args - (token); \ |
1115 |
args = strip(args+1);
|
1116 |
|
1117 |
VCardEmulOptions * |
1118 |
vcard_emul_options(const char *args) |
1119 |
{ |
1120 |
int reader_count = 0; |
1121 |
VCardEmulOptions *opts; |
1122 |
|
1123 |
/* Allow the future use of allocating the options structure on the fly */
|
1124 |
memcpy(&options, &default_options, sizeof(options));
|
1125 |
opts = &options; |
1126 |
|
1127 |
do {
|
1128 |
args = strip(args); /* strip off the leading spaces */
|
1129 |
if (*args == ',') { |
1130 |
continue;
|
1131 |
} |
1132 |
/* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
|
1133 |
* cert_2,cert_3...) */
|
1134 |
if (strncmp(args, "soft=", 5) == 0) { |
1135 |
const char *name; |
1136 |
size_t name_length; |
1137 |
const char *vname; |
1138 |
size_t vname_length; |
1139 |
const char *type_params; |
1140 |
size_t type_params_length; |
1141 |
char type_str[100]; |
1142 |
VCardEmulType type; |
1143 |
int count, i;
|
1144 |
VirtualReaderOptions *vreaderOpt = NULL;
|
1145 |
|
1146 |
args = strip(args + 5);
|
1147 |
if (*args != '(') { |
1148 |
continue;
|
1149 |
} |
1150 |
args = strip(args+1);
|
1151 |
|
1152 |
NEXT_TOKEN(name) |
1153 |
NEXT_TOKEN(vname) |
1154 |
NEXT_TOKEN(type_params) |
1155 |
type_params_length = MIN(type_params_length, sizeof(type_str)-1); |
1156 |
strncpy(type_str, type_params, type_params_length); |
1157 |
type_str[type_params_length] = 0;
|
1158 |
type = vcard_emul_type_from_string(type_str); |
1159 |
|
1160 |
NEXT_TOKEN(type_params) |
1161 |
|
1162 |
if (*args == 0) { |
1163 |
break;
|
1164 |
} |
1165 |
|
1166 |
if (opts->vreader_count >= reader_count) {
|
1167 |
reader_count += READER_STEP; |
1168 |
vreaderOpt = realloc(opts->vreader, |
1169 |
reader_count * sizeof(*vreaderOpt));
|
1170 |
if (vreaderOpt == NULL) { |
1171 |
return opts; /* we're done */ |
1172 |
} |
1173 |
} |
1174 |
opts->vreader = vreaderOpt; |
1175 |
vreaderOpt = &vreaderOpt[opts->vreader_count]; |
1176 |
vreaderOpt->name = g_strndup(name, name_length); |
1177 |
vreaderOpt->vname = g_strndup(vname, vname_length); |
1178 |
vreaderOpt->card_type = type; |
1179 |
vreaderOpt->type_params = |
1180 |
g_strndup(type_params, type_params_length); |
1181 |
count = count_tokens(args, ',', ')') + 1; |
1182 |
vreaderOpt->cert_count = count; |
1183 |
vreaderOpt->cert_name = (char **)g_malloc(count*sizeof(char *)); |
1184 |
for (i = 0; i < count; i++) { |
1185 |
const char *cert = args; |
1186 |
args = strpbrk(args, ",)");
|
1187 |
vreaderOpt->cert_name[i] = g_strndup(cert, args - cert); |
1188 |
args = strip(args+1);
|
1189 |
} |
1190 |
if (*args == ')') { |
1191 |
args++; |
1192 |
} |
1193 |
opts->vreader_count++; |
1194 |
/* use_hw= */
|
1195 |
} else if (strncmp(args, "use_hw=", 7) == 0) { |
1196 |
args = strip(args+7);
|
1197 |
if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') { |
1198 |
opts->use_hw = PR_FALSE; |
1199 |
} else {
|
1200 |
opts->use_hw = PR_TRUE; |
1201 |
} |
1202 |
args = find_blank(args); |
1203 |
/* hw_type= */
|
1204 |
} else if (strncmp(args, "hw_type=", 8) == 0) { |
1205 |
args = strip(args+8);
|
1206 |
opts->hw_card_type = vcard_emul_type_from_string(args); |
1207 |
args = find_blank(args); |
1208 |
/* hw_params= */
|
1209 |
} else if (strncmp(args, "hw_params=", 10) == 0) { |
1210 |
const char *params; |
1211 |
args = strip(args+10);
|
1212 |
params = args; |
1213 |
args = find_blank(args); |
1214 |
opts->hw_type_params = g_strndup(params, args-params); |
1215 |
/* db="/data/base/path" */
|
1216 |
} else if (strncmp(args, "db=", 3) == 0) { |
1217 |
const char *db; |
1218 |
args = strip(args+3);
|
1219 |
if (*args != '"') { |
1220 |
continue;
|
1221 |
} |
1222 |
args++; |
1223 |
db = args; |
1224 |
args = strpbrk(args, "\"\n");
|
1225 |
opts->nss_db = g_strndup(db, args-db); |
1226 |
if (*args != 0) { |
1227 |
args++; |
1228 |
} |
1229 |
} else {
|
1230 |
args = find_blank(args); |
1231 |
} |
1232 |
} while (*args != 0); |
1233 |
|
1234 |
return opts;
|
1235 |
} |
1236 |
|
1237 |
void
|
1238 |
vcard_emul_usage(void)
|
1239 |
{ |
1240 |
fprintf(stderr, |
1241 |
"emul args: comma separated list of the following arguments\n"
|
1242 |
" db={nss_database} (default sql:/etc/pki/nssdb)\n"
|
1243 |
" use_hw=[yes|no] (default yes)\n"
|
1244 |
" hw_type={card_type_to_emulate} (default CAC)\n"
|
1245 |
" hw_param={param_for_card} (default \"\")\n"
|
1246 |
" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
|
1247 |
" {cert1},{cert2},{cert3} (default none)\n"
|
1248 |
"\n"
|
1249 |
" {nss_database} The location of the NSS cert & key database\n"
|
1250 |
" {card_type_to_emulate} What card interface to present to the guest\n"
|
1251 |
" {param_for_card} Card interface specific parameters\n"
|
1252 |
" {slot_name} NSS slot that contains the certs\n"
|
1253 |
" {vreader_name} Virtual reader name to present to the guest\n"
|
1254 |
" {certN} Nickname of the certificate n on the virtual card\n"
|
1255 |
"\n"
|
1256 |
"These parameters come as a single string separated by blanks or newlines."
|
1257 |
"\n"
|
1258 |
"Unless use_hw is set to no, all tokens that look like removable hardware\n"
|
1259 |
"tokens will be presented to the guest using the emulator specified by\n"
|
1260 |
"hw_type, and parameters of hw_param.\n"
|
1261 |
"\n"
|
1262 |
"If more one or more soft= parameters are specified, these readers will be\n"
|
1263 |
"presented to the guest\n");
|
1264 |
} |