/src/opensc/src/libopensc/reader-tr03119.c
Line | Count | Source |
1 | | /* |
2 | | * reader-escape.c: implementation related to escape commands with pseudo APDUs |
3 | | * |
4 | | * Copyright (C) 2013-2018 Frank Morgner |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include "reader-tr03119.h" |
26 | | #include "ccid-types.h" |
27 | | #include "internal.h" |
28 | | #include "libopensc/asn1.h" |
29 | | #include "libopensc/log.h" |
30 | | #include "libopensc/opensc.h" |
31 | | #include "libopensc/pace.h" |
32 | | #include <stdlib.h> |
33 | | #include <string.h> |
34 | | |
35 | | #if _WIN32 |
36 | | /* FIXME might not always work */ |
37 | | #define htole16(x) (x) |
38 | | #define htole32(x) (x) |
39 | | #elif __APPLE__ |
40 | | #include <libkern/OSByteOrder.h> |
41 | | #define htole16(x) OSSwapHostToLittleInt16(x) |
42 | | #define htole32(x) OSSwapHostToLittleInt32(x) |
43 | | #else |
44 | | #ifndef _BSD_SOURCE |
45 | | #define _BSD_SOURCE /* See feature_test_macros(7) */ |
46 | | #endif |
47 | | #ifdef HAVE_SYS_ENDIAN_H |
48 | | #include <sys/endian.h> |
49 | | #endif |
50 | | #ifdef HAVE_ENDIAN_H |
51 | | #include <endian.h> |
52 | | #endif |
53 | | #endif |
54 | | |
55 | | int get_pace_capabilities(u8 *bitmap) |
56 | 0 | { |
57 | 0 | if (!bitmap) |
58 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
59 | | |
60 | | /* BitMap */ |
61 | 0 | *bitmap = EAC_BITMAP_PACE|EAC_BITMAP_EID|EAC_BITMAP_ESIGN; |
62 | |
|
63 | 0 | return SC_SUCCESS; |
64 | 0 | } |
65 | | |
66 | | const u8 escape_cla = 0xff; |
67 | | const u8 escape_ins = 0x9a; |
68 | | |
69 | | const u8 escape_p1_PIN = 0x04; |
70 | | const u8 escape_p2_GetReaderPACECapabilities = 0x01; |
71 | | const u8 escape_p2_EstablishPACEChannel = 0x02; |
72 | | /*const u8 escape_p2_DestroyPACEChannel = 0x03;*/ |
73 | | const u8 escape_p2_PC_to_RDR_Secure = 0x10; |
74 | | |
75 | | const u8 escape_p1_IFD = 0x01; |
76 | | const u8 escape_p2_vendor = 0x01; |
77 | | /*const u8 escape_p2_product = 0x03;*/ |
78 | | const u8 escape_p2_version_firmware = 0x06; |
79 | | /*const u8 escape_p2_version_driver = 0x07;*/ |
80 | | |
81 | | struct sc_asn1_entry g_boolean[] = { |
82 | | { "boolean", |
83 | | SC_ASN1_BOOLEAN, SC_ASN1_TAG_BOOLEAN, 0, NULL, NULL }, |
84 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
85 | | }; |
86 | | struct sc_asn1_entry g_int_as_octet_string[] = { |
87 | | { "int as octet string", |
88 | | SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, |
89 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
90 | | }; |
91 | | struct sc_asn1_entry g_octet_string[] = { |
92 | | { "octet string", |
93 | | SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL }, |
94 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
95 | | }; |
96 | | struct sc_asn1_entry g_numeric_string_as_octet_string[] = { |
97 | | { "utf8string", |
98 | | SC_ASN1_OCTET_STRING, SC_ASN1_TAG_NUMERICSTRING, SC_ASN1_ALLOC, NULL, NULL }, |
99 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
100 | | }; |
101 | | |
102 | | const struct sc_asn1_entry g_EstablishPACEChannelInput_data[] = { |
103 | | { "passwordID", |
104 | | /* use an OCTET STRING to avoid a conversion to int */ |
105 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, 0, NULL, NULL }, |
106 | | { "transmittedPassword", |
107 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x02|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
108 | | { "cHAT", |
109 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x03|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
110 | | { "certificateDescription", |
111 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x04|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
112 | | { "hashOID", |
113 | | /* use an OCTET STRING to avoid a conversion to struct sc_object_id */ |
114 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x05|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
115 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
116 | | }; |
117 | | const struct sc_asn1_entry g_EstablishPACEChannelOutput_data[] = { |
118 | | { "errorCode", |
119 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, 0, NULL, NULL }, |
120 | | { "statusMSESetAT", |
121 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x02|SC_ASN1_CONS, 0, NULL, NULL }, |
122 | | { "efCardAccess", |
123 | | SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x03|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
124 | | { "idPICC", |
125 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x04|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
126 | | { "curCAR", |
127 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x05|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
128 | | { "prevCAR", |
129 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x06|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL }, |
130 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
131 | | }; |
132 | | const struct sc_asn1_entry g_EstablishPACEChannel[] = { |
133 | | { "EstablishPACEChannel", |
134 | | SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE|SC_ASN1_CONS, 0, NULL, NULL }, |
135 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
136 | | }; |
137 | | |
138 | | int escape_pace_input_to_buf(sc_context_t *ctx, |
139 | | const struct establish_pace_channel_input *input, |
140 | | unsigned char **asn1, size_t *asn1_len) |
141 | 0 | { |
142 | 0 | size_t pin_id_len = sizeof input->pin_id; |
143 | 0 | struct sc_asn1_entry EstablishPACEChannelInput_data[ |
144 | 0 | sizeof g_EstablishPACEChannelInput_data/ |
145 | 0 | sizeof *g_EstablishPACEChannelInput_data]; |
146 | 0 | struct sc_asn1_entry EstablishPACEChannel[ |
147 | 0 | sizeof g_EstablishPACEChannel/ |
148 | 0 | sizeof *g_EstablishPACEChannel]; |
149 | 0 | struct sc_asn1_entry passwordID[ |
150 | 0 | sizeof g_int_as_octet_string/ |
151 | 0 | sizeof *g_int_as_octet_string]; |
152 | 0 | struct sc_asn1_entry transmittedPassword[ |
153 | 0 | sizeof g_numeric_string_as_octet_string/ |
154 | 0 | sizeof *g_numeric_string_as_octet_string]; |
155 | 0 | struct sc_asn1_entry cHAT[ |
156 | 0 | sizeof g_octet_string/ |
157 | 0 | sizeof *g_octet_string]; |
158 | |
|
159 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannel, |
160 | 0 | EstablishPACEChannel); |
161 | 0 | sc_format_asn1_entry(EstablishPACEChannel, |
162 | 0 | EstablishPACEChannelInput_data, 0, 1); |
163 | |
|
164 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannelInput_data, |
165 | 0 | EstablishPACEChannelInput_data); |
166 | |
|
167 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+0, |
168 | 0 | passwordID, 0, 1); |
169 | 0 | sc_copy_asn1_entry(g_int_as_octet_string, |
170 | 0 | passwordID); |
171 | 0 | sc_format_asn1_entry(passwordID, |
172 | 0 | (unsigned char *) &input->pin_id, &pin_id_len, 1); |
173 | |
|
174 | 0 | if (input->pin) { |
175 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+1, |
176 | 0 | transmittedPassword, |
177 | 0 | 0, 1); |
178 | 0 | sc_copy_asn1_entry(g_numeric_string_as_octet_string, |
179 | 0 | transmittedPassword); |
180 | 0 | sc_format_asn1_entry(transmittedPassword, |
181 | 0 | (unsigned char *) input->pin, |
182 | 0 | (size_t *) &input->pin_length, 1); |
183 | 0 | } |
184 | |
|
185 | 0 | if (input->chat) { |
186 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+2, |
187 | 0 | cHAT, |
188 | 0 | 0, 1); |
189 | 0 | sc_copy_asn1_entry(g_octet_string, |
190 | 0 | cHAT); |
191 | 0 | sc_format_asn1_entry(cHAT, |
192 | 0 | (unsigned char *) input->chat, |
193 | 0 | (size_t *) &input->chat_length, 1); |
194 | 0 | } |
195 | |
|
196 | 0 | if (input->certificate_description) { |
197 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+3, |
198 | 0 | (unsigned char *) input->certificate_description, |
199 | 0 | (size_t *) &input->certificate_description_length, 1); |
200 | 0 | } |
201 | |
|
202 | 0 | return sc_asn1_encode(ctx, EstablishPACEChannel, asn1, asn1_len); |
203 | 0 | } |
204 | | |
205 | | int escape_buf_to_pace_input(sc_context_t *ctx, |
206 | | const unsigned char *asn1, size_t asn1_len, |
207 | | struct establish_pace_channel_input *input) |
208 | 0 | { |
209 | 0 | size_t pin_id_len = sizeof input->pin_id; |
210 | 0 | struct sc_asn1_entry EstablishPACEChannelInput_data[ |
211 | 0 | sizeof g_EstablishPACEChannelInput_data/ |
212 | 0 | sizeof *g_EstablishPACEChannelInput_data]; |
213 | 0 | struct sc_asn1_entry EstablishPACEChannel[ |
214 | 0 | sizeof g_EstablishPACEChannel/ |
215 | 0 | sizeof *g_EstablishPACEChannel]; |
216 | 0 | struct sc_asn1_entry passwordID[ |
217 | 0 | sizeof g_int_as_octet_string/ |
218 | 0 | sizeof *g_int_as_octet_string]; |
219 | 0 | struct sc_asn1_entry transmittedPassword[ |
220 | 0 | sizeof g_numeric_string_as_octet_string/ |
221 | 0 | sizeof *g_numeric_string_as_octet_string]; |
222 | 0 | struct sc_asn1_entry cHAT[ |
223 | 0 | sizeof g_octet_string/ |
224 | 0 | sizeof *g_octet_string]; |
225 | | /* FIXME handle hashOID */ |
226 | |
|
227 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannel, |
228 | 0 | EstablishPACEChannel); |
229 | 0 | sc_format_asn1_entry(EstablishPACEChannel, |
230 | 0 | EstablishPACEChannelInput_data, 0, 0); |
231 | |
|
232 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannelInput_data, |
233 | 0 | EstablishPACEChannelInput_data); |
234 | |
|
235 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+0, |
236 | 0 | passwordID, 0, 0); |
237 | 0 | sc_copy_asn1_entry(g_int_as_octet_string, |
238 | 0 | passwordID); |
239 | 0 | sc_format_asn1_entry(passwordID, |
240 | 0 | &input->pin_id, &pin_id_len, 0); |
241 | |
|
242 | 0 | if (input->pin) { |
243 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+1, |
244 | 0 | transmittedPassword, 0, 0); |
245 | 0 | sc_copy_asn1_entry(g_numeric_string_as_octet_string, |
246 | 0 | transmittedPassword); |
247 | 0 | sc_format_asn1_entry(transmittedPassword, |
248 | 0 | (unsigned char *) &input->pin, &input->pin_length, 0); |
249 | 0 | } |
250 | |
|
251 | 0 | if (input->chat) { |
252 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+2, |
253 | 0 | cHAT, 0, 0); |
254 | 0 | sc_copy_asn1_entry(g_octet_string, |
255 | 0 | cHAT); |
256 | 0 | sc_format_asn1_entry(cHAT, |
257 | 0 | (unsigned char *) &input->chat, &input->chat_length, 0); |
258 | 0 | } |
259 | |
|
260 | 0 | if (input->certificate_description) { |
261 | 0 | sc_format_asn1_entry(EstablishPACEChannelInput_data+3, |
262 | 0 | (unsigned char *) &input->certificate_description, |
263 | 0 | &input->certificate_description_length, 0); |
264 | 0 | } |
265 | |
|
266 | 0 | LOG_TEST_RET(ctx, |
267 | 0 | sc_asn1_decode(ctx, EstablishPACEChannel, asn1, asn1_len, NULL, NULL), |
268 | 0 | "Error decoding EstablishPACEChannel"); |
269 | | |
270 | 0 | if (pin_id_len != sizeof input->pin_id) |
271 | 0 | return SC_ERROR_UNKNOWN_DATA_RECEIVED; |
272 | | |
273 | 0 | return SC_SUCCESS; |
274 | 0 | } |
275 | | |
276 | | int escape_pace_output_to_buf(sc_context_t *ctx, |
277 | | const struct establish_pace_channel_output *output, |
278 | | unsigned char **asn1, size_t *asn1_len) |
279 | 0 | { |
280 | 0 | uint16_t status_mse_set_at = ((output->mse_set_at_sw1 & 0xff) << 8) | output->mse_set_at_sw2; |
281 | 0 | size_t result_len = sizeof output->result, |
282 | 0 | status_mse_set_at_len = sizeof status_mse_set_at; |
283 | 0 | struct sc_asn1_entry EstablishPACEChannelOutput_data[ |
284 | 0 | sizeof g_EstablishPACEChannelOutput_data/ |
285 | 0 | sizeof *g_EstablishPACEChannelOutput_data]; |
286 | 0 | struct sc_asn1_entry EstablishPACEChannel[ |
287 | 0 | sizeof g_EstablishPACEChannel/ |
288 | 0 | sizeof *g_EstablishPACEChannel]; |
289 | 0 | struct sc_asn1_entry errorCode[ |
290 | 0 | sizeof g_octet_string/ |
291 | 0 | sizeof *g_octet_string]; |
292 | 0 | struct sc_asn1_entry statusMSESetAT[ |
293 | 0 | sizeof g_octet_string/ |
294 | 0 | sizeof *g_octet_string]; |
295 | 0 | struct sc_asn1_entry idPICC[ |
296 | 0 | sizeof g_octet_string/ |
297 | 0 | sizeof *g_octet_string]; |
298 | 0 | struct sc_asn1_entry curCAR[ |
299 | 0 | sizeof g_octet_string/ |
300 | 0 | sizeof *g_octet_string]; |
301 | 0 | struct sc_asn1_entry prevCAR[ |
302 | 0 | sizeof g_octet_string/ |
303 | 0 | sizeof *g_octet_string]; |
304 | |
|
305 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannel, |
306 | 0 | EstablishPACEChannel); |
307 | 0 | sc_format_asn1_entry(EstablishPACEChannel, |
308 | 0 | EstablishPACEChannelOutput_data, 0, 1); |
309 | |
|
310 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannelOutput_data, |
311 | 0 | EstablishPACEChannelOutput_data); |
312 | |
|
313 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+0, |
314 | 0 | errorCode, 0, 1); |
315 | 0 | sc_copy_asn1_entry(g_octet_string, |
316 | 0 | errorCode); |
317 | 0 | sc_format_asn1_entry(errorCode, |
318 | 0 | (unsigned char *) &output->result, &result_len, 1); |
319 | |
|
320 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+1, |
321 | 0 | statusMSESetAT, 0, 1); |
322 | 0 | sc_copy_asn1_entry(g_octet_string, |
323 | 0 | statusMSESetAT); |
324 | 0 | sc_format_asn1_entry(statusMSESetAT, |
325 | 0 | &status_mse_set_at, &status_mse_set_at_len, 1); |
326 | |
|
327 | 0 | if (output->ef_cardaccess) { |
328 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+2, |
329 | 0 | output->ef_cardaccess, (size_t *) &output->ef_cardaccess_length, 1); |
330 | 0 | } |
331 | |
|
332 | 0 | if (output->id_icc) { |
333 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+3, |
334 | 0 | idPICC, 0, 1); |
335 | 0 | sc_copy_asn1_entry(g_octet_string, |
336 | 0 | idPICC); |
337 | 0 | sc_format_asn1_entry(idPICC, |
338 | 0 | output->id_icc, (size_t *) &output->id_icc_length, 1); |
339 | 0 | } |
340 | |
|
341 | 0 | if (output->recent_car) { |
342 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+4, |
343 | 0 | curCAR, 0, 1); |
344 | 0 | sc_copy_asn1_entry(g_octet_string, |
345 | 0 | curCAR); |
346 | 0 | sc_format_asn1_entry(curCAR, |
347 | 0 | output->recent_car, (size_t *) &output->recent_car_length, 1); |
348 | 0 | } |
349 | |
|
350 | 0 | if (output->previous_car) { |
351 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+5, |
352 | 0 | prevCAR, 0, 1); |
353 | 0 | sc_copy_asn1_entry(g_octet_string, |
354 | 0 | prevCAR); |
355 | 0 | sc_format_asn1_entry(prevCAR, |
356 | 0 | output->previous_car, (size_t *) &output->previous_car_length, 1); |
357 | 0 | } |
358 | |
|
359 | 0 | return sc_asn1_encode(ctx, EstablishPACEChannel, asn1, asn1_len); |
360 | 0 | } |
361 | | |
362 | | int escape_buf_to_pace_output(sc_context_t *ctx, |
363 | | const unsigned char *asn1, size_t asn1_len, |
364 | | struct establish_pace_channel_output *output) |
365 | 0 | { |
366 | 0 | uint16_t status_mse_set_at; |
367 | 0 | size_t result_len = sizeof output->result, |
368 | 0 | status_mse_set_at_len = sizeof status_mse_set_at; |
369 | 0 | struct sc_asn1_entry EstablishPACEChannelOutput_data[ |
370 | 0 | sizeof g_EstablishPACEChannelOutput_data/ |
371 | 0 | sizeof *g_EstablishPACEChannelOutput_data]; |
372 | 0 | struct sc_asn1_entry EstablishPACEChannel[ |
373 | 0 | sizeof g_EstablishPACEChannel/ |
374 | 0 | sizeof *g_EstablishPACEChannel]; |
375 | 0 | struct sc_asn1_entry errorCode[ |
376 | 0 | sizeof g_octet_string/ |
377 | 0 | sizeof *g_octet_string]; |
378 | 0 | struct sc_asn1_entry statusMSESetAT[ |
379 | 0 | sizeof g_octet_string/ |
380 | 0 | sizeof *g_octet_string]; |
381 | 0 | struct sc_asn1_entry idPICC[ |
382 | 0 | sizeof g_octet_string/ |
383 | 0 | sizeof *g_octet_string]; |
384 | 0 | struct sc_asn1_entry curCAR[ |
385 | 0 | sizeof g_octet_string/ |
386 | 0 | sizeof *g_octet_string]; |
387 | 0 | struct sc_asn1_entry prevCAR[ |
388 | 0 | sizeof g_octet_string/ |
389 | 0 | sizeof *g_octet_string]; |
390 | |
|
391 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannel, |
392 | 0 | EstablishPACEChannel); |
393 | 0 | sc_format_asn1_entry(EstablishPACEChannel, |
394 | 0 | EstablishPACEChannelOutput_data, 0, 0); |
395 | |
|
396 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannelOutput_data, |
397 | 0 | EstablishPACEChannelOutput_data); |
398 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+0, |
399 | 0 | errorCode, 0, 0); |
400 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+1, |
401 | 0 | statusMSESetAT, 0, 0); |
402 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+2, |
403 | 0 | &output->ef_cardaccess, &output->ef_cardaccess_length, 0); |
404 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+3, |
405 | 0 | idPICC, 0, 0); |
406 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+4, |
407 | 0 | curCAR, 0, 0); |
408 | 0 | sc_format_asn1_entry(EstablishPACEChannelOutput_data+5, |
409 | 0 | prevCAR, 0, 0); |
410 | |
|
411 | 0 | sc_copy_asn1_entry(g_octet_string, |
412 | 0 | errorCode); |
413 | 0 | sc_format_asn1_entry(errorCode, |
414 | 0 | &output->result, &result_len, 0); |
415 | | /* we already allocated memory for the result */ |
416 | 0 | errorCode->flags = 0; |
417 | |
|
418 | 0 | sc_copy_asn1_entry(g_octet_string, |
419 | 0 | statusMSESetAT); |
420 | 0 | sc_format_asn1_entry(statusMSESetAT, |
421 | 0 | &status_mse_set_at, &status_mse_set_at_len, 0); |
422 | | /* we already allocated memory for the result */ |
423 | 0 | statusMSESetAT->flags = 0; |
424 | |
|
425 | 0 | sc_copy_asn1_entry(g_octet_string, |
426 | 0 | idPICC); |
427 | 0 | sc_format_asn1_entry(idPICC, |
428 | 0 | &output->id_icc, &output->id_icc_length, 0); |
429 | |
|
430 | 0 | sc_copy_asn1_entry(g_octet_string, |
431 | 0 | curCAR); |
432 | 0 | sc_format_asn1_entry(curCAR, |
433 | 0 | &output->recent_car, &output->recent_car_length, 0); |
434 | |
|
435 | 0 | sc_copy_asn1_entry(g_octet_string, |
436 | 0 | prevCAR); |
437 | 0 | sc_format_asn1_entry(prevCAR, |
438 | 0 | &output->previous_car, &output->previous_car_length, 0); |
439 | |
|
440 | 0 | LOG_TEST_RET(ctx, |
441 | 0 | sc_asn1_decode(ctx, EstablishPACEChannel, |
442 | 0 | asn1, asn1_len, NULL, NULL), |
443 | 0 | "Error decoding EstablishPACEChannel"); |
444 | | |
445 | 0 | if (status_mse_set_at_len != sizeof status_mse_set_at |
446 | 0 | || result_len != sizeof output->result) |
447 | 0 | return SC_ERROR_UNKNOWN_DATA_RECEIVED; |
448 | | |
449 | 0 | output->mse_set_at_sw1 = (status_mse_set_at >> 8) & 0xff; |
450 | 0 | output->mse_set_at_sw2 = status_mse_set_at & 0xff; |
451 | |
|
452 | 0 | return SC_SUCCESS; |
453 | 0 | } |
454 | | |
455 | 0 | #define CCID_PIN_TIMEOUT 30 |
456 | 0 | #define CCID_DISPLAY_DEFAULT 0xff |
457 | | static int escape_pin_cmd_to_buf(sc_context_t *ctx, |
458 | | const struct sc_pin_cmd_data *data, |
459 | | unsigned char **pc_to_rdr_secure, size_t *pc_to_rdr_secure_len) |
460 | 0 | { |
461 | 0 | PC_to_RDR_Secure_t *secure; |
462 | 0 | abPINDataStucture_Modification_t *modify; |
463 | 0 | abPINDataStucture_Verification_t *verify; |
464 | 0 | uint16_t wLangId = 0, |
465 | 0 | bTeoPrologue2 = 0, |
466 | 0 | wPINMaxExtraDigit; |
467 | 0 | uint8_t bTimeOut = CCID_PIN_TIMEOUT, |
468 | 0 | bNumberMessage = CCID_DISPLAY_DEFAULT, |
469 | 0 | bTeoPrologue1 = 0, |
470 | 0 | bMsgIndex = 0, |
471 | 0 | bMessageType = 0x69, |
472 | 0 | bSlot = 0, |
473 | 0 | bSeq = 0, |
474 | 0 | bBWI = 0xff, |
475 | 0 | wLevelParameter = 0, |
476 | 0 | bEntryValidationCondition = CCID_ENTRY_VALIDATE, |
477 | 0 | bmFormatString, bmPINLengthFormat, bmPINBlockString; |
478 | 0 | const struct sc_pin_cmd_pin *pin_ref; |
479 | 0 | int r; |
480 | 0 | unsigned char *pinapdu = NULL; |
481 | 0 | size_t pinapdu_len = 0; |
482 | |
|
483 | 0 | if (!data || !pc_to_rdr_secure || !pc_to_rdr_secure_len) { |
484 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
485 | 0 | goto err; |
486 | 0 | } |
487 | | |
488 | 0 | pin_ref = data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? |
489 | 0 | &data->pin2 : &data->pin1; |
490 | |
|
491 | 0 | wPINMaxExtraDigit = htole16( |
492 | 0 | (0xff & pin_ref->min_length) << 8) |
493 | 0 | | (pin_ref->max_length & 0xff); |
494 | |
|
495 | 0 | bmFormatString = CCID_PIN_UNITS_BYTES |
496 | 0 | | ((pin_ref->offset & 0xf) << 3); |
497 | 0 | switch (pin_ref->encoding) { |
498 | 0 | case SC_PIN_ENCODING_ASCII: |
499 | 0 | bmFormatString |= CCID_PIN_ENCODING_ASCII; |
500 | 0 | break; |
501 | 0 | case SC_PIN_ENCODING_BCD: |
502 | 0 | bmFormatString |= CCID_PIN_ENCODING_BCD; |
503 | 0 | break; |
504 | 0 | default: |
505 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
506 | 0 | goto err; |
507 | 0 | } |
508 | | |
509 | | /* GLP PINs expect the effective PIN length from bit 4 */ |
510 | 0 | bmPINLengthFormat = pin_ref->encoding == SC_PIN_ENCODING_GLP ? |
511 | 0 | 0x04 : 0x00; |
512 | |
|
513 | 0 | if (pin_ref->encoding == SC_PIN_ENCODING_GLP) { |
514 | | /* GLP PIN length is encoded in 4 bits and block size is always 8 bytes */ |
515 | 0 | bmPINBlockString = 0x40 | 0x08; |
516 | 0 | } else if (pin_ref->encoding == SC_PIN_ENCODING_ASCII && data->flags & SC_PIN_CMD_NEED_PADDING) { |
517 | 0 | bmPINBlockString = (uint8_t) pin_ref->pad_length; |
518 | 0 | } else { |
519 | 0 | bmPINBlockString = 0x00; |
520 | 0 | } |
521 | |
|
522 | 0 | r = sc_apdu_get_octets(ctx, data->apdu, &pinapdu, &pinapdu_len, |
523 | 0 | SC_PROTO_T1); |
524 | 0 | if (r < 0) |
525 | 0 | goto err; |
526 | | |
527 | 0 | switch (data->cmd) { |
528 | 0 | case SC_PIN_CMD_VERIFY: |
529 | 0 | *pc_to_rdr_secure_len = sizeof *secure + 1 |
530 | 0 | + sizeof *verify + pinapdu_len; |
531 | 0 | break; |
532 | | |
533 | 0 | case SC_PIN_CMD_CHANGE: |
534 | 0 | *pc_to_rdr_secure_len = sizeof *secure + 1 |
535 | 0 | + sizeof *modify + 3 + pinapdu_len; |
536 | 0 | break; |
537 | | |
538 | 0 | default: |
539 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
540 | 0 | goto err; |
541 | 0 | } |
542 | | |
543 | 0 | *pc_to_rdr_secure = malloc(*pc_to_rdr_secure_len); |
544 | 0 | if (!*pc_to_rdr_secure) { |
545 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
546 | 0 | goto err; |
547 | 0 | } |
548 | 0 | secure = (PC_to_RDR_Secure_t *) *pc_to_rdr_secure; |
549 | 0 | secure->bMessageType = bMessageType; |
550 | 0 | secure->dwLength = htole32((*pc_to_rdr_secure_len) - sizeof *secure); |
551 | 0 | secure->bSlot = bSlot; |
552 | 0 | secure->bSeq = bSeq; |
553 | 0 | secure->bBWI = bBWI; |
554 | 0 | secure->wLevelParameter = wLevelParameter; |
555 | |
|
556 | 0 | switch (data->cmd) { |
557 | 0 | case SC_PIN_CMD_VERIFY: |
558 | | /* bPINOperation */ |
559 | 0 | *((*pc_to_rdr_secure) + sizeof *secure) = CCID_OPERATION_VERIFY; |
560 | 0 | verify = (abPINDataStucture_Verification_t *) |
561 | 0 | ((*pc_to_rdr_secure) + sizeof *secure + 1); |
562 | 0 | verify->bTimeOut = bTimeOut; |
563 | 0 | verify->bmFormatString = bmFormatString; |
564 | 0 | verify->bmPINBlockString = bmPINBlockString; |
565 | 0 | verify->bmPINLengthFormat = bmPINLengthFormat; |
566 | 0 | verify->wPINMaxExtraDigit = wPINMaxExtraDigit; |
567 | 0 | verify->bEntryValidationCondition = bEntryValidationCondition; |
568 | 0 | verify->bNumberMessage = bNumberMessage; |
569 | 0 | verify->wLangId = wLangId; |
570 | 0 | verify->bMsgIndex = bMsgIndex; |
571 | 0 | verify->bTeoPrologue1 = bTeoPrologue1; |
572 | 0 | verify->bTeoPrologue2 = bTeoPrologue2; |
573 | |
|
574 | 0 | memcpy((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *verify, |
575 | 0 | pinapdu, pinapdu_len); |
576 | 0 | break; |
577 | | |
578 | 0 | case SC_PIN_CMD_CHANGE: |
579 | | /* bPINOperation */ |
580 | 0 | *((*pc_to_rdr_secure) + sizeof *secure) = CCID_OPERATION_MODIFY; |
581 | 0 | modify = (abPINDataStucture_Modification_t *) |
582 | 0 | ((*pc_to_rdr_secure) + sizeof *secure + 1); |
583 | 0 | modify->bTimeOut = bTimeOut; |
584 | 0 | modify->bmFormatString = bmFormatString; |
585 | 0 | modify->bmPINBlockString = bmPINBlockString; |
586 | 0 | modify->bmPINLengthFormat = bmPINLengthFormat; |
587 | 0 | if (!(data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) |
588 | 0 | && data->pin1.offset) { |
589 | 0 | modify->bInsertionOffsetOld = (uint8_t) data->pin1.offset - 5; |
590 | 0 | } else { |
591 | 0 | modify->bInsertionOffsetOld = 0; |
592 | 0 | } |
593 | 0 | modify->bInsertionOffsetNew = data->pin2.offset ? (uint8_t) data->pin2.offset - 5 : 0; |
594 | 0 | modify->wPINMaxExtraDigit = wPINMaxExtraDigit; |
595 | 0 | modify->bConfirmPIN = CCID_PIN_CONFIRM_NEW |
596 | 0 | | (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0 : CCID_PIN_INSERT_OLD); |
597 | 0 | modify->bEntryValidationCondition = bEntryValidationCondition; |
598 | 0 | modify->bNumberMessage = bNumberMessage; |
599 | 0 | modify->wLangId = wLangId; |
600 | 0 | modify->bMsgIndex1 = bMsgIndex; |
601 | 0 | *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 0) = |
602 | 0 | bTeoPrologue1; |
603 | 0 | *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 1) = |
604 | 0 | bTeoPrologue1; |
605 | 0 | *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 2) = |
606 | 0 | bTeoPrologue1; |
607 | |
|
608 | 0 | memcpy((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 3, |
609 | 0 | pinapdu, pinapdu_len); |
610 | 0 | break; |
611 | | |
612 | 0 | default: |
613 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
614 | 0 | goto err; |
615 | 0 | } |
616 | | |
617 | 0 | r = SC_SUCCESS; |
618 | |
|
619 | 0 | err: |
620 | 0 | free(pinapdu); |
621 | 0 | if (r < 0 && pc_to_rdr_secure && *pc_to_rdr_secure) { |
622 | 0 | free(*pc_to_rdr_secure); |
623 | 0 | *pc_to_rdr_secure = NULL; |
624 | 0 | } |
625 | |
|
626 | 0 | return r; |
627 | 0 | } |
628 | | |
629 | 0 | #define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */ |
630 | | static int escape_buf_to_verify_result(sc_context_t *ctx, |
631 | | const unsigned char *rdr_to_pc_datablock, |
632 | | size_t rdr_to_pc_datablock_len, |
633 | | sc_apdu_t *apdu) |
634 | 0 | { |
635 | 0 | RDR_to_PC_DataBlock_t *datablock = |
636 | 0 | (RDR_to_PC_DataBlock_t *) rdr_to_pc_datablock; |
637 | |
|
638 | 0 | if (!rdr_to_pc_datablock |
639 | 0 | || rdr_to_pc_datablock_len < sizeof *datablock |
640 | 0 | || datablock->bMessageType != 0x80) |
641 | 0 | return SC_ERROR_UNKNOWN_DATA_RECEIVED; |
642 | | |
643 | 0 | if (datablock->bStatus != CCID_BSTATUS_OK_ACTIVE) |
644 | 0 | return SC_ERROR_TRANSMIT_FAILED; |
645 | | |
646 | 0 | return sc_apdu_set_resp(ctx, apdu, |
647 | 0 | rdr_to_pc_datablock + sizeof *datablock, |
648 | 0 | htole32(datablock->dwLength)); |
649 | 0 | } |
650 | | |
651 | | static int escape_perform_verify(struct sc_reader *reader, |
652 | | struct sc_pin_cmd_data *data) |
653 | 0 | { |
654 | 0 | u8 rbuf[0xff]; |
655 | 0 | sc_apdu_t apdu; |
656 | 0 | int r; |
657 | |
|
658 | 0 | memset(&apdu, 0, sizeof(apdu)); |
659 | 0 | apdu.cse = SC_APDU_CASE_4_SHORT; |
660 | 0 | apdu.cla = escape_cla; |
661 | 0 | apdu.ins = escape_ins; |
662 | 0 | apdu.p1 = escape_p1_PIN; |
663 | 0 | apdu.p2 = escape_p2_PC_to_RDR_Secure; |
664 | 0 | apdu.resp = rbuf; |
665 | 0 | apdu.resplen = sizeof rbuf; |
666 | 0 | apdu.le = sizeof rbuf; |
667 | |
|
668 | 0 | if (!reader || !reader->ops || !reader->ops->transmit) { |
669 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
670 | 0 | goto err; |
671 | 0 | } |
672 | | |
673 | 0 | r = escape_pin_cmd_to_buf(reader->ctx, data, |
674 | 0 | (unsigned char **) &apdu.data, &apdu.datalen); |
675 | 0 | if (r < 0) { |
676 | 0 | sc_log(reader->ctx, |
677 | 0 | "Error encoding PC_to_RDR_Secure"); |
678 | 0 | goto err; |
679 | 0 | } |
680 | 0 | apdu.lc = apdu.datalen; |
681 | |
|
682 | 0 | r = reader->ops->transmit(reader, &apdu); |
683 | 0 | if (r < 0) { |
684 | 0 | sc_log(reader->ctx, |
685 | 0 | "Error performing PC_to_RDR_Secure"); |
686 | 0 | goto err; |
687 | 0 | } |
688 | | |
689 | 0 | if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { |
690 | 0 | sc_log(reader->ctx, |
691 | 0 | "Error decoding PC_to_RDR_Secure"); |
692 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
693 | 0 | goto err; |
694 | 0 | } |
695 | | |
696 | 0 | r = escape_buf_to_verify_result(reader->ctx, apdu.resp, apdu.resplen, |
697 | 0 | data->apdu); |
698 | |
|
699 | 0 | err: |
700 | 0 | free((unsigned char *) apdu.data); |
701 | |
|
702 | 0 | return r; |
703 | 0 | } |
704 | | |
705 | | static int escape_perform_pace(struct sc_reader *reader, |
706 | | void *establish_pace_channel_input, |
707 | | void *establish_pace_channel_output) |
708 | 0 | { |
709 | 0 | u8 rbuf[0xffff]; |
710 | 0 | sc_apdu_t apdu; |
711 | 0 | int r; |
712 | 0 | struct establish_pace_channel_input *input = |
713 | 0 | establish_pace_channel_input; |
714 | 0 | struct establish_pace_channel_output *output = |
715 | 0 | establish_pace_channel_output; |
716 | |
|
717 | 0 | memset(&apdu, 0, sizeof(apdu)); |
718 | 0 | apdu.cse = SC_APDU_CASE_4_EXT; |
719 | 0 | apdu.cla = escape_cla; |
720 | 0 | apdu.ins = escape_ins; |
721 | 0 | apdu.p1 = escape_p1_PIN; |
722 | 0 | apdu.p2 = escape_p2_EstablishPACEChannel; |
723 | 0 | apdu.resp = rbuf; |
724 | 0 | apdu.resplen = sizeof rbuf; |
725 | 0 | apdu.le = sizeof rbuf; |
726 | |
|
727 | 0 | if (!reader || !reader->ops || !reader->ops->transmit) { |
728 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
729 | 0 | goto err; |
730 | 0 | } |
731 | | |
732 | 0 | r = escape_pace_input_to_buf(reader->ctx, input, |
733 | 0 | (unsigned char **) &apdu.data, &apdu.datalen); |
734 | 0 | if (r < 0) { |
735 | 0 | sc_log(reader->ctx, |
736 | 0 | "Error encoding EstablishPACEChannel"); |
737 | 0 | goto err; |
738 | 0 | } |
739 | 0 | apdu.lc = apdu.datalen; |
740 | |
|
741 | 0 | r = reader->ops->transmit(reader, &apdu); |
742 | 0 | if (r < 0) { |
743 | 0 | sc_log(reader->ctx, |
744 | 0 | "Error performing EstablishPACEChannel"); |
745 | 0 | goto err; |
746 | 0 | } |
747 | | |
748 | 0 | if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { |
749 | 0 | sc_log(reader->ctx, |
750 | 0 | "Error decoding EstablishPACEChannel"); |
751 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
752 | 0 | goto err; |
753 | 0 | } |
754 | | |
755 | 0 | r = escape_buf_to_pace_output(reader->ctx, apdu.resp, apdu.resplen, |
756 | 0 | output); |
757 | |
|
758 | 0 | err: |
759 | 0 | free((unsigned char *) apdu.data); |
760 | |
|
761 | 0 | return r; |
762 | 0 | } |
763 | | |
764 | | struct sc_asn1_entry g_PACECapabilities_data[] = { |
765 | | { "capabilityPACE", |
766 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
767 | | { "capabilityEID", |
768 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x02|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
769 | | { "capabilityESign", |
770 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x03|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
771 | | { "capabilityDestroy", |
772 | | SC_ASN1_STRUCT, SC_ASN1_CTX|0x04|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL }, |
773 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
774 | | }; |
775 | | struct sc_asn1_entry g_PACECapabilities[] = { |
776 | | { "PACECapabilities", |
777 | | SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE|SC_ASN1_CONS, 0, NULL, NULL }, |
778 | | { NULL , 0 , 0 , 0 , NULL , NULL } |
779 | | }; |
780 | | |
781 | | int escape_buf_to_pace_capabilities(sc_context_t *ctx, |
782 | | const unsigned char *asn1, size_t asn1_len, |
783 | | unsigned long *sc_reader_t_capabilities) |
784 | 0 | { |
785 | 0 | int pace = 0, eid = 0, esign = 0, destroy = 0; |
786 | 0 | struct sc_asn1_entry PACECapabilities_data[ |
787 | 0 | sizeof g_PACECapabilities_data/ |
788 | 0 | sizeof *g_PACECapabilities_data]; |
789 | 0 | struct sc_asn1_entry PACECapabilities[ |
790 | 0 | sizeof g_PACECapabilities/ |
791 | 0 | sizeof *g_PACECapabilities]; |
792 | 0 | struct sc_asn1_entry capabilityPACE[ |
793 | 0 | sizeof g_boolean/ |
794 | 0 | sizeof *g_boolean]; |
795 | 0 | struct sc_asn1_entry capabilityEID[ |
796 | 0 | sizeof g_boolean/ |
797 | 0 | sizeof *g_boolean]; |
798 | 0 | struct sc_asn1_entry capabilityESign[ |
799 | 0 | sizeof g_boolean/ |
800 | 0 | sizeof *g_boolean]; |
801 | 0 | struct sc_asn1_entry capabilityDestroy[ |
802 | 0 | sizeof g_boolean/ |
803 | 0 | sizeof *g_boolean]; |
804 | |
|
805 | 0 | sc_copy_asn1_entry(g_PACECapabilities, |
806 | 0 | PACECapabilities); |
807 | 0 | sc_format_asn1_entry(PACECapabilities, |
808 | 0 | PACECapabilities_data, 0, 1); |
809 | |
|
810 | 0 | sc_copy_asn1_entry(g_PACECapabilities_data, |
811 | 0 | PACECapabilities_data); |
812 | 0 | sc_format_asn1_entry(PACECapabilities_data+0, |
813 | 0 | &capabilityPACE, NULL, 1); |
814 | 0 | sc_format_asn1_entry(PACECapabilities_data+1, |
815 | 0 | &capabilityEID, NULL, 1); |
816 | 0 | sc_format_asn1_entry(PACECapabilities_data+2, |
817 | 0 | &capabilityESign, NULL, 1); |
818 | 0 | sc_format_asn1_entry(PACECapabilities_data+3, |
819 | 0 | &capabilityDestroy, NULL, 1); |
820 | |
|
821 | 0 | sc_copy_asn1_entry(g_boolean, |
822 | 0 | capabilityPACE); |
823 | 0 | sc_format_asn1_entry(capabilityPACE+0, |
824 | 0 | &pace, NULL, 0); |
825 | |
|
826 | 0 | sc_copy_asn1_entry(g_boolean, |
827 | 0 | capabilityEID); |
828 | 0 | sc_format_asn1_entry(capabilityEID+0, |
829 | 0 | &eid, NULL, 0); |
830 | |
|
831 | 0 | sc_copy_asn1_entry(g_boolean, |
832 | 0 | capabilityESign); |
833 | 0 | sc_format_asn1_entry(capabilityESign+0, |
834 | 0 | &esign, NULL, 0); |
835 | |
|
836 | 0 | sc_copy_asn1_entry(g_boolean, |
837 | 0 | capabilityDestroy); |
838 | 0 | sc_format_asn1_entry(capabilityDestroy+0, |
839 | 0 | &destroy, NULL, 0); |
840 | |
|
841 | 0 | LOG_TEST_RET(ctx, |
842 | 0 | sc_asn1_decode(ctx, PACECapabilities, |
843 | 0 | asn1, asn1_len, NULL, NULL), |
844 | 0 | "Error decoding PACECapabilities"); |
845 | | |
846 | | /* We got a valid PACE Capabilities reply. There is currently no mechanism |
847 | | * to determine support PIN verification/modification with a escape |
848 | | * command. Since the reader implements this mechanism it is reasonable to |
849 | | * assume that PIN verification/modification is available. */ |
850 | 0 | *sc_reader_t_capabilities = SC_READER_CAP_PIN_PAD; |
851 | |
|
852 | 0 | if (pace) |
853 | 0 | *sc_reader_t_capabilities |= SC_READER_CAP_PACE_GENERIC; |
854 | 0 | if (eid) |
855 | 0 | *sc_reader_t_capabilities |= SC_READER_CAP_PACE_EID; |
856 | 0 | if (esign) |
857 | 0 | *sc_reader_t_capabilities |= SC_READER_CAP_PACE_ESIGN; |
858 | 0 | if (destroy) |
859 | 0 | *sc_reader_t_capabilities |= SC_READER_CAP_PACE_DESTROY_CHANNEL; |
860 | |
|
861 | 0 | return SC_SUCCESS; |
862 | 0 | } |
863 | | |
864 | | int escape_pace_capabilities_to_buf(sc_context_t *ctx, |
865 | | const unsigned long sc_reader_t_capabilities, |
866 | | unsigned char **asn1, size_t *asn1_len) |
867 | 0 | { |
868 | 0 | int yes = 1, no = 0; |
869 | 0 | struct sc_asn1_entry PACECapabilities_data[ |
870 | 0 | sizeof g_PACECapabilities_data/ |
871 | 0 | sizeof *g_PACECapabilities_data]; |
872 | 0 | struct sc_asn1_entry PACECapabilities[ |
873 | 0 | sizeof g_PACECapabilities/ |
874 | 0 | sizeof *g_PACECapabilities]; |
875 | 0 | struct sc_asn1_entry capabilityPACE[ |
876 | 0 | sizeof g_boolean/ |
877 | 0 | sizeof *g_boolean]; |
878 | 0 | struct sc_asn1_entry capabilityEID[ |
879 | 0 | sizeof g_boolean/ |
880 | 0 | sizeof *g_boolean]; |
881 | 0 | struct sc_asn1_entry capabilityESign[ |
882 | 0 | sizeof g_boolean/ |
883 | 0 | sizeof *g_boolean]; |
884 | 0 | struct sc_asn1_entry capabilityDestroy[ |
885 | 0 | sizeof g_boolean/ |
886 | 0 | sizeof *g_boolean]; |
887 | |
|
888 | 0 | sc_copy_asn1_entry(g_EstablishPACEChannel, |
889 | 0 | PACECapabilities); |
890 | 0 | sc_format_asn1_entry(PACECapabilities, |
891 | 0 | PACECapabilities_data, 0, 1); |
892 | |
|
893 | 0 | sc_copy_asn1_entry(g_PACECapabilities_data, |
894 | 0 | PACECapabilities_data); |
895 | 0 | sc_format_asn1_entry(PACECapabilities_data+0, |
896 | 0 | &capabilityPACE, NULL, 1); |
897 | 0 | sc_format_asn1_entry(PACECapabilities_data+1, |
898 | 0 | &capabilityEID, NULL, 1); |
899 | 0 | sc_format_asn1_entry(PACECapabilities_data+2, |
900 | 0 | &capabilityESign, NULL, 1); |
901 | 0 | sc_format_asn1_entry(PACECapabilities_data+3, |
902 | 0 | &capabilityDestroy, NULL, 1); |
903 | |
|
904 | 0 | sc_copy_asn1_entry(g_boolean, |
905 | 0 | capabilityPACE); |
906 | 0 | sc_format_asn1_entry(capabilityPACE, |
907 | 0 | sc_reader_t_capabilities & SC_READER_CAP_PACE_GENERIC |
908 | 0 | ? &yes : &no, NULL, 1); |
909 | |
|
910 | 0 | sc_copy_asn1_entry(g_boolean, |
911 | 0 | capabilityEID); |
912 | 0 | sc_format_asn1_entry(capabilityEID, |
913 | 0 | sc_reader_t_capabilities & SC_READER_CAP_PACE_EID |
914 | 0 | ? &yes : &no, NULL, 1); |
915 | |
|
916 | 0 | sc_copy_asn1_entry(g_boolean, |
917 | 0 | capabilityESign); |
918 | 0 | sc_format_asn1_entry(capabilityESign, |
919 | 0 | sc_reader_t_capabilities & SC_READER_CAP_PACE_ESIGN |
920 | 0 | ? &yes : &no, NULL, 1); |
921 | |
|
922 | 0 | sc_copy_asn1_entry(g_boolean, |
923 | 0 | capabilityDestroy); |
924 | 0 | sc_format_asn1_entry(capabilityDestroy, |
925 | 0 | sc_reader_t_capabilities & SC_READER_CAP_PACE_DESTROY_CHANNEL |
926 | 0 | ? &yes : &no, NULL, 1); |
927 | |
|
928 | 0 | return sc_asn1_encode(ctx, PACECapabilities, asn1, asn1_len); |
929 | 0 | } |
930 | | |
931 | 0 | #define MAX_RESPLEN 0xFF |
932 | | void sc_detect_escape_cmds(sc_reader_t *reader) |
933 | 0 | { |
934 | 0 | int error = 0; |
935 | 0 | u8 rbuf[MAX_RESPLEN + 1]; |
936 | 0 | sc_apdu_t apdu; |
937 | 0 | unsigned long capabilities; |
938 | |
|
939 | 0 | if (reader && reader->ops && reader->ops->transmit) { |
940 | 0 | memset(&apdu, 0, sizeof(apdu)); |
941 | 0 | apdu.cse = SC_APDU_CASE_2_SHORT; |
942 | 0 | apdu.cla = escape_cla; |
943 | 0 | apdu.ins = escape_ins; |
944 | 0 | apdu.p1 = escape_p1_PIN; |
945 | 0 | apdu.p2 = escape_p2_GetReaderPACECapabilities; |
946 | 0 | apdu.resp = rbuf; |
947 | 0 | apdu.resplen = MAX_RESPLEN; |
948 | 0 | apdu.le = MAX_RESPLEN; |
949 | |
|
950 | 0 | if (reader->ops->transmit(reader, &apdu) == SC_SUCCESS |
951 | 0 | && apdu.sw1 == 0x90 && apdu.sw2 == 0x00 |
952 | 0 | && escape_buf_to_pace_capabilities(reader->ctx, |
953 | 0 | apdu.resp, apdu.resplen, &capabilities) == SC_SUCCESS) { |
954 | 0 | if (capabilities & SC_READER_CAP_PIN_PAD |
955 | 0 | && !(reader->capabilities & SC_READER_CAP_PIN_PAD)) { |
956 | 0 | ((struct sc_reader_operations *) reader->ops)->perform_verify = |
957 | 0 | escape_perform_verify; |
958 | 0 | sc_log(reader->ctx, |
959 | 0 | "Added escape command wrappers for PIN verification/modification to '%s'", reader->name); |
960 | 0 | } |
961 | |
|
962 | 0 | if (capabilities & SC_READER_CAP_PACE_GENERIC |
963 | 0 | && !(reader->capabilities & SC_READER_CAP_PACE_GENERIC)) { |
964 | 0 | ((struct sc_reader_operations *) reader->ops)->perform_pace = |
965 | 0 | escape_perform_pace; |
966 | 0 | sc_log(reader->ctx, |
967 | 0 | "Added escape command wrappers for PACE to '%s'", reader->name); |
968 | 0 | } |
969 | |
|
970 | 0 | reader->capabilities |= capabilities; |
971 | 0 | } else { |
972 | 0 | error++; |
973 | 0 | sc_log(reader->ctx, |
974 | 0 | "%s does not support escape commands", reader->name); |
975 | 0 | } |
976 | |
|
977 | 0 | apdu.p1 = escape_p1_IFD; |
978 | 0 | apdu.p2 = escape_p2_vendor; |
979 | 0 | apdu.resplen = MAX_RESPLEN; |
980 | 0 | if (reader->ops->transmit(reader, &apdu) == SC_SUCCESS |
981 | 0 | && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
982 | 0 | if (!reader->vendor) { |
983 | | /* add NUL termination, just in case... */ |
984 | 0 | rbuf[apdu.resplen] = '\0'; |
985 | 0 | reader->vendor = strdup((const char *) rbuf); |
986 | 0 | } |
987 | 0 | } else { |
988 | 0 | error++; |
989 | 0 | } |
990 | |
|
991 | 0 | apdu.p1 = escape_p1_IFD; |
992 | 0 | apdu.p2 = escape_p2_version_firmware; |
993 | 0 | apdu.resplen = MAX_RESPLEN; |
994 | 0 | if (reader->ops->transmit(reader, &apdu) == SC_SUCCESS |
995 | 0 | && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
996 | 0 | if (!reader->version_major && !reader->version_minor) { |
997 | 0 | unsigned int major = 0, minor = 0; |
998 | | /* add NUL termination, just in case... */ |
999 | 0 | rbuf[apdu.resplen] = '\0'; |
1000 | 0 | sscanf((const char *) rbuf, "%u.%u", &major, &minor); |
1001 | 0 | reader->version_major = major>0xff ? 0xff : major; |
1002 | 0 | reader->version_minor = minor>0xff ? 0xff : minor; |
1003 | 0 | } |
1004 | 0 | } else { |
1005 | 0 | error++; |
1006 | 0 | } |
1007 | 0 | } |
1008 | |
|
1009 | 0 | if (error && reader) { |
1010 | 0 | sc_log(reader->ctx, |
1011 | 0 | "%d escape command%s failed, need to reset the card", |
1012 | 0 | error, error == 1 ? "" : "s"); |
1013 | 0 | if (reader->ops && reader->ops->transmit) { |
1014 | 0 | memset(&apdu, 0, sizeof(apdu)); |
1015 | 0 | apdu.cse = SC_APDU_CASE_3_SHORT; |
1016 | 0 | apdu.cla = 0x00; |
1017 | 0 | apdu.ins = 0xA4; |
1018 | 0 | apdu.p1 = 8; |
1019 | 0 | apdu.p2 = 0x0C; |
1020 | 0 | apdu.data = rbuf; |
1021 | 0 | rbuf[0] = 0x3F; |
1022 | 0 | rbuf[1] = 0x00; |
1023 | 0 | apdu.datalen = 2; |
1024 | 0 | apdu.lc = 2; |
1025 | | apdu.resp = NULL; |
1026 | 0 | apdu.resplen = 0; |
1027 | 0 | apdu.le = 0; |
1028 | 0 | reader->ops->transmit(reader, &apdu); |
1029 | 0 | } |
1030 | 0 | } |
1031 | 0 | } |