summaryrefslogtreecommitdiff
path: root/docs/libcacard.txt
blob: 499cf7d79cac4d49a2de325114806b5e7579a3a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
This file documents the CAC (Common Access Card) library in the libcacard
subdirectory.

Virtual Smart Card Emulator

This emulator is designed to provide emulation of actual smart cards to a
virtual card reader running in a guest virtual machine. The emulated smart
cards can be representations of real smart cards, where the necessary functions
such as signing, card removal/insertion, etc. are mapped to real, physical
cards which are shared with the client machine the emulator is running on, or
the cards could be pure software constructs.

The emulator is structured to allow multiple replaceable or additional pieces,
so it can be easily modified for future requirements. The primary envisioned
modifications are:

1) The socket connection to the virtual card reader (presumably a CCID reader,
but other ISO-7816 compatible readers could be used). The code that handles
this is in vscclient.c.

2) The virtual card low level emulation. This is currently supplied by using
NSS. This emulation could be replaced by implementations based on other
security libraries, including but not limitted to openssl+pkcs#11 library,
raw pkcs#11, Microsoft CAPI, direct opensc calls, etc. The code that handles
this is in vcard_emul_nss.c.

3) Emulation for new types of cards. The current implementation emulates the
original DoD CAC standard with separate pki containers. This emulator lives in
cac.c. More than one card type emulator could be included. Other cards could
be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc.

--------------------
Replacing the Socket Based Virtual Reader Interface.

The current implementation contains a replaceable module vscclient.c. The
current vscclient.c implements a sockets interface to the virtual ccid reader
on the guest. CCID commands that are pertinent to emulation are passed
across the socket, and their responses are passed back along that same socket.
The protocol that vscclient uses is defined in vscard_common.h and connects
to a qemu ccid usb device. Since this socket runs as a client, vscclient.c
implements a program with a main entry. It also handles argument parsing for
the emulator.

An application that wants to use the virtual reader can replace vscclient.c
with its own implementation that connects to its own CCID reader.  The calls
that the CCID reader can call are:

      VReaderList * vreader_get_reader_list();

  This function returns a list of virtual readers.  These readers may map to
  physical devices, or simulated devices depending on vcard the back end. Each
  reader in the list should represent a reader to the virtual machine. Virtual
  USB address mapping is left to the CCID reader front end. This call can be
  made any time to get an updated list. The returned list is a copy of the
  internal list that can be referenced by the caller without locking. This copy
  must be freed by the caller with vreader_list_delete when it is no longer
  needed.

      VReaderListEntry *vreader_list_get_first(VReaderList *);

  This function gets the first entry on the reader list. Along with
  vreader_list_get_next(), vreader_list_get_first() can be used to walk the
  reader list returned from vreader_get_reader_list(). VReaderListEntries are
  part of the list themselves and do not need to be freed separately from the
  list. If there are no entries on the list, it will return NULL.

      VReaderListEntry *vreader_list_get_next(VReaderListEntry *);

  This function gets the next entry in the list. If there are no more entries
  it will return NULL.

      VReader * vreader_list_get_reader(VReaderListEntry *)

  This function returns the reader stored in the reader List entry. Caller gets
  a new reference to a reader. The caller must free its reference when it is
  finished with vreader_free().

      void vreader_free(VReader *reader);

   This function frees a reference to a reader. Readers are reference counted
   and are automatically deleted when the last reference is freed.

      void vreader_list_delete(VReaderList *list);

   This function frees the list, all the elements on the list, and all the
   reader references held by the list.

      VReaderStatus vreader_power_on(VReader *reader, char *atr, int *len);

  This function simulates a card power on. A virtual card does not care about
  the actual voltage and other physical parameters, but it does care that the
  card is actually on or off. Cycling the card causes the card to reset. If
  the caller provides enough space, vreader_power_on will return the ATR of
  the virtual card. The amount of space provided in atr should be indicated
  in *len. The function modifies *len to be the actual length of of the
  returned ATR.

      VReaderStatus vreader_power_off(VReader *reader);

  This function simulates a power off of a virtual card.

      VReaderStatus vreader_xfer_bytes(VReader *reader, unsigne char *send_buf,
                                       int send_buf_len,
                                       unsigned char *receive_buf,
                                       int receive_buf_len);

  This function sends a raw apdu to a card and returns the card's response.
  The CCID front end should return the response back. Most of the emulation
  is driven from these APDUs.

      VReaderStatus vreader_card_is_present(VReader *reader);

  This function returns whether or not the reader has a card inserted. The
  vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return
  VREADER_NO_CARD.

       const char *vreader_get_name(VReader *reader);

  This function returns the name of the reader. The name comes from the card
  emulator level and is usually related to the name of the physical reader.

       VReaderID vreader_get_id(VReader *reader);

  This function returns the id of a reader. All readers start out with an id
  of -1. The application can set the id with vreader_set_id.

       VReaderStatus vreader_get_id(VReader *reader, VReaderID id);

  This function sets the reader id. The application is responsible for making
  sure that the id is unique for all readers it is actively using.

       VReader *vreader_find_reader_by_id(VReaderID id);

  This function returns the reader which matches the id. If two readers match,
  only one is returned. The function returns NULL if the id is -1.

       Event *vevent_wait_next_vevent();

  This function blocks waiting for reader and card insertion events. There
  will be one event for each card insertion, each card removal, each reader
  insertion and each reader removal. At start up, events are created for all
  the initial readers found, as well as all the cards that are inserted.

       Event *vevent_get_next_vevent();

  This function returns a pending event if it exists, otherwise it returns
  NULL. It does not block.

----------------
Card Type Emulator: Adding a New Virtual Card Type

The ISO 7816 card spec describes 2 types of cards:
 1) File system cards, where the smartcard is managed by reading and writing
data to files in a file system. There is currently only boiler plate
implemented for file system cards.
 2) VM cards, where the card has loadable applets which perform the card
functions. The current implementation supports VM cards.

In the case of VM cards, the difference between various types of cards is
really what applets have been installed in that card. This structure is
mirrored in card type emulators. The 7816 emulator already handles the basic
ISO 7186 commands. Card type emulators simply need to add the virtual applets
which emulate the real card applets. Card type emulators have exactly one
public entry point:

       VCARDStatus xxx_card_init(VCard *card, const char *flags,
                               const unsigned char *cert[],
                               int cert_len[],
                               VCardKey *key[],
                               int cert_count);

  The parameters for this are:
  card       - the virtual card structure which will represent this card.
  flags      - option flags that may be specific to this card type.
  cert       - array of binary certificates.
  cert_len   - array of lengths of each of the certificates specified in cert.
  key        - array of opaque key structures representing the private keys on
               the card.
  cert_count - number of entries in cert, cert_len, and key arrays.

  Any cert, cert_len, or key with the same index are matching sets. That is
  cert[0] is cert_len[0] long and has the corresponding private key of key[0].

The card type emulator is expected to own the VCardKeys, but it should copy
any raw cert data it wants to save. It can create new applets and add them to
the card using the following functions:

       VCardApplet *vcard_new_applet(VCardProcessAPDU apdu_func,
                                     VCardResetApplet reset_func,
                                     const unsigned char *aid,
                                     int aid_len);

  This function creates a new applet. Applet structures store the following
  information:
     1) the AID of the applet (set by aid and aid_len).
     2) a function to handle APDUs for this applet. (set by apdu_func, more on
        this below).
     3) a function to reset the applet state when the applet is selected.
        (set by reset_func, more on this below).
     3) applet private data, a data pointer used by the card type emulator to
        store any data or state it needs to complete requests. (set by a
        separate call).
     4) applet private data free, a function used to free the applet private
        data when the applet itself is destroyed.
  The created applet can be added to the card with vcard_add_applet below.

        void vcard_set_applet_private(VCardApplet *applet,
                                      VCardAppletPrivate *private,
                                      VCardAppletPrivateFree private_free);
  This function sets the private data and the corresponding free function.
  VCardAppletPrivate is an opaque data structure to the rest of the emulator.
  The card type emulator can define it any way it wants by defining
  struct VCardAppletPrivateStruct {};. If there is already a private data
  structure on the applet, the old one is freed before the new one is set up.
  passing two NULL clear any existing private data.

         VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);

  Add an applet onto the list of applets attached to the card. Once an applet
  has been added, it can be selected by its AID, and then commands will be
  routed to it VCardProcessAPDU function. This function adopts the applet that
  is passed into it. Note: 2 applets with the same AID should not be added to
  the same card. It is permissible to add more than one applet. Multiple applets
  may have the same VCardPRocessAPDU entry point.

The certs and keys should be attached to private data associated with one or
more appropriate applets for that card. Control will come to the card type
emulators once one of its applets are selected through the VCardProcessAPDU
function it specified when it created the applet.

The signature of VCardResetApplet is:
        VCardStatus (*VCardResetApplet) (VCard *card, int channel);
  This function will reset the any internal applet state that needs to be
  cleared after a select applet call. It should return VCARD_DONE;

The signature of VCardProcessAPDU is:
        VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu,
                                         VCardResponse **response);
  This function examines the APDU and determines whether it should process
  the apdu directly, reject the apdu as invalid, or pass the apdu on to
  the basic 7816 emulator for processing.
      If the 7816 emulator should process the apdu, then the VCardProcessAPDU
  should return VCARD_NEXT.
      If there is an error, then VCardProcessAPDU should return an error
  response using vcard_make_response and the appropriate 7816 error code
  (see card_7816t.h) or vcard_make_response with a card type specific error
  code. It should then return VCARD_DONE.
      If the apdu can be processed correctly, VCardProcessAPDU should do so,
  set the response value appropriately for that APDU, and return VCARD_DONE.
  VCardProcessAPDU should always set the response if it returns VCARD_DONE.
  It should always either return VCARD_DONE or VCARD_NEXT.

Parsing the APDU --

Prior to processing calling the card type emulator's VCardProcessAPDU function, the emulator has already decoded the APDU header and set several fields:

   apdu->a_data - The raw apdu data bytes.
   apdu->a_len  - The len of the raw apdu data.
   apdu->a_body - The start of any post header parameter data.
   apdu->a_Lc   - The parameter length value.
   apdu->a_Le   - The expected length of any returned data.
   apdu->a_cla  - The raw apdu class.
   apdu->a_channel - The channel (decoded from the class).
   apdu->a_secure_messaging_type - The decoded secure messaging type
                                   (from class).
   apdu->a_type - The decode class type.
   apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS).
   apdu->a_ins  - The instruction byte.
   apdu->a_p1   - Parameter 1.
   apdu->a_p2   - Parameter 2.

Creating a Response --

The expected result of any APDU call is a response. The card type emulator must
set *response with an appropriate VCardResponse value if it returns VCARD_DONE.
Responses could be as simple as returning a 2 byte status word response, to as
complex as returning a block of data along with a 2 byte response. Which is
returned will depend on the semantics of the APDU. The following functions will
create card responses.

        VCardResponse *vcard_make_response(VCard7816Status status);

    This is the most basic function to get a response. This function will
    return a response the consists solely one 2 byte status code. If that status
    code is defined in card_7816t.h, then this function is guaranteed to
    return a response with that status. If a cart type specific status code
    is passed and vcard_make_response fails to allocate the appropriate memory
    for that response, then vcard_make_response will return a VCardResponse
    of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is
    guaranteed to return a valid VCardResponse.

        VCardResponse *vcard_response_new(unsigned char *buf, int len,
                                          VCard7816Status status);

    This function is similar to vcard_make_response except it includes some
    returned data with the response. It could also fail to allocate enough
    memory, in which case it will return NULL.

        VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
                                                       unsigned char sw2);

    Sometimes in 7816 the response bytes are treated as two separate bytes with
    split meanings. This function allows you to create a response based on
    two separate bytes. This function could fail, in which case it will return
    NULL.

       VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len,
                                               unsigned char sw1,
                                               unsigned char sw2);

    This function is the same as vcard_response_new except you may specify
    the status as two separate bytes like vcard_response_new_status_bytes.


Implementing functionality ---

The following helper functions access information about the current card
and applet.

        VCARDAppletPrivate *vcard_get_current_applet_private(VCard *card,
                                                             int channel);

    This function returns any private data set by the card type emulator on
    the currently selected applet. The card type emulator keeps track of the
    current applet state in this data structure. Any certs and keys associated
    with a particular applet is also stored here.

        int vcard_emul_get_login_count(VCard *card);

    This function returns the number of remaining login attempts for this
    card. If the card emulator does not know, or the card does not have a
    way of giving this information, this function returns -1.


         VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin,
                                          int pin_len);

    This function logs into the card and returns the standard 7816 status
    word depending on the success or failure of the call.

         void vcard_emul_delete_key(VCardKey *key);

     This function frees the VCardKey passed in to xxxx_card_init. The card
     type emulator is responsible for freeing this key when it no longer needs
     it.

         VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key,
                                           unsigned char *buffer,
                                           int buffer_size);

     This function does a raw rsa op on the buffer with the given key.

The sample card type emulator is found in cac.c. It implements the cac specific
applets.  Only those applets needed by the coolkey pkcs#11 driver on the guest
have been implemented. To support the full range CAC middleware, a complete CAC
card according to the CAC specs should be implemented here.

------------------------------
Virtual Card Emulator

This code accesses both real smart cards and simulated smart cards through
services provided on the client. The current implementation uses NSS, which
already knows how to talk to various PKCS #11 modules on the client, and is
portable to most operating systems. A particular emulator can have only one
virtual card implementation at a time.

The virtual card emulator consists of a series of virtual card services. In
addition to the services describe above (services starting with
vcard_emul_xxxx), the virtual card emulator also provides the following
functions:

    VCardEmulError vcard_emul_init(cont VCardEmulOptions *options);

  The options structure is built by another function in the virtual card
  interface where a string of virtual card emulator specific strings are
  mapped to the options. The actual structure is defined by the virtual card
  emulator and is used to determine the configuration of soft cards, or to
  determine which physical cards to present to the guest.

  The vcard_emul_init function will build up sets of readers, create any
  threads that are needed to watch for changes in the reader state. If readers
  have cards present in them, they are also initialized.

  Readers are created with the function.

          VReader *vreader_new(VReaderEmul *reader_emul,
                               VReaderEmulFree reader_emul_free);

      The freeFunc is used to free the VReaderEmul * when the reader is
      destroyed.  The VReaderEmul structure is an opaque structure to the
      rest of the code, but defined by the virtual card emulator, which can
      use it to store any reader specific state.

  Once the reader has been created, it can be added to the front end with the
  call:

           VReaderStatus vreader_add_reader(VReader *reader);

      This function will automatically generate the appropriate new reader
      events and add the reader to the list.

  To create a new card, the virtual card emulator will call a similar
  function.

           VCard *vcard_new(VCardEmul *card_emul,
                            VCardEmulFree card_emul_free);

      Like vreader_new, this function takes a virtual card emulator specific
      structure which it uses to keep track of the card state.

  Once the card is created, it is attached to a card type emulator with the
  following function:

            VCardStatus vcard_init(VCard *vcard, VCardEmulType type,
                                   const char *flags,
                                   unsigned char *const *certs,
                                   int *cert_len,
                                   VCardKey *key[],
                                   int cert_count);

      The vcard is the value returned from vcard_new. The type is the
      card type emulator that this card should presented to the guest as.
      The flags are card type emulator specific options. The certs,
      cert_len, and keys are all arrays of length cert_count. These are
      the same of the parameters xxxx_card_init() accepts.

   Finally the card is associated with its reader by the call:

            VReaderStatus vreader_insert_card(VReader *vreader, VCard *vcard);

      This function, like vreader_add_reader, will take care of any event
      notification for the card insert.


    VCardEmulError vcard_emul_force_card_remove(VReader *vreader);

  Force a card that is present to appear to be removed to the guest, even if
  that card is a physical card and is present.


    VCardEmulError vcard_emul_force_card_insert(VReader *reader);

  Force a card that has been removed by vcard_emul_force_card_remove to be
  reinserted from the point of view of the guest. This will only work if the
  card is physically present (which is always true fro a soft card).

     void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len);

  Return the virtual ATR for the card. By convention this should be the value
  VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this
  particular emulator. For instance the NSS emulator returns
  {VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len;

     void vcard_emul_reset(VCard *card, VCardPower power)

   Set the state of 'card' to the current power level and reset its internal
   state (logout, etc).

-------------------------------------------------------
List of files and their function:
README - This file
card_7816.c - emulate basic 7816 functionality. Parse APDUs.
card_7816.h - apdu and response services definitions.
card_7816t.h - 7816 specific structures, types and definitions.
event.c - event handling code.
event.h - event handling services definitions.
eventt.h - event handling structures and types
vcard.c - handle common virtual card services like creation, destruction, and
          applet management.
vcard.h - common virtual card services function definitions.
vcardt.h - comon virtual card types
vreader.c - common virtual reader services.
vreader.h - common virtual reader services definitions.
vreadert.h - comon virtual reader types.
vcard_emul_type.c - manage the card type emulators.
vcard_emul_type.h - definitions for card type emulators.
cac.c - card type emulator for CAC cards
vcard_emul.h - virtual card emulator service definitions.
vcard_emul_nss.c - virtual card emulator implementation for nss.
vscclient.c - socket connection to guest qemu usb driver.
vscard_common.h - common header with the guest qemu usb driver.
mutex.h - header file for machine independent mutexes.
link_test.c - static test to make sure all the symbols are properly defined.