/src/opensc/src/libopensc/card-eoi.c
Line | Count | Source |
1 | | /* |
2 | | * Support for the eOI card |
3 | | * |
4 | | * Copyright (C) 2022 Luka Logar <luka.logar@iname.com> |
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 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #ifdef HAVE_CONFIG_H |
25 | | #include "config.h" |
26 | | #endif |
27 | | #include "opensc.h" |
28 | | |
29 | | #if defined(ENABLE_SM) && defined(ENABLE_OPENPACE) |
30 | | |
31 | | #include <openssl/aes.h> |
32 | | #include <openssl/sha.h> |
33 | | #include "internal.h" |
34 | | #include "sm/sm-eac.h" |
35 | | #include "common/compat_strlcpy.h" |
36 | | #include "card-eoi.h" |
37 | | |
38 | | static struct sc_card_operations eoi_ops; |
39 | | |
40 | | static struct { |
41 | | int len; |
42 | | struct sc_object_id oid; |
43 | | } eoi_curves[] = { |
44 | | /* secp384r1 */ |
45 | | {384, {{1, 3, 132, 0, 34, -1}}} |
46 | | }; |
47 | | |
48 | | static char *eoi_model = "ChipDocLite"; |
49 | | |
50 | | /* The description of the driver. */ |
51 | | static struct sc_card_driver eoi_drv = |
52 | | { |
53 | | "eOI (Slovenian eID card)", |
54 | | "eOI", |
55 | | &eoi_ops, |
56 | | NULL, 0, NULL |
57 | | }; |
58 | | |
59 | | static const struct sc_atr_table eoi_atrs[] = { |
60 | | /* Contact interface */ |
61 | | { "3b:d5:18:ff:81:91:fe:1f:c3:80:73:c8:21:10:0a", NULL, NULL, SC_CARD_TYPE_EOI, 0, NULL }, |
62 | | /* Contactless interface */ |
63 | | { "3b:85:80:01:80:73:c8:21:10:0e", NULL, NULL, SC_CARD_TYPE_EOI_CONTACTLESS, 0, NULL }, |
64 | | { NULL, NULL, NULL, 0, 0, NULL } |
65 | | }; |
66 | | |
67 | | /* |
68 | | * CAN is stored encrypted in a file that (looks like) is pointed to by 'Card CAN' PIN object. |
69 | | * eoi_decrypt_can() decrypts CAN from it's encrypted form |
70 | | */ |
71 | | |
72 | | static void rol(u8 *to, const u8 *from) |
73 | 0 | { |
74 | 0 | int i; |
75 | 0 | u8 b = from[0] & 0x80; |
76 | 0 | for (i = 15; i >= 0; i--) { |
77 | 0 | u8 bo = b; |
78 | 0 | b = from[i] & 0x80; |
79 | 0 | to[i] = (from[i] << 1) | (bo ? 1 : 0); |
80 | 0 | if ((i == 15) && bo) |
81 | 0 | to[i] = (to[i] ^ 0x87) | 1; |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | static int aes256_ecb_encrypt(const u8 *key, const u8 input[AES_BLOCK_SIZE], u8 output[AES_BLOCK_SIZE]) |
86 | 0 | { |
87 | 0 | EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); |
88 | 0 | int r = 0, pos, len = pos = AES_BLOCK_SIZE; |
89 | 0 | if (!ctx) |
90 | 0 | goto err; |
91 | 0 | if (!EVP_EncryptInit(ctx, EVP_aes_256_ecb(), key, NULL)) |
92 | 0 | goto err; |
93 | | /* Disable padding, otherwise EVP_EncryptFinal() will fail */ |
94 | 0 | if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) |
95 | 0 | goto err; |
96 | 0 | if (!EVP_EncryptUpdate(ctx, output, &pos, input, len)) |
97 | 0 | goto err; |
98 | 0 | len -= pos; |
99 | 0 | if (!EVP_EncryptFinal(ctx, output + pos, &len)) |
100 | 0 | goto err; |
101 | 0 | r = 1; |
102 | 0 | err: |
103 | 0 | if (ctx) |
104 | 0 | EVP_CIPHER_CTX_free(ctx); |
105 | 0 | return r; |
106 | 0 | } |
107 | | |
108 | | static int aes256_ecb_decrypt(const u8 *key, const u8 input[AES_BLOCK_SIZE], u8 output[AES_BLOCK_SIZE]) |
109 | 0 | { |
110 | 0 | EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); |
111 | 0 | int r = 0, pos, len = pos = AES_BLOCK_SIZE; |
112 | 0 | if (!ctx) |
113 | 0 | goto err; |
114 | 0 | if (!EVP_DecryptInit(ctx, EVP_aes_256_ecb(), key, NULL)) |
115 | 0 | goto err; |
116 | | /* Disable padding, otherwise it will fail to decrypt non-padded inputs */ |
117 | 0 | if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) |
118 | 0 | goto err; |
119 | 0 | if (!EVP_DecryptUpdate(ctx, output, &pos, input, len)) |
120 | 0 | goto err; |
121 | 0 | len -= pos; |
122 | 0 | if (!EVP_DecryptFinal(ctx, output + pos, &len)) |
123 | 0 | goto err; |
124 | 0 | r = 1; |
125 | 0 | err: |
126 | 0 | if (ctx) |
127 | 0 | EVP_CIPHER_CTX_free(ctx); |
128 | 0 | return r; |
129 | 0 | } |
130 | | |
131 | | /* |
132 | | * CAN decrypt magic... |
133 | | */ |
134 | | static int get_can_key(const u8 *key, const u8 round, const u8 *input, u8 *output) |
135 | 0 | { |
136 | 0 | size_t i; |
137 | 0 | u8 tmp[3][AES_BLOCK_SIZE]; |
138 | 0 | memset(tmp[0], 0, AES_BLOCK_SIZE); |
139 | 0 | if (!aes256_ecb_encrypt(key, tmp[0], tmp[0])) |
140 | 0 | return 0; |
141 | 0 | rol(tmp[1], tmp[0]); |
142 | 0 | rol(tmp[0], tmp[1]); |
143 | 0 | memset(tmp[1], 0, AES_BLOCK_SIZE); |
144 | 0 | tmp[1][11] = 4; |
145 | 0 | tmp[1][13] = 1; |
146 | 0 | tmp[1][15] = round; |
147 | 0 | if (!aes256_ecb_encrypt(key, tmp[1], tmp[2])) |
148 | 0 | return 0; |
149 | 0 | memset(tmp[1], 0, AES_BLOCK_SIZE); |
150 | 0 | memcpy(tmp[1], &input[AES_BLOCK_SIZE], 8); |
151 | 0 | tmp[1][8] = 0x80; |
152 | 0 | for (i = 0; i < AES_BLOCK_SIZE; i++) |
153 | 0 | tmp[0][i] = tmp[0][i] ^ tmp[1][i] ^ tmp[2][i]; |
154 | 0 | if (!aes256_ecb_encrypt(key, tmp[0], output)) |
155 | 0 | return 0; |
156 | 0 | return 1; |
157 | 0 | } |
158 | | |
159 | | #define AES256_KEY_LEN 32 |
160 | | |
161 | | /* Decrypt the 24-byte encrypted CAN blob (16 enc || 8 SN) into its 16-byte |
162 | | * plaintext block. Exposed for card-chipdocit: same chip, same key. */ |
163 | | int |
164 | | chipdoc_decrypt_can_block(const u8 *enc_can, size_t enc_can_len, u8 out[AES_BLOCK_SIZE]) |
165 | 0 | { |
166 | | /* Magic key that is used to decrypt CAN */ |
167 | 0 | const u8 magic_key[AES256_KEY_LEN] = {0xC8, 0x12, 0x0F, 0xD8, 0x21, 0x20, 0x1F, 0x77, 0xF1, 0x83, 0x9D, 0xD8, 0x86, 0xB0, 0x5C, 0xF2, 0x4F, 0x7E, 0x52, 0x66, 0xE5, 0x87, 0x89, 0x2B, 0xF4, 0xC5, 0xE5, 0x4C, 0x54, 0xA1, 0x55, 0x30}; |
168 | 0 | u8 can_key[AES256_KEY_LEN] = { 0 }; |
169 | |
|
170 | 0 | if (!enc_can || !out || enc_can_len != 24) |
171 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
172 | 0 | if (!get_can_key(magic_key, 0x01, enc_can, &can_key[0])) |
173 | 0 | return SC_ERROR_INTERNAL; |
174 | 0 | if (!get_can_key(magic_key, 0x02, enc_can, &can_key[AES_BLOCK_SIZE])) |
175 | 0 | return SC_ERROR_INTERNAL; |
176 | 0 | if (!aes256_ecb_decrypt(can_key, enc_can, out)) |
177 | 0 | return SC_ERROR_INTERNAL; |
178 | 0 | return SC_SUCCESS; |
179 | 0 | } |
180 | | |
181 | | static int |
182 | | eoi_decrypt_can(struct sc_pkcs15_u8 *enc_can, char *can) |
183 | 0 | { |
184 | 0 | int r; |
185 | |
|
186 | 0 | if (!can || !enc_can || !enc_can->value) |
187 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
188 | 0 | r = chipdoc_decrypt_can_block(enc_can->value, enc_can->len, (u8 *)can); |
189 | 0 | if (r != SC_SUCCESS) |
190 | 0 | return r; |
191 | 0 | can[AES_BLOCK_SIZE - 1] = 0; |
192 | 0 | return SC_SUCCESS; |
193 | 0 | } |
194 | | |
195 | | static int eoi_sm_open(struct sc_card *card) |
196 | 0 | { |
197 | 0 | int r; |
198 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
199 | 0 | struct establish_pace_channel_input pace_input; |
200 | 0 | struct establish_pace_channel_output pace_output; |
201 | |
|
202 | 0 | if (!privdata) |
203 | 0 | return SC_ERROR_INTERNAL; |
204 | | |
205 | 0 | if (!privdata->can[0]) { |
206 | | /* If no CAN is specified in conf, try to decrypt it from enc_can file */ |
207 | 0 | r = eoi_decrypt_can(&privdata->enc_can, privdata->can); |
208 | 0 | sc_log_openssl(card->ctx); |
209 | 0 | LOG_TEST_RET(card->ctx, r, "Cannot decrypt CAN"); |
210 | 0 | } |
211 | | /* CAN should be 6 chars long */ |
212 | 0 | if (strlen(privdata->can) != 6) |
213 | 0 | return SC_ERROR_DECRYPT_FAILED; |
214 | | |
215 | 0 | memset(&pace_input, 0, sizeof pace_input); |
216 | 0 | memset(&pace_output, 0, sizeof pace_output); |
217 | |
|
218 | 0 | pace_input.pin_id = PACE_PIN_ID_CAN; |
219 | 0 | pace_input.pin = (u8 *)privdata->can; |
220 | 0 | pace_input.pin_length = strlen(privdata->can); |
221 | | |
222 | | /* EF.CardAccess can only be read from MF */ |
223 | 0 | r = sc_select_file(card, sc_get_mf_path(), NULL); |
224 | 0 | LOG_TEST_RET(card->ctx, r, "sc_select_file failed"); |
225 | | |
226 | 0 | r = perform_pace(card, pace_input, &pace_output, EAC_TR_VERSION_2_02); |
227 | 0 | LOG_TEST_RET(card->ctx, r, "Error verifying CAN"); |
228 | | |
229 | 0 | return SC_SUCCESS; |
230 | 0 | } |
231 | | |
232 | | static int eoi_get_data(sc_card_t *card, u8 data_id, u8 *buf, size_t len) |
233 | 0 | { |
234 | 0 | int r; |
235 | 0 | sc_apdu_t apdu; |
236 | |
|
237 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, data_id); |
238 | 0 | apdu.resp = buf; |
239 | 0 | apdu.resplen = len; |
240 | 0 | apdu.le = len; |
241 | |
|
242 | 0 | r = sc_transmit_apdu(card, &apdu); |
243 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
244 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
245 | 0 | return r; |
246 | 0 | } |
247 | | |
248 | | #define ATR_MATCH 1 |
249 | | |
250 | 2.46k | static int eoi_match_card(sc_card_t* card) { |
251 | 2.46k | LOG_FUNC_CALLED(card->ctx); |
252 | 2.46k | if (_sc_match_atr(card, eoi_atrs, &card->type) >= 0) { |
253 | 0 | sc_log(card->ctx, "ATR recognized as Slovenian eID card"); |
254 | 0 | LOG_FUNC_RETURN(card->ctx, ATR_MATCH); |
255 | 0 | } |
256 | 2.46k | LOG_FUNC_RETURN(card->ctx, !ATR_MATCH); |
257 | 2.46k | } |
258 | | |
259 | 0 | static int eoi_init(sc_card_t* card) { |
260 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
261 | 0 | u8 version[6]; |
262 | 0 | size_t i, j; |
263 | 0 | scconf_block **found_blocks, *block; |
264 | 0 | int r; |
265 | 0 | char *can; |
266 | |
|
267 | 0 | LOG_FUNC_CALLED(card->ctx); |
268 | |
|
269 | 0 | if (eoi_get_data(card, 0x16, version, sizeof(version)) != SC_SUCCESS) |
270 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_CARD); |
271 | | |
272 | 0 | if (privdata) |
273 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
274 | 0 | privdata = sc_mem_secure_alloc(sizeof(struct eoi_privdata)); |
275 | 0 | if (!privdata) |
276 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
277 | | /* sc_mem_secure_alloc()-ed memory may not be zeroized */ |
278 | 0 | memset(privdata, 0, sizeof(struct eoi_privdata)); |
279 | 0 | card->drv_data = privdata; |
280 | |
|
281 | 0 | sprintf(privdata->version, "%X%02X.%02X%02X", version[0], version[1], version[2], version[3]); |
282 | 0 | sc_log(card->ctx, "App version: %s", privdata->version); |
283 | |
|
284 | 0 | memset(&card->sm_ctx, 0, sizeof card->sm_ctx); |
285 | 0 | card->sm_ctx.ops.open = eoi_sm_open; |
286 | |
|
287 | 0 | card->max_send_size = SC_MAX_APDU_DATA_SIZE; |
288 | 0 | card->max_recv_size = SC_MAX_APDU_RESP_SIZE; |
289 | |
|
290 | 0 | for (i = 0; i < sizeof eoi_curves / sizeof * eoi_curves; ++i) { |
291 | 0 | r = _sc_card_add_ec_alg(card, eoi_curves[i].len, SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDSA_HASH_NONE, 0, &eoi_curves[i].oid); |
292 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Add EC alg failed"); |
293 | 0 | } |
294 | | |
295 | 0 | can = getenv("EOI_CAN"); |
296 | 0 | if (can) |
297 | 0 | strlcpy(privdata->can, can, sizeof(privdata->can)); |
298 | 0 | for (i = 0; card->ctx->conf_blocks[i]; i++) { |
299 | 0 | found_blocks = scconf_find_blocks(card->ctx->conf, card->ctx->conf_blocks[i], |
300 | 0 | "card_driver", "eoi"); |
301 | 0 | if (!found_blocks) |
302 | 0 | continue; |
303 | | |
304 | 0 | for (j = 0, block = found_blocks[j]; block; j++, block = found_blocks[j]) { |
305 | 0 | if (!privdata->can[0]) { |
306 | 0 | const char *can = scconf_get_str(block, "can", NULL); |
307 | 0 | if (can) |
308 | 0 | strlcpy(privdata->can, can, sizeof(privdata->can)); |
309 | 0 | } |
310 | 0 | } |
311 | 0 | free(found_blocks); |
312 | 0 | } |
313 | |
|
314 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
315 | | |
316 | 0 | err: |
317 | 0 | if (privdata) { |
318 | 0 | sc_mem_clear(privdata, sizeof(struct eoi_privdata)); |
319 | 0 | sc_mem_secure_free(privdata, sizeof(struct eoi_privdata)); |
320 | 0 | } |
321 | 0 | card->drv_data = NULL; |
322 | |
|
323 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
324 | 0 | } |
325 | | |
326 | | static int eoi_finish(sc_card_t* card) |
327 | 0 | { |
328 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
329 | |
|
330 | 0 | LOG_FUNC_CALLED(card->ctx); |
331 | |
|
332 | 0 | if (privdata) { |
333 | 0 | sc_mem_clear(privdata, sizeof(struct eoi_privdata)); |
334 | 0 | sc_mem_secure_free(privdata, sizeof(struct eoi_privdata)); |
335 | 0 | } |
336 | |
|
337 | 0 | card->drv_data = NULL; |
338 | |
|
339 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
340 | 0 | } |
341 | | |
342 | | static int eoi_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) |
343 | 0 | { |
344 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
345 | 0 | int i; |
346 | |
|
347 | 0 | LOG_FUNC_CALLED(card->ctx); |
348 | |
|
349 | 0 | if (!privdata) |
350 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
351 | | |
352 | 0 | for (i = 0; i < MAX_OBJECTS && privdata->pin_paths[i]; i++) { |
353 | 0 | if (privdata->pin_paths[i] && sc_compare_path(privdata->pin_paths[i], in_path)) { |
354 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
355 | 0 | } |
356 | 0 | } |
357 | | |
358 | 0 | LOG_FUNC_RETURN(card->ctx, sc_get_iso7816_driver()->ops->select_file(card, in_path, file_out)); |
359 | 0 | } |
360 | | |
361 | | static int eoi_logout(struct sc_card *card) |
362 | 0 | { |
363 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
364 | 0 | struct sc_apdu apdu; |
365 | 0 | u8 buf[256]; |
366 | 0 | int r = SC_SUCCESS; |
367 | |
|
368 | 0 | LOG_FUNC_CALLED(card->ctx); |
369 | |
|
370 | 0 | if (!privdata) |
371 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
372 | | |
373 | 0 | iso_sm_close(card); |
374 | 0 | card->sm_ctx.sm_mode = SM_MODE_NONE; |
375 | |
|
376 | 0 | if (card->reader->flags & SC_READER_ENABLE_ESCAPE) { |
377 | | /* |
378 | | * Get the UID of the ISO 14443 A card. (see PCSC Part 3) |
379 | | * The "official" PKCS#11 does it and we do the same. |
380 | | */ |
381 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x00, 0x00); |
382 | 0 | apdu.cla = 0xFF; |
383 | 0 | apdu.resp = buf; |
384 | 0 | apdu.resplen = 256; |
385 | 0 | apdu.lc = 0; |
386 | 0 | apdu.le = 256; |
387 | |
|
388 | 0 | r = sc_transmit_apdu(card, &apdu); |
389 | 0 | } |
390 | |
|
391 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
392 | 0 | } |
393 | | |
394 | | static int eoi_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data) |
395 | 0 | { |
396 | 0 | int r; |
397 | |
|
398 | 0 | LOG_FUNC_CALLED(card->ctx); |
399 | |
|
400 | 0 | if (data->cmd == SC_PIN_CMD_VERIFY && card->sm_ctx.sm_mode == SM_MODE_NONE) { |
401 | | /* Establish SM before any PIN VERIFY command */ |
402 | 0 | r = eoi_sm_open(card); |
403 | 0 | if (r != SC_SUCCESS) |
404 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
405 | 0 | } |
406 | | |
407 | 0 | if (data->cmd == SC_PIN_CMD_UNBLOCK) { |
408 | 0 | int pin_reference = data->pin_reference; |
409 | 0 | size_t pin2_len = data->pin2.len; |
410 | | /* Verify PUK, establish SM if necessary */ |
411 | 0 | data->cmd = SC_PIN_CMD_VERIFY; |
412 | 0 | data->pin_reference = data->puk_reference; |
413 | 0 | r = eoi_pin_cmd(card, data); |
414 | 0 | if (r != SC_SUCCESS) |
415 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
416 | | /* RESET RETRY COUNTER */ |
417 | 0 | data->cmd = SC_PIN_CMD_UNBLOCK; |
418 | 0 | data->pin_reference = 0x80|pin_reference; |
419 | 0 | data->pin1.len = 0; |
420 | 0 | data->pin2.len = 0; |
421 | 0 | r = sc_get_iso7816_driver()->ops->pin_cmd(card, data); |
422 | 0 | if (r != SC_SUCCESS) |
423 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
424 | | /* Continue as CHANGE PIN */ |
425 | 0 | data->cmd = SC_PIN_CMD_CHANGE; |
426 | 0 | data->pin2.len = pin2_len; |
427 | 0 | } |
428 | | |
429 | | /* CHANGE PIN command does not send the old PIN as it should already be verified */ |
430 | 0 | if (data->cmd == SC_PIN_CMD_CHANGE) |
431 | 0 | data->pin1.len = 0; |
432 | |
|
433 | 0 | LOG_FUNC_RETURN(card->ctx, sc_get_iso7816_driver()->ops->pin_cmd(card, data)); |
434 | 0 | } |
435 | | |
436 | | static int |
437 | | eoi_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) |
438 | 0 | { |
439 | 0 | struct sc_card_driver *iso_driver = NULL; |
440 | 0 | int r = SC_ERROR_NOT_SUPPORTED; |
441 | |
|
442 | 0 | LOG_FUNC_CALLED(card->ctx); |
443 | 0 | switch (cmd) { |
444 | 0 | case SC_CARDCTL_GET_MODEL: |
445 | 0 | if (!ptr) { |
446 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
447 | 0 | } else { |
448 | 0 | *(char **)ptr = eoi_model; |
449 | 0 | r = SC_SUCCESS; |
450 | 0 | } |
451 | 0 | break; |
452 | 0 | default: |
453 | 0 | iso_driver = sc_get_iso7816_driver(); |
454 | 0 | if (iso_driver->ops->card_ctl != NULL) { |
455 | 0 | r = sc_get_iso7816_driver()->ops->card_ctl(card, cmd, ptr); |
456 | 0 | } |
457 | 0 | } |
458 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
459 | 0 | } |
460 | | |
461 | 0 | #define ALREADY_PROCESSED 0x80000000 |
462 | | |
463 | | static int eoi_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num) |
464 | 0 | { |
465 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
466 | 0 | struct sc_apdu apdu; |
467 | 0 | u8 sbuf[4]; |
468 | 0 | int i, r, locked = 0; |
469 | |
|
470 | 0 | LOG_FUNC_CALLED(card->ctx); |
471 | |
|
472 | 0 | if (!privdata) |
473 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
474 | | |
475 | 0 | if (!card || !env) |
476 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
477 | | |
478 | | /* We don't know yet which hash is used. So just store the security_env data and return */ |
479 | 0 | if (!(env->algorithm_flags & ALREADY_PROCESSED)) { |
480 | 0 | privdata->key_len = BYTES4BITS(env->algorithm_ref); |
481 | 0 | memcpy(&privdata->sec_env, env, sizeof(struct sc_security_env)); |
482 | 0 | privdata->se_num = se_num; |
483 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
484 | 0 | } |
485 | | |
486 | 0 | if (env->operation != SC_SEC_OPERATION_SIGN) |
487 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
488 | 0 | if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)) |
489 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
490 | 0 | if (env->key_ref_len != 1) |
491 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
492 | 0 | if (env->algorithm != SC_ALGORITHM_EC) |
493 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
494 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81, 0xB6); |
495 | 0 | sbuf[0] = 0x91; |
496 | 0 | sbuf[1] = 0x02; |
497 | 0 | if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA1) |
498 | 0 | sbuf[2] = 0x11; |
499 | 0 | else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA256) |
500 | 0 | sbuf[2] = 0x21; |
501 | 0 | else if (env->algorithm_flags & (SC_ALGORITHM_ECDSA_RAW|SC_ALGORITHM_ECDSA_HASH_NONE)) |
502 | 0 | sbuf[2] = 0x22; |
503 | 0 | else |
504 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
505 | 0 | for (i = 0; i < MAX_OBJECTS && privdata->prkey_mappings[i][1]; i++) { |
506 | 0 | if (privdata->prkey_mappings[i][0] == env->key_ref[0]) |
507 | 0 | break; |
508 | 0 | } |
509 | 0 | if (i == MAX_OBJECTS) |
510 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
511 | 0 | sbuf[3] = privdata->prkey_mappings[i][1]; |
512 | 0 | apdu.lc = 4; |
513 | 0 | apdu.datalen = 4; |
514 | 0 | apdu.data = sbuf; |
515 | 0 | if (se_num > 0) { |
516 | 0 | r = sc_lock(card); |
517 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
518 | 0 | locked = 1; |
519 | 0 | } |
520 | 0 | if (apdu.datalen) { |
521 | 0 | r = sc_transmit_apdu(card, &apdu); |
522 | 0 | if (r) { |
523 | 0 | sc_log(card->ctx, "%s: APDU transmit failed", sc_strerror(r)); |
524 | 0 | goto err; |
525 | 0 | } |
526 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
527 | 0 | if (r) { |
528 | 0 | sc_log(card->ctx, "%s: Card returned error", sc_strerror(r)); |
529 | 0 | goto err; |
530 | 0 | } |
531 | 0 | } |
532 | 0 | if (se_num <= 0) { |
533 | 0 | r = SC_SUCCESS; |
534 | 0 | goto err; |
535 | 0 | } |
536 | 0 | sc_unlock(card); |
537 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
538 | | |
539 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
540 | 0 | err: |
541 | 0 | if (locked) |
542 | 0 | sc_unlock(card); |
543 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
544 | 0 | } |
545 | | |
546 | | static int eoi_compute_signature(struct sc_card *card, const u8 * data, size_t data_len, u8 *out, size_t outlen) |
547 | 0 | { |
548 | 0 | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
549 | 0 | int r; |
550 | |
|
551 | 0 | LOG_FUNC_CALLED(card->ctx); |
552 | |
|
553 | 0 | if (!privdata) |
554 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
555 | | |
556 | | /* |
557 | | * Guess the correct mode. If the size is less than the full-key-len, it must be a hash then |
558 | | */ |
559 | 0 | if (privdata->key_len != data_len) { |
560 | 0 | switch (data_len) { |
561 | 0 | case SHA_DIGEST_LENGTH: |
562 | 0 | privdata->sec_env.algorithm_flags = SC_ALGORITHM_ECDSA_HASH_SHA1; |
563 | 0 | break; |
564 | 0 | case SHA256_DIGEST_LENGTH: |
565 | 0 | privdata->sec_env.algorithm_flags = SC_ALGORITHM_ECDSA_HASH_SHA256; |
566 | 0 | break; |
567 | 0 | } |
568 | 0 | } |
569 | | /* Now we know which hash is used */ |
570 | 0 | privdata->sec_env.algorithm_flags |= ALREADY_PROCESSED; |
571 | | |
572 | | /* Perform the true set_security_env */ |
573 | 0 | r = eoi_set_security_env(card, &privdata->sec_env, privdata->se_num); |
574 | 0 | LOG_TEST_RET(card->ctx, r, "set_security_env failed"); |
575 | | |
576 | 0 | LOG_FUNC_RETURN(card->ctx, sc_get_iso7816_driver()->ops->compute_signature(card, data, data_len, out, outlen)); |
577 | 0 | } |
578 | | |
579 | | struct sc_card_driver *sc_get_eoi_driver(void) |
580 | 11.9k | { |
581 | 11.9k | eoi_ops = *sc_get_iso7816_driver()->ops; |
582 | | |
583 | 11.9k | eoi_ops.match_card = eoi_match_card; |
584 | 11.9k | eoi_ops.init = eoi_init; |
585 | 11.9k | eoi_ops.finish = eoi_finish; |
586 | 11.9k | eoi_ops.select_file = eoi_select_file; |
587 | 11.9k | eoi_ops.logout = eoi_logout; |
588 | 11.9k | eoi_ops.pin_cmd = eoi_pin_cmd; |
589 | 11.9k | eoi_ops.card_ctl = eoi_card_ctl; |
590 | 11.9k | eoi_ops.set_security_env = eoi_set_security_env; |
591 | 11.9k | eoi_ops.compute_signature = eoi_compute_signature; |
592 | | |
593 | 11.9k | return &eoi_drv; |
594 | 11.9k | } |
595 | | |
596 | | #else |
597 | | |
598 | | struct sc_card_driver* sc_get_eoi_driver(void) { |
599 | | return NULL; |
600 | | } |
601 | | |
602 | | #endif |