]> Git Repo - qemu.git/blob - libcacard/cac.c
hw/virtio-blk: add a constant for max number of merged requests
[qemu.git] / libcacard / cac.c
1 /*
2  * implement the applets for the CAC card.
3  *
4  * This code is licensed under the GNU LGPL, version 2.1 or later.
5  * See the COPYING.LIB file in the top-level directory.
6  */
7
8 #include "qemu-common.h"
9
10 #include "cac.h"
11 #include "vcard.h"
12 #include "vcard_emul.h"
13 #include "card_7816.h"
14
15 /* private data for PKI applets */
16 typedef struct CACPKIAppletDataStruct {
17     unsigned char *cert;
18     int cert_len;
19     unsigned char *cert_buffer;
20     int cert_buffer_len;
21     unsigned char *sign_buffer;
22     int sign_buffer_len;
23     VCardKey *key;
24 } CACPKIAppletData;
25
26 /*
27  * CAC applet private data
28  */
29 struct VCardAppletPrivateStruct {
30     union {
31         CACPKIAppletData pki_data;
32         void *reserved;
33     } u;
34 };
35
36 /*
37  * handle all the APDU's that are common to all CAC applets
38  */
39 static VCardStatus
40 cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
41 {
42     int ef;
43     VCardStatus ret = VCARD_FAIL;
44
45     switch (apdu->a_ins) {
46     case VCARD7816_INS_SELECT_FILE:
47         if (apdu->a_p1 != 0x02) {
48             /* let the 7816 code handle applet switches */
49             ret = VCARD_NEXT;
50             break;
51         }
52         /* handle file id setting */
53         if (apdu->a_Lc != 2) {
54             *response = vcard_make_response(
55                 VCARD7816_STATUS_ERROR_DATA_INVALID);
56             ret = VCARD_DONE;
57             break;
58         }
59         /* CAC 1.0 only supports ef = 0 */
60         ef = apdu->a_body[0] | (apdu->a_body[1] << 8);
61         if (ef != 0) {
62             *response = vcard_make_response(
63                 VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
64             ret = VCARD_DONE;
65             break;
66         }
67         *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
68         ret = VCARD_DONE;
69         break;
70     case VCARD7816_INS_GET_RESPONSE:
71     case VCARD7816_INS_VERIFY:
72         /* let the 7816 code handle these */
73         ret = VCARD_NEXT;
74         break;
75     case CAC_GET_PROPERTIES:
76     case CAC_GET_ACR:
77         /* skip these for now, this will probably be needed */
78         *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
79         ret = VCARD_DONE;
80         break;
81     default:
82         *response = vcard_make_response(
83             VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
84         ret = VCARD_DONE;
85         break;
86     }
87     return ret;
88 }
89
90 /*
91  *  reset the inter call state between applet selects
92  */
93 static VCardStatus
94 cac_applet_pki_reset(VCard *card, int channel)
95 {
96     VCardAppletPrivate *applet_private;
97     CACPKIAppletData *pki_applet;
98     applet_private = vcard_get_current_applet_private(card, channel);
99     assert(applet_private);
100     pki_applet = &(applet_private->u.pki_data);
101
102     pki_applet->cert_buffer = NULL;
103     g_free(pki_applet->sign_buffer);
104     pki_applet->sign_buffer = NULL;
105     pki_applet->cert_buffer_len = 0;
106     pki_applet->sign_buffer_len = 0;
107     return VCARD_DONE;
108 }
109
110 static VCardStatus
111 cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
112                             VCardResponse **response)
113 {
114     CACPKIAppletData *pki_applet;
115     VCardAppletPrivate *applet_private;
116     int size, next;
117     unsigned char *sign_buffer;
118     bool retain_sign_buffer = FALSE;
119     vcard_7816_status_t status;
120     VCardStatus ret = VCARD_FAIL;
121
122     applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
123     assert(applet_private);
124     pki_applet = &(applet_private->u.pki_data);
125
126     switch (apdu->a_ins) {
127     case CAC_UPDATE_BUFFER:
128         *response = vcard_make_response(
129             VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
130         ret = VCARD_DONE;
131         break;
132     case CAC_GET_CERTIFICATE:
133         if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) {
134             *response = vcard_make_response(
135                              VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
136             break;
137         }
138         assert(pki_applet->cert != NULL);
139         size = apdu->a_Le;
140         if (pki_applet->cert_buffer == NULL) {
141             pki_applet->cert_buffer = pki_applet->cert;
142             pki_applet->cert_buffer_len = pki_applet->cert_len;
143         }
144         size = MIN(size, pki_applet->cert_buffer_len);
145         next = MIN(255, pki_applet->cert_buffer_len - size);
146         *response = vcard_response_new_bytes(
147                         card, pki_applet->cert_buffer, size,
148                         apdu->a_Le, next ?
149                         VCARD7816_SW1_WARNING_CHANGE :
150                         VCARD7816_SW1_SUCCESS,
151                         next);
152         pki_applet->cert_buffer += size;
153         pki_applet->cert_buffer_len -= size;
154         if ((*response == NULL) || (next == 0)) {
155             pki_applet->cert_buffer = NULL;
156         }
157         if (*response == NULL) {
158             *response = vcard_make_response(
159                             VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
160         }
161         ret = VCARD_DONE;
162         break;
163     case CAC_SIGN_DECRYPT:
164         if (apdu->a_p2 != 0) {
165             *response = vcard_make_response(
166                              VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
167             break;
168         }
169         size = apdu->a_Lc;
170
171         sign_buffer = g_realloc(pki_applet->sign_buffer,
172                                 pki_applet->sign_buffer_len + size);
173         memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size);
174         size += pki_applet->sign_buffer_len;
175         switch (apdu->a_p1) {
176         case  0x80:
177             /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
178              * the rest */
179             pki_applet->sign_buffer = sign_buffer;
180             pki_applet->sign_buffer_len = size;
181             *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
182             retain_sign_buffer = TRUE;
183             break;
184         case 0x00:
185             /* we now have the whole buffer, do the operation, result will be
186              * in the sign_buffer */
187             status = vcard_emul_rsa_op(card, pki_applet->key,
188                                        sign_buffer, size);
189             if (status != VCARD7816_STATUS_SUCCESS) {
190                 *response = vcard_make_response(status);
191                 break;
192             }
193             *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le,
194                                                      VCARD7816_STATUS_SUCCESS);
195             if (*response == NULL) {
196                 *response = vcard_make_response(
197                                 VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
198             }
199             break;
200         default:
201            *response = vcard_make_response(
202                                 VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
203             break;
204         }
205         if (!retain_sign_buffer) {
206             g_free(sign_buffer);
207             pki_applet->sign_buffer = NULL;
208             pki_applet->sign_buffer_len = 0;
209         }
210         ret = VCARD_DONE;
211         break;
212     case CAC_READ_BUFFER:
213         /* new CAC call, go ahead and use the old version for now */
214         /* TODO: implement */
215         *response = vcard_make_response(
216                                 VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
217         ret = VCARD_DONE;
218         break;
219     default:
220         ret = cac_common_process_apdu(card, apdu, response);
221         break;
222     }
223     return ret;
224 }
225
226
227 static VCardStatus
228 cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
229                            VCardResponse **response)
230 {
231     VCardStatus ret = VCARD_FAIL;
232
233     switch (apdu->a_ins) {
234     case CAC_UPDATE_BUFFER:
235         *response = vcard_make_response(
236                         VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
237         ret = VCARD_DONE;
238         break;
239     case CAC_READ_BUFFER:
240         /* new CAC call, go ahead and use the old version for now */
241         /* TODO: implement */
242         *response = vcard_make_response(
243                         VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
244         ret = VCARD_DONE;
245         break;
246     default:
247         ret = cac_common_process_apdu(card, apdu, response);
248         break;
249     }
250     return ret;
251 }
252
253
254 /*
255  * TODO: if we ever want to support general CAC middleware, we will need to
256  * implement the various containers.
257  */
258 static VCardStatus
259 cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
260                                   VCardResponse **response)
261 {
262     VCardStatus ret = VCARD_FAIL;
263
264     switch (apdu->a_ins) {
265     case CAC_READ_BUFFER:
266     case CAC_UPDATE_BUFFER:
267         *response = vcard_make_response(
268                         VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
269         ret = VCARD_DONE;
270         break;
271     default:
272         ret = cac_common_process_apdu(card, apdu, response);
273         break;
274     }
275     return ret;
276 }
277
278 /*
279  * utilities for creating and destroying the private applet data
280  */
281 static void
282 cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
283 {
284     CACPKIAppletData *pki_applet_data;
285
286     if (applet_private == NULL) {
287         return;
288     }
289     pki_applet_data = &(applet_private->u.pki_data);
290     g_free(pki_applet_data->cert);
291     g_free(pki_applet_data->sign_buffer);
292     if (pki_applet_data->key != NULL) {
293         vcard_emul_delete_key(pki_applet_data->key);
294     }
295     g_free(applet_private);
296 }
297
298 static VCardAppletPrivate *
299 cac_new_pki_applet_private(const unsigned char *cert,
300                            int cert_len, VCardKey *key)
301 {
302     CACPKIAppletData *pki_applet_data;
303     VCardAppletPrivate *applet_private;
304
305     applet_private = g_new0(VCardAppletPrivate, 1);
306     pki_applet_data = &(applet_private->u.pki_data);
307     pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1);
308     /*
309      * if we want to support compression, then we simply change the 0 to a 1
310      * and compress the cert data with libz
311      */
312     pki_applet_data->cert[0] = 0; /* not compressed */
313     memcpy(&pki_applet_data->cert[1], cert, cert_len);
314     pki_applet_data->cert_len = cert_len+1;
315
316     pki_applet_data->key = key;
317     return applet_private;
318 }
319
320
321 /*
322  * create a new cac applet which links to a given cert
323  */
324 static VCardApplet *
325 cac_new_pki_applet(int i, const unsigned char *cert,
326                    int cert_len, VCardKey *key)
327 {
328     VCardAppletPrivate *applet_private;
329     VCardApplet *applet;
330     unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
331     int pki_aid_len = sizeof(pki_aid);
332
333     pki_aid[pki_aid_len-1] = i;
334
335     applet_private = cac_new_pki_applet_private(cert, cert_len, key);
336     if (applet_private == NULL) {
337         goto failure;
338     }
339     applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset,
340                               pki_aid, pki_aid_len);
341     if (applet == NULL) {
342         goto failure;
343     }
344     vcard_set_applet_private(applet, applet_private,
345                              cac_delete_pki_applet_private);
346     applet_private = NULL;
347
348     return applet;
349
350 failure:
351     if (applet_private != NULL) {
352         cac_delete_pki_applet_private(applet_private);
353     }
354     return NULL;
355 }
356
357
358 static unsigned char cac_default_container_aid[] = {
359     0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
360 static unsigned char cac_id_aid[] = {
361     0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
362 /*
363  * Initialize the cac card. This is the only public function in this file. All
364  * the rest are connected through function pointers.
365  */
366 VCardStatus
367 cac_card_init(VReader *reader, VCard *card,
368               const char *params,
369               unsigned char * const *cert,
370               int cert_len[],
371               VCardKey *key[] /* adopt the keys*/,
372               int cert_count)
373 {
374     int i;
375     VCardApplet *applet;
376
377     /* CAC Cards are VM Cards */
378     vcard_set_type(card, VCARD_VM);
379
380     /* create one PKI applet for each cert */
381     for (i = 0; i < cert_count; i++) {
382         applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]);
383         if (applet == NULL) {
384             goto failure;
385         }
386         vcard_add_applet(card, applet);
387     }
388
389     /* create a default blank container applet */
390     applet = vcard_new_applet(cac_applet_container_process_apdu,
391                               NULL, cac_default_container_aid,
392                               sizeof(cac_default_container_aid));
393     if (applet == NULL) {
394         goto failure;
395     }
396     vcard_add_applet(card, applet);
397
398     /* create a default blank container applet */
399     applet = vcard_new_applet(cac_applet_id_process_apdu,
400                               NULL, cac_id_aid,
401                               sizeof(cac_id_aid));
402     if (applet == NULL) {
403         goto failure;
404     }
405     vcard_add_applet(card, applet);
406     return VCARD_DONE;
407
408 failure:
409     return VCARD_FAIL;
410 }
411
This page took 0.046495 seconds and 4 git commands to generate.