/src/opensc/src/libopensc/card.c
Line | Count | Source |
1 | | /* |
2 | | * card.c: General smart card functions |
3 | | * |
4 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
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 <assert.h> |
26 | | #include <stdlib.h> |
27 | | #ifdef HAVE_UNISTD_H |
28 | | #include <unistd.h> |
29 | | #endif |
30 | | #include <string.h> |
31 | | #include <limits.h> |
32 | | |
33 | | #include "reader-tr03119.h" |
34 | | #include "internal.h" |
35 | | #include "asn1.h" |
36 | | #include "common/compat_strlcpy.h" |
37 | | |
38 | | #ifdef ENABLE_SM |
39 | | static int sc_card_sm_load(sc_card_t *card, const char *path, const char *module); |
40 | | static int sc_card_sm_unload(sc_card_t *card); |
41 | | static int sc_card_sm_check(sc_card_t *card); |
42 | | #endif |
43 | | |
44 | | int sc_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2) |
45 | 425k | { |
46 | 425k | if (card == NULL) |
47 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
48 | 425k | if (card->ops->check_sw == NULL) |
49 | 0 | return SC_ERROR_NOT_SUPPORTED; |
50 | 425k | return card->ops->check_sw(card, sw1, sw2); |
51 | 425k | } |
52 | | |
53 | | void sc_format_apdu(sc_card_t *card, sc_apdu_t *apdu, |
54 | | int cse, int ins, int p1, int p2) |
55 | 492k | { |
56 | 492k | if (card == NULL || apdu == NULL) { |
57 | 0 | return; |
58 | 0 | } |
59 | 492k | memset(apdu, 0, sizeof(*apdu)); |
60 | 492k | apdu->cla = (u8) card->cla; |
61 | 492k | apdu->cse = cse; |
62 | 492k | apdu->ins = (u8) ins; |
63 | 492k | apdu->p1 = (u8) p1; |
64 | 492k | apdu->p2 = (u8) p2; |
65 | 492k | } |
66 | | |
67 | | void sc_format_apdu_cse_lc_le(struct sc_apdu *apdu) |
68 | 5.63k | { |
69 | | /* TODO calculating the APDU case, Lc and Le should actually only be |
70 | | * done in sc_apdu2bytes, but to gradually change OpenSC we start here. */ |
71 | | /* Let sc_detect_apdu_cse set short or extended and test for chaining */ |
72 | | |
73 | 5.63k | if (!apdu) |
74 | 0 | return; |
75 | 5.63k | if (apdu->datalen > SC_MAX_APDU_DATA_SIZE |
76 | 5.63k | || apdu->resplen > SC_MAX_APDU_RESP_SIZE) { |
77 | | /* extended length or data chaining and/or get response */ |
78 | 96 | if (apdu->datalen <= SC_MAX_EXT_APDU_DATA_SIZE) |
79 | 96 | apdu->lc = apdu->datalen; |
80 | 96 | if (apdu->resplen <= SC_MAX_EXT_APDU_RESP_SIZE) |
81 | 96 | apdu->le = apdu->resplen; |
82 | 96 | if (apdu->resplen && !apdu->datalen) |
83 | 96 | apdu->cse = SC_APDU_CASE_2; |
84 | 96 | if (!apdu->resplen && apdu->datalen) |
85 | 0 | apdu->cse = SC_APDU_CASE_3; |
86 | 96 | if (apdu->resplen && apdu->datalen) |
87 | 0 | apdu->cse = SC_APDU_CASE_4; |
88 | 5.54k | } else { |
89 | | /* short length */ |
90 | 5.54k | if (apdu->datalen <= SC_MAX_APDU_DATA_SIZE) |
91 | 5.54k | apdu->lc = apdu->datalen; |
92 | 5.54k | if (apdu->resplen <= SC_MAX_APDU_RESP_SIZE) |
93 | 5.54k | apdu->le = apdu->resplen; |
94 | 5.54k | if (!apdu->resplen && !apdu->datalen) |
95 | 170 | apdu->cse = SC_APDU_CASE_1; |
96 | 5.54k | if (apdu->resplen && !apdu->datalen) |
97 | 1.36k | apdu->cse = SC_APDU_CASE_2_SHORT; |
98 | 5.54k | if (!apdu->resplen && apdu->datalen) |
99 | 2.73k | apdu->cse = SC_APDU_CASE_3_SHORT; |
100 | 5.54k | if (apdu->resplen && apdu->datalen) |
101 | 1.27k | apdu->cse = SC_APDU_CASE_4_SHORT; |
102 | 5.54k | } |
103 | 5.63k | } |
104 | | |
105 | | void sc_format_apdu_ex(struct sc_apdu *apdu, |
106 | | u8 cla, u8 ins, u8 p1, u8 p2, |
107 | | const u8 *data, size_t datalen, |
108 | | u8 *resp, size_t resplen) |
109 | 5.63k | { |
110 | 5.63k | if (!apdu) { |
111 | 0 | return; |
112 | 0 | } |
113 | | |
114 | 5.63k | memset(apdu, 0, sizeof(*apdu)); |
115 | 5.63k | apdu->cla = cla; |
116 | 5.63k | apdu->ins = ins; |
117 | 5.63k | apdu->p1 = p1; |
118 | 5.63k | apdu->p2 = p2; |
119 | 5.63k | apdu->resp = resp; |
120 | 5.63k | apdu->resplen = resplen; |
121 | 5.63k | apdu->data = data; |
122 | 5.63k | apdu->datalen = datalen; |
123 | 5.63k | sc_format_apdu_cse_lc_le(apdu); |
124 | 5.63k | } |
125 | | |
126 | | static sc_card_t * sc_card_new(sc_context_t *ctx) |
127 | 14.4k | { |
128 | 14.4k | sc_card_t *card; |
129 | | |
130 | 14.4k | if (ctx == NULL) |
131 | 0 | return NULL; |
132 | | |
133 | 14.4k | card = calloc(1, sizeof(struct sc_card)); |
134 | 14.4k | if (card == NULL) |
135 | 0 | return NULL; |
136 | 14.4k | card->ops = malloc(sizeof(struct sc_card_operations)); |
137 | 14.4k | if (card->ops == NULL) { |
138 | 0 | free(card); |
139 | 0 | return NULL; |
140 | 0 | } |
141 | | |
142 | 14.4k | card->ctx = ctx; |
143 | 14.4k | if (sc_mutex_create(ctx, &card->mutex) != SC_SUCCESS) { |
144 | 0 | free(card->ops); |
145 | 0 | free(card); |
146 | 0 | return NULL; |
147 | 0 | } |
148 | | |
149 | 14.4k | card->type = -1; |
150 | 14.4k | card->app_count = -1; |
151 | | |
152 | 14.4k | return card; |
153 | 14.4k | } |
154 | | |
155 | | static void sc_card_free(sc_card_t *card) |
156 | 14.4k | { |
157 | 14.4k | sc_free_apps(card); |
158 | 14.4k | sc_free_ef_atr(card); |
159 | | |
160 | 14.4k | free(card->ops); |
161 | | |
162 | 14.4k | if (card->algorithms != NULL) { |
163 | 10.0k | int i; |
164 | 53.2k | for (i=0; i<card->algorithm_count; i++) { |
165 | 43.2k | struct sc_algorithm_info *info = (card->algorithms + i); |
166 | 43.2k | if (info->algorithm == SC_ALGORITHM_EC || |
167 | 36.7k | info->algorithm == SC_ALGORITHM_EDDSA || |
168 | 36.5k | info->algorithm == SC_ALGORITHM_XEDDSA) { |
169 | 8.45k | sc_clear_ec_params(&info->u._ec.params); |
170 | 8.45k | } |
171 | 43.2k | } |
172 | 10.0k | free(card->algorithms); |
173 | | |
174 | 10.0k | card->algorithms = NULL; |
175 | 10.0k | card->algorithm_count = 0; |
176 | 10.0k | } |
177 | | |
178 | 14.4k | if (card->mutex != NULL) { |
179 | 0 | int r = sc_mutex_destroy(card->ctx, card->mutex); |
180 | 0 | if (r != SC_SUCCESS) |
181 | 0 | sc_log(card->ctx, "unable to destroy mutex"); |
182 | 0 | } |
183 | 14.4k | sc_mem_clear(card, sizeof(*card)); |
184 | 14.4k | free(card); |
185 | 14.4k | } |
186 | | |
187 | | size_t sc_get_max_recv_size(const sc_card_t *card) |
188 | 294k | { |
189 | 294k | size_t max_recv_size; |
190 | 294k | if (card == NULL || card->reader == NULL) { |
191 | 0 | return 0; |
192 | 0 | } |
193 | 294k | max_recv_size = card->max_recv_size; |
194 | | |
195 | | /* initialize max_recv_size to a meaningful value */ |
196 | 294k | if (card->caps & SC_CARD_CAP_APDU_EXT) { |
197 | 55.5k | if (!max_recv_size) |
198 | 2.18k | max_recv_size = 65536; |
199 | 239k | } else { |
200 | 239k | if (!max_recv_size) |
201 | 164k | max_recv_size = 256; |
202 | 239k | } |
203 | | |
204 | | /* Override card limitations with reader limitations. */ |
205 | 294k | if (card->reader->max_recv_size != 0 |
206 | 7.21k | && (card->reader->max_recv_size < card->max_recv_size)) |
207 | 0 | max_recv_size = card->reader->max_recv_size; |
208 | | |
209 | 294k | return max_recv_size; |
210 | 294k | } |
211 | | |
212 | | size_t sc_get_max_send_size(const sc_card_t *card) |
213 | 60.9k | { |
214 | 60.9k | size_t max_send_size; |
215 | | |
216 | 60.9k | if (card == NULL || card->reader == NULL) { |
217 | 0 | return 0; |
218 | 0 | } |
219 | | |
220 | 60.9k | max_send_size = card->max_send_size; |
221 | | |
222 | | /* initialize max_send_size to a meaningful value */ |
223 | 60.9k | if (card->caps & SC_CARD_CAP_APDU_EXT |
224 | 25.1k | && card->reader->active_protocol != SC_PROTO_T0) { |
225 | 25.1k | if (!max_send_size) |
226 | 1.20k | max_send_size = 65535; |
227 | 35.8k | } else { |
228 | 35.8k | if (!max_send_size) |
229 | 10.5k | max_send_size = 255; |
230 | 35.8k | } |
231 | | |
232 | | /* Override card limitations with reader limitations. */ |
233 | 60.9k | if (card->reader->max_send_size != 0 |
234 | 0 | && (card->reader->max_send_size < card->max_send_size)) |
235 | 0 | max_send_size = card->reader->max_send_size; |
236 | | |
237 | 60.9k | return max_send_size; |
238 | 60.9k | } |
239 | | |
240 | | int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out) |
241 | 14.4k | { |
242 | 14.4k | sc_card_t *card; |
243 | 14.4k | sc_context_t *ctx; |
244 | 14.4k | struct sc_card_driver *driver; |
245 | 14.4k | int i, r = 0, idx, connected = 0; |
246 | | |
247 | 14.4k | if (card_out == NULL || reader == NULL) |
248 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
249 | 14.4k | ctx = reader->ctx; |
250 | 14.4k | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
251 | 14.4k | if (reader->ops->connect == NULL) |
252 | 14.4k | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
253 | | |
254 | 14.4k | card = sc_card_new(ctx); |
255 | 14.4k | if (card == NULL) |
256 | 14.4k | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
257 | 14.4k | r = reader->ops->connect(reader); |
258 | 14.4k | if (r) |
259 | 0 | goto err; |
260 | | |
261 | 14.4k | connected = 1; |
262 | 14.4k | card->reader = reader; |
263 | 14.4k | card->ctx = ctx; |
264 | | |
265 | 14.4k | if (reader->flags & SC_READER_ENABLE_ESCAPE) |
266 | 0 | sc_detect_escape_cmds(reader); |
267 | | |
268 | 14.4k | memcpy(&card->atr, &reader->atr, sizeof(card->atr)); |
269 | 14.4k | memcpy(&card->uid, &reader->uid, sizeof(card->uid)); |
270 | | |
271 | 14.4k | _sc_parse_atr(reader); |
272 | | |
273 | | /* See if the ATR matches any ATR specified in the config file */ |
274 | 14.4k | if ((driver = ctx->forced_driver) == NULL) { |
275 | 14.4k | sc_log(ctx, "matching configured ATRs"); |
276 | 620k | for (i = 0; ctx->card_drivers[i] != NULL; i++) { |
277 | 606k | driver = ctx->card_drivers[i]; |
278 | | |
279 | 606k | if (driver->atr_map == NULL || |
280 | 606k | !strcmp(driver->short_name, "default")) { |
281 | 606k | driver = NULL; |
282 | 606k | continue; |
283 | 606k | } |
284 | 0 | sc_log(ctx, "trying driver '%s'", driver->short_name); |
285 | 0 | idx = _sc_match_atr(card, driver->atr_map, NULL); |
286 | 0 | if (idx >= 0) { |
287 | 0 | struct sc_atr_table *src = &driver->atr_map[idx]; |
288 | |
|
289 | 0 | sc_log(ctx, "matched driver '%s'", driver->name); |
290 | | /* It's up to card driver to notice these correctly */ |
291 | 0 | card->name = src->name; |
292 | 0 | card->type = src->type; |
293 | 0 | card->flags = src->flags; |
294 | 0 | break; |
295 | 0 | } |
296 | 0 | driver = NULL; |
297 | 0 | } |
298 | 14.4k | } |
299 | | |
300 | 14.4k | if (driver != NULL) { |
301 | | /* Forced driver, or matched via ATR mapping from config file */ |
302 | 0 | card->driver = driver; |
303 | |
|
304 | 0 | memcpy(card->ops, card->driver->ops, sizeof(struct sc_card_operations)); |
305 | 0 | if (card->ops->match_card != NULL) |
306 | 0 | if (card->ops->match_card(card) != 1) |
307 | 0 | sc_log(ctx, "driver '%s' match_card() failed: %s (will continue anyway)", card->driver->name, sc_strerror(r)); |
308 | |
|
309 | 0 | if (card->ops->init != NULL) { |
310 | 0 | r = card->ops->init(card); |
311 | 0 | if (r) { |
312 | 0 | sc_log(ctx, "driver '%s' init() failed: %s", card->driver->name, sc_strerror(r)); |
313 | 0 | goto err; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | } |
317 | 14.4k | else { |
318 | 14.4k | sc_card_t uninitialized = *card; |
319 | 14.4k | sc_log(ctx, "matching built-in ATRs"); |
320 | 345k | for (i = 0; ctx->card_drivers[i] != NULL; i++) { |
321 | | /* FIXME If we had a clean API description, we'd probably get a |
322 | | * cleaner implementation of the driver's match_card and init, |
323 | | * which should normally *not* modify the card object if |
324 | | * unsuccessful. However, after years of relentless hacking, reality |
325 | | * is different: The card object is changed in virtually every card |
326 | | * driver so in order to prevent unwanted interaction, we reset the |
327 | | * card object here and hope that the card driver at least doesn't |
328 | | * allocate any internal resources that need to be freed. If we |
329 | | * had more time, we should refactor the existing code to not |
330 | | * modify sc_card_t until complete success (possibly by combining |
331 | | * `match_card()` and `init()`) */ |
332 | 343k | *card = uninitialized; |
333 | | |
334 | 343k | struct sc_card_driver *drv = ctx->card_drivers[i]; |
335 | 343k | const struct sc_card_operations *ops = drv->ops; |
336 | | |
337 | 343k | sc_log(ctx, "trying driver '%s'", drv->short_name); |
338 | 343k | if (ops == NULL || ops->match_card == NULL) { |
339 | 0 | continue; |
340 | 0 | } |
341 | 343k | else if (!(ctx->flags & SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER) |
342 | 343k | && !strcmp("default", drv->short_name)) { |
343 | 2.46k | sc_log(ctx , "ignore 'default' card driver"); |
344 | 2.46k | continue; |
345 | 2.46k | } |
346 | | |
347 | | /* Needed if match_card() needs to talk with the card (e.g. card-muscle) */ |
348 | 340k | *card->ops = *ops; |
349 | 340k | if (ops->match_card(card) != 1) |
350 | 327k | continue; |
351 | 12.8k | sc_log(ctx, "matched: %s", drv->name); |
352 | 12.8k | memcpy(card->ops, ops, sizeof(struct sc_card_operations)); |
353 | 12.8k | card->driver = drv; |
354 | 12.8k | r = ops->init(card); |
355 | 12.8k | if (r) { |
356 | 1.71k | sc_log(ctx, "driver '%s' init() failed: %s", drv->name, sc_strerror(r)); |
357 | 1.71k | if (r == SC_ERROR_INVALID_CARD) { |
358 | 929 | card->driver = NULL; |
359 | 929 | continue; |
360 | 929 | } |
361 | 784 | goto err; |
362 | 1.71k | } |
363 | 11.1k | break; |
364 | 12.8k | } |
365 | 14.4k | } |
366 | 13.6k | if (card->driver == NULL) { |
367 | 2.46k | sc_log(ctx, "unable to find driver for inserted card"); |
368 | 2.46k | r = SC_ERROR_INVALID_CARD; |
369 | 2.46k | goto err; |
370 | 2.46k | } |
371 | 11.1k | if (card->name == NULL) |
372 | 2.50k | card->name = card->driver->name; |
373 | | |
374 | | /* initialize max_send_size/max_recv_size to a meaningful value */ |
375 | 11.1k | card->max_recv_size = sc_get_max_recv_size(card); |
376 | 11.1k | card->max_send_size = sc_get_max_send_size(card); |
377 | | |
378 | 11.1k | sc_log(ctx, |
379 | 11.1k | "card info name:'%s', type:%i, flags:0x%lX, max_send/recv_size:%"SC_FORMAT_LEN_SIZE_T"u/%"SC_FORMAT_LEN_SIZE_T"u", |
380 | 11.1k | card->name, card->type, card->flags, card->max_send_size, |
381 | 11.1k | card->max_recv_size); |
382 | | |
383 | 11.1k | #ifdef ENABLE_SM |
384 | | /* Check, if secure messaging module present. */ |
385 | 11.1k | r = sc_card_sm_check(card); |
386 | 11.1k | if (r) { |
387 | 0 | sc_log(ctx, "cannot load secure messaging module"); |
388 | 0 | goto err; |
389 | 0 | } |
390 | 11.1k | #endif |
391 | 11.1k | *card_out = card; |
392 | | |
393 | 11.1k | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
394 | 3.24k | err: |
395 | 3.24k | if (connected) |
396 | 3.24k | reader->ops->disconnect(reader); |
397 | 3.24k | if (card != NULL) |
398 | 3.24k | sc_card_free(card); |
399 | 3.24k | LOG_FUNC_RETURN(ctx, r); |
400 | 3.24k | } |
401 | | |
402 | | int sc_disconnect_card(sc_card_t *card) |
403 | 14.4k | { |
404 | 14.4k | sc_context_t *ctx; |
405 | | |
406 | 14.4k | if (!card) |
407 | 3.24k | return SC_ERROR_INVALID_ARGUMENTS; |
408 | | |
409 | 11.1k | ctx = card->ctx; |
410 | 11.1k | LOG_FUNC_CALLED(ctx); |
411 | | |
412 | 11.1k | if (card->ops->finish) { |
413 | 10.6k | int r = card->ops->finish(card); |
414 | 10.6k | if (r) |
415 | 480 | sc_log(ctx, "card driver finish() failed: %s", sc_strerror(r)); |
416 | 10.6k | } |
417 | | |
418 | 11.1k | if (card->reader->ops->disconnect) { |
419 | 11.1k | int r = card->reader->ops->disconnect(card->reader); |
420 | 11.1k | if (r) |
421 | 0 | sc_log(ctx, "disconnect() failed: %s", sc_strerror(r)); |
422 | 11.1k | } |
423 | | |
424 | 11.1k | #ifdef ENABLE_SM |
425 | | /* release SM related resources */ |
426 | 11.1k | sc_card_sm_unload(card); |
427 | 11.1k | #endif |
428 | | |
429 | 11.1k | sc_card_free(card); |
430 | 11.1k | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
431 | 11.1k | } |
432 | | |
433 | | int sc_reset(sc_card_t *card, int do_cold_reset) |
434 | 0 | { |
435 | 0 | int r, r2; |
436 | |
|
437 | 0 | if (card == NULL) |
438 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
439 | 0 | if (card->reader->ops->reset == NULL) |
440 | 0 | return SC_ERROR_NOT_SUPPORTED; |
441 | | |
442 | 0 | r = sc_mutex_lock(card->ctx, card->mutex); |
443 | 0 | if (r != SC_SUCCESS) |
444 | 0 | return r; |
445 | | |
446 | 0 | r = card->reader->ops->reset(card->reader, do_cold_reset); |
447 | |
|
448 | 0 | r2 = sc_mutex_unlock(card->ctx, card->mutex); |
449 | 0 | if (r2 != SC_SUCCESS) { |
450 | 0 | sc_log(card->ctx, "unable to release lock"); |
451 | 0 | r = r != SC_SUCCESS ? r : r2; |
452 | 0 | } |
453 | |
|
454 | 0 | return r; |
455 | 0 | } |
456 | | |
457 | | int sc_lock(sc_card_t *card) |
458 | 560k | { |
459 | 560k | int r = 0, r2 = 0; |
460 | 560k | int was_reset = 0; |
461 | 560k | int reader_lock_obtained = 0; |
462 | | |
463 | 560k | if (card == NULL) |
464 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
465 | | |
466 | 560k | LOG_FUNC_CALLED(card->ctx); |
467 | | |
468 | 560k | r = sc_mutex_lock(card->ctx, card->mutex); |
469 | 560k | if (r != SC_SUCCESS) |
470 | 0 | return r; |
471 | 560k | if (card->lock_count == 0) { |
472 | 261k | if (card->reader->ops->lock != NULL) { |
473 | 261k | r = card->reader->ops->lock(card->reader); |
474 | 261k | while (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) { |
475 | 0 | if (was_reset++ > 4) /* TODO retry a few times */ |
476 | 0 | break; |
477 | 0 | r = card->reader->ops->lock(card->reader); |
478 | 0 | } |
479 | 261k | if (r == 0) |
480 | 261k | reader_lock_obtained = 1; |
481 | 261k | } |
482 | 261k | } |
483 | 560k | if (r == 0) |
484 | 560k | card->lock_count++; |
485 | | |
486 | 560k | r2 = sc_mutex_unlock(card->ctx, card->mutex); |
487 | 560k | if (r2 != SC_SUCCESS) { |
488 | 0 | sc_log(card->ctx, "unable to release card->mutex lock"); |
489 | 0 | r = r != SC_SUCCESS ? r : r2; |
490 | 0 | } |
491 | | |
492 | 560k | if (r == 0 && was_reset > 0) { |
493 | 0 | #ifdef ENABLE_SM |
494 | 0 | if (card->sm_ctx.ops.open) |
495 | 0 | card->sm_ctx.ops.open(card); |
496 | 0 | #endif |
497 | 0 | } |
498 | | |
499 | | /* give card driver a chance to do something when reader lock first obtained */ |
500 | 560k | if (r == 0 && reader_lock_obtained == 1 && card->ops->card_reader_lock_obtained) { |
501 | 56.4k | if (SC_SUCCESS != card->ops->card_reader_lock_obtained(card, was_reset)) |
502 | 482 | sc_log(card->ctx, "card_reader_lock_obtained failed"); |
503 | 56.4k | } |
504 | | |
505 | 560k | LOG_FUNC_RETURN(card->ctx, r); |
506 | 560k | } |
507 | | |
508 | | int sc_unlock(sc_card_t *card) |
509 | 560k | { |
510 | 560k | int r, r2; |
511 | | |
512 | 560k | if (!card) |
513 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
514 | | |
515 | 560k | LOG_FUNC_CALLED(card->ctx); |
516 | | |
517 | 560k | r = sc_mutex_lock(card->ctx, card->mutex); |
518 | 560k | if (r != SC_SUCCESS) |
519 | 560k | LOG_FUNC_RETURN(card->ctx, r); |
520 | | |
521 | 560k | if (card->lock_count < 1) { |
522 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
523 | 0 | } |
524 | 560k | if (--card->lock_count == 0) { |
525 | | /* release reader lock */ |
526 | 261k | if (card->reader->ops->unlock != NULL) |
527 | 261k | r = card->reader->ops->unlock(card->reader); |
528 | 261k | } |
529 | 560k | r2 = sc_mutex_unlock(card->ctx, card->mutex); |
530 | 560k | if (r2 != SC_SUCCESS) { |
531 | 0 | sc_log(card->ctx, "unable to release lock"); |
532 | 0 | r = (r == SC_SUCCESS) ? r2 : r; |
533 | 0 | } |
534 | | |
535 | 560k | return r; |
536 | 560k | } |
537 | | |
538 | | int sc_list_files(sc_card_t *card, u8 *buf, size_t buflen) |
539 | 0 | { |
540 | 0 | int r; |
541 | |
|
542 | 0 | if (card == NULL) { |
543 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
544 | 0 | } |
545 | 0 | LOG_FUNC_CALLED(card->ctx); |
546 | |
|
547 | 0 | if (card->ops->list_files == NULL) |
548 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
549 | 0 | r = card->ops->list_files(card, buf, buflen); |
550 | |
|
551 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
552 | 0 | } |
553 | | |
554 | | int sc_create_file(sc_card_t *card, sc_file_t *file) |
555 | 0 | { |
556 | 0 | int r; |
557 | 0 | char pbuf[SC_MAX_PATH_STRING_SIZE]; |
558 | 0 | const sc_path_t *in_path; |
559 | |
|
560 | 0 | if (card == NULL || file == NULL) { |
561 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
562 | 0 | } |
563 | | |
564 | 0 | in_path = &file->path; |
565 | 0 | r = sc_path_print(pbuf, sizeof(pbuf), in_path); |
566 | 0 | if (r != SC_SUCCESS) |
567 | 0 | pbuf[0] = '\0'; |
568 | |
|
569 | 0 | sc_log(card->ctx, |
570 | 0 | "called; type=%d, path=%s, id=%04i, size=%"SC_FORMAT_LEN_SIZE_T"u", |
571 | 0 | in_path->type, pbuf, file->id, file->size); |
572 | | /* ISO 7816-4: "Number of data bytes in the file, including structural information if any" |
573 | | * can not be bigger than two bytes */ |
574 | 0 | if (file->size > 0xFFFF) |
575 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
576 | | |
577 | 0 | if (card->ops->create_file == NULL) |
578 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
579 | | |
580 | 0 | r = card->ops->create_file(card, file); |
581 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
582 | 0 | } |
583 | | |
584 | | int sc_delete_file(sc_card_t *card, const sc_path_t *path) |
585 | 0 | { |
586 | 0 | int r; |
587 | 0 | char pbuf[SC_MAX_PATH_STRING_SIZE]; |
588 | |
|
589 | 0 | if (card == NULL) { |
590 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
591 | 0 | } |
592 | | |
593 | 0 | r = sc_path_print(pbuf, sizeof(pbuf), path); |
594 | 0 | if (r != SC_SUCCESS) |
595 | 0 | pbuf[0] = '\0'; |
596 | |
|
597 | 0 | sc_log(card->ctx, "called; type=%d, path=%s", path->type, pbuf); |
598 | 0 | if (card->ops->delete_file == NULL) |
599 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
600 | 0 | r = card->ops->delete_file(card, path); |
601 | |
|
602 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
603 | 0 | } |
604 | | |
605 | | int sc_read_binary(sc_card_t *card, unsigned int idx, |
606 | | unsigned char *buf, size_t count, unsigned long *flags) |
607 | 9.45k | { |
608 | 9.45k | size_t max_le = sc_get_max_recv_size(card); |
609 | 9.45k | size_t todo = count; |
610 | 9.45k | int r; |
611 | | |
612 | 9.45k | if (card == NULL || card->ops == NULL || buf == NULL) { |
613 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
614 | 0 | } |
615 | 9.45k | sc_log(card->ctx, "called; %"SC_FORMAT_LEN_SIZE_T"u bytes at index %d", |
616 | 9.45k | count, idx); |
617 | 9.45k | if (count == 0) |
618 | 9.45k | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
619 | | |
620 | 9.27k | #ifdef ENABLE_SM |
621 | 9.27k | if (card->sm_ctx.ops.read_binary) { |
622 | 271 | r = card->sm_ctx.ops.read_binary(card, idx, buf, count); |
623 | 271 | if (r) |
624 | 271 | LOG_FUNC_RETURN(card->ctx, r); |
625 | 271 | } |
626 | 9.08k | #endif |
627 | | |
628 | 9.08k | if (card->ops->read_binary == NULL) |
629 | 9.08k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
630 | | |
631 | | /* lock the card now to avoid deselection of the file */ |
632 | 9.08k | r = sc_lock(card); |
633 | 9.08k | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
634 | | |
635 | 36.7k | while (todo > 0) { |
636 | 35.1k | size_t chunk = MIN(todo, max_le); |
637 | | |
638 | 35.1k | r = card->ops->read_binary(card, idx, buf, chunk, flags); |
639 | 35.1k | if (r == 0 || r == SC_ERROR_FILE_END_REACHED) |
640 | 1.70k | break; |
641 | 33.4k | if (r < 0 && todo != count) { |
642 | | /* the last command failed, but previous ones succeeded. |
643 | | * Let's just return what we've successfully read. */ |
644 | 4.17k | sc_log(card->ctx, "Subsequent read failed with %d, returning what was read successfully.", r); |
645 | 4.17k | break; |
646 | 4.17k | } |
647 | 29.2k | if (r < 0) { |
648 | 1.64k | sc_unlock(card); |
649 | 1.64k | LOG_FUNC_RETURN(card->ctx, r); |
650 | 1.64k | } |
651 | 27.6k | if ((idx > SIZE_MAX - (size_t) r) || (size_t) r > todo) { |
652 | | /* `idx + r` or `todo - r` would overflow */ |
653 | 0 | sc_unlock(card); |
654 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OFFSET_TOO_LARGE); |
655 | 0 | } |
656 | | |
657 | 27.6k | todo -= (size_t) r; |
658 | 27.6k | buf += (size_t) r; |
659 | 27.6k | idx += (size_t) r; |
660 | 27.6k | } |
661 | | |
662 | 7.43k | sc_unlock(card); |
663 | | |
664 | 7.43k | LOG_FUNC_RETURN(card->ctx, (int)(count - todo)); |
665 | 7.43k | } |
666 | | |
667 | | int sc_write_binary(sc_card_t *card, unsigned int idx, |
668 | | const u8 *buf, size_t count, unsigned long flags) |
669 | 0 | { |
670 | 0 | size_t max_lc = sc_get_max_send_size(card); |
671 | 0 | size_t todo = count; |
672 | 0 | int r; |
673 | |
|
674 | 0 | if (card == NULL || card->ops == NULL || buf == NULL) { |
675 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
676 | 0 | } |
677 | 0 | sc_log(card->ctx, "called; %"SC_FORMAT_LEN_SIZE_T"u bytes at index %d", |
678 | 0 | count, idx); |
679 | 0 | if (count == 0) |
680 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
681 | | |
682 | 0 | if (card->ops->write_binary == NULL) |
683 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
684 | | |
685 | | /* lock the card now to avoid deselection of the file */ |
686 | 0 | r = sc_lock(card); |
687 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
688 | | |
689 | 0 | while (todo > 0) { |
690 | 0 | size_t chunk = MIN(todo, max_lc); |
691 | |
|
692 | 0 | r = card->ops->write_binary(card, idx, buf, chunk, flags); |
693 | 0 | if (r == 0 || r == SC_ERROR_FILE_END_REACHED) |
694 | 0 | break; |
695 | 0 | if (r < 0) { |
696 | 0 | sc_unlock(card); |
697 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
698 | 0 | } |
699 | 0 | if ((idx > SIZE_MAX - (size_t) r) || (size_t) r > todo) { |
700 | | /* `idx + r` or `todo - r` would overflow */ |
701 | 0 | sc_unlock(card); |
702 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OFFSET_TOO_LARGE); |
703 | 0 | } |
704 | | |
705 | 0 | todo -= (size_t) r; |
706 | 0 | buf += (size_t) r; |
707 | 0 | idx += (size_t) r; |
708 | 0 | } |
709 | | |
710 | 0 | sc_unlock(card); |
711 | |
|
712 | 0 | LOG_FUNC_RETURN(card->ctx, (int)(count - todo)); |
713 | 0 | } |
714 | | |
715 | | int sc_update_binary(sc_card_t *card, unsigned int idx, |
716 | | const u8 *buf, size_t count, unsigned long flags) |
717 | 0 | { |
718 | 0 | size_t max_lc = sc_get_max_send_size(card); |
719 | 0 | size_t todo = count; |
720 | 0 | int r; |
721 | |
|
722 | 0 | if (card == NULL || card->ops == NULL || buf == NULL) { |
723 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
724 | 0 | } |
725 | 0 | sc_log(card->ctx, "called; %"SC_FORMAT_LEN_SIZE_T"u bytes at index %d", |
726 | 0 | count, idx); |
727 | 0 | if (count == 0) |
728 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
729 | | |
730 | 0 | #ifdef ENABLE_SM |
731 | 0 | if (card->sm_ctx.ops.update_binary) { |
732 | 0 | r = card->sm_ctx.ops.update_binary(card, idx, buf, count); |
733 | 0 | if (r) |
734 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
735 | 0 | } |
736 | 0 | #endif |
737 | | |
738 | 0 | if (card->ops->update_binary == NULL) |
739 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
740 | | |
741 | | /* lock the card now to avoid deselection of the file */ |
742 | 0 | r = sc_lock(card); |
743 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
744 | | |
745 | 0 | while (todo > 0) { |
746 | 0 | size_t chunk = MIN(todo, max_lc); |
747 | |
|
748 | 0 | r = card->ops->update_binary(card, idx, buf, chunk, flags); |
749 | 0 | if (r == 0 || r == SC_ERROR_FILE_END_REACHED) |
750 | 0 | break; |
751 | 0 | if (r < 0) { |
752 | 0 | sc_unlock(card); |
753 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
754 | 0 | } |
755 | 0 | if ((idx > SIZE_MAX - (size_t) r) || (size_t) r > todo) { |
756 | | /* `idx + r` or `todo - r` would overflow */ |
757 | 0 | sc_unlock(card); |
758 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OFFSET_TOO_LARGE); |
759 | 0 | } |
760 | | |
761 | 0 | todo -= (size_t) r; |
762 | 0 | buf += (size_t) r; |
763 | 0 | idx += (size_t) r; |
764 | 0 | } |
765 | | |
766 | 0 | sc_unlock(card); |
767 | |
|
768 | 0 | LOG_FUNC_RETURN(card->ctx, (int)(count - todo)); |
769 | 0 | } |
770 | | |
771 | | |
772 | | int sc_erase_binary(struct sc_card *card, unsigned int idx, size_t count, unsigned long flags) |
773 | 0 | { |
774 | 0 | int r; |
775 | 0 | size_t todo = count; |
776 | |
|
777 | 0 | if (card == NULL || card->ops == NULL) { |
778 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
779 | 0 | } |
780 | 0 | sc_log(card->ctx, |
781 | 0 | "called; erase %"SC_FORMAT_LEN_SIZE_T"u bytes from offset %d", |
782 | 0 | count, idx); |
783 | 0 | if (count == 0) |
784 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
785 | | |
786 | 0 | if (card->ops->erase_binary == NULL) |
787 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
788 | | |
789 | | /* lock the card now to avoid deselection of the file */ |
790 | 0 | r = sc_lock(card); |
791 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
792 | | |
793 | 0 | while (todo > 0) { |
794 | 0 | r = card->ops->erase_binary(card, idx, todo, flags); |
795 | 0 | if (r == 0 || r == SC_ERROR_FILE_END_REACHED) |
796 | 0 | break; |
797 | 0 | if (r < 0) { |
798 | 0 | sc_unlock(card); |
799 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
800 | 0 | } |
801 | 0 | if ((idx > SIZE_MAX - (size_t) r) || (size_t) r > todo) { |
802 | | /* `idx + r` or `todo - r` would overflow */ |
803 | 0 | sc_unlock(card); |
804 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OFFSET_TOO_LARGE); |
805 | 0 | } |
806 | | |
807 | 0 | todo -= (size_t) r; |
808 | 0 | idx += (size_t) r; |
809 | 0 | } |
810 | | |
811 | 0 | sc_unlock(card); |
812 | |
|
813 | 0 | LOG_FUNC_RETURN(card->ctx, (int)(count - todo)); |
814 | 0 | } |
815 | | |
816 | | |
817 | | int sc_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file) |
818 | 83.2k | { |
819 | 83.2k | int r; |
820 | 83.2k | char pbuf[SC_MAX_PATH_STRING_SIZE]; |
821 | | |
822 | 83.2k | if (card == NULL || in_path == NULL) { |
823 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
824 | 0 | } |
825 | | |
826 | 83.2k | r = sc_path_print(pbuf, sizeof(pbuf), in_path); |
827 | 83.2k | if (r != SC_SUCCESS) |
828 | 72 | pbuf[0] = '\0'; |
829 | | |
830 | | /* FIXME We should be a bit less strict and let the upper layers do |
831 | | * the initialization (including reuse of existing file objects). We |
832 | | * implemented this here because we are lazy. */ |
833 | 83.2k | if (file != NULL) |
834 | 40.2k | *file = NULL; |
835 | | |
836 | 83.2k | sc_log(card->ctx, "called; type=%d, path=%s", in_path->type, pbuf); |
837 | 83.2k | if (in_path->len > SC_MAX_PATH_SIZE) |
838 | 83.2k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
839 | | |
840 | 83.2k | if (in_path->type == SC_PATH_TYPE_PATH) { |
841 | | /* Perform a sanity check */ |
842 | 58.8k | size_t i; |
843 | | |
844 | 58.8k | if ((in_path->len & 1) != 0) |
845 | 58.8k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
846 | | |
847 | 175k | for (i = 0; i < in_path->len/2; i++) { |
848 | 116k | u8 p1 = in_path->value[2*i], |
849 | 116k | p2 = in_path->value[2*i+1]; |
850 | | |
851 | 116k | if ((p1 == 0x3F && p2 == 0x00) && i != 0) |
852 | 116k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
853 | 116k | } |
854 | 58.7k | } |
855 | 83.2k | if (card->ops->select_file == NULL) |
856 | 83.2k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
857 | 83.2k | r = card->ops->select_file(card, in_path, file); |
858 | 83.2k | LOG_TEST_RET(card->ctx, r, "'SELECT' error"); |
859 | | |
860 | 16.7k | if (file) { |
861 | 9.88k | if (*file) |
862 | | /* Remember file path */ |
863 | 9.79k | (*file)->path = *in_path; |
864 | 89 | else |
865 | | /* FIXME We should be a bit less strict and let the upper layers do |
866 | | * the error checking. We implemented this here because we are |
867 | | * lazy. */ |
868 | 89 | r = SC_ERROR_INVALID_DATA; |
869 | 9.88k | } |
870 | | |
871 | 16.7k | LOG_FUNC_RETURN(card->ctx, r); |
872 | 16.7k | } |
873 | | |
874 | | |
875 | | int sc_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t len) |
876 | 5.14k | { |
877 | 5.14k | int r; |
878 | | |
879 | 5.14k | sc_log(card->ctx, "called, tag=%04x", tag); |
880 | 5.14k | if (card->ops->get_data == NULL) |
881 | 5.14k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
882 | 5.14k | r = card->ops->get_data(card, tag, buf, len); |
883 | | |
884 | 5.14k | LOG_FUNC_RETURN(card->ctx, r); |
885 | 5.14k | } |
886 | | |
887 | | int sc_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t len) |
888 | 0 | { |
889 | 0 | int r; |
890 | |
|
891 | 0 | sc_log(card->ctx,"called, tag=%04x", tag); |
892 | |
|
893 | 0 | if (card->ops->put_data == NULL) |
894 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
895 | 0 | r = card->ops->put_data(card, tag, buf, len); |
896 | |
|
897 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
898 | 0 | } |
899 | | |
900 | | int sc_get_challenge(sc_card_t *card, u8 *rnd, size_t len) |
901 | 0 | { |
902 | 0 | int r; |
903 | |
|
904 | 0 | if (len == 0) |
905 | 0 | return SC_SUCCESS; |
906 | | |
907 | 0 | if (card == NULL || rnd == NULL) { |
908 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
909 | 0 | } |
910 | | |
911 | 0 | LOG_FUNC_CALLED(card->ctx); |
912 | |
|
913 | 0 | if (card->ops == NULL || card->ops->get_challenge == NULL) |
914 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
915 | | |
916 | 0 | r = sc_lock(card); |
917 | 0 | if (r != SC_SUCCESS) |
918 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
919 | | |
920 | 0 | while (len > 0) { |
921 | 0 | r = card->ops->get_challenge(card, rnd, len); |
922 | 0 | if (r == 0) |
923 | 0 | r = SC_ERROR_INVALID_DATA; |
924 | 0 | if (r < 0) { |
925 | 0 | sc_unlock(card); |
926 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
927 | 0 | } |
928 | | |
929 | 0 | rnd += (size_t) r; |
930 | 0 | len -= (size_t) r; |
931 | 0 | } |
932 | | |
933 | 0 | sc_unlock(card); |
934 | |
|
935 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
936 | 0 | } |
937 | | |
938 | | int sc_read_record(sc_card_t *card, unsigned int rec_nr, unsigned int idx, |
939 | | u8 *buf ,size_t count, unsigned long flags) |
940 | 16.1k | { |
941 | 16.1k | size_t max_le = sc_get_max_recv_size(card); |
942 | 16.1k | size_t todo = count; |
943 | 16.1k | int r; |
944 | | |
945 | 16.1k | if (card == NULL || card->ops == NULL || buf == NULL) { |
946 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
947 | 0 | } |
948 | 16.1k | LOG_FUNC_CALLED(card->ctx); |
949 | 16.1k | if (count == 0) |
950 | 16.1k | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
951 | | |
952 | 12.7k | if (card->ops->read_record == NULL) |
953 | 12.7k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
954 | | |
955 | | /* lock the card now to avoid deselection of the file */ |
956 | 12.7k | r = sc_lock(card); |
957 | 12.7k | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
958 | | |
959 | 24.9k | while (todo > 0) { |
960 | 24.7k | size_t chunk = MIN(todo, max_le); |
961 | | |
962 | 24.7k | r = card->ops->read_record(card, rec_nr, idx, buf, chunk, flags); |
963 | 24.7k | if (r == 0 || r == SC_ERROR_FILE_END_REACHED) |
964 | 857 | break; |
965 | 23.9k | if (r < 0 && todo != count) { |
966 | | /* the last command failed, but previous ones succeeded. |
967 | | * Let's just return what we've successfully read. */ |
968 | 10.6k | sc_log(card->ctx, "Subsequent read failed with %d, returning what was read successfully.", r); |
969 | 10.6k | break; |
970 | 10.6k | } |
971 | 13.2k | if (r < 0) { |
972 | 1.01k | sc_unlock(card); |
973 | 1.01k | LOG_FUNC_RETURN(card->ctx, r); |
974 | 1.01k | } |
975 | 12.2k | if ((idx > SIZE_MAX - (size_t) r) || (size_t) r > todo) { |
976 | | /* `idx + r` or `todo - r` would overflow */ |
977 | 0 | sc_unlock(card); |
978 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OFFSET_TOO_LARGE); |
979 | 0 | } |
980 | | |
981 | 12.2k | todo -= (size_t) r; |
982 | 12.2k | buf += (size_t) r; |
983 | 12.2k | idx += (size_t) r; |
984 | 12.2k | } |
985 | | |
986 | 11.7k | sc_unlock(card); |
987 | | |
988 | 11.7k | LOG_FUNC_RETURN(card->ctx, (int)(count - todo)); |
989 | 11.7k | } |
990 | | |
991 | | int sc_write_record(sc_card_t *card, unsigned int rec_nr, const u8 * buf, |
992 | | size_t count, unsigned long flags) |
993 | 0 | { |
994 | 0 | int r; |
995 | |
|
996 | 0 | if (card == NULL) { |
997 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
998 | 0 | } |
999 | 0 | LOG_FUNC_CALLED(card->ctx); |
1000 | |
|
1001 | 0 | if (card->ops->write_record == NULL) |
1002 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1003 | | |
1004 | 0 | r = card->ops->write_record(card, rec_nr, buf, count, flags); |
1005 | 0 | if (r == SC_SUCCESS) { |
1006 | 0 | r = (int)count; |
1007 | 0 | } |
1008 | |
|
1009 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1010 | 0 | } |
1011 | | |
1012 | | int sc_append_record(sc_card_t *card, const u8 * buf, size_t count, |
1013 | | unsigned long flags) |
1014 | 0 | { |
1015 | 0 | int r; |
1016 | |
|
1017 | 0 | if (card == NULL) { |
1018 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1019 | 0 | } |
1020 | 0 | LOG_FUNC_CALLED(card->ctx); |
1021 | |
|
1022 | 0 | if (card->ops->append_record == NULL) |
1023 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1024 | | |
1025 | 0 | r = card->ops->append_record(card, buf, count, flags); |
1026 | 0 | if (r == SC_SUCCESS) { |
1027 | 0 | r = (int)count; |
1028 | 0 | } |
1029 | |
|
1030 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1031 | 0 | } |
1032 | | |
1033 | | int sc_update_record(sc_card_t *card, unsigned int rec_nr, unsigned int idx, |
1034 | | const u8 * buf, size_t count, unsigned long flags) |
1035 | 0 | { |
1036 | 0 | size_t max_lc = sc_get_max_send_size(card); |
1037 | 0 | size_t todo = count; |
1038 | 0 | int r; |
1039 | |
|
1040 | 0 | if (card == NULL || card->ops == NULL || buf == NULL) { |
1041 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1042 | 0 | } |
1043 | 0 | LOG_FUNC_CALLED(card->ctx); |
1044 | 0 | if (count == 0) |
1045 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1046 | | |
1047 | 0 | if (card->ops->update_record == NULL) |
1048 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1049 | | |
1050 | | /* lock the card now to avoid deselection of the file */ |
1051 | 0 | r = sc_lock(card); |
1052 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
1053 | | |
1054 | 0 | while (todo > 0) { |
1055 | 0 | size_t chunk = MIN(todo, max_lc); |
1056 | |
|
1057 | 0 | r = card->ops->update_record(card, rec_nr, idx, buf, chunk, flags); |
1058 | 0 | if (r == 0 || r == SC_ERROR_FILE_END_REACHED) |
1059 | 0 | break; |
1060 | 0 | if (r < 0) { |
1061 | 0 | sc_unlock(card); |
1062 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1063 | 0 | } |
1064 | 0 | if ((idx > SIZE_MAX - (size_t) r) || (size_t) r > todo) { |
1065 | | /* `idx + r` or `todo - r` would overflow */ |
1066 | 0 | sc_unlock(card); |
1067 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OFFSET_TOO_LARGE); |
1068 | 0 | } |
1069 | | |
1070 | 0 | todo -= (size_t) r; |
1071 | 0 | buf += (size_t) r; |
1072 | 0 | idx += (size_t) r; |
1073 | 0 | } |
1074 | | |
1075 | 0 | sc_unlock(card); |
1076 | |
|
1077 | 0 | LOG_FUNC_RETURN(card->ctx, (int)(count - todo)); |
1078 | 0 | } |
1079 | | |
1080 | | int sc_delete_record(sc_card_t *card, unsigned int rec_nr) |
1081 | 0 | { |
1082 | 0 | int r; |
1083 | |
|
1084 | 0 | if (card == NULL) { |
1085 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1086 | 0 | } |
1087 | 0 | LOG_FUNC_CALLED(card->ctx); |
1088 | |
|
1089 | 0 | if (card->ops->delete_record == NULL) |
1090 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1091 | | |
1092 | 0 | r = card->ops->delete_record(card, rec_nr); |
1093 | |
|
1094 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1095 | 0 | } |
1096 | | |
1097 | | int |
1098 | | sc_card_ctl(sc_card_t *card, unsigned long cmd, void *args) |
1099 | 94.7k | { |
1100 | 94.7k | int r = SC_ERROR_NOT_SUPPORTED; |
1101 | | |
1102 | 94.7k | if (card == NULL) { |
1103 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1104 | 0 | } |
1105 | 94.7k | sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "called with cmd=%lu\n", cmd); |
1106 | | |
1107 | 94.7k | if (card->ops->card_ctl != NULL) |
1108 | 94.4k | r = card->ops->card_ctl(card, cmd, args); |
1109 | | |
1110 | | /* suppress "not supported" error messages */ |
1111 | 94.7k | if (r == SC_ERROR_NOT_SUPPORTED) { |
1112 | 2.04k | sc_log(card->ctx, "card_ctl(%lu) not supported", cmd); |
1113 | 2.04k | return r; |
1114 | 2.04k | } |
1115 | 92.6k | LOG_FUNC_RETURN(card->ctx, r); |
1116 | 92.6k | } |
1117 | | |
1118 | | int _sc_card_add_algorithm(sc_card_t *card, const sc_algorithm_info_t *info) |
1119 | 43.2k | { |
1120 | 43.2k | sc_algorithm_info_t *p; |
1121 | | |
1122 | 43.2k | if (info == NULL) { |
1123 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1124 | 0 | } |
1125 | 43.2k | p = (sc_algorithm_info_t *) realloc(card->algorithms, (card->algorithm_count + 1) * sizeof(*info)); |
1126 | 43.2k | if (!p) { |
1127 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1128 | 0 | } |
1129 | 43.2k | card->algorithms = p; |
1130 | 43.2k | p += card->algorithm_count; |
1131 | 43.2k | card->algorithm_count++; |
1132 | 43.2k | *p = *info; |
1133 | 43.2k | return SC_SUCCESS; |
1134 | 43.2k | } |
1135 | | |
1136 | | int _sc_card_add_symmetric_alg(sc_card_t *card, unsigned int algorithm, |
1137 | | unsigned int key_length, unsigned long flags) |
1138 | 143 | { |
1139 | 143 | sc_algorithm_info_t info; |
1140 | | |
1141 | 143 | memset(&info, 0, sizeof(info)); |
1142 | 143 | info.algorithm = algorithm; |
1143 | 143 | info.key_length = key_length; |
1144 | 143 | info.flags = flags; |
1145 | | |
1146 | 143 | return _sc_card_add_algorithm(card, &info); |
1147 | 143 | } |
1148 | | |
1149 | | static int |
1150 | | _sc_card_add_ec_alg_int(sc_card_t *card, size_t key_length, |
1151 | | unsigned long flags, unsigned long ext_flags, |
1152 | | struct sc_object_id *curve_oid, |
1153 | | int algorithm) |
1154 | 8.45k | { |
1155 | 8.45k | sc_algorithm_info_t info; |
1156 | 8.45k | int r; |
1157 | | |
1158 | 8.45k | memset(&info, 0, sizeof(info)); |
1159 | 8.45k | sc_init_oid(&info.u._ec.params.id); |
1160 | | |
1161 | 8.45k | info.algorithm = algorithm; |
1162 | 8.45k | info.key_length = key_length; |
1163 | 8.45k | info.flags = flags; |
1164 | | |
1165 | 8.45k | info.u._ec.ext_flags = ext_flags; |
1166 | 8.45k | if (curve_oid) { |
1167 | 4.20k | info.u._ec.params.id = *curve_oid; |
1168 | 4.20k | r = sc_encode_oid(card->ctx, &info.u._ec.params.id, &info.u._ec.params.der.value, &info.u._ec.params.der.len); |
1169 | 4.20k | LOG_TEST_GOTO_ERR(card->ctx, r, "sc_encode_oid failed"); |
1170 | 4.20k | r = sc_pkcs15_fix_ec_parameters(card->ctx, &info.u._ec.params); |
1171 | 4.20k | LOG_TEST_GOTO_ERR(card->ctx, r, "sc_pkcs15_fix_ec_parameters failed"); |
1172 | 4.20k | } |
1173 | | |
1174 | 8.45k | r = _sc_card_add_algorithm(card, &info); |
1175 | 8.45k | return r; |
1176 | 0 | err: |
1177 | 0 | sc_clear_ec_params(&info.u._ec.params); |
1178 | 0 | return r; |
1179 | 8.45k | } |
1180 | | |
1181 | | int _sc_card_add_ec_alg(sc_card_t *card, size_t key_length, |
1182 | | unsigned long flags, unsigned long ext_flags, |
1183 | | struct sc_object_id *curve_oid) |
1184 | 6.44k | { |
1185 | 6.44k | return _sc_card_add_ec_alg_int(card, key_length, flags, ext_flags, |
1186 | 6.44k | curve_oid, SC_ALGORITHM_EC); |
1187 | 6.44k | } |
1188 | | |
1189 | | int _sc_card_add_eddsa_alg(sc_card_t *card, size_t key_length, |
1190 | | unsigned long flags, unsigned long ext_flags, |
1191 | | struct sc_object_id *curve_oid) |
1192 | 238 | { |
1193 | | /* For simplicity, share the ec union with the curve information */ |
1194 | 238 | return _sc_card_add_ec_alg_int(card, key_length, flags, ext_flags, |
1195 | 238 | curve_oid, SC_ALGORITHM_EDDSA); |
1196 | 238 | } |
1197 | | |
1198 | | int _sc_card_add_xeddsa_alg(sc_card_t *card, size_t key_length, |
1199 | | unsigned long flags, unsigned long ext_flags, |
1200 | | struct sc_object_id *curve_oid) |
1201 | 1.77k | { |
1202 | | /* For simplicity, share the ec union with the curve information */ |
1203 | 1.77k | return _sc_card_add_ec_alg_int(card, key_length, flags, ext_flags, |
1204 | 1.77k | curve_oid, SC_ALGORITHM_XEDDSA); |
1205 | 1.77k | } |
1206 | | |
1207 | | sc_algorithm_info_t *sc_card_find_alg(sc_card_t *card, |
1208 | | unsigned int algorithm, size_t key_length, void *param) |
1209 | 0 | { |
1210 | 0 | int i; |
1211 | |
|
1212 | 0 | for (i = 0; i < card->algorithm_count; i++) { |
1213 | 0 | sc_algorithm_info_t *info = &card->algorithms[i]; |
1214 | |
|
1215 | 0 | if (param && (info->algorithm == SC_ALGORITHM_EC || |
1216 | 0 | info->algorithm == SC_ALGORITHM_EDDSA || |
1217 | 0 | info->algorithm == SC_ALGORITHM_XEDDSA)) { |
1218 | 0 | if (sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id)) |
1219 | 0 | return info; |
1220 | 0 | } else if (info->algorithm != algorithm) { |
1221 | 0 | continue; |
1222 | 0 | } else if (info->key_length == key_length) |
1223 | 0 | return info; |
1224 | 0 | } |
1225 | 0 | return NULL; |
1226 | 0 | } |
1227 | | |
1228 | | sc_algorithm_info_t *sc_card_find_ec_alg(sc_card_t *card, |
1229 | | size_t key_length, struct sc_object_id *curve_name) |
1230 | 0 | { |
1231 | 0 | return sc_card_find_alg(card, SC_ALGORITHM_EC, key_length, curve_name); |
1232 | 0 | } |
1233 | | |
1234 | | sc_algorithm_info_t *sc_card_find_eddsa_alg(sc_card_t *card, |
1235 | | size_t key_length, struct sc_object_id *curve_name) |
1236 | 0 | { |
1237 | 0 | return sc_card_find_alg(card, SC_ALGORITHM_EDDSA, key_length, curve_name); |
1238 | 0 | } |
1239 | | |
1240 | | sc_algorithm_info_t *sc_card_find_xeddsa_alg(sc_card_t *card, |
1241 | | size_t key_length, struct sc_object_id *curve_name) |
1242 | 0 | { |
1243 | 0 | return sc_card_find_alg(card, SC_ALGORITHM_XEDDSA, key_length, curve_name); |
1244 | 0 | } |
1245 | | |
1246 | | int _sc_card_add_rsa_alg(sc_card_t *card, size_t key_length, |
1247 | | unsigned long flags, unsigned long exponent) |
1248 | 34.5k | { |
1249 | 34.5k | sc_algorithm_info_t info; |
1250 | | |
1251 | 34.5k | memset(&info, 0, sizeof(info)); |
1252 | 34.5k | info.algorithm = SC_ALGORITHM_RSA; |
1253 | 34.5k | info.key_length = key_length; |
1254 | 34.5k | info.flags = flags; |
1255 | | /* disable particular PKCS1 v1.5 padding type if also RAW is supported on card */ |
1256 | 34.5k | if ((info.flags & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_RAW)) == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_RAW)) { |
1257 | 6.27k | if (card->ctx->disable_hw_pkcs1_padding & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01) |
1258 | 0 | info.flags &= ~SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01; |
1259 | 6.27k | if (card->ctx->disable_hw_pkcs1_padding & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02) |
1260 | 6.27k | info.flags &= ~SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02; |
1261 | 6.27k | } |
1262 | 34.5k | info.u._rsa.exponent = exponent; |
1263 | | |
1264 | 34.5k | return _sc_card_add_algorithm(card, &info); |
1265 | 34.5k | } |
1266 | | |
1267 | | sc_algorithm_info_t *sc_card_find_rsa_alg(sc_card_t *card, size_t key_length) |
1268 | 0 | { |
1269 | 0 | return sc_card_find_alg(card, SC_ALGORITHM_RSA, key_length, NULL); |
1270 | 0 | } |
1271 | | |
1272 | | sc_algorithm_info_t *sc_card_find_gostr3410_alg(sc_card_t *card, size_t key_length) |
1273 | 0 | { |
1274 | 0 | return sc_card_find_alg(card, SC_ALGORITHM_GOSTR3410, key_length, NULL); |
1275 | 0 | } |
1276 | | |
1277 | | static int match_atr_table(sc_context_t *ctx, const struct sc_atr_table *table, struct sc_atr *atr) |
1278 | 308k | { |
1279 | 308k | u8 *card_atr_bin; |
1280 | 308k | size_t card_atr_bin_len; |
1281 | 308k | char card_atr_hex[3 * SC_MAX_ATR_SIZE]; |
1282 | 308k | size_t card_atr_hex_len; |
1283 | 308k | unsigned int i = 0; |
1284 | | |
1285 | 308k | if (ctx == NULL || table == NULL || atr == NULL) |
1286 | 11.1k | return -1; |
1287 | 297k | card_atr_bin = atr->value; |
1288 | 297k | card_atr_bin_len = atr->len; |
1289 | 297k | sc_bin_to_hex(card_atr_bin, card_atr_bin_len, card_atr_hex, sizeof(card_atr_hex), ':'); |
1290 | 297k | card_atr_hex_len = strlen(card_atr_hex); |
1291 | | |
1292 | 297k | sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ATR : %s", card_atr_hex); |
1293 | | |
1294 | 2.55M | for (i = 0; table[i].atr != NULL; i++) { |
1295 | 2.26M | const char *tatr = table[i].atr; |
1296 | 2.26M | const char *matr = table[i].atrmask; |
1297 | 2.26M | size_t tatr_len = strlen(tatr); |
1298 | 2.26M | u8 mbin[SC_MAX_ATR_SIZE], tbin[SC_MAX_ATR_SIZE]; |
1299 | 2.26M | size_t mbin_len, tbin_len, s, matr_len; |
1300 | 2.26M | size_t fix_hex_len = card_atr_hex_len; |
1301 | 2.26M | size_t fix_bin_len = card_atr_bin_len; |
1302 | | |
1303 | 2.26M | sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ATR try : %s", tatr); |
1304 | | |
1305 | 2.26M | if (tatr_len != fix_hex_len) { |
1306 | 2.18M | sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ignored - wrong length"); |
1307 | 2.18M | continue; |
1308 | 2.18M | } |
1309 | 82.4k | if (matr != NULL) { |
1310 | 26.0k | sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ATR mask: %s", matr); |
1311 | | |
1312 | 26.0k | matr_len = strlen(matr); |
1313 | 26.0k | if (tatr_len != matr_len) |
1314 | 0 | continue; |
1315 | 26.0k | tbin_len = sizeof(tbin); |
1316 | 26.0k | sc_hex_to_bin(tatr, tbin, &tbin_len); |
1317 | 26.0k | mbin_len = sizeof(mbin); |
1318 | 26.0k | sc_hex_to_bin(matr, mbin, &mbin_len); |
1319 | 26.0k | if (mbin_len != fix_bin_len) { |
1320 | 0 | sc_debug(ctx, SC_LOG_DEBUG_MATCH, "length of atr and atr mask do not match - ignored: %s - %s", tatr, matr); |
1321 | 0 | continue; |
1322 | 0 | } |
1323 | 525k | for (s = 0; s < tbin_len; s++) { |
1324 | | /* reduce tatr with mask */ |
1325 | 499k | tbin[s] = (tbin[s] & mbin[s]); |
1326 | | /* create copy of card_atr_bin masked) */ |
1327 | 499k | mbin[s] = (card_atr_bin[s] & mbin[s]); |
1328 | 499k | } |
1329 | 26.0k | if (memcmp(tbin, mbin, tbin_len) != 0) |
1330 | 21.8k | continue; |
1331 | 56.3k | } else { |
1332 | 56.3k | if (strncasecmp(tatr, card_atr_hex, tatr_len) != 0) |
1333 | 51.2k | continue; |
1334 | 56.3k | } |
1335 | 9.24k | return i; |
1336 | 82.4k | } |
1337 | 288k | return -1; |
1338 | 297k | } |
1339 | | |
1340 | | int _sc_match_atr(sc_card_t *card, const struct sc_atr_table *table, int *type_out) |
1341 | 297k | { |
1342 | 297k | int res; |
1343 | | |
1344 | 297k | if (card == NULL) |
1345 | 0 | return -1; |
1346 | 297k | res = match_atr_table(card->ctx, table, &card->atr); |
1347 | 297k | if (res < 0) |
1348 | 288k | return res; |
1349 | 9.24k | if (type_out != NULL) |
1350 | 9.08k | *type_out = table[res].type; |
1351 | 9.24k | return res; |
1352 | 297k | } |
1353 | | |
1354 | | scconf_block *_sc_match_atr_block(sc_context_t *ctx, struct sc_card_driver *driver, struct sc_atr *atr) |
1355 | 11.1k | { |
1356 | 11.1k | struct sc_card_driver *drv; |
1357 | 11.1k | struct sc_atr_table *table; |
1358 | 11.1k | int res; |
1359 | | |
1360 | 11.1k | if (ctx == NULL) |
1361 | 0 | return NULL; |
1362 | 11.1k | if (driver) { |
1363 | 11.1k | drv = driver; |
1364 | 11.1k | table = drv->atr_map; |
1365 | 11.1k | res = match_atr_table(ctx, table, atr); |
1366 | 11.1k | if (res < 0) |
1367 | 11.1k | return NULL; |
1368 | 0 | return table[res].card_atr; |
1369 | 11.1k | } else { |
1370 | 0 | unsigned int i; |
1371 | |
|
1372 | 0 | for (i = 0; ctx->card_drivers[i] != NULL; i++) { |
1373 | 0 | drv = ctx->card_drivers[i]; |
1374 | 0 | table = drv->atr_map; |
1375 | 0 | res = match_atr_table(ctx, table, atr); |
1376 | 0 | if (res < 0) |
1377 | 0 | continue; |
1378 | 0 | return table[res].card_atr; |
1379 | 0 | } |
1380 | 0 | } |
1381 | 0 | return NULL; |
1382 | 11.1k | } |
1383 | | |
1384 | | int _sc_add_atr(sc_context_t *ctx, struct sc_card_driver *driver, struct sc_atr_table *src) |
1385 | 0 | { |
1386 | 0 | struct sc_atr_table *map, *dst; |
1387 | |
|
1388 | 0 | map = (struct sc_atr_table *) realloc(driver->atr_map, |
1389 | 0 | (driver->natrs + 2) * sizeof(struct sc_atr_table)); |
1390 | 0 | if (!map) |
1391 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1392 | 0 | driver->atr_map = map; |
1393 | |
|
1394 | 0 | dst = &driver->atr_map[driver->natrs++]; |
1395 | 0 | memset(dst, 0, sizeof(*dst)); |
1396 | 0 | memset(&driver->atr_map[driver->natrs], 0, sizeof(struct sc_atr_table)); |
1397 | 0 | dst->atr = strdup(src->atr); |
1398 | 0 | if (!dst->atr) |
1399 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1400 | | |
1401 | 0 | if (src->atrmask) { |
1402 | 0 | dst->atrmask = strdup(src->atrmask); |
1403 | 0 | if (!dst->atrmask) |
1404 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1405 | 0 | } |
1406 | 0 | else { |
1407 | 0 | dst->atrmask = NULL; |
1408 | 0 | } |
1409 | | |
1410 | 0 | if (src->name) { |
1411 | 0 | dst->name = strdup(src->name); |
1412 | 0 | if (!dst->name) |
1413 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1414 | 0 | } |
1415 | 0 | else { |
1416 | 0 | dst->name = NULL; |
1417 | 0 | } |
1418 | | |
1419 | 0 | dst->type = src->type; |
1420 | 0 | dst->flags = src->flags; |
1421 | 0 | dst->card_atr = src->card_atr; |
1422 | |
|
1423 | 0 | return SC_SUCCESS; |
1424 | 0 | } |
1425 | | |
1426 | | |
1427 | | int _sc_free_atr(sc_context_t *ctx, struct sc_card_driver *driver) |
1428 | 0 | { |
1429 | 0 | unsigned int i; |
1430 | |
|
1431 | 0 | for (i = 0; i < driver->natrs; i++) { |
1432 | 0 | struct sc_atr_table *src = &driver->atr_map[i]; |
1433 | |
|
1434 | 0 | if (src->atr) |
1435 | 0 | free((void *)src->atr); |
1436 | 0 | if (src->atrmask) |
1437 | 0 | free((void *)src->atrmask); |
1438 | 0 | if (src->name) |
1439 | 0 | free((void *)src->name); |
1440 | 0 | src->card_atr = NULL; |
1441 | 0 | src = NULL; |
1442 | 0 | } |
1443 | 0 | if (driver->atr_map) |
1444 | 0 | free(driver->atr_map); |
1445 | 0 | driver->atr_map = NULL; |
1446 | 0 | driver->natrs = 0; |
1447 | |
|
1448 | 0 | return SC_SUCCESS; |
1449 | 0 | } |
1450 | | |
1451 | | |
1452 | | scconf_block *sc_get_conf_block(sc_context_t *ctx, const char *name1, const char *name2, int priority) |
1453 | 38.8k | { |
1454 | 38.8k | int i; |
1455 | 38.8k | scconf_block *conf_block = NULL; |
1456 | | |
1457 | 77.7k | for (i = 0; ctx->conf_blocks[i] != NULL; i++) { |
1458 | 38.8k | scconf_block **blocks; |
1459 | | |
1460 | 38.8k | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], name1, name2); |
1461 | 38.8k | if (blocks != NULL) { |
1462 | 38.8k | conf_block = blocks[0]; |
1463 | 38.8k | free(blocks); |
1464 | 38.8k | } |
1465 | 38.8k | if (conf_block != NULL && priority) |
1466 | 0 | break; |
1467 | 38.8k | } |
1468 | 38.8k | return conf_block; |
1469 | 38.8k | } |
1470 | | |
1471 | | void |
1472 | | sc_clear_ec_params(struct sc_ec_parameters *ecp) |
1473 | 8.45k | { |
1474 | 8.45k | if (ecp) { |
1475 | 8.45k | free(ecp->named_curve); |
1476 | 8.45k | free(ecp->der.value); |
1477 | 8.45k | memset(ecp, 0, sizeof(struct sc_ec_parameters)); |
1478 | 8.45k | } |
1479 | 8.45k | return; |
1480 | 8.45k | } |
1481 | | |
1482 | | int sc_copy_ec_params(struct sc_ec_parameters *dst, struct sc_ec_parameters *src) |
1483 | 0 | { |
1484 | 0 | if (!dst || !src) |
1485 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1486 | | |
1487 | 0 | memset(dst, 0, sizeof(*dst)); |
1488 | 0 | if (src->named_curve) { |
1489 | 0 | dst->named_curve = strdup(src->named_curve); |
1490 | 0 | if (!dst->named_curve) |
1491 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1492 | 0 | } |
1493 | 0 | dst->id = src->id; |
1494 | 0 | if (src->der.value && src->der.len) { |
1495 | 0 | dst->der.value = malloc(src->der.len); |
1496 | 0 | if (!dst->der.value) { |
1497 | 0 | free(dst->named_curve); |
1498 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1499 | 0 | } |
1500 | 0 | memcpy(dst->der.value, src->der.value, src->der.len); |
1501 | 0 | dst->der.len = src->der.len; |
1502 | 0 | } |
1503 | 0 | dst->type = src->type; |
1504 | 0 | dst->field_length = src->field_length; |
1505 | 0 | dst->key_type = src->key_type; |
1506 | |
|
1507 | 0 | return SC_SUCCESS; |
1508 | 0 | } |
1509 | | |
1510 | | scconf_block * |
1511 | | sc_match_atr_block(sc_context_t *ctx, struct sc_card_driver *driver, struct sc_atr *atr) |
1512 | 0 | { |
1513 | 0 | return _sc_match_atr_block(ctx, driver, atr); |
1514 | 0 | } |
1515 | | |
1516 | | #ifdef ENABLE_SM |
1517 | | static int |
1518 | | sc_card_sm_unload(struct sc_card *card) |
1519 | 11.1k | { |
1520 | 11.1k | if (card->sm_ctx.module.ops.module_cleanup) |
1521 | 0 | card->sm_ctx.module.ops.module_cleanup(card->ctx); |
1522 | | |
1523 | 11.1k | if (card->sm_ctx.module.handle) |
1524 | 0 | sc_dlclose(card->sm_ctx.module.handle); |
1525 | 11.1k | card->sm_ctx.module.handle = NULL; |
1526 | 11.1k | return 0; |
1527 | 11.1k | } |
1528 | | |
1529 | | |
1530 | | static int |
1531 | | sc_card_sm_load(struct sc_card *card, const char *module_path, const char *in_module) |
1532 | 0 | { |
1533 | 0 | struct sc_context *ctx = NULL; |
1534 | 0 | int rv = SC_ERROR_INTERNAL; |
1535 | 0 | char *module = NULL; |
1536 | | #ifdef _WIN32 |
1537 | | const char path_delim = '\\'; |
1538 | | #else |
1539 | 0 | const char path_delim = '/'; |
1540 | 0 | #endif |
1541 | |
|
1542 | 0 | if (card == NULL) { |
1543 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1544 | 0 | } |
1545 | 0 | ctx = card->ctx; |
1546 | 0 | LOG_FUNC_CALLED(ctx); |
1547 | 0 | if (!in_module) |
1548 | 0 | return sc_card_sm_unload(card); |
1549 | | |
1550 | 0 | sc_log(ctx, "SM module '%s' located in '%s'", in_module, module_path); |
1551 | 0 | if (module_path && strlen(module_path) > 0) { |
1552 | 0 | size_t sz = strlen(in_module) + strlen(module_path) + 3; |
1553 | 0 | module = malloc(sz); |
1554 | 0 | if (module) |
1555 | 0 | snprintf(module, sz, "%s%c%s", module_path, path_delim, in_module); |
1556 | 0 | } |
1557 | 0 | else { |
1558 | 0 | module = strdup(in_module); |
1559 | 0 | } |
1560 | |
|
1561 | 0 | if (!module) |
1562 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1563 | | |
1564 | 0 | sc_log(ctx, "try to load SM module '%s'", module); |
1565 | 0 | do { |
1566 | 0 | struct sm_module_operations *mod_ops = &card->sm_ctx.module.ops; |
1567 | 0 | void *mod_handle; |
1568 | |
|
1569 | 0 | card->sm_ctx.module.handle = sc_dlopen(module); |
1570 | 0 | if (!card->sm_ctx.module.handle) { |
1571 | 0 | sc_log(ctx, "cannot open dynamic library '%s': %s", module, sc_dlerror()); |
1572 | 0 | break; |
1573 | 0 | } |
1574 | 0 | mod_handle = card->sm_ctx.module.handle; |
1575 | |
|
1576 | 0 | mod_ops->initialize = sc_dlsym(mod_handle, "initialize"); |
1577 | 0 | if (!mod_ops->initialize) { |
1578 | 0 | sc_log(ctx, "SM handler 'initialize' not exported: %s", sc_dlerror()); |
1579 | 0 | break; |
1580 | 0 | } |
1581 | | |
1582 | 0 | mod_ops->get_apdus = sc_dlsym(mod_handle, "get_apdus"); |
1583 | 0 | if (!mod_ops->get_apdus) { |
1584 | 0 | sc_log(ctx, "SM handler 'get_apdus' not exported: %s", sc_dlerror()); |
1585 | 0 | break; |
1586 | 0 | } |
1587 | | |
1588 | 0 | mod_ops->finalize = sc_dlsym(mod_handle, "finalize"); |
1589 | 0 | if (!mod_ops->finalize) |
1590 | 0 | sc_log(ctx, "SM handler 'finalize' not exported -- ignored"); |
1591 | |
|
1592 | 0 | mod_ops->module_init = sc_dlsym(mod_handle, "module_init"); |
1593 | 0 | if (!mod_ops->module_init) |
1594 | 0 | sc_log(ctx, "SM handler 'module_init' not exported -- ignored"); |
1595 | |
|
1596 | 0 | mod_ops->module_cleanup = sc_dlsym(mod_handle, "module_cleanup"); |
1597 | 0 | if (!mod_ops->module_cleanup) |
1598 | 0 | sc_log(ctx, "SM handler 'module_cleanup' not exported -- ignored"); |
1599 | |
|
1600 | 0 | mod_ops->test = sc_dlsym(mod_handle, "test"); |
1601 | 0 | if (mod_ops->test) |
1602 | 0 | sc_log(ctx, "SM handler 'test' not exported -- ignored"); |
1603 | |
|
1604 | 0 | rv = 0; |
1605 | 0 | break; |
1606 | 0 | } while(0); |
1607 | |
|
1608 | 0 | if (rv) |
1609 | 0 | sc_card_sm_unload(card); |
1610 | |
|
1611 | 0 | card->sm_ctx.sm_mode = SM_MODE_ACL; |
1612 | 0 | if (module) |
1613 | 0 | free(module); |
1614 | |
|
1615 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, rv); |
1616 | 0 | } |
1617 | | |
1618 | | |
1619 | | /* get SM related configuration settings and initialize SM session, SM module, ... */ |
1620 | | static int |
1621 | | sc_card_sm_check(struct sc_card *card) |
1622 | 11.1k | { |
1623 | 11.1k | const char *sm = NULL, *module_name = NULL, *module_path = NULL, *module_data = NULL, *sm_mode = NULL; |
1624 | 11.1k | struct sc_context *ctx = card->ctx; |
1625 | 11.1k | scconf_block *atrblock = NULL, *sm_conf_block = NULL; |
1626 | 11.1k | int rv, ii; |
1627 | | #ifdef _WIN32 |
1628 | | char temp_path[PATH_MAX]; |
1629 | | size_t temp_len = PATH_MAX - 1; |
1630 | | char expanded_val[PATH_MAX]; |
1631 | | DWORD expanded_len = PATH_MAX; |
1632 | | #endif |
1633 | | |
1634 | 11.1k | LOG_FUNC_CALLED(ctx); |
1635 | | |
1636 | | /* get the name of card specific SM configuration section */ |
1637 | 11.1k | atrblock = _sc_match_atr_block(ctx, card->driver, &card->atr); |
1638 | 11.1k | if (atrblock == NULL) |
1639 | 11.1k | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1640 | 0 | sm = scconf_get_str(atrblock, "secure_messaging", NULL); |
1641 | 0 | if (!sm) |
1642 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1643 | | |
1644 | | /* get SM configuration section by the name */ |
1645 | 0 | sc_log(ctx, "secure_messaging configuration block '%s'", sm); |
1646 | 0 | for (ii = 0; ctx->conf_blocks[ii]; ii++) { |
1647 | 0 | scconf_block **blocks; |
1648 | |
|
1649 | 0 | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[ii], "secure_messaging", sm); |
1650 | 0 | if (blocks) { |
1651 | 0 | sm_conf_block = blocks[0]; |
1652 | 0 | free(blocks); |
1653 | 0 | } |
1654 | 0 | if (sm_conf_block != NULL) |
1655 | 0 | break; |
1656 | 0 | } |
1657 | |
|
1658 | 0 | if (!sm_conf_block) |
1659 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_CONFIGURATION, "SM configuration block not preset"); |
1660 | | |
1661 | | /* check if an external SM module has to be used */ |
1662 | | #ifdef _WIN32 |
1663 | | rv = sc_ctx_win32_get_config_value(NULL, "SmDir", "Software\\" OPENSC_VS_FF_COMPANY_NAME "\\OpenSC" OPENSC_ARCH_SUFFIX, |
1664 | | temp_path, &temp_len); |
1665 | | if (rv == SC_SUCCESS) { |
1666 | | temp_path[temp_len] = '\0'; |
1667 | | module_path = temp_path; |
1668 | | } |
1669 | | expanded_len = ExpandEnvironmentStringsA(module_path, expanded_val, expanded_len); |
1670 | | if (0 < expanded_len && expanded_len < sizeof expanded_val) |
1671 | | module_path = expanded_val; |
1672 | | #else |
1673 | 0 | module_path = scconf_get_str(sm_conf_block, "module_path", DEFAULT_SM_MODULE_PATH); |
1674 | 0 | #endif |
1675 | 0 | module_name = scconf_get_str(sm_conf_block, "module_name", DEFAULT_SM_MODULE); |
1676 | 0 | sc_log(ctx, "SM module '%s' in '%s'", module_name, module_path); |
1677 | 0 | if (!module_name) |
1678 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_CONFIGURATION, "Invalid SM configuration: module not defined"); |
1679 | | |
1680 | 0 | rv = sc_card_sm_load(card, module_path, module_name); |
1681 | 0 | LOG_TEST_RET(ctx, rv, "Failed to load SM module"); |
1682 | | |
1683 | 0 | strlcpy(card->sm_ctx.module.filename, module_name, sizeof(card->sm_ctx.module.filename)); |
1684 | 0 | strlcpy(card->sm_ctx.config_section, sm, sizeof(card->sm_ctx.config_section)); |
1685 | | |
1686 | | /* allocate resources for the external SM module */ |
1687 | 0 | if (card->sm_ctx.module.ops.module_init) { |
1688 | 0 | module_data = scconf_get_str(sm_conf_block, "module_data", NULL); |
1689 | |
|
1690 | 0 | rv = card->sm_ctx.module.ops.module_init(ctx, module_data); |
1691 | 0 | LOG_TEST_RET(ctx, rv, "Cannot initialize SM module"); |
1692 | 0 | } |
1693 | | |
1694 | | /* initialize SM session in the case of 'APDU TRANSMIT' SM mode */ |
1695 | 0 | sm_mode = scconf_get_str(sm_conf_block, "mode", NULL); |
1696 | 0 | if (sm_mode && !strcasecmp("Transmit", sm_mode)) { |
1697 | 0 | if (!card->sm_ctx.ops.open || !card->sm_ctx.ops.get_sm_apdu || !card->sm_ctx.ops.free_sm_apdu) |
1698 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "'Transmit' SM asked but not supported by card driver"); |
1699 | | |
1700 | 0 | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
1701 | 0 | rv = card->sm_ctx.ops.open(card); |
1702 | 0 | LOG_TEST_RET(ctx, rv, "Cannot initialize SM"); |
1703 | 0 | } |
1704 | | |
1705 | 0 | sc_log(ctx, "SM mode:%X", card->sm_ctx.sm_mode); |
1706 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, rv); |
1707 | 0 | } |
1708 | | #endif |