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