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