/src/opensc/src/libopensc/card-lteid.c
Line | Count | Source |
1 | | /* |
2 | | * This library is free software; you can redistribute it and/or |
3 | | * modify it under the terms of the GNU Lesser General Public |
4 | | * License as published by the Free Software Foundation; either |
5 | | * version 2.1 of the License, or (at your option) any later version. |
6 | | * |
7 | | * This library is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
10 | | * Lesser General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU Lesser General Public |
13 | | * License along with this library; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
15 | | */ |
16 | | |
17 | | #ifdef HAVE_CONFIG_H |
18 | | #include "config.h" |
19 | | #endif |
20 | | |
21 | | #if defined(ENABLE_SM) && defined(ENABLE_OPENPACE) |
22 | | |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | |
26 | | #include "asn1.h" |
27 | | #include "common/compat_strlcat.h" |
28 | | #include "internal.h" |
29 | | #include "opensc.h" |
30 | | #include "sm/sm-eac.h" |
31 | | |
32 | | static const struct sc_card_operations *iso_ops = NULL; |
33 | | static struct sc_card_operations lteid_ops; |
34 | | |
35 | | static struct sc_card_driver lteid_drv = { |
36 | | "Lithuanian eID card (asmens tapatybÄ—s kortelÄ—)", "lteid", |
37 | | <eid_ops, NULL, 0, NULL}; |
38 | | |
39 | 0 | #define DRVDATA(card) ((struct lteid_drv_data *)((card)->drv_data)) |
40 | 0 | #define LTEID_CAN_LENGTH 6 |
41 | | |
42 | | struct lteid_drv_data { |
43 | | unsigned char pace; |
44 | | unsigned char pace_pin_ref; |
45 | | unsigned char can[LTEID_CAN_LENGTH]; |
46 | | unsigned char can_from_cache; |
47 | | }; |
48 | | |
49 | | void |
50 | | lteid_get_can_cache_path(sc_card_t *card, char *buf, size_t buf_len) |
51 | 0 | { |
52 | 0 | sc_get_cache_dir(card->ctx, buf, buf_len); |
53 | |
|
54 | | #ifdef _WIN32 |
55 | | strlcat(buf, "\\", buf_len); |
56 | | #else |
57 | 0 | strlcat(buf, "/", buf_len); |
58 | 0 | #endif |
59 | |
|
60 | 0 | strlcat(buf, "lteid_can", buf_len); |
61 | 0 | } |
62 | | |
63 | | static int |
64 | | lteid_get_cached_can(sc_card_t *card, unsigned char *can) |
65 | 0 | { |
66 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
67 | 0 | char path[PATH_MAX]; |
68 | |
|
69 | 0 | lteid_get_can_cache_path(card, path, sizeof(path)); |
70 | |
|
71 | 0 | FILE *fd = fopen(path, "r"); |
72 | |
|
73 | 0 | if (!fd) { |
74 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
75 | 0 | } |
76 | | |
77 | 0 | if (LTEID_CAN_LENGTH != fread(can, 1, LTEID_CAN_LENGTH, fd)) { |
78 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
79 | 0 | } |
80 | | |
81 | 0 | fclose(fd); |
82 | |
|
83 | 0 | LOG_FUNC_RETURN(card->ctx, 1); |
84 | 0 | } |
85 | | |
86 | | static int |
87 | | lteid_cache_can(sc_card_t *card, const char *can) |
88 | 0 | { |
89 | 0 | int rv; |
90 | 0 | char path[PATH_MAX]; |
91 | |
|
92 | 0 | lteid_get_can_cache_path(card, path, sizeof(path)); |
93 | |
|
94 | 0 | FILE *fd = fopen(path, "w"); |
95 | |
|
96 | 0 | if (!fd && errno == ENOENT) { |
97 | 0 | if ((rv = sc_make_cache_dir(card->ctx)) < 0) |
98 | 0 | return rv; |
99 | | |
100 | 0 | fd = fopen(path, "w"); |
101 | 0 | } |
102 | | |
103 | 0 | if (!fd) { |
104 | 0 | return SC_ERROR_INTERNAL; |
105 | 0 | } |
106 | | |
107 | 0 | fwrite(can, 1, 6, fd); |
108 | 0 | fclose(fd); |
109 | |
|
110 | 0 | return SC_SUCCESS; |
111 | 0 | } |
112 | | |
113 | | static int |
114 | | lteid_clear_cached_can(sc_card_t *card) |
115 | 0 | { |
116 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
117 | |
|
118 | 0 | char path[PATH_MAX]; |
119 | |
|
120 | 0 | lteid_get_can_cache_path(card, path, sizeof(path)); |
121 | |
|
122 | 0 | if (!unlink(path)) { |
123 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
124 | 0 | } |
125 | | |
126 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
127 | 0 | } |
128 | | |
129 | | static int |
130 | | lteid_get_can(sc_card_t *card, struct establish_pace_channel_input *pace_input) |
131 | 0 | { |
132 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
133 | 0 | struct lteid_drv_data *drv_data = DRVDATA(card); |
134 | 0 | int got_can = 0; |
135 | |
|
136 | 0 | drv_data->can_from_cache = 0; |
137 | | |
138 | | // Try env variables first |
139 | 0 | const char *can_from_env = getenv("LTEID_CAN"); |
140 | 0 | if (can_from_env && strlen(can_from_env) == LTEID_CAN_LENGTH) { |
141 | 0 | got_can = 1; |
142 | 0 | memcpy(drv_data->can, can_from_env, LTEID_CAN_LENGTH); |
143 | 0 | } |
144 | | |
145 | | // Try getting one from the cache |
146 | 0 | if (!got_can && lteid_get_cached_can(card, drv_data->can)) { |
147 | 0 | got_can = 1; |
148 | 0 | drv_data->can_from_cache = 1; |
149 | 0 | } |
150 | | |
151 | | // Finally see if there is a default in configuration |
152 | 0 | if (!got_can) { |
153 | 0 | const char *can_from_config = NULL; |
154 | |
|
155 | 0 | for (size_t i = 0; card->ctx->conf_blocks[i]; ++i) { |
156 | 0 | scconf_block **blocks = scconf_find_blocks(card->ctx->conf, card->ctx->conf_blocks[i], "card_driver", "lteid"); |
157 | 0 | if (!blocks) |
158 | 0 | continue; |
159 | 0 | for (size_t j = 0; blocks[j]; ++j) |
160 | 0 | if ((can_from_config = scconf_get_str(blocks[j], "can", NULL))) |
161 | 0 | break; |
162 | 0 | free(blocks); |
163 | 0 | } |
164 | |
|
165 | 0 | if (can_from_config && strlen(can_from_config) == LTEID_CAN_LENGTH) { |
166 | 0 | got_can = 1; |
167 | 0 | memcpy(drv_data->can, can_from_config, LTEID_CAN_LENGTH); |
168 | 0 | } |
169 | 0 | } |
170 | |
|
171 | 0 | if (!got_can) { |
172 | 0 | sc_log(card->ctx, "Missing or invalid CAN. 6 digits required."); |
173 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN); |
174 | 0 | } |
175 | | |
176 | 0 | pace_input->pin_id = PACE_PIN_ID_CAN; |
177 | 0 | pace_input->pin = drv_data->can; |
178 | 0 | pace_input->pin_length = LTEID_CAN_LENGTH; |
179 | |
|
180 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
181 | 0 | } |
182 | | |
183 | | static int |
184 | | lteid_perform_pace(struct sc_card *card, const int ref, const unsigned char *pin, size_t pinlen, int *tries_left) |
185 | 0 | { |
186 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
187 | |
|
188 | 0 | struct lteid_drv_data *drv_data = DRVDATA(card); |
189 | 0 | struct establish_pace_channel_input pace_input = {0}; |
190 | 0 | struct establish_pace_channel_output pace_output = {0}; |
191 | |
|
192 | 0 | if (drv_data->pace) { |
193 | 0 | sc_sm_stop(card); |
194 | 0 | drv_data->pace = 0; |
195 | 0 | drv_data->pace_pin_ref = 0; |
196 | 0 | } |
197 | |
|
198 | 0 | if (ref == PACE_PIN_ID_CAN && !pin) { |
199 | 0 | if (SC_SUCCESS != lteid_get_can(card, &pace_input)) { |
200 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN); |
201 | 0 | } |
202 | 0 | } else { |
203 | 0 | pace_input.pin_id = ref; |
204 | 0 | pace_input.pin = pin; |
205 | 0 | pace_input.pin_length = pinlen; |
206 | 0 | } |
207 | | |
208 | 0 | int rv = perform_pace(card, pace_input, &pace_output, EAC_TR_VERSION_2_02); |
209 | 0 | if (rv != SC_SUCCESS) { |
210 | 0 | sc_log(card->ctx, "Error performing PACE for pin ref 0x%02x.", ref); |
211 | |
|
212 | 0 | drv_data->pace = 0; |
213 | 0 | drv_data->pace_pin_ref = 0; |
214 | | |
215 | | // Special case after entering incorrect PACE PIN twice. Card locks with 1 PIN attempt remaining. |
216 | 0 | if (ref == PACE_PIN_ID_PIN && rv == SC_ERROR_NO_CARD_SUPPORT) { |
217 | 0 | rv = SC_ERROR_AUTH_METHOD_BLOCKED; |
218 | 0 | } |
219 | | |
220 | | // When CAN code authentication fails and CAN code comes from cache - clear it. |
221 | | // We don't want to make multiple attempts if code is wrong. User should run lteid-tool |
222 | | // again to set up the card. |
223 | 0 | if (ref == PACE_PIN_ID_CAN && drv_data->can_from_cache && rv != SC_ERROR_INTERNAL) { |
224 | 0 | if (lteid_clear_cached_can(card)) { |
225 | 0 | drv_data->can_from_cache = 0; |
226 | 0 | } |
227 | 0 | } |
228 | |
|
229 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
230 | 0 | } |
231 | | |
232 | | // If caller provided CAN is valid - cache it. |
233 | 0 | if (ref == PACE_PIN_ID_CAN && pin) { |
234 | 0 | lteid_cache_can(card, (const char *)pin); |
235 | 0 | } |
236 | | |
237 | | // Track PACE status |
238 | 0 | drv_data->pace = 1; |
239 | 0 | drv_data->pace_pin_ref = ref; |
240 | |
|
241 | 0 | free(pace_output.ef_cardaccess); |
242 | 0 | free(pace_output.recent_car); |
243 | 0 | free(pace_output.previous_car); |
244 | 0 | free(pace_output.id_icc); |
245 | 0 | free(pace_output.id_pcd); |
246 | |
|
247 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
248 | 0 | } |
249 | | |
250 | | static int |
251 | | lteid_unlock(sc_card_t *card) |
252 | 0 | { |
253 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
254 | |
|
255 | 0 | if (SC_SUCCESS != lteid_perform_pace(card, PACE_PIN_ID_CAN, NULL, 0, NULL)) { |
256 | 0 | sc_log(card->ctx, "Unlock with CAN code failed. No CAN found in environment, opensc.conf nor cache."); |
257 | 0 | } |
258 | |
|
259 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
260 | 0 | } |
261 | | |
262 | | static int |
263 | | lteid_init(sc_card_t *card) |
264 | 0 | { |
265 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
266 | 0 | int rv; |
267 | |
|
268 | 0 | struct lteid_drv_data *drv_data = calloc(1, sizeof(struct lteid_drv_data)); |
269 | |
|
270 | 0 | if (drv_data == NULL) |
271 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
272 | | |
273 | 0 | drv_data->pace = 0; |
274 | 0 | drv_data->pace_pin_ref = 0; |
275 | 0 | card->drv_data = drv_data; |
276 | |
|
277 | 0 | memset(&card->sm_ctx, 0, sizeof card->sm_ctx); |
278 | |
|
279 | 0 | card->max_send_size = 65535; |
280 | 0 | card->max_recv_size = 65535; |
281 | 0 | card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO | SC_CARD_CAP_APDU_EXT; |
282 | |
|
283 | 0 | _sc_card_add_ec_alg(card, 384, SC_ALGORITHM_ECDSA_HASH_NONE | SC_ALGORITHM_ECDSA_RAW, 0, NULL); |
284 | |
|
285 | 0 | rv = sc_enum_apps(card); |
286 | 0 | LOG_TEST_RET(card->ctx, rv, "Enumerate apps failed"); |
287 | | |
288 | 0 | rv = lteid_unlock(card); |
289 | 0 | LOG_TEST_RET(card->ctx, rv, "Unlock card failed"); |
290 | | |
291 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
292 | 0 | } |
293 | | |
294 | | static int |
295 | | lteid_finish(sc_card_t *card) |
296 | 0 | { |
297 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
298 | |
|
299 | 0 | sc_sm_stop(card); |
300 | |
|
301 | 0 | free(card->drv_data); |
302 | 0 | card->drv_data = NULL; |
303 | |
|
304 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
305 | 0 | } |
306 | | |
307 | | static int |
308 | | lteid_logout(sc_card_t *card) |
309 | 0 | { |
310 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
311 | |
|
312 | 0 | sc_sm_stop(card); |
313 | |
|
314 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
315 | 0 | } |
316 | | |
317 | | static int |
318 | | lteid_pin_cmd_verify(struct sc_card *card, struct sc_pin_cmd_data *data) |
319 | 0 | { |
320 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
321 | |
|
322 | 0 | int rv; |
323 | | |
324 | | // Authentication key refers to PACE PIN -> 0x03 |
325 | | // Meanwhile, signing key refers to PIN.QES -> 0x81. This pin is verifiable via regular iso7816 cmd verify call. |
326 | 0 | switch (data->pin_reference) { |
327 | 0 | case PACE_PIN_ID_CAN: |
328 | 0 | case PACE_PIN_ID_PIN: |
329 | 0 | case PACE_PIN_ID_PUK: |
330 | 0 | rv = lteid_perform_pace(card, data->pin_reference, data->pin1.data, data->pin1.len, &data->pin1.tries_left); |
331 | 0 | break; |
332 | 0 | default: |
333 | 0 | rv = iso_ops->pin_cmd(card, data); |
334 | 0 | break; |
335 | 0 | } |
336 | | |
337 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
338 | 0 | } |
339 | | |
340 | | static int |
341 | | lteid_pin_cmd_get_info(struct sc_card *card, struct sc_pin_cmd_data *data) |
342 | 0 | { |
343 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
344 | |
|
345 | 0 | struct lteid_drv_data *drv_data = DRVDATA(card); |
346 | 0 | int rv; |
347 | | |
348 | | // PACE CAN code info: as far as we know there's no limit to CAN verification attempts |
349 | 0 | if (data->pin_reference == PACE_PIN_ID_CAN) { |
350 | 0 | data->pin1.max_tries = -1; |
351 | 0 | data->pin1.tries_left = -1; |
352 | |
|
353 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
354 | 0 | } |
355 | | |
356 | | // PACE PIN and PUK codes: max and remaining attempts are stored in ACE3 and ACE4 files. |
357 | 0 | if (data->pin_reference == PACE_PIN_ID_PIN || data->pin_reference == PACE_PIN_ID_PUK) { |
358 | 0 | struct sc_apdu apdu; |
359 | 0 | unsigned char buf[0xbe] = {0}; |
360 | 0 | u8 id[] = {0xac, 0x00}; |
361 | 0 | size_t taglen = 0; |
362 | |
|
363 | 0 | switch (data->pin_reference) { |
364 | 0 | case PACE_PIN_ID_PIN: |
365 | 0 | id[1] = 0xe3; |
366 | 0 | break; |
367 | 0 | case PACE_PIN_ID_PUK: |
368 | 0 | id[1] = 0xe4; |
369 | 0 | break; |
370 | 0 | default: |
371 | 0 | break; |
372 | 0 | } |
373 | | |
374 | 0 | sc_format_apdu_ex(&apdu, 0x00, 0xa4, 0x00, 0x04, id, sizeof(id), buf, sizeof(buf)); |
375 | |
|
376 | 0 | rv = sc_transmit_apdu(card, &apdu); |
377 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
378 | | |
379 | 0 | const u8 *tag = sc_asn1_find_tag(card->ctx, buf, apdu.resplen, 0x62, &taglen); |
380 | 0 | tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0xa5, &taglen); |
381 | 0 | tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0xa2, &taglen); |
382 | 0 | tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0xa3, &taglen); |
383 | 0 | tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0x82, &taglen); |
384 | |
|
385 | 0 | if (tag && taglen == 2) { |
386 | 0 | data->pin1.tries_left = tag[0]; |
387 | 0 | data->pin1.max_tries = tag[1]; |
388 | 0 | } else { |
389 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND); |
390 | 0 | } |
391 | | |
392 | 0 | if (drv_data->pace_pin_ref == data->pin_reference) { |
393 | 0 | data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN; |
394 | 0 | } else { |
395 | 0 | data->pin1.logged_in = SC_PIN_STATE_LOGGED_OUT; |
396 | 0 | } |
397 | |
|
398 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
399 | 0 | } |
400 | | |
401 | | // PIN.QES is a regular iso7816 pin |
402 | 0 | if (data->pin_reference == 0x81) { |
403 | 0 | rv = iso_ops->pin_cmd(card, data); |
404 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
405 | 0 | } |
406 | | |
407 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND); |
408 | 0 | } |
409 | | |
410 | | static int |
411 | | lteid_pin_cmd_unblock(struct sc_card *card, struct sc_pin_cmd_data *data) |
412 | 0 | { |
413 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
414 | |
|
415 | 0 | int rv; |
416 | | |
417 | | // PACE PIN for unblocking command is known as pin ref 0x07 |
418 | 0 | if (data->pin_reference == PACE_PIN_ID_PIN) { |
419 | 0 | struct sc_pin_cmd_data with_changed_pin_ref = *data; |
420 | |
|
421 | 0 | with_changed_pin_ref.pin_reference = 0x07; |
422 | 0 | rv = iso_ops->pin_cmd(card, &with_changed_pin_ref); |
423 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
424 | 0 | } |
425 | | |
426 | | // PIN.QES is a regular iso7816 pin |
427 | 0 | if (data->pin_reference == 0x81) { |
428 | 0 | rv = iso_ops->pin_cmd(card, data); |
429 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
430 | 0 | } |
431 | | |
432 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND); |
433 | 0 | } |
434 | | |
435 | | static int |
436 | | lteid_pin_cmd_change(struct sc_card *card, struct sc_pin_cmd_data *data) |
437 | 0 | { |
438 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
439 | |
|
440 | 0 | int rv; |
441 | | |
442 | | // PACE PIN for unblocking command is known as pin ref 0x07 |
443 | 0 | if (data->pin_reference == PACE_PIN_ID_PIN) { |
444 | 0 | struct sc_pin_cmd_data with_changed_pin_ref = *data; |
445 | |
|
446 | 0 | with_changed_pin_ref.pin_reference = 0x07; |
447 | 0 | rv = iso_ops->pin_cmd(card, &with_changed_pin_ref); |
448 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
449 | 0 | } |
450 | | |
451 | | // PIN.QES is a regular iso7816 pin |
452 | 0 | if (data->pin_reference == 0x81) { |
453 | 0 | rv = iso_ops->pin_cmd(card, data); |
454 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
455 | 0 | } |
456 | | |
457 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND); |
458 | 0 | } |
459 | | |
460 | | static int |
461 | | lteid_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data) |
462 | 0 | { |
463 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
464 | |
|
465 | 0 | int rv; |
466 | |
|
467 | 0 | switch (data->cmd) { |
468 | 0 | case SC_PIN_CMD_VERIFY: |
469 | 0 | rv = lteid_pin_cmd_verify(card, data); |
470 | 0 | break; |
471 | 0 | case SC_PIN_CMD_GET_INFO: |
472 | 0 | rv = lteid_pin_cmd_get_info(card, data); |
473 | 0 | break; |
474 | 0 | case SC_PIN_CMD_UNBLOCK: |
475 | 0 | rv = lteid_pin_cmd_unblock(card, data); |
476 | 0 | break; |
477 | 0 | case SC_PIN_CMD_CHANGE: |
478 | 0 | rv = lteid_pin_cmd_change(card, data); |
479 | 0 | break; |
480 | 0 | default: |
481 | 0 | rv = SC_ERROR_NOT_SUPPORTED; |
482 | 0 | break; |
483 | 0 | } |
484 | | |
485 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
486 | 0 | } |
487 | | |
488 | | static int |
489 | | lteid_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num) |
490 | 0 | { |
491 | 0 | LOG_FUNC_CALLED(card->ctx); |
492 | |
|
493 | 0 | struct sc_apdu apdu; |
494 | 0 | int rv; |
495 | |
|
496 | 0 | if (env == NULL || env->key_ref_len != 1) |
497 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
498 | | |
499 | 0 | sc_log(card->ctx, "algo: %lu operation: %d keyref: %d", env->algorithm, env->operation, env->key_ref[0]); |
500 | |
|
501 | 0 | if (env->algorithm != SC_ALGORITHM_EC || env->operation != SC_SEC_OPERATION_SIGN) |
502 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
503 | | |
504 | 0 | const u8 data[] = {0x84, 0x01, env->key_ref[0]}; |
505 | 0 | sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x41, 0xB6, data, sizeof(data), NULL, 0); |
506 | |
|
507 | 0 | rv = sc_transmit_apdu(card, &apdu); |
508 | 0 | LOG_TEST_RET(card->ctx, rv, "APDU transmit failed"); |
509 | | |
510 | 0 | rv = sc_check_sw(card, apdu.sw1, apdu.sw2); |
511 | 0 | LOG_TEST_RET(card->ctx, rv, "SET SECURITY ENV failed"); |
512 | | |
513 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
514 | 0 | } |
515 | | |
516 | | static int |
517 | | lteid_compute_signature(struct sc_card *card, const u8 *data, size_t data_len, u8 *out, size_t outlen) |
518 | 0 | { |
519 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
520 | | |
521 | | // Usually this is called with 104 bytes buffer. But we expect card to return 96 byte hash. |
522 | 0 | if (outlen < 96) |
523 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); |
524 | | |
525 | 0 | memset(out, 0, outlen); |
526 | |
|
527 | 0 | const int rv = iso_ops->compute_signature(card, data, data_len, out, 96); |
528 | |
|
529 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
530 | 0 | } |
531 | | |
532 | | static int |
533 | | lteid_process_fci(struct sc_card *card, struct sc_file *file, const u8 *buf, size_t buflen) |
534 | 0 | { |
535 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
536 | |
|
537 | 0 | int rv = iso_ops->process_fci(card, file, buf, buflen); |
538 | |
|
539 | 0 | if (rv != SC_SUCCESS) { |
540 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
541 | 0 | } |
542 | | |
543 | | // Card reports most of the file size as 0, even if they're not empty. |
544 | | // This confuses PKCS#15 loader, and it fails to load/init keys/certs/pins/etc. |
545 | | // As a quick workaround - lets report size to be something large enough to fit any object. |
546 | 0 | if (file->size == 0) { |
547 | 0 | file->size = 2048; |
548 | 0 | } |
549 | |
|
550 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
551 | 0 | } |
552 | | |
553 | | struct sc_card_driver * |
554 | | sc_get_lteid_driver(void) |
555 | 13.3k | { |
556 | 13.3k | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
557 | | |
558 | 13.3k | if (iso_ops == NULL) |
559 | 1 | iso_ops = iso_drv->ops; |
560 | | |
561 | 13.3k | lteid_ops = *iso_ops; |
562 | 13.3k | lteid_ops.init = lteid_init; |
563 | 13.3k | lteid_ops.finish = lteid_finish; |
564 | 13.3k | lteid_ops.set_security_env = lteid_set_security_env; |
565 | 13.3k | lteid_ops.compute_signature = lteid_compute_signature; |
566 | 13.3k | lteid_ops.pin_cmd = lteid_pin_cmd; |
567 | 13.3k | lteid_ops.logout = lteid_logout; |
568 | 13.3k | lteid_ops.process_fci = lteid_process_fci; |
569 | | |
570 | 13.3k | return <eid_drv; |
571 | 13.3k | } |
572 | | |
573 | | #else |
574 | | |
575 | | #include "opensc.h" |
576 | | |
577 | | struct sc_card_driver * |
578 | | sc_get_lteid_driver(void) |
579 | | { |
580 | | return NULL; |
581 | | } |
582 | | |
583 | | #endif |