Statistics
| Branch: | Revision:

root / libcacard / vcard_emul_nss.c @ 2542bfd5

History | View | Annotate | Download (37.1 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 111a38b0 Robert Relyea
        slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
686 111a38b0 Robert Relyea
        if (slot == NULL) {
687 111a38b0 Robert Relyea
            break;
688 111a38b0 Robert Relyea
        }
689 111a38b0 Robert Relyea
        vreader = vcard_emul_find_vreader_from_slot(slot);
690 111a38b0 Robert Relyea
        if (vreader == NULL) {
691 111a38b0 Robert Relyea
            /* new vreader */
692 111a38b0 Robert Relyea
            vreader_emul = vreader_emul_new(slot, default_card_type,
693 111a38b0 Robert Relyea
                                            default_type_params);
694 111a38b0 Robert Relyea
            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
695 111a38b0 Robert Relyea
                                  vreader_emul_delete);
696 111a38b0 Robert Relyea
            PK11_FreeSlot(slot);
697 111a38b0 Robert Relyea
            slot = NULL;
698 111a38b0 Robert Relyea
            vreader_add_reader(vreader);
699 111a38b0 Robert Relyea
            vreader_free(vreader);
700 111a38b0 Robert Relyea
            continue;
701 111a38b0 Robert Relyea
        }
702 111a38b0 Robert Relyea
        /* card remove/insert */
703 111a38b0 Robert Relyea
        vreader_emul = vreader_get_private(vreader);
704 111a38b0 Robert Relyea
        if (PK11_IsPresent(slot)) {
705 111a38b0 Robert Relyea
            int series = PK11_GetSlotSeries(slot);
706 111a38b0 Robert Relyea
            if (series != vreader_emul->series) {
707 111a38b0 Robert Relyea
                if (vreader_emul->present) {
708 111a38b0 Robert Relyea
                    vreader_insert_card(vreader, NULL);
709 111a38b0 Robert Relyea
                }
710 111a38b0 Robert Relyea
                vcard = vcard_emul_mirror_card(vreader);
711 111a38b0 Robert Relyea
                vreader_insert_card(vreader, vcard);
712 111a38b0 Robert Relyea
                vcard_free(vcard);
713 111a38b0 Robert Relyea
            }
714 111a38b0 Robert Relyea
            vreader_emul->series = series;
715 111a38b0 Robert Relyea
            vreader_emul->present = 1;
716 111a38b0 Robert Relyea
            vreader_free(vreader);
717 111a38b0 Robert Relyea
            PK11_FreeSlot(slot);
718 111a38b0 Robert Relyea
            continue;
719 111a38b0 Robert Relyea
        }
720 111a38b0 Robert Relyea
        if (vreader_emul->present) {
721 111a38b0 Robert Relyea
            vreader_insert_card(vreader, NULL);
722 111a38b0 Robert Relyea
        }
723 111a38b0 Robert Relyea
        vreader_emul->series = 0;
724 111a38b0 Robert Relyea
        vreader_emul->present = 0;
725 111a38b0 Robert Relyea
        PK11_FreeSlot(slot);
726 111a38b0 Robert Relyea
        vreader_free(vreader);
727 111a38b0 Robert Relyea
    } while (1);
728 111a38b0 Robert Relyea
}
729 111a38b0 Robert Relyea
730 111a38b0 Robert Relyea
/* if the card is inserted when we start up, make sure our state is correct */
731 111a38b0 Robert Relyea
static void
732 111a38b0 Robert Relyea
vcard_emul_init_series(VReader *vreader, VCard *vcard)
733 111a38b0 Robert Relyea
{
734 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul = vreader_get_private(vreader);
735 111a38b0 Robert Relyea
    PK11SlotInfo *slot = vreader_emul->slot;
736 111a38b0 Robert Relyea
737 111a38b0 Robert Relyea
    vreader_emul->present = PK11_IsPresent(slot);
738 111a38b0 Robert Relyea
    vreader_emul->series = PK11_GetSlotSeries(slot);
739 111a38b0 Robert Relyea
    if (vreader_emul->present == 0) {
740 111a38b0 Robert Relyea
        vreader_insert_card(vreader, NULL);
741 111a38b0 Robert Relyea
    }
742 111a38b0 Robert Relyea
}
743 111a38b0 Robert Relyea
744 111a38b0 Robert Relyea
/*
745 111a38b0 Robert Relyea
 * each module has a separate wait call, create a thread for each module that
746 111a38b0 Robert Relyea
 * we are using.
747 111a38b0 Robert Relyea
 */
748 111a38b0 Robert Relyea
static void
749 111a38b0 Robert Relyea
vcard_emul_new_event_thread(SECMODModule *module)
750 111a38b0 Robert Relyea
{
751 111a38b0 Robert Relyea
    PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
752 111a38b0 Robert Relyea
                     module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
753 111a38b0 Robert Relyea
                     PR_UNJOINABLE_THREAD, 0);
754 111a38b0 Robert Relyea
}
755 111a38b0 Robert Relyea
756 111a38b0 Robert Relyea
static const VCardEmulOptions default_options = {
757 111a38b0 Robert Relyea
    .nss_db = NULL,
758 111a38b0 Robert Relyea
    .vreader = NULL,
759 111a38b0 Robert Relyea
    .vreader_count = 0,
760 111a38b0 Robert Relyea
    .hw_card_type = VCARD_EMUL_CAC,
761 111a38b0 Robert Relyea
    .hw_type_params = "",
762 111a38b0 Robert Relyea
    .use_hw = PR_TRUE
763 111a38b0 Robert Relyea
};
764 111a38b0 Robert Relyea
765 111a38b0 Robert Relyea
766 111a38b0 Robert Relyea
/*
767 111a38b0 Robert Relyea
 *  NSS needs the app to supply a password prompt. In our case the only time
768 111a38b0 Robert Relyea
 *  the password is supplied is as part of the Login APDU. The actual password
769 111a38b0 Robert Relyea
 *  is passed in the pw_arg in that case. In all other cases pw_arg should be
770 111a38b0 Robert Relyea
 *  NULL.
771 111a38b0 Robert Relyea
 */
772 111a38b0 Robert Relyea
static char *
773 111a38b0 Robert Relyea
vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg)
774 111a38b0 Robert Relyea
{
775 111a38b0 Robert Relyea
    /* if it didn't work the first time, don't keep trying */
776 111a38b0 Robert Relyea
    if (retries) {
777 111a38b0 Robert Relyea
        return NULL;
778 111a38b0 Robert Relyea
    }
779 111a38b0 Robert Relyea
    /* we are looking up a password when we don't have one in hand */
780 111a38b0 Robert Relyea
    if (pw_arg == NULL) {
781 111a38b0 Robert Relyea
        return NULL;
782 111a38b0 Robert Relyea
    }
783 111a38b0 Robert Relyea
    /* TODO: we really should verify that were are using the right slot */
784 111a38b0 Robert Relyea
    return PORT_Strdup(pw_arg);
785 111a38b0 Robert Relyea
}
786 111a38b0 Robert Relyea
787 111a38b0 Robert Relyea
/* Force a card removal even if the card is not physically removed */
788 111a38b0 Robert Relyea
VCardEmulError
789 111a38b0 Robert Relyea
vcard_emul_force_card_remove(VReader *vreader)
790 111a38b0 Robert Relyea
{
791 111a38b0 Robert Relyea
    if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
792 111a38b0 Robert Relyea
        return VCARD_EMUL_FAIL; /* card is already removed */
793 111a38b0 Robert Relyea
    }
794 111a38b0 Robert Relyea
795 111a38b0 Robert Relyea
    /* OK, remove it */
796 111a38b0 Robert Relyea
    vreader_insert_card(vreader, NULL);
797 111a38b0 Robert Relyea
    return VCARD_EMUL_OK;
798 111a38b0 Robert Relyea
}
799 111a38b0 Robert Relyea
800 111a38b0 Robert Relyea
/* Re-insert of a card that has been removed by force removal */
801 111a38b0 Robert Relyea
VCardEmulError
802 111a38b0 Robert Relyea
vcard_emul_force_card_insert(VReader *vreader)
803 111a38b0 Robert Relyea
{
804 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
805 111a38b0 Robert Relyea
    VCard *vcard;
806 111a38b0 Robert Relyea
807 111a38b0 Robert Relyea
    if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
808 111a38b0 Robert Relyea
        return VCARD_EMUL_FAIL; /* card is already removed */
809 111a38b0 Robert Relyea
    }
810 111a38b0 Robert Relyea
    vreader_emul = vreader_get_private(vreader);
811 111a38b0 Robert Relyea
812 111a38b0 Robert Relyea
    /* if it's a softcard, get the saved vcard from the reader emul structure */
813 111a38b0 Robert Relyea
    if (vreader_emul->saved_vcard) {
814 111a38b0 Robert Relyea
        vcard = vcard_reference(vreader_emul->saved_vcard);
815 111a38b0 Robert Relyea
    } else {
816 111a38b0 Robert Relyea
        /* it must be a physical card, rebuild it */
817 111a38b0 Robert Relyea
        if (!PK11_IsPresent(vreader_emul->slot)) {
818 111a38b0 Robert Relyea
            /* physical card has been removed, not way to reinsert it */
819 111a38b0 Robert Relyea
            return VCARD_EMUL_FAIL;
820 111a38b0 Robert Relyea
        }
821 111a38b0 Robert Relyea
        vcard = vcard_emul_mirror_card(vreader);
822 111a38b0 Robert Relyea
    }
823 111a38b0 Robert Relyea
    vreader_insert_card(vreader, vcard);
824 111a38b0 Robert Relyea
    vcard_free(vcard);
825 111a38b0 Robert Relyea
826 111a38b0 Robert Relyea
    return VCARD_EMUL_OK;
827 111a38b0 Robert Relyea
}
828 111a38b0 Robert Relyea
829 111a38b0 Robert Relyea
830 111a38b0 Robert Relyea
static PRBool
831 111a38b0 Robert Relyea
module_has_removable_hw_slots(SECMODModule *mod)
832 111a38b0 Robert Relyea
{
833 111a38b0 Robert Relyea
    int i;
834 111a38b0 Robert Relyea
    PRBool ret = PR_FALSE;
835 111a38b0 Robert Relyea
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
836 111a38b0 Robert Relyea
837 111a38b0 Robert Relyea
    if (!moduleLock) {
838 111a38b0 Robert Relyea
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
839 111a38b0 Robert Relyea
        return ret;
840 111a38b0 Robert Relyea
    }
841 111a38b0 Robert Relyea
    SECMOD_GetReadLock(moduleLock);
842 111a38b0 Robert Relyea
    for (i = 0; i < mod->slotCount; i++) {
843 111a38b0 Robert Relyea
        PK11SlotInfo *slot = mod->slots[i];
844 111a38b0 Robert Relyea
        if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) {
845 111a38b0 Robert Relyea
            ret = PR_TRUE;
846 111a38b0 Robert Relyea
            break;
847 111a38b0 Robert Relyea
        }
848 111a38b0 Robert Relyea
    }
849 111a38b0 Robert Relyea
    SECMOD_ReleaseReadLock(moduleLock);
850 111a38b0 Robert Relyea
    return ret;
851 111a38b0 Robert Relyea
}
852 111a38b0 Robert Relyea
853 111a38b0 Robert Relyea
/* Previously we returned FAIL if no readers found. This makes
854 111a38b0 Robert Relyea
 * no sense when using hardware, since there may be no readers connected
855 111a38b0 Robert Relyea
 * at the time vcard_emul_init is called, but they will be properly
856 111a38b0 Robert Relyea
 * recognized later. So Instead return FAIL only if no_hw==1 and no
857 111a38b0 Robert Relyea
 * vcards can be created (indicates error with certificates provided
858 111a38b0 Robert Relyea
 * or db), or if any other higher level error (NSS error, missing coolkey). */
859 111a38b0 Robert Relyea
static int vcard_emul_init_called;
860 111a38b0 Robert Relyea
861 111a38b0 Robert Relyea
VCardEmulError
862 111a38b0 Robert Relyea
vcard_emul_init(const VCardEmulOptions *options)
863 111a38b0 Robert Relyea
{
864 111a38b0 Robert Relyea
    SECStatus rv;
865 111a38b0 Robert Relyea
    PRBool ret, has_readers = PR_FALSE, need_coolkey_module;
866 111a38b0 Robert Relyea
    VReader *vreader;
867 111a38b0 Robert Relyea
    VReaderEmul *vreader_emul;
868 111a38b0 Robert Relyea
    SECMODListLock *module_lock;
869 111a38b0 Robert Relyea
    SECMODModuleList *module_list;
870 111a38b0 Robert Relyea
    SECMODModuleList *mlp;
871 111a38b0 Robert Relyea
    int i;
872 111a38b0 Robert Relyea
873 111a38b0 Robert Relyea
    if (vcard_emul_init_called) {
874 111a38b0 Robert Relyea
        return VCARD_EMUL_INIT_ALREADY_INITED;
875 111a38b0 Robert Relyea
    }
876 111a38b0 Robert Relyea
    vcard_emul_init_called = 1;
877 111a38b0 Robert Relyea
    vreader_init();
878 111a38b0 Robert Relyea
    vevent_queue_init();
879 111a38b0 Robert Relyea
880 111a38b0 Robert Relyea
    if (options == NULL) {
881 111a38b0 Robert Relyea
        options = &default_options;
882 111a38b0 Robert Relyea
    }
883 111a38b0 Robert Relyea
884 111a38b0 Robert Relyea
    /* first initialize NSS */
885 111a38b0 Robert Relyea
    if (options->nss_db) {
886 111a38b0 Robert Relyea
        rv = NSS_Init(options->nss_db);
887 111a38b0 Robert Relyea
    } else {
888 111a38b0 Robert Relyea
        rv = NSS_Init("sql:/etc/pki/nssdb");
889 111a38b0 Robert Relyea
    }
890 111a38b0 Robert Relyea
    if (rv != SECSuccess) {
891 111a38b0 Robert Relyea
        return VCARD_EMUL_FAIL;
892 111a38b0 Robert Relyea
    }
893 111a38b0 Robert Relyea
    /* Set password callback function */
894 111a38b0 Robert Relyea
    PK11_SetPasswordFunc(vcard_emul_get_password);
895 111a38b0 Robert Relyea
896 111a38b0 Robert Relyea
    /* set up soft cards emulated by software certs rather than physical cards
897 111a38b0 Robert Relyea
     * */
898 111a38b0 Robert Relyea
    for (i = 0; i < options->vreader_count; i++) {
899 111a38b0 Robert Relyea
        int j;
900 111a38b0 Robert Relyea
        int cert_count;
901 111a38b0 Robert Relyea
        unsigned char **certs;
902 111a38b0 Robert Relyea
        int *cert_len;
903 111a38b0 Robert Relyea
        VCardKey **keys;
904 111a38b0 Robert Relyea
        PK11SlotInfo *slot;
905 111a38b0 Robert Relyea
906 111a38b0 Robert Relyea
        slot = PK11_FindSlotByName(options->vreader[i].name);
907 111a38b0 Robert Relyea
        if (slot == NULL) {
908 111a38b0 Robert Relyea
            continue;
909 111a38b0 Robert Relyea
        }
910 111a38b0 Robert Relyea
        vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
911 111a38b0 Robert Relyea
                                        options->vreader[i].type_params);
912 111a38b0 Robert Relyea
        vreader = vreader_new(options->vreader[i].vname, vreader_emul,
913 111a38b0 Robert Relyea
                              vreader_emul_delete);
914 111a38b0 Robert Relyea
        vreader_add_reader(vreader);
915 111a38b0 Robert Relyea
        cert_count = options->vreader[i].cert_count;
916 111a38b0 Robert Relyea
917 111a38b0 Robert Relyea
        ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
918 111a38b0 Robert Relyea
                                      options->vreader[i].cert_count);
919 111a38b0 Robert Relyea
        if (ret == PR_FALSE) {
920 111a38b0 Robert Relyea
            continue;
921 111a38b0 Robert Relyea
        }
922 111a38b0 Robert Relyea
        cert_count = 0;
923 111a38b0 Robert Relyea
        for (j = 0; j < options->vreader[i].cert_count; j++) {
924 111a38b0 Robert Relyea
            /* we should have a better way of identifying certs than by
925 111a38b0 Robert Relyea
             * nickname here */
926 111a38b0 Robert Relyea
            CERTCertificate *cert = PK11_FindCertFromNickname(
927 111a38b0 Robert Relyea
                                        options->vreader[i].cert_name[j],
928 111a38b0 Robert Relyea
                                        NULL);
929 111a38b0 Robert Relyea
            if (cert == NULL) {
930 111a38b0 Robert Relyea
                continue;
931 111a38b0 Robert Relyea
            }
932 111a38b0 Robert Relyea
            certs[cert_count] = cert->derCert.data;
933 111a38b0 Robert Relyea
            cert_len[cert_count] = cert->derCert.len;
934 111a38b0 Robert Relyea
            keys[cert_count] = vcard_emul_make_key(slot, cert);
935 111a38b0 Robert Relyea
            /* this is safe because the key is still holding a cert reference */
936 111a38b0 Robert Relyea
            CERT_DestroyCertificate(cert);
937 111a38b0 Robert Relyea
            cert_count++;
938 111a38b0 Robert Relyea
        }
939 111a38b0 Robert Relyea
        if (cert_count) {
940 111a38b0 Robert Relyea
            VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
941 111a38b0 Robert Relyea
                                                keys, cert_count);
942 111a38b0 Robert Relyea
            vreader_insert_card(vreader, vcard);
943 111a38b0 Robert Relyea
            vcard_emul_init_series(vreader, vcard);
944 111a38b0 Robert Relyea
            /* allow insertion and removal of soft cards */
945 111a38b0 Robert Relyea
            vreader_emul->saved_vcard = vcard_reference(vcard);
946 111a38b0 Robert Relyea
            vcard_free(vcard);
947 111a38b0 Robert Relyea
            vreader_free(vreader);
948 111a38b0 Robert Relyea
            has_readers = PR_TRUE;
949 111a38b0 Robert Relyea
        }
950 7267c094 Anthony Liguori
        g_free(certs);
951 7267c094 Anthony Liguori
        g_free(cert_len);
952 7267c094 Anthony Liguori
        g_free(keys);
953 111a38b0 Robert Relyea
    }
954 111a38b0 Robert Relyea
955 111a38b0 Robert Relyea
    /* if we aren't suppose to use hw, skip looking up hardware tokens */
956 111a38b0 Robert Relyea
    if (!options->use_hw) {
957 111a38b0 Robert Relyea
        nss_emul_init = has_readers;
958 111a38b0 Robert Relyea
        return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
959 111a38b0 Robert Relyea
    }
960 111a38b0 Robert Relyea
961 111a38b0 Robert Relyea
    /* make sure we have some PKCS #11 module loaded */
962 111a38b0 Robert Relyea
    module_lock = SECMOD_GetDefaultModuleListLock();
963 111a38b0 Robert Relyea
    module_list = SECMOD_GetDefaultModuleList();
964 111a38b0 Robert Relyea
    need_coolkey_module = !has_readers;
965 111a38b0 Robert Relyea
    SECMOD_GetReadLock(module_lock);
966 111a38b0 Robert Relyea
    for (mlp = module_list; mlp; mlp = mlp->next) {
967 111a38b0 Robert Relyea
        SECMODModule *module = mlp->module;
968 111a38b0 Robert Relyea
        if (module_has_removable_hw_slots(module)) {
969 111a38b0 Robert Relyea
            need_coolkey_module = PR_FALSE;
970 111a38b0 Robert Relyea
            break;
971 111a38b0 Robert Relyea
        }
972 111a38b0 Robert Relyea
    }
973 111a38b0 Robert Relyea
    SECMOD_ReleaseReadLock(module_lock);
974 111a38b0 Robert Relyea
975 111a38b0 Robert Relyea
    if (need_coolkey_module) {
976 111a38b0 Robert Relyea
        SECMODModule *module;
977 111a38b0 Robert Relyea
        module = SECMOD_LoadUserModule(
978 111a38b0 Robert Relyea
                    (char *)"library=libcoolkeypk11.so name=Coolkey",
979 111a38b0 Robert Relyea
                    NULL, PR_FALSE);
980 111a38b0 Robert Relyea
        if (module == NULL) {
981 111a38b0 Robert Relyea
            return VCARD_EMUL_FAIL;
982 111a38b0 Robert Relyea
        }
983 111a38b0 Robert Relyea
        SECMOD_DestroyModule(module); /* free our reference, Module will still
984 111a38b0 Robert Relyea
                                       * be on the list.
985 111a38b0 Robert Relyea
                                       * until we destroy it */
986 111a38b0 Robert Relyea
    }
987 111a38b0 Robert Relyea
988 111a38b0 Robert Relyea
    /* now examine all the slots, finding which should be readers */
989 111a38b0 Robert Relyea
    /* We should control this with options. For now we mirror out any
990 111a38b0 Robert Relyea
     * removable hardware slot */
991 111a38b0 Robert Relyea
    default_card_type = options->hw_card_type;
992 111a38b0 Robert Relyea
    default_type_params = strdup(options->hw_type_params);
993 111a38b0 Robert Relyea
994 111a38b0 Robert Relyea
    SECMOD_GetReadLock(module_lock);
995 111a38b0 Robert Relyea
    for (mlp = module_list; mlp; mlp = mlp->next) {
996 111a38b0 Robert Relyea
        SECMODModule *module = mlp->module;
997 111a38b0 Robert Relyea
        PRBool has_emul_slots = PR_FALSE;
998 111a38b0 Robert Relyea
999 111a38b0 Robert Relyea
        if (module == NULL) {
1000 111a38b0 Robert Relyea
                continue;
1001 111a38b0 Robert Relyea
        }
1002 111a38b0 Robert Relyea
1003 111a38b0 Robert Relyea
        for (i = 0; i < module->slotCount; i++) {
1004 111a38b0 Robert Relyea
            PK11SlotInfo *slot = module->slots[i];
1005 111a38b0 Robert Relyea
1006 111a38b0 Robert Relyea
            /* only map removable HW slots */
1007 111a38b0 Robert Relyea
            if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
1008 111a38b0 Robert Relyea
                continue;
1009 111a38b0 Robert Relyea
            }
1010 111a38b0 Robert Relyea
            vreader_emul = vreader_emul_new(slot, options->hw_card_type,
1011 111a38b0 Robert Relyea
                                            options->hw_type_params);
1012 111a38b0 Robert Relyea
            vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
1013 111a38b0 Robert Relyea
                                  vreader_emul_delete);
1014 111a38b0 Robert Relyea
            vreader_add_reader(vreader);
1015 111a38b0 Robert Relyea
1016 111a38b0 Robert Relyea
            has_readers = PR_TRUE;
1017 111a38b0 Robert Relyea
            has_emul_slots = PR_TRUE;
1018 111a38b0 Robert Relyea
1019 111a38b0 Robert Relyea
            if (PK11_IsPresent(slot)) {
1020 111a38b0 Robert Relyea
                VCard *vcard;
1021 111a38b0 Robert Relyea
                vcard = vcard_emul_mirror_card(vreader);
1022 111a38b0 Robert Relyea
                vreader_insert_card(vreader, vcard);
1023 111a38b0 Robert Relyea
                vcard_emul_init_series(vreader, vcard);
1024 111a38b0 Robert Relyea
                vcard_free(vcard);
1025 111a38b0 Robert Relyea
            }
1026 111a38b0 Robert Relyea
        }
1027 111a38b0 Robert Relyea
        if (has_emul_slots) {
1028 111a38b0 Robert Relyea
            vcard_emul_new_event_thread(module);
1029 111a38b0 Robert Relyea
        }
1030 111a38b0 Robert Relyea
    }
1031 111a38b0 Robert Relyea
    SECMOD_ReleaseReadLock(module_lock);
1032 111a38b0 Robert Relyea
    nss_emul_init = has_readers;
1033 111a38b0 Robert Relyea
1034 111a38b0 Robert Relyea
    return VCARD_EMUL_OK;
1035 111a38b0 Robert Relyea
}
1036 111a38b0 Robert Relyea
1037 111a38b0 Robert Relyea
/* Recreate card insert events for all readers (user should
1038 111a38b0 Robert Relyea
 * deduce implied reader insert. perhaps do a reader insert as well?)
1039 111a38b0 Robert Relyea
 */
1040 111a38b0 Robert Relyea
void
1041 111a38b0 Robert Relyea
vcard_emul_replay_insertion_events(void)
1042 111a38b0 Robert Relyea
{
1043 111a38b0 Robert Relyea
    VReaderListEntry *current_entry;
1044 111a38b0 Robert Relyea
    VReaderListEntry *next_entry = NULL;
1045 111a38b0 Robert Relyea
    VReaderList *list = vreader_get_reader_list();
1046 111a38b0 Robert Relyea
1047 111a38b0 Robert Relyea
    for (current_entry = vreader_list_get_first(list); current_entry;
1048 111a38b0 Robert Relyea
            current_entry = next_entry) {
1049 111a38b0 Robert Relyea
        VReader *vreader = vreader_list_get_reader(current_entry);
1050 111a38b0 Robert Relyea
        next_entry = vreader_list_get_next(current_entry);
1051 111a38b0 Robert Relyea
        vreader_queue_card_event(vreader);
1052 111a38b0 Robert Relyea
    }
1053 111a38b0 Robert Relyea
}
1054 111a38b0 Robert Relyea
1055 111a38b0 Robert Relyea
/*
1056 111a38b0 Robert Relyea
 *  Silly little functions to help parsing our argument string
1057 111a38b0 Robert Relyea
 */
1058 111a38b0 Robert Relyea
static int
1059 111a38b0 Robert Relyea
count_tokens(const char *str, char token, char token_end)
1060 111a38b0 Robert Relyea
{
1061 111a38b0 Robert Relyea
    int count = 0;
1062 111a38b0 Robert Relyea
1063 111a38b0 Robert Relyea
    for (; *str; str++) {
1064 111a38b0 Robert Relyea
        if (*str == token) {
1065 111a38b0 Robert Relyea
            count++;
1066 111a38b0 Robert Relyea
        }
1067 111a38b0 Robert Relyea
        if (*str == token_end) {
1068 111a38b0 Robert Relyea
            break;
1069 111a38b0 Robert Relyea
        }
1070 111a38b0 Robert Relyea
    }
1071 111a38b0 Robert Relyea
    return count;
1072 111a38b0 Robert Relyea
}
1073 111a38b0 Robert Relyea
1074 111a38b0 Robert Relyea
static const char *
1075 111a38b0 Robert Relyea
strip(const char *str)
1076 111a38b0 Robert Relyea
{
1077 685ff50f Alon Levy
    for (; *str && isspace(*str); str++) {
1078 111a38b0 Robert Relyea
    }
1079 111a38b0 Robert Relyea
    return str;
1080 111a38b0 Robert Relyea
}
1081 111a38b0 Robert Relyea
1082 111a38b0 Robert Relyea
static const char *
1083 111a38b0 Robert Relyea
find_blank(const char *str)
1084 111a38b0 Robert Relyea
{
1085 685ff50f Alon Levy
    for (; *str && !isspace(*str); str++) {
1086 111a38b0 Robert Relyea
    }
1087 111a38b0 Robert Relyea
    return str;
1088 111a38b0 Robert Relyea
}
1089 111a38b0 Robert Relyea
1090 111a38b0 Robert Relyea
1091 111a38b0 Robert Relyea
/*
1092 111a38b0 Robert Relyea
 *  We really want to use some existing argument parsing library here. That
1093 fc27eefe Stefan Weil
 *  would give us a consistent look */
1094 111a38b0 Robert Relyea
static VCardEmulOptions options;
1095 111a38b0 Robert Relyea
#define READER_STEP 4
1096 111a38b0 Robert Relyea
1097 d246b3cf Christophe Fergeau
/* Expects "args" to be at the beginning of a token (ie right after the ','
1098 d246b3cf Christophe Fergeau
 * ending the previous token), and puts the next token start in "token",
1099 d246b3cf Christophe Fergeau
 * and its length in "token_length". "token" will not be nul-terminated.
1100 d246b3cf Christophe Fergeau
 * After calling the macro, "args" will be advanced to the beginning of
1101 d246b3cf Christophe Fergeau
 * the next token.
1102 d246b3cf Christophe Fergeau
 * This macro may call continue or break.
1103 d246b3cf Christophe Fergeau
 */
1104 d246b3cf Christophe Fergeau
#define NEXT_TOKEN(token) \
1105 d246b3cf Christophe Fergeau
            (token) = args; \
1106 d246b3cf Christophe Fergeau
            args = strpbrk(args, ",)"); \
1107 d246b3cf Christophe Fergeau
            if (*args == 0) { \
1108 d246b3cf Christophe Fergeau
                break; \
1109 d246b3cf Christophe Fergeau
            } \
1110 d246b3cf Christophe Fergeau
            if (*args == ')') { \
1111 d246b3cf Christophe Fergeau
                args++; \
1112 d246b3cf Christophe Fergeau
                continue; \
1113 d246b3cf Christophe Fergeau
            } \
1114 d246b3cf Christophe Fergeau
            (token##_length) = args - (token); \
1115 d246b3cf Christophe Fergeau
            args = strip(args+1);
1116 d246b3cf Christophe Fergeau
1117 111a38b0 Robert Relyea
VCardEmulOptions *
1118 111a38b0 Robert Relyea
vcard_emul_options(const char *args)
1119 111a38b0 Robert Relyea
{
1120 111a38b0 Robert Relyea
    int reader_count = 0;
1121 111a38b0 Robert Relyea
    VCardEmulOptions *opts;
1122 111a38b0 Robert Relyea
1123 111a38b0 Robert Relyea
    /* Allow the future use of allocating the options structure on the fly */
1124 111a38b0 Robert Relyea
    memcpy(&options, &default_options, sizeof(options));
1125 111a38b0 Robert Relyea
    opts = &options;
1126 111a38b0 Robert Relyea
1127 111a38b0 Robert Relyea
    do {
1128 111a38b0 Robert Relyea
        args = strip(args); /* strip off the leading spaces */
1129 111a38b0 Robert Relyea
        if (*args == ',') {
1130 111a38b0 Robert Relyea
            continue;
1131 111a38b0 Robert Relyea
        }
1132 111a38b0 Robert Relyea
        /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
1133 111a38b0 Robert Relyea
         *       cert_2,cert_3...) */
1134 111a38b0 Robert Relyea
        if (strncmp(args, "soft=", 5) == 0) {
1135 111a38b0 Robert Relyea
            const char *name;
1136 a5aa842a Christophe Fergeau
            size_t name_length;
1137 111a38b0 Robert Relyea
            const char *vname;
1138 a5aa842a Christophe Fergeau
            size_t vname_length;
1139 111a38b0 Robert Relyea
            const char *type_params;
1140 a5aa842a Christophe Fergeau
            size_t type_params_length;
1141 a5aa842a Christophe Fergeau
            char type_str[100];
1142 111a38b0 Robert Relyea
            VCardEmulType type;
1143 a5aa842a Christophe Fergeau
            int count, i;
1144 111a38b0 Robert Relyea
            VirtualReaderOptions *vreaderOpt = NULL;
1145 111a38b0 Robert Relyea
1146 111a38b0 Robert Relyea
            args = strip(args + 5);
1147 111a38b0 Robert Relyea
            if (*args != '(') {
1148 111a38b0 Robert Relyea
                continue;
1149 111a38b0 Robert Relyea
            }
1150 a5aa842a Christophe Fergeau
            args = strip(args+1);
1151 a5aa842a Christophe Fergeau
1152 d246b3cf Christophe Fergeau
            NEXT_TOKEN(name)
1153 d246b3cf Christophe Fergeau
            NEXT_TOKEN(vname)
1154 d246b3cf Christophe Fergeau
            NEXT_TOKEN(type_params)
1155 a5aa842a Christophe Fergeau
            type_params_length = MIN(type_params_length, sizeof(type_str)-1);
1156 a5aa842a Christophe Fergeau
            strncpy(type_str, type_params, type_params_length);
1157 a5aa842a Christophe Fergeau
            type_str[type_params_length] = 0;
1158 a5aa842a Christophe Fergeau
            type = vcard_emul_type_from_string(type_str);
1159 a5aa842a Christophe Fergeau
1160 d246b3cf Christophe Fergeau
            NEXT_TOKEN(type_params)
1161 a5aa842a Christophe Fergeau
1162 111a38b0 Robert Relyea
            if (*args == 0) {
1163 111a38b0 Robert Relyea
                break;
1164 111a38b0 Robert Relyea
            }
1165 111a38b0 Robert Relyea
1166 111a38b0 Robert Relyea
            if (opts->vreader_count >= reader_count) {
1167 111a38b0 Robert Relyea
                reader_count += READER_STEP;
1168 111a38b0 Robert Relyea
                vreaderOpt = realloc(opts->vreader,
1169 111a38b0 Robert Relyea
                                reader_count * sizeof(*vreaderOpt));
1170 111a38b0 Robert Relyea
                if (vreaderOpt == NULL) {
1171 111a38b0 Robert Relyea
                    return opts; /* we're done */
1172 111a38b0 Robert Relyea
                }
1173 111a38b0 Robert Relyea
            }
1174 111a38b0 Robert Relyea
            opts->vreader = vreaderOpt;
1175 111a38b0 Robert Relyea
            vreaderOpt = &vreaderOpt[opts->vreader_count];
1176 7267c094 Anthony Liguori
            vreaderOpt->name = g_strndup(name, name_length);
1177 7267c094 Anthony Liguori
            vreaderOpt->vname = g_strndup(vname, vname_length);
1178 111a38b0 Robert Relyea
            vreaderOpt->card_type = type;
1179 111a38b0 Robert Relyea
            vreaderOpt->type_params =
1180 7267c094 Anthony Liguori
                g_strndup(type_params, type_params_length);
1181 a5aa842a Christophe Fergeau
            count = count_tokens(args, ',', ')') + 1;
1182 111a38b0 Robert Relyea
            vreaderOpt->cert_count = count;
1183 7267c094 Anthony Liguori
            vreaderOpt->cert_name = (char **)g_malloc(count*sizeof(char *));
1184 111a38b0 Robert Relyea
            for (i = 0; i < count; i++) {
1185 a5aa842a Christophe Fergeau
                const char *cert = args;
1186 a5aa842a Christophe Fergeau
                args = strpbrk(args, ",)");
1187 7267c094 Anthony Liguori
                vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
1188 a5aa842a Christophe Fergeau
                args = strip(args+1);
1189 111a38b0 Robert Relyea
            }
1190 111a38b0 Robert Relyea
            if (*args == ')') {
1191 111a38b0 Robert Relyea
                args++;
1192 111a38b0 Robert Relyea
            }
1193 111a38b0 Robert Relyea
            opts->vreader_count++;
1194 111a38b0 Robert Relyea
        /* use_hw= */
1195 111a38b0 Robert Relyea
        } else if (strncmp(args, "use_hw=", 7) == 0) {
1196 111a38b0 Robert Relyea
            args = strip(args+7);
1197 111a38b0 Robert Relyea
            if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
1198 111a38b0 Robert Relyea
                opts->use_hw = PR_FALSE;
1199 111a38b0 Robert Relyea
            } else {
1200 111a38b0 Robert Relyea
                opts->use_hw = PR_TRUE;
1201 111a38b0 Robert Relyea
            }
1202 111a38b0 Robert Relyea
            args = find_blank(args);
1203 111a38b0 Robert Relyea
        /* hw_type= */
1204 111a38b0 Robert Relyea
        } else if (strncmp(args, "hw_type=", 8) == 0) {
1205 111a38b0 Robert Relyea
            args = strip(args+8);
1206 111a38b0 Robert Relyea
            opts->hw_card_type = vcard_emul_type_from_string(args);
1207 111a38b0 Robert Relyea
            args = find_blank(args);
1208 111a38b0 Robert Relyea
        /* hw_params= */
1209 111a38b0 Robert Relyea
        } else if (strncmp(args, "hw_params=", 10) == 0) {
1210 111a38b0 Robert Relyea
            const char *params;
1211 111a38b0 Robert Relyea
            args = strip(args+10);
1212 111a38b0 Robert Relyea
            params = args;
1213 111a38b0 Robert Relyea
            args = find_blank(args);
1214 7267c094 Anthony Liguori
            opts->hw_type_params = g_strndup(params, args-params);
1215 111a38b0 Robert Relyea
        /* db="/data/base/path" */
1216 111a38b0 Robert Relyea
        } else if (strncmp(args, "db=", 3) == 0) {
1217 111a38b0 Robert Relyea
            const char *db;
1218 111a38b0 Robert Relyea
            args = strip(args+3);
1219 111a38b0 Robert Relyea
            if (*args != '"') {
1220 111a38b0 Robert Relyea
                continue;
1221 111a38b0 Robert Relyea
            }
1222 111a38b0 Robert Relyea
            args++;
1223 111a38b0 Robert Relyea
            db = args;
1224 111a38b0 Robert Relyea
            args = strpbrk(args, "\"\n");
1225 7267c094 Anthony Liguori
            opts->nss_db = g_strndup(db, args-db);
1226 111a38b0 Robert Relyea
            if (*args != 0) {
1227 111a38b0 Robert Relyea
                args++;
1228 111a38b0 Robert Relyea
            }
1229 111a38b0 Robert Relyea
        } else {
1230 111a38b0 Robert Relyea
            args = find_blank(args);
1231 111a38b0 Robert Relyea
        }
1232 111a38b0 Robert Relyea
    } while (*args != 0);
1233 111a38b0 Robert Relyea
1234 111a38b0 Robert Relyea
    return opts;
1235 111a38b0 Robert Relyea
}
1236 111a38b0 Robert Relyea
1237 111a38b0 Robert Relyea
void
1238 111a38b0 Robert Relyea
vcard_emul_usage(void)
1239 111a38b0 Robert Relyea
{
1240 111a38b0 Robert Relyea
   fprintf(stderr,
1241 111a38b0 Robert Relyea
"emul args: comma separated list of the following arguments\n"
1242 111a38b0 Robert Relyea
" db={nss_database}               (default sql:/etc/pki/nssdb)\n"
1243 111a38b0 Robert Relyea
" use_hw=[yes|no]                 (default yes)\n"
1244 111a38b0 Robert Relyea
" hw_type={card_type_to_emulate}  (default CAC)\n"
1245 111a38b0 Robert Relyea
" hw_param={param_for_card}       (default \"\")\n"
1246 111a38b0 Robert Relyea
" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
1247 111a38b0 Robert Relyea
"       {cert1},{cert2},{cert3}    (default none)\n"
1248 111a38b0 Robert Relyea
"\n"
1249 111a38b0 Robert Relyea
"  {nss_database}          The location of the NSS cert & key database\n"
1250 111a38b0 Robert Relyea
"  {card_type_to_emulate}  What card interface to present to the guest\n"
1251 111a38b0 Robert Relyea
"  {param_for_card}        Card interface specific parameters\n"
1252 111a38b0 Robert Relyea
"  {slot_name}             NSS slot that contains the certs\n"
1253 111a38b0 Robert Relyea
"  {vreader_name}          Virutal reader name to present to the guest\n"
1254 111a38b0 Robert Relyea
"  {certN}                 Nickname of the certificate n on the virtual card\n"
1255 111a38b0 Robert Relyea
"\n"
1256 111a38b0 Robert Relyea
"These parameters come as a single string separated by blanks or newlines."
1257 111a38b0 Robert Relyea
"\n"
1258 111a38b0 Robert Relyea
"Unless use_hw is set to no, all tokens that look like removable hardware\n"
1259 111a38b0 Robert Relyea
"tokens will be presented to the guest using the emulator specified by\n"
1260 111a38b0 Robert Relyea
"hw_type, and parameters of hw_param.\n"
1261 111a38b0 Robert Relyea
"\n"
1262 111a38b0 Robert Relyea
"If more one or more soft= parameters are specified, these readers will be\n"
1263 111a38b0 Robert Relyea
"presented to the guest\n");
1264 111a38b0 Robert Relyea
}