Branch data Line data Source code
1 : : /*
2 : : * Implement the 7816 portion of the card spec
3 : : *
4 : : * This code is licensed under the GNU LGPL, version 2.1 or later.
5 : : * See the COPYING file in the top-level directory.
6 : : */
7 : :
8 : : #include <glib.h>
9 : :
10 : : #include <string.h>
11 : :
12 : : #include "vcard.h"
13 : : #include "vcard_emul.h"
14 : : #include "card_7816.h"
15 : : #include "common.h"
16 : :
17 : :
18 : : /* Global Platform Card Manager applet AID */
19 : : static const unsigned char gp_aid[] = {
20 : : 0xa0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00 };
21 : : /* Global Platform Card Manager response on select applet */
22 : : static const unsigned char gp_response[] = {
23 : : 0x6F, 0x19, 0x84, 0x08, 0xA0, 0x00, 0x00, 0x00,
24 : : 0x03, 0x00, 0x00, 0x00, 0xA5, 0x0D, 0x9F, 0x6E,
25 : : 0x06, 0x12, 0x91, 0x51, 0x81, 0x01, 0x00, 0x9F,
26 : : 0x65, 0x01, 0xFF};
27 : :
28 : :
29 : : /*
30 : : * set the status bytes based on the status word
31 : : */
32 : : static void
33 : : vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status)
34 : : {
35 : : unsigned char sw1, sw2;
36 : 157 : response->b_status = status; /* make sure the status and swX representations
37 : : * are consistent */
38 : 157 : sw1 = (status >> 8) & 0xff;
39 : 157 : sw2 = status & 0xff;
40 : 157 : response->b_sw1 = sw1;
41 : 157 : response->b_sw2 = sw2;
42 : 157 : response->b_data[response->b_len] = sw1;
43 : 157 : response->b_data[response->b_len+1] = sw2;
44 : : }
45 : :
46 : : /*
47 : : * set the status bytes in a response buffer
48 : : */
49 : : void
50 : 457 : vcard_response_set_status_bytes(VCardResponse *response,
51 : : unsigned char sw1, unsigned char sw2)
52 : : {
53 : 457 : response->b_status = sw1 << 8 | sw2;
54 : 457 : response->b_sw1 = sw1;
55 : 457 : response->b_sw2 = sw2;
56 : 457 : response->b_data[response->b_len] = sw1;
57 : 457 : response->b_data[response->b_len+1] = sw2;
58 : 457 : }
59 : :
60 : : /*
61 : : * allocate a VCardResponse structure, plus space for the data buffer, and
62 : : * set up everything but the resonse bytes.
63 : : */
64 : : VCardResponse *
65 : 248 : vcard_response_new_data(const unsigned char *buf, int len)
66 : : {
67 : : VCardResponse *new_response;
68 : :
69 : 248 : new_response = g_new0(VCardResponse, 1);
70 : 248 : new_response->b_data = g_malloc(len + 2);
71 : 248 : memcpy(new_response->b_data, buf, len);
72 : 248 : new_response->b_total_len = len+2;
73 : 248 : new_response->b_len = len;
74 : 248 : new_response->b_type = VCARD_MALLOC;
75 : 248 : return new_response;
76 : : }
77 : :
78 : : static VCardResponse *
79 : 227 : vcard_init_buffer_response(VCard *card, const unsigned char *buf, int len)
80 : : {
81 : : VCardResponse *response;
82 : : VCardBufferResponse *buffer_response;
83 : :
84 : 227 : buffer_response = vcard_get_buffer_response(card);
85 [ - + ]: 227 : if (buffer_response) {
86 : 0 : vcard_set_buffer_response(card, NULL);
87 : 0 : vcard_buffer_response_delete(buffer_response);
88 : : }
89 : 227 : buffer_response = vcard_buffer_response_new(buf, len);
90 [ - + ]: 227 : if (buffer_response == NULL) {
91 : : return NULL;
92 : : }
93 [ + + ]: 432 : response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES,
94 : : len > 255 ? 0 : len);
95 [ - + ]: 227 : if (response == NULL) {
96 : : return NULL;
97 : : }
98 : 227 : vcard_set_buffer_response(card, buffer_response);
99 : 227 : return response;
100 : : }
101 : :
102 : : /*
103 : : * general buffer to hold results from APDU calls
104 : : */
105 : : VCardResponse *
106 : 375 : vcard_response_new(VCard *card, const unsigned char *buf,
107 : : int len, int Le, vcard_7816_status_t status)
108 : : {
109 : : VCardResponse *new_response;
110 : :
111 : 375 : g_debug("%s: Sending response (len = %d, Le = %d)", __func__, len, Le);
112 [ + + ]: 375 : if (len > Le) {
113 : 218 : return vcard_init_buffer_response(card, buf, len);
114 : : }
115 : 157 : new_response = vcard_response_new_data(buf, len);
116 [ + - ]: 157 : if (new_response == NULL) {
117 : : return NULL;
118 : : }
119 : : vcard_response_set_status(new_response, status);
120 : 157 : return new_response;
121 : : }
122 : :
123 : : /*
124 : : * general buffer to hold results from APDU calls
125 : : */
126 : : VCardResponse *
127 : 99 : vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le,
128 : : unsigned char sw1, unsigned char sw2)
129 : : {
130 : : VCardResponse *new_response;
131 : :
132 : 99 : g_debug("%s: Sending response (len = %d, Le = %d)", __func__, len, Le);
133 [ + + ]: 99 : if (len > Le) {
134 : 9 : return vcard_init_buffer_response(card, buf, len);
135 : : }
136 : 90 : new_response = vcard_response_new_data(buf, len);
137 [ + - ]: 90 : if (new_response == NULL) {
138 : : return NULL;
139 : : }
140 : 90 : vcard_response_set_status_bytes(new_response, sw1, sw2);
141 : 90 : return new_response;
142 : : }
143 : :
144 : : /*
145 : : * get a new Response buffer that only has a status.
146 : : */
147 : : static VCardResponse *
148 : 0 : vcard_response_new_status(vcard_7816_status_t status)
149 : : {
150 : : VCardResponse *new_response;
151 : :
152 : 0 : new_response = g_new(VCardResponse, 1);
153 : 0 : new_response->b_data = &new_response->b_sw1;
154 : 0 : new_response->b_len = 0;
155 : 0 : new_response->b_total_len = 2;
156 : 0 : new_response->b_type = VCARD_MALLOC_STRUCT;
157 : : vcard_response_set_status(new_response, status);
158 : 0 : return new_response;
159 : : }
160 : :
161 : : /*
162 : : * same as above, but specify the status as separate bytes
163 : : */
164 : : VCardResponse *
165 : 367 : vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2)
166 : : {
167 : : VCardResponse *new_response;
168 : :
169 : 367 : new_response = g_new(VCardResponse, 1);
170 : 367 : new_response->b_data = &new_response->b_sw1;
171 : 367 : new_response->b_len = 0;
172 : 367 : new_response->b_total_len = 2;
173 : 367 : new_response->b_type = VCARD_MALLOC_STRUCT;
174 : 367 : vcard_response_set_status_bytes(new_response, sw1, sw2);
175 : 367 : return new_response;
176 : : }
177 : :
178 : :
179 : : /*
180 : : * free the response buffer. The Buffer has a type to handle the buffer
181 : : * allocated in other ways than through malloc.
182 : : */
183 : : void
184 : 752 : vcard_response_delete(VCardResponse *response)
185 : : {
186 [ + - ]: 752 : if (response == NULL) {
187 : : return;
188 : : }
189 [ + - + - : 752 : switch (response->b_type) {
+ ]
190 : 248 : case VCARD_MALLOC:
191 : : /* everything was malloc'ed */
192 : 248 : g_free(response->b_data);
193 : 248 : g_free(response);
194 : 248 : break;
195 : 0 : case VCARD_MALLOC_DATA:
196 : : /* only the data buffer was malloc'ed */
197 : 0 : g_free(response->b_data);
198 : 0 : break;
199 : 367 : case VCARD_MALLOC_STRUCT:
200 : : /* only the structure was malloc'ed */
201 : 367 : g_free(response);
202 : 367 : break;
203 : : case VCARD_STATIC:
204 : : break;
205 : 0 : default:
206 : 0 : g_warn_if_reached();
207 : : }
208 : : }
209 : :
210 : : /*
211 : : * decode the class bit and set our generic type field, channel, and
212 : : * secure messaging values.
213 : : */
214 : : static vcard_7816_status_t
215 : 751 : vcard_apdu_set_class(VCardAPDU *apdu) {
216 : 751 : apdu->a_channel = 0;
217 : 751 : apdu->a_secure_messaging = 0;
218 : 751 : apdu->a_type = apdu->a_cla & 0xf0;
219 : 751 : apdu->a_gen_type = VCARD_7816_ISO;
220 : :
221 : : /* parse the class tables 8 & 9 of the 7816-4 Part 4 spec */
222 [ + + + + ]: 751 : switch (apdu->a_type) {
223 : : /* we only support the basic types */
224 : 724 : case 0x00:
225 : : case 0x80:
226 : : case 0x90:
227 : : case 0xa0:
228 : 724 : apdu->a_channel = apdu->a_cla & 3;
229 : 724 : apdu->a_secure_messaging = apdu->a_cla & 0xe;
230 : 724 : break;
231 : : case 0xb0:
232 : : case 0xc0:
233 : : break;
234 : :
235 : 23 : case 0x10:
236 : : case 0x20:
237 : : case 0x30:
238 : : case 0x40:
239 : : case 0x50:
240 : : case 0x60:
241 : : case 0x70:
242 : : /* Reserved for future use */
243 : 23 : apdu->a_gen_type = VCARD_7816_RFU;
244 : 23 : break;
245 : 2 : case 0xd0:
246 : : case 0xe0:
247 : : case 0xf0:
248 : : default:
249 : 2 : apdu->a_gen_type =
250 [ + + ]: 2 : (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPRIETARY;
251 : 2 : break;
252 : : }
253 : 751 : return VCARD7816_STATUS_SUCCESS;
254 : : }
255 : :
256 : : /*
257 : : * set the Le and Lc fields according to table 5 of the
258 : : * 7816-4 part 4 spec
259 : : */
260 : : static vcard_7816_status_t
261 : 751 : vcard_apdu_set_length(VCardAPDU *apdu)
262 : : {
263 : : int L, Le;
264 : :
265 : : /* process according to table 5 of the 7816-4 Part 4 spec.
266 : : * variable names match the variables in the spec */
267 : 751 : L = apdu->a_len-4; /* fixed APDU header */
268 : 751 : apdu->a_Lc = 0;
269 : 751 : apdu->a_Le = 0;
270 : 751 : apdu->a_body = NULL;
271 [ + + + ]: 751 : switch (L) {
272 : : case 0:
273 : : /* 1 minimal apdu */
274 : : return VCARD7816_STATUS_SUCCESS;
275 : 314 : case 1:
276 : : /* 2S only return values apdu */
277 : : /* zero maps to 256 here */
278 : 628 : apdu->a_Le = apdu->a_header->ah_Le ?
279 [ + + ]: 314 : apdu->a_header->ah_Le : 256;
280 : 314 : return VCARD7816_STATUS_SUCCESS;
281 : 351 : default:
282 : : /* if the ah_Le byte is zero and we have more than
283 : : * 1 byte in the header, then we must be using extended Le and Lc.
284 : : * process the extended now. */
285 [ + + ]: 351 : if (apdu->a_header->ah_Le == 0) {
286 [ + - ]: 12 : if (L < 3) {
287 : : /* coding error, need at least 3 bytes */
288 : : return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
289 : : }
290 : : /* calculate the first extended value. Could be either Le or Lc */
291 : 12 : Le = (apdu->a_header->ah_body[0] << 8)
292 : 12 : | apdu->a_header->ah_body[1];
293 [ - + ]: 12 : if (L == 3) {
294 : : /* 2E extended, return data only */
295 : : /* zero maps to 65536 */
296 [ # # ]: 0 : apdu->a_Le = Le ? Le : 65536;
297 : 0 : return VCARD7816_STATUS_SUCCESS;
298 : : }
299 [ + - ]: 12 : if (Le == 0) {
300 : : /* reserved for future use, probably for next time we need
301 : : * to extend the lengths */
302 : : return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
303 : : }
304 : : /* we know that the first extended value is Lc now */
305 : 12 : apdu->a_Lc = Le;
306 : 12 : apdu->a_body = &apdu->a_header->ah_body[2];
307 [ + - ]: 12 : if (L == Le+3) {
308 : : /* 3E extended, only body parameters */
309 : : return VCARD7816_STATUS_SUCCESS;
310 : : }
311 [ # # ]: 0 : if (L == Le+5) {
312 : : /* 4E extended, parameters and return data */
313 : 0 : Le = (apdu->a_data[apdu->a_len-2] << 8)
314 : 0 : | apdu->a_data[apdu->a_len-1];
315 [ # # ]: 0 : apdu->a_Le = Le ? Le : 65536;
316 : 0 : return VCARD7816_STATUS_SUCCESS;
317 : : }
318 : : return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
319 : : }
320 : : /* not extended */
321 : 339 : apdu->a_Lc = apdu->a_header->ah_Le;
322 : 339 : apdu->a_body = &apdu->a_header->ah_body[0];
323 [ + + ]: 339 : if (L == apdu->a_Lc + 1) {
324 : : /* 3S only body parameters */
325 : : return VCARD7816_STATUS_SUCCESS;
326 : : }
327 [ + - ]: 140 : if (L == apdu->a_Lc + 2) {
328 : : /* 4S parameters and return data */
329 : 140 : Le = apdu->a_data[apdu->a_len-1];
330 [ + + ]: 140 : apdu->a_Le = Le ? Le : 256;
331 : 140 : return VCARD7816_STATUS_SUCCESS;
332 : : }
333 : : break;
334 : : }
335 : : return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
336 : : }
337 : :
338 : : /*
339 : : * create a new APDU from a raw set of bytes. This will decode all the
340 : : * above fields. users of VCARDAPDU's can then depend on the already decoded
341 : : * values.
342 : : */
343 : : VCardAPDU *
344 : 752 : vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status)
345 : : {
346 : : VCardAPDU *new_apdu;
347 : :
348 : 752 : *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
349 [ + + ]: 752 : if (len < 4) {
350 : 1 : *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH;
351 : 1 : return NULL;
352 : : }
353 : :
354 : 751 : new_apdu = g_new(VCardAPDU, 1);
355 : 751 : new_apdu->a_data = g_memdup2(raw_apdu, len);
356 : 751 : new_apdu->a_len = len;
357 : 751 : *status = vcard_apdu_set_class(new_apdu);
358 [ - + ]: 751 : if (*status != VCARD7816_STATUS_SUCCESS) {
359 : 0 : vcard_apdu_delete(new_apdu);
360 : 0 : return NULL;
361 : : }
362 : 751 : *status = vcard_apdu_set_length(new_apdu);
363 [ - + ]: 751 : if (*status != VCARD7816_STATUS_SUCCESS) {
364 : 0 : vcard_apdu_delete(new_apdu);
365 : : new_apdu = NULL;
366 : : }
367 : : return new_apdu;
368 : : }
369 : :
370 : : void
371 : 752 : vcard_apdu_delete(VCardAPDU *apdu)
372 : : {
373 [ + + ]: 752 : if (apdu == NULL) {
374 : : return;
375 : : }
376 : 751 : g_free(apdu->a_data);
377 : 751 : g_free(apdu);
378 : : }
379 : :
380 : :
381 : : /*
382 : : * declare response buffers for all the 7816 defined error codes
383 : : */
384 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS)
385 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING)
386 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT)
387 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE)
388 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED)
389 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID)
390 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE)
391 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED)
392 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR)
393 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE)
394 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE)
395 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH)
396 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED)
397 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED)
398 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED)
399 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED)
400 : : VCARD_RESPONSE_NEW_STATIC_STATUS(
401 : : VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE)
402 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED)
403 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED)
404 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID)
405 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED)
406 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF)
407 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING)
408 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT)
409 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS)
410 : : VCARD_RESPONSE_NEW_STATIC_STATUS(
411 : : VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA)
412 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED)
413 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND)
414 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND)
415 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE)
416 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT)
417 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT)
418 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT)
419 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND)
420 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2)
421 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID)
422 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID)
423 : : VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL)
424 : :
425 : : /*
426 : : * return a single response code. This function cannot fail. It will always
427 : : * return a response.
428 : : */
429 : : VCardResponse *
430 : 137 : vcard_make_response(vcard_7816_status_t status)
431 : : {
432 : : VCardResponse *response;
433 : :
434 [ - - - - : 137 : switch (status) {
- - - - -
- + - - +
+ - - - +
+ - - - +
+ + + - -
- + - + -
+ - - -
+ ]
435 : : /* known 7816 response codes */
436 : : case VCARD7816_STATUS_SUCCESS:
437 : : return VCARD_RESPONSE_GET_STATIC(
438 : : VCARD7816_STATUS_SUCCESS);
439 : 0 : case VCARD7816_STATUS_WARNING:
440 : 0 : return VCARD_RESPONSE_GET_STATIC(
441 : : VCARD7816_STATUS_WARNING);
442 : 0 : case VCARD7816_STATUS_WARNING_RET_CORUPT:
443 : 0 : return VCARD_RESPONSE_GET_STATIC(
444 : : VCARD7816_STATUS_WARNING_RET_CORUPT);
445 : 0 : case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE:
446 : 0 : return VCARD_RESPONSE_GET_STATIC(
447 : : VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE);
448 : 0 : case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED:
449 : 0 : return VCARD_RESPONSE_GET_STATIC(
450 : : VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED);
451 : 0 : case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID:
452 : 0 : return VCARD_RESPONSE_GET_STATIC(
453 : : VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID);
454 : 0 : case VCARD7816_STATUS_WARNING_CHANGE:
455 : 0 : return VCARD_RESPONSE_GET_STATIC(
456 : : VCARD7816_STATUS_WARNING_CHANGE);
457 : 0 : case VCARD7816_STATUS_WARNING_FILE_FILLED:
458 : 0 : return VCARD_RESPONSE_GET_STATIC(
459 : : VCARD7816_STATUS_WARNING_FILE_FILLED);
460 : 0 : case VCARD7816_STATUS_EXC_ERROR:
461 : 0 : return VCARD_RESPONSE_GET_STATIC(
462 : : VCARD7816_STATUS_EXC_ERROR);
463 : 0 : case VCARD7816_STATUS_EXC_ERROR_CHANGE:
464 : 0 : return VCARD_RESPONSE_GET_STATIC(
465 : : VCARD7816_STATUS_EXC_ERROR_CHANGE);
466 : : case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE:
467 : : return VCARD_RESPONSE_GET_STATIC(
468 : : VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
469 : 1 : case VCARD7816_STATUS_ERROR_WRONG_LENGTH:
470 : 1 : return VCARD_RESPONSE_GET_STATIC(
471 : : VCARD7816_STATUS_ERROR_WRONG_LENGTH);
472 : 0 : case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED:
473 : 0 : return VCARD_RESPONSE_GET_STATIC(
474 : : VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED);
475 : 0 : case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED:
476 : 0 : return VCARD_RESPONSE_GET_STATIC(
477 : : VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED);
478 : 1 : case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED:
479 : 1 : return VCARD_RESPONSE_GET_STATIC(
480 : : VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
481 : 7 : case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED:
482 : 7 : return VCARD_RESPONSE_GET_STATIC(
483 : : VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
484 : 0 : case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE:
485 : 0 : return VCARD_RESPONSE_GET_STATIC(
486 : : VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE);
487 : 0 : case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED:
488 : 0 : return VCARD_RESPONSE_GET_STATIC(
489 : : VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED);
490 : 0 : case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED:
491 : 0 : return VCARD_RESPONSE_GET_STATIC(
492 : : VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED);
493 : 27 : case VCARD7816_STATUS_ERROR_DATA_INVALID:
494 : 27 : return VCARD_RESPONSE_GET_STATIC(
495 : : VCARD7816_STATUS_ERROR_DATA_INVALID);
496 : 2 : case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED:
497 : 2 : return VCARD_RESPONSE_GET_STATIC(
498 : : VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
499 : 0 : case VCARD7816_STATUS_ERROR_DATA_NO_EF:
500 : 0 : return VCARD_RESPONSE_GET_STATIC(
501 : : VCARD7816_STATUS_ERROR_DATA_NO_EF);
502 : 0 : case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING:
503 : 0 : return VCARD_RESPONSE_GET_STATIC(
504 : : VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING);
505 : 0 : case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT:
506 : 0 : return VCARD_RESPONSE_GET_STATIC(
507 : : VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT);
508 : 3 : case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS:
509 : 3 : return VCARD_RESPONSE_GET_STATIC(
510 : : VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
511 : 1 : case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA:
512 : 1 : return VCARD_RESPONSE_GET_STATIC(
513 : : VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA);
514 : 1 : case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED:
515 : 1 : return VCARD_RESPONSE_GET_STATIC(
516 : : VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
517 : 3 : case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND:
518 : 3 : return VCARD_RESPONSE_GET_STATIC(
519 : : VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
520 : 0 : case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND:
521 : 0 : return VCARD_RESPONSE_GET_STATIC(
522 : : VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND);
523 : 0 : case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE:
524 : 0 : return VCARD_RESPONSE_GET_STATIC(
525 : : VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE);
526 : 0 : case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT:
527 : 0 : return VCARD_RESPONSE_GET_STATIC(
528 : : VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT);
529 : 16 : case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT:
530 : 16 : return VCARD_RESPONSE_GET_STATIC(
531 : : VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
532 : 0 : case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT:
533 : 0 : return VCARD_RESPONSE_GET_STATIC(
534 : : VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT);
535 : 14 : case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND:
536 : 14 : return VCARD_RESPONSE_GET_STATIC(
537 : : VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
538 : 0 : case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2:
539 : 0 : return VCARD_RESPONSE_GET_STATIC(
540 : : VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2);
541 : 2 : case VCARD7816_STATUS_ERROR_INS_CODE_INVALID:
542 : 2 : return VCARD_RESPONSE_GET_STATIC(
543 : : VCARD7816_STATUS_ERROR_INS_CODE_INVALID);
544 : 0 : case VCARD7816_STATUS_ERROR_CLA_INVALID:
545 : 0 : return VCARD_RESPONSE_GET_STATIC(
546 : : VCARD7816_STATUS_ERROR_CLA_INVALID);
547 : 0 : case VCARD7816_STATUS_ERROR_GENERAL:
548 : 0 : return VCARD_RESPONSE_GET_STATIC(
549 : : VCARD7816_STATUS_ERROR_GENERAL);
550 : 0 : default:
551 : : /* we don't know this status code, create a response buffer to
552 : : * hold it */
553 : 0 : response = vcard_response_new_status(status);
554 [ # # ]: 0 : if (response == NULL) {
555 : : /* couldn't allocate the buffer, return memmory error */
556 : : return VCARD_RESPONSE_GET_STATIC(
557 : : VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
558 : : }
559 : : return response;
560 : : }
561 : : }
562 : :
563 : : /*
564 : : * Add File card support here if you need it.
565 : : */
566 : : static VCardStatus
567 : : vcard7816_file_system_process_apdu(G_GNUC_UNUSED VCard *card,
568 : : G_GNUC_UNUSED VCardAPDU *apdu,
569 : : VCardResponse **response)
570 : : {
571 : : /* TODO: if we want to support a virtual file system card, we do it here.
572 : : * It would probably be a pkcs #15 card type */
573 : 0 : *response = vcard_make_response(
574 : : VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
575 : : return VCARD_DONE;
576 : : }
577 : :
578 : : /*
579 : : * VM card (including java cards)
580 : : */
581 : : static VCardStatus
582 : 204 : vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu,
583 : : VCardResponse **response)
584 : : {
585 : : int bytes_to_copy, next_byte_count, count;
586 : : VCardApplet *current_applet;
587 : : VCardBufferResponse *buffer_response;
588 : : vcard_7816_status_t status;
589 : :
590 : : /* parse the class first */
591 [ + + ]: 204 : if (apdu->a_gen_type != VCARD_7816_ISO) {
592 : 1 : *response = vcard_make_response(
593 : : VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
594 : 1 : return VCARD_DONE;
595 : : }
596 : :
597 : : /* use a switch so that if we need to support secure channel stuff later,
598 : : * we know where to put it */
599 [ + + ]: 203 : switch (apdu->a_secure_messaging) {
600 : : case 0x0: /* no SM */
601 : : break;
602 : 1 : case 0x4: /* proprietary SM */
603 : : case 0x8: /* header not authenticated */
604 : : case 0xc: /* header authenticated */
605 : : default:
606 : : /* for now, don't try to support secure channel stuff in the
607 : : * virtual card. */
608 : 1 : *response = vcard_make_response(
609 : : VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
610 : 1 : return VCARD_DONE;
611 : : }
612 : :
613 : : /* now parse the instruction */
614 [ + + + + : 202 : switch (apdu->a_ins) {
- + ]
615 : 1 : case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */
616 : : case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */
617 : : case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */
618 : : case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */
619 : : case VCARD7816_INS_ERASE_BINARY: /* applet control op */
620 : : case VCARD7816_INS_READ_BINARY: /* applet control op */
621 : : case VCARD7816_INS_WRITE_BINARY: /* applet control op */
622 : : case VCARD7816_INS_UPDATE_BINARY: /* applet control op */
623 : : case VCARD7816_INS_READ_RECORD: /* file op */
624 : : case VCARD7816_INS_WRITE_RECORD: /* file op */
625 : : case VCARD7816_INS_UPDATE_RECORD: /* file op */
626 : : case VCARD7816_INS_APPEND_RECORD: /* file op */
627 : : case VCARD7816_INS_ENVELOPE:
628 : : case VCARD7816_INS_PUT_DATA:
629 : 1 : *response = vcard_make_response(
630 : : VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
631 : 1 : break;
632 : :
633 : 98 : case VCARD7816_INS_SELECT_FILE:
634 : : /* GSC-IS: 5.3.3.2 Select Applet APDU: P1 = 0x04 */
635 [ + + ]: 98 : if (apdu->a_p1 != 0x04) {
636 : 1 : *response = vcard_make_response(
637 : : VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
638 : 1 : break;
639 : : }
640 : 97 : g_debug("%s: Selecting file %s", __func__, hex_dump(apdu->a_body, apdu->a_Lc));
641 : :
642 : : /* side effect, deselect the current applet if no applet has been found
643 : : */
644 : 97 : current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc);
645 : 97 : vcard_select_applet(card, apdu->a_channel, current_applet);
646 [ + + ]: 97 : if (current_applet) {
647 : 96 : VCardApplet *gp_applet = vcard_find_applet(card,
648 : : gp_aid, sizeof(gp_aid));
649 [ + + ]: 96 : if (current_applet == gp_applet) {
650 : : /* if the new applet is Global Platform Card Manager, we need to
651 : : * return a response (from Card Specification v2.3.1):
652 : : *
653 : : * 6F 19 : FCI Template
654 : : * 84 08 : Application / file AID
655 : : * A0 00 00 00 03 00 00 00
656 : : * A5 0D : Proprietary data
657 : : * 9F 6E 06 : Application Producution Life Cycle
658 : : * 12 91 51 81 01 00
659 : : * 9F 65 01 : Maximum Length of data field in comand message
660 : : * FF
661 : : */
662 : 6 : *response = vcard_response_new(card, gp_response,
663 : : sizeof(gp_response), apdu->a_Le, VCARD7816_STATUS_SUCCESS);
664 : : } else {
665 : 90 : unsigned char fci_template[] = {
666 : : 0x6F, 0x0B, /* Outer lenght to be replaced later */
667 : : 0x84, 0x07, /* AID length to be replaced later */
668 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* AID */
669 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 : : 0xA5, 0x00}; /* The rest */
671 : 90 : size_t fci_template_len = 6 + apdu->a_Lc;
672 : : /* with GSC-IS 2 applets, we do not need to return anything
673 : : * for select applet, but cards generally do, at least this
674 : : * FCI template stub:
675 : : *
676 : : * 6F 0B : FCI Template
677 : : * 84 07 : Application / file AID
678 : : * A0 00 00 00 79 03 00
679 : : * A5 00 : Proprietary data
680 : : */
681 : : /* Insert the correct AID in the structure */
682 [ - + ]: 90 : g_assert_cmpint(fci_template_len, <=, sizeof(fci_template));
683 : 90 : fci_template[1] = apdu->a_Lc + 4;
684 : 90 : fci_template[3] = apdu->a_Lc;
685 : 90 : memcpy(&fci_template[4], apdu->a_body, apdu->a_Lc);
686 : 90 : fci_template[apdu->a_Lc + 4] = 0xA5;
687 : 90 : fci_template[apdu->a_Lc + 5] = 0x00;
688 : 90 : *response = vcard_response_new(card, fci_template,
689 : : fci_template_len, apdu->a_Le, VCARD7816_STATUS_SUCCESS);
690 : : }
691 : : } else {
692 : : /* the real CAC returns (SW1=0x6A, SW2=0x82) */
693 : 1 : *response = vcard_make_response(
694 : : VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
695 : : }
696 : : break;
697 : :
698 : 49 : case VCARD7816_INS_VERIFY:
699 [ + + - + ]: 49 : if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) {
700 : 3 : *response = vcard_make_response(
701 : : VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
702 : : } else {
703 [ + + ]: 46 : if (apdu->a_Lc == 0) {
704 : : /* If we are already logged in, we should succeed just now */
705 [ + + ]: 26 : if (vcard_emul_is_logged_in(card)) {
706 : 22 : *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
707 : 22 : break;
708 : : }
709 : : /* handle pin count if possible (not possible now) */
710 : 4 : count = vcard_get_login_count(card);
711 [ + + ]: 4 : if (count < 0) {
712 : 2 : *response = vcard_make_response(
713 : : VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
714 : : } else {
715 : 2 : if (count > 0xf) {
716 : : count = 0xf;
717 : : }
718 : 4 : *response = vcard_response_new_status_bytes(
719 : : VCARD7816_SW1_WARNING_CHANGE,
720 : 2 : 0xc0 | count);
721 [ - + ]: 2 : if (*response == NULL) {
722 : 0 : *response = vcard_make_response(
723 : : VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
724 : : }
725 : : }
726 : : } else {
727 : 20 : status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc);
728 : 20 : *response = vcard_make_response(status);
729 : : }
730 : : }
731 : : break;
732 : :
733 : 53 : case VCARD7816_INS_GET_RESPONSE:
734 : 53 : buffer_response = vcard_get_buffer_response(card);
735 [ + + ]: 53 : if (!buffer_response) {
736 : 3 : *response = vcard_make_response(
737 : : VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
738 : : /* handle error */
739 : 3 : break;
740 : : }
741 : 50 : bytes_to_copy = MIN(buffer_response->len, apdu->a_Le);
742 : 50 : next_byte_count = MIN(256, buffer_response->len - bytes_to_copy);
743 [ + + ]: 99 : *response = vcard_response_new_bytes(
744 : : card, buffer_response->current, bytes_to_copy,
745 : : apdu->a_Le,
746 : : next_byte_count ?
747 : : VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS,
748 : : next_byte_count);
749 : 50 : buffer_response->current += bytes_to_copy;
750 : 50 : buffer_response->len -= bytes_to_copy;
751 [ + - + + ]: 50 : if (*response == NULL || (next_byte_count == 0)) {
752 : 49 : vcard_set_buffer_response(card, NULL);
753 : 49 : vcard_buffer_response_delete(buffer_response);
754 : : }
755 [ - + ]: 50 : if (*response == NULL) {
756 : 0 : *response =
757 : 0 : vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
758 : : }
759 : : break;
760 : :
761 : 0 : case VCARD7816_INS_GET_DATA:
762 : 0 : *response =
763 : 0 : vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
764 : 0 : break;
765 : :
766 : 1 : default:
767 : 1 : *response =
768 : 1 : vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
769 : 1 : break;
770 : : }
771 : :
772 : : /* response should have been set somewhere */
773 [ - + - + ]: 202 : g_assert(*response != NULL);
774 : : return VCARD_DONE;
775 : : }
776 : :
777 : :
778 : : /*
779 : : * APDU processing starts here. This routes the card processing stuff to the
780 : : * right location.
781 : : */
782 : : VCardStatus
783 : 751 : vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
784 : : {
785 : : VCardStatus status;
786 : : VCardBufferResponse *buffer_response;
787 : :
788 : : /* first handle any PTS commands, which aren't really APDU's */
789 [ + + ]: 751 : if (apdu->a_gen_type == VCARD_7816_PTS) {
790 : : /* the PTS responses aren't really responses either */
791 : 1 : *response = vcard_response_new_data(apdu->a_data, apdu->a_len);
792 : : /* PTS responses have no status bytes */
793 : 1 : (*response)->b_total_len = (*response)->b_len;
794 : 1 : return VCARD_DONE;
795 : : }
796 : 750 : buffer_response = vcard_get_buffer_response(card);
797 [ + + + + ]: 750 : if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) {
798 : : /* clear out buffer_response, do not return an error */
799 : 177 : vcard_set_buffer_response(card, NULL);
800 : 177 : vcard_buffer_response_delete(buffer_response);
801 : : }
802 : :
803 : 750 : status = vcard_process_applet_apdu(card, apdu, response);
804 [ + + ]: 750 : if (status != VCARD_NEXT) {
805 : : return status;
806 : : }
807 [ - + - - ]: 204 : switch (vcard_get_type(card)) {
808 : : case VCARD_FILE_SYSTEM:
809 : 0 : return vcard7816_file_system_process_apdu(card, apdu, response);
810 : 204 : case VCARD_VM:
811 : 204 : return vcard7816_vm_process_apdu(card, apdu, response);
812 : : case VCARD_DIRECT:
813 : : /* if we are type direct, then the applet should handle everything */
814 : 0 : g_assert(!"VCARD_DIRECT: applet failure");
815 : : break;
816 : 0 : default:
817 : 0 : g_warn_if_reached();
818 : : }
819 : 0 : *response =
820 : 0 : vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
821 : 0 : return VCARD_DONE;
822 : : }
823 : :
824 : : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
|