1 /*
2 * APDU handling
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7 #include "internal.h"
8 #include <string.h>
9
10 /*
11 * Check the APDU type and length
12 */
__ifd_apdu_check(const void * sbuf,size_t len,ifd_iso_apdu_t * iso)13 static int __ifd_apdu_check(const void *sbuf, size_t len, ifd_iso_apdu_t * iso)
14 {
15 unsigned char *data = (unsigned char *)sbuf;
16 unsigned int b;
17
18 memset(iso, 0, sizeof(*iso));
19 if (len < 5) {
20 iso->cse = IFD_APDU_CASE_1;
21 return 0;
22 }
23
24 b = data[4];
25 len -= 5;
26
27 /* APDU + Le */
28 if (len == 0) {
29 iso->cse = IFD_APDU_CASE_2S;
30 iso->le = b ? b : 256;
31 return 0;
32 }
33
34 data += 5;
35 if (b == 0)
36 b = 256;
37
38 iso->lc = b;
39 iso->len = len;
40 iso->data = data;
41
42 /* APDU + Lc + data */
43 if (len == b) {
44 iso->cse = IFD_APDU_CASE_3S;
45 return 0;
46 }
47
48 /* APDU + Lc + data + Le */
49 if (len == b + 1) {
50 iso->cse = IFD_APDU_CASE_4S;
51 iso->le = data[b] ? data[b] : 256;
52 iso->len--;
53 return 0;
54 }
55
56 return -1;
57 }
58
ifd_apdu_case(const void * buf,size_t len)59 int ifd_apdu_case(const void *buf, size_t len)
60 {
61 ifd_iso_apdu_t iso;
62
63 if (__ifd_apdu_check(buf, len, &iso) < 0)
64 return -1;
65 return iso.cse;
66 }
67
68 /*
69 * Convert internal APDU type to an ISO-7816-4 APDU
70 */
ifd_iso_apdu_parse(const void * data,size_t len,ifd_iso_apdu_t * iso)71 int ifd_iso_apdu_parse(const void *data, size_t len, ifd_iso_apdu_t * iso)
72 {
73 unsigned char *p;
74
75 if (len < 4)
76 return -1;
77
78 if (__ifd_apdu_check(data, len, iso) < 0)
79 return -1;
80
81 p = (unsigned char *)data;
82 iso->cla = *p++;
83 iso->ins = *p++;
84 iso->p1 = *p++;
85 iso->p2 = *p++;
86
87 return 0;
88 }
89