]> Git Repo - qemu.git/blob - libcacard/cac.c
virtio-scsi-dataplane: Code to run virtio-scsi on iothread
[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     vcard_7816_status_t status;
119     VCardStatus ret = VCARD_FAIL;
120
121     applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
122     assert(applet_private);
123     pki_applet = &(applet_private->u.pki_data);
124
125     switch (apdu->a_ins) {
126     case CAC_UPDATE_BUFFER:
127         *response = vcard_make_response(
128             VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
129         ret = VCARD_DONE;
130         break;
131     case CAC_GET_CERTIFICATE:
132         if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) {
133             *response = vcard_make_response(
134                              VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
135             break;
136         }
137         assert(pki_applet->cert != NULL);
138         size = apdu->a_Le;
139         if (pki_applet->cert_buffer == NULL) {
140             pki_applet->cert_buffer = pki_applet->cert;
141             pki_applet->cert_buffer_len = pki_applet->cert_len;
142         }
143         size = MIN(size, pki_applet->cert_buffer_len);
144         next = MIN(255, pki_applet->cert_buffer_len - size);
145         *response = vcard_response_new_bytes(
146                         card, pki_applet->cert_buffer, size,
147                         apdu->a_Le, next ?
148                         VCARD7816_SW1_WARNING_CHANGE :
149                         VCARD7816_SW1_SUCCESS,
150                         next);
151         pki_applet->cert_buffer += size;
152         pki_applet->cert_buffer_len -= size;
153         if ((*response == NULL) || (next == 0)) {
154             pki_applet->cert_buffer = NULL;
155         }
156         if (*response == NULL) {
157             *response = vcard_make_response(
158                             VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
159         }
160         ret = VCARD_DONE;
161         break;
162     case CAC_SIGN_DECRYPT:
163         if (apdu->a_p2 != 0) {
164             *response = vcard_make_response(
165                              VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
166             break;
167         }
168         size = apdu->a_Lc;
169
170         sign_buffer = g_realloc(pki_applet->sign_buffer,
171                                 pki_applet->sign_buffer_len + size);
172         memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size);
173         size += pki_applet->sign_buffer_len;
174         switch (apdu->a_p1) {
175         case  0x80:
176             /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
177              * the rest */
178             pki_applet->sign_buffer = sign_buffer;
179             pki_applet->sign_buffer_len = size;
180             *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
181             break;
182         case 0x00:
183             /* we now have the whole buffer, do the operation, result will be
184              * in the sign_buffer */
185             status = vcard_emul_rsa_op(card, pki_applet->key,
186                                        sign_buffer, size);
187             if (status != VCARD7816_STATUS_SUCCESS) {
188                 *response = vcard_make_response(status);
189                 break;
190             }
191             *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le,
192                                                      VCARD7816_STATUS_SUCCESS);
193             if (*response == NULL) {
194                 *response = vcard_make_response(
195                                 VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
196             }
197             break;
198         default:
199            *response = vcard_make_response(
200                                 VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
201             break;
202         }
203         g_free(sign_buffer);
204         pki_applet->sign_buffer = NULL;
205         pki_applet->sign_buffer_len = 0;
206         ret = VCARD_DONE;
207         break;
208     case CAC_READ_BUFFER:
209         /* new CAC call, go ahead and use the old version for now */
210         /* TODO: implement */
211         *response = vcard_make_response(
212                                 VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
213         ret = VCARD_DONE;
214         break;
215     default:
216         ret = cac_common_process_apdu(card, apdu, response);
217         break;
218     }
219     return ret;
220 }
221
222
223 static VCardStatus
224 cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
225                            VCardResponse **response)
226 {
227     VCardStatus ret = VCARD_FAIL;
228
229     switch (apdu->a_ins) {
230     case CAC_UPDATE_BUFFER:
231         *response = vcard_make_response(
232                         VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
233         ret = VCARD_DONE;
234         break;
235     case CAC_READ_BUFFER:
236         /* new CAC call, go ahead and use the old version for now */
237         /* TODO: implement */
238         *response = vcard_make_response(
239                         VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
240         ret = VCARD_DONE;
241         break;
242     default:
243         ret = cac_common_process_apdu(card, apdu, response);
244         break;
245     }
246     return ret;
247 }
248
249
250 /*
251  * TODO: if we ever want to support general CAC middleware, we will need to
252  * implement the various containers.
253  */
254 static VCardStatus
255 cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
256                                   VCardResponse **response)
257 {
258     VCardStatus ret = VCARD_FAIL;
259
260     switch (apdu->a_ins) {
261     case CAC_READ_BUFFER:
262     case CAC_UPDATE_BUFFER:
263         *response = vcard_make_response(
264                         VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
265         ret = VCARD_DONE;
266         break;
267     default:
268         ret = cac_common_process_apdu(card, apdu, response);
269         break;
270     }
271     return ret;
272 }
273
274 /*
275  * utilities for creating and destroying the private applet data
276  */
277 static void
278 cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
279 {
280     CACPKIAppletData *pki_applet_data;
281
282     if (applet_private == NULL) {
283         return;
284     }
285     pki_applet_data = &(applet_private->u.pki_data);
286     g_free(pki_applet_data->cert);
287     g_free(pki_applet_data->sign_buffer);
288     if (pki_applet_data->key != NULL) {
289         vcard_emul_delete_key(pki_applet_data->key);
290     }
291     g_free(applet_private);
292 }
293
294 static VCardAppletPrivate *
295 cac_new_pki_applet_private(const unsigned char *cert,
296                            int cert_len, VCardKey *key)
297 {
298     CACPKIAppletData *pki_applet_data;
299     VCardAppletPrivate *applet_private;
300
301     applet_private = g_new0(VCardAppletPrivate, 1);
302     pki_applet_data = &(applet_private->u.pki_data);
303     pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1);
304     /*
305      * if we want to support compression, then we simply change the 0 to a 1
306      * and compress the cert data with libz
307      */
308     pki_applet_data->cert[0] = 0; /* not compressed */
309     memcpy(&pki_applet_data->cert[1], cert, cert_len);
310     pki_applet_data->cert_len = cert_len+1;
311
312     pki_applet_data->key = key;
313     return applet_private;
314 }
315
316
317 /*
318  * create a new cac applet which links to a given cert
319  */
320 static VCardApplet *
321 cac_new_pki_applet(int i, const unsigned char *cert,
322                    int cert_len, VCardKey *key)
323 {
324     VCardAppletPrivate *applet_private;
325     VCardApplet *applet;
326     unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
327     int pki_aid_len = sizeof(pki_aid);
328
329     pki_aid[pki_aid_len-1] = i;
330
331     applet_private = cac_new_pki_applet_private(cert, cert_len, key);
332     if (applet_private == NULL) {
333         goto failure;
334     }
335     applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset,
336                               pki_aid, pki_aid_len);
337     if (applet == NULL) {
338         goto failure;
339     }
340     vcard_set_applet_private(applet, applet_private,
341                              cac_delete_pki_applet_private);
342     applet_private = NULL;
343
344     return applet;
345
346 failure:
347     if (applet_private != NULL) {
348         cac_delete_pki_applet_private(applet_private);
349     }
350     return NULL;
351 }
352
353
354 static unsigned char cac_default_container_aid[] = {
355     0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
356 static unsigned char cac_id_aid[] = {
357     0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
358 /*
359  * Initialize the cac card. This is the only public function in this file. All
360  * the rest are connected through function pointers.
361  */
362 VCardStatus
363 cac_card_init(VReader *reader, VCard *card,
364               const char *params,
365               unsigned char * const *cert,
366               int cert_len[],
367               VCardKey *key[] /* adopt the keys*/,
368               int cert_count)
369 {
370     int i;
371     VCardApplet *applet;
372
373     /* CAC Cards are VM Cards */
374     vcard_set_type(card, VCARD_VM);
375
376     /* create one PKI applet for each cert */
377     for (i = 0; i < cert_count; i++) {
378         applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]);
379         if (applet == NULL) {
380             goto failure;
381         }
382         vcard_add_applet(card, applet);
383     }
384
385     /* create a default blank container applet */
386     applet = vcard_new_applet(cac_applet_container_process_apdu,
387                               NULL, cac_default_container_aid,
388                               sizeof(cac_default_container_aid));
389     if (applet == NULL) {
390         goto failure;
391     }
392     vcard_add_applet(card, applet);
393
394     /* create a default blank container applet */
395     applet = vcard_new_applet(cac_applet_id_process_apdu,
396                               NULL, cac_id_aid,
397                               sizeof(cac_id_aid));
398     if (applet == NULL) {
399         goto failure;
400     }
401     vcard_add_applet(card, applet);
402     return VCARD_DONE;
403
404 failure:
405     return VCARD_FAIL;
406 }
407
This page took 0.046946 seconds and 4 git commands to generate.