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