Statistics
| Branch: | Revision:

root / libcacard / vcard_emul_nss.c @ 1b902f7d

History | View | Annotate | Download (37.6 kB)

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