/src/opensc/src/libopensc/card-epass2003.c
Line | Count | Source |
1 | | /* |
2 | | * Support for ePass2003 smart cards |
3 | | * |
4 | | * Copyright (C) 2008, Weitao Sun <weitao@ftsafe.com> |
5 | | * Copyright (C) 2011, Xiaoshuo Wu <xiaoshuo@ftsafe.com> |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #ifdef HAVE_CONFIG_H |
23 | | #include "config.h" |
24 | | #endif |
25 | | #ifdef ENABLE_SM /* empty file without SM enabled */ |
26 | | #ifdef ENABLE_OPENSSL /* empty file without openssl */ |
27 | | |
28 | | #include <ctype.h> |
29 | | #include <stdlib.h> |
30 | | #include <string.h> |
31 | | |
32 | | #include <openssl/evp.h> |
33 | | #include <openssl/sha.h> |
34 | | |
35 | | #include "internal.h" |
36 | | #include "asn1.h" |
37 | | |
38 | | #include <ctype.h> |
39 | | #include <stdlib.h> |
40 | | #include <string.h> |
41 | | |
42 | | #include <openssl/cmac.h> |
43 | | #include <openssl/rand.h> |
44 | | #include <openssl/sha.h> |
45 | | |
46 | | #include "internal.h" |
47 | | #include "asn1.h" |
48 | | #include "cardctl.h" |
49 | | |
50 | | /* |
51 | | * See https://github.com/OpenSC/OpenSC/issues/2572 |
52 | | * 2012 ATR: note version 01:00:11 |
53 | | * 3b:9f:95:81:31:fe:9f:00:66:46:53:05:01:00:11:71:df:00:00:03:90:00:80 |
54 | | * 2022 ATRs: note version 23:00:25 |
55 | | * OpenSC-initialized ATR: |
56 | | * 3b 9f:95:81:31:fe:9f:00:66:46:53:05:23:00:25:71:df:00:00:03:90:00:96 |
57 | | * Feitian-initalized ATR: |
58 | | * 3b:9f:95:81:31:fe:9f:00:66:46:53:05:23:00:25:71:df:00:00:00:00:00:05 |
59 | | */ |
60 | | |
61 | | static const struct sc_atr_table epass2003_atrs[] = { |
62 | | /* This is a FIPS certified card using SCP01 security messaging. */ |
63 | | /* will match all the above */ |
64 | | {"3B:9F:95:81:31:FE:9F:00:66:46:53:05:00:00:00:71:df:00:00:00:00:00:00", |
65 | | "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:FF:FF:FF:FF:00:00:00:00", |
66 | | "FTCOS/ePass2003", SC_CARD_TYPE_ENTERSAFE_FTCOS_EPASS2003, 0, NULL }, |
67 | | {NULL, NULL, NULL, 0, 0, NULL} |
68 | | }; |
69 | | |
70 | | static struct sc_card_operations *iso_ops = NULL; |
71 | | static struct sc_card_operations epass2003_ops; |
72 | | |
73 | | static struct sc_card_driver epass2003_drv = { |
74 | | "epass2003", |
75 | | "epass2003", |
76 | | &epass2003_ops, |
77 | | NULL, 0, NULL |
78 | | }; |
79 | | |
80 | 26.3k | #define KEY_TYPE_AES 0x01 /* FIPS mode */ |
81 | 7.94k | #define KEY_TYPE_DES 0x02 /* Non-FIPS mode */ |
82 | | |
83 | | #define KEY_LEN_AES 16 |
84 | | #define KEY_LEN_DES 8 |
85 | | #define KEY_LEN_DES3 24 |
86 | 20 | #define HASH_LEN 24 |
87 | | |
88 | | static unsigned char PIN_ID[2] = { ENTERSAFE_USER_PIN_ID, ENTERSAFE_SO_PIN_ID }; |
89 | | |
90 | | /*0x00:plain; 0x01:scp01 sm*/ |
91 | 9.13k | #define SM_PLAIN 0x00 |
92 | 4.36k | #define SM_SCP01 0x01 |
93 | | |
94 | | static unsigned char g_init_key_enc[16] = { |
95 | | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, |
96 | | 0x0D, 0x0E, 0x0F, 0x10 |
97 | | }; |
98 | | |
99 | | static unsigned char g_init_key_mac[16] = { |
100 | | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, |
101 | | 0x0D, 0x0E, 0x0F, 0x10 |
102 | | }; |
103 | | |
104 | | static unsigned char g_random[8]; |
105 | | |
106 | | typedef struct epass2003_exdata_st { |
107 | | unsigned char sm; /* SM_PLAIN or SM_SCP01 */ |
108 | | unsigned char smtype; /* KEY_TYPE_AES or KEY_TYPE_DES */ |
109 | | unsigned char sk_enc[16]; /* encrypt session key */ |
110 | | unsigned char sk_mac[16]; /* mac session key */ |
111 | | unsigned char icv_mac[16]; /* instruction counter vector(for sm) */ |
112 | | unsigned char bFipsCertification; /* fips mode Alg */ |
113 | | unsigned char currAlg; /* current Alg */ |
114 | | unsigned int ecAlgFlags; /* Ec Alg mechanism type*/ |
115 | | } epass2003_exdata; |
116 | | |
117 | 20 | #define REVERSE_ORDER4(x) ( \ |
118 | 20 | ((unsigned long)x & 0xFF000000)>> 24 | \ |
119 | 20 | ((unsigned long)x & 0x00FF0000)>> 8 | \ |
120 | 20 | ((unsigned long)x & 0x0000FF00)<< 8 | \ |
121 | 20 | ((unsigned long)x & 0x000000FF)<< 24) |
122 | | |
123 | | |
124 | | static const struct sc_card_error epass2003_errors[] = { |
125 | | { 0x6200, SC_ERROR_CARD_CMD_FAILED, "Warning: no information given, non-volatile memory is unchanged" }, |
126 | | { 0x6281, SC_ERROR_CORRUPTED_DATA, "Part of returned data may be corrupted" }, |
127 | | { 0x6282, SC_ERROR_FILE_END_REACHED, "End of file/record reached before reading Le bytes" }, |
128 | | { 0x6283, SC_ERROR_CARD_CMD_FAILED, "Selected file invalidated" }, |
129 | | { 0x6284, SC_ERROR_CARD_CMD_FAILED, "FCI not formatted according to ISO 7816-4" }, |
130 | | |
131 | | { 0x6300, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
132 | | { 0x63C1, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed. One tries left"}, |
133 | | { 0x63C2, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed. Two tries left"}, |
134 | | { 0x63C3, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
135 | | { 0x63C4, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
136 | | { 0x63C5, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
137 | | { 0x63C6, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
138 | | { 0x63C7, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
139 | | { 0x63C8, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
140 | | { 0x63C9, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
141 | | { 0x63CA, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, |
142 | | |
143 | | { 0x6381, SC_ERROR_CARD_CMD_FAILED, "Warning: file filled up by last write" }, |
144 | | |
145 | | { 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure" }, |
146 | | |
147 | | { 0x6700, SC_ERROR_WRONG_LENGTH, "Wrong length" }, |
148 | | |
149 | | { 0x6800, SC_ERROR_NO_CARD_SUPPORT, "Functions in CLA not supported" }, |
150 | | { 0x6881, SC_ERROR_NO_CARD_SUPPORT, "Logical channel not supported" }, |
151 | | { 0x6882, SC_ERROR_NO_CARD_SUPPORT, "Secure messaging not supported" }, |
152 | | |
153 | | { 0x6900, SC_ERROR_NOT_ALLOWED, "Command not allowed" }, |
154 | | { 0x6981, SC_ERROR_CARD_CMD_FAILED, "Command incompatible with file structure" }, |
155 | | { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" }, |
156 | | { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "Authentication method blocked" }, |
157 | | { 0x6984, SC_ERROR_REF_DATA_NOT_USABLE, "Referenced data not usable" }, |
158 | | { 0x6985, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied" }, |
159 | | { 0x6986, SC_ERROR_NOT_ALLOWED, "Command not allowed (no current EF)" }, |
160 | | { 0x6987, SC_ERROR_INCORRECT_PARAMETERS,"Expected SM data objects missing" }, |
161 | | { 0x6988, SC_ERROR_INCORRECT_PARAMETERS,"SM data objects incorrect" }, |
162 | | |
163 | | { 0x6A00, SC_ERROR_INCORRECT_PARAMETERS,"Wrong parameter(s) P1-P2" }, |
164 | | { 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect parameters in the data field" }, |
165 | | { 0x6A81, SC_ERROR_NO_CARD_SUPPORT, "Function not supported" }, |
166 | | { 0x6A82, SC_ERROR_FILE_NOT_FOUND, "File not found" }, |
167 | | { 0x6A83, SC_ERROR_RECORD_NOT_FOUND, "Record not found" }, |
168 | | { 0x6A84, SC_ERROR_NOT_ENOUGH_MEMORY, "Not enough memory space in the file" }, |
169 | | { 0x6A85, SC_ERROR_INCORRECT_PARAMETERS,"Lc inconsistent with TLV structure" }, |
170 | | { 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect parameters P1-P2" }, |
171 | | { 0x6A87, SC_ERROR_INCORRECT_PARAMETERS,"Lc inconsistent with P1-P2" }, |
172 | | { 0x6A88, SC_ERROR_DATA_OBJECT_NOT_FOUND,"Referenced data not found" }, |
173 | | { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File already exists"}, |
174 | | { 0x6A8A, SC_ERROR_FILE_ALREADY_EXISTS, "DF name already exists"}, |
175 | | |
176 | | { 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Wrong parameter(s) P1-P2" }, |
177 | | { 0x6D00, SC_ERROR_INS_NOT_SUPPORTED, "Instruction code not supported or invalid" }, |
178 | | { 0x6E00, SC_ERROR_CLASS_NOT_SUPPORTED, "Class not supported" }, |
179 | | { 0x6F00, SC_ERROR_CARD_CMD_FAILED, "No precise diagnosis" }, |
180 | | |
181 | | { 0x9000,SC_SUCCESS, NULL } |
182 | | }; |
183 | | |
184 | | typedef struct sec_attr_to_acl_entries { |
185 | | unsigned int file_type; /* file->type */ |
186 | | unsigned int file_ef_structure; /* file->ef_structure */ |
187 | | int index; /* index in epass2003 iversion of sec_attr */ |
188 | | /* use the follow for sc_file_add_entry */ |
189 | | int op; /* SC_AC_OP_* */ |
190 | | } sec_attr_to_acl_entries_t; |
191 | | |
192 | | // clang-format off |
193 | | /* Known combinations of file type and methods. More can be added as needed */ |
194 | | static const sec_attr_to_acl_entries_t sec_attr_to_acl_entry[] = { |
195 | | {SC_FILE_TYPE_DF, 0, 0, SC_AC_OP_LIST_FILES}, |
196 | | {SC_FILE_TYPE_DF, 0, 1, SC_AC_OP_CREATE}, |
197 | | {SC_FILE_TYPE_DF, 0, 3, SC_AC_OP_DELETE}, |
198 | | |
199 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 0, SC_AC_OP_READ}, |
200 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 1, SC_AC_OP_UPDATE}, |
201 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 3, SC_AC_OP_DELETE}, |
202 | | |
203 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 0, SC_AC_OP_READ}, |
204 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 1, SC_AC_OP_UPDATE}, |
205 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 3, SC_AC_OP_DELETE}, |
206 | | |
207 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 0, SC_AC_OP_READ}, |
208 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 1, SC_AC_OP_UPDATE}, |
209 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 2, SC_AC_OP_WRITE}, |
210 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 3, SC_AC_OP_DELETE}, |
211 | | |
212 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 0, SC_AC_OP_READ}, |
213 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 1, SC_AC_OP_UPDATE}, |
214 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 2, SC_AC_OP_WRITE}, |
215 | | {SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 3, SC_AC_OP_DELETE}, |
216 | | |
217 | | {SC_FILE_TYPE_BSO, 0, 0, SC_AC_OP_UPDATE}, |
218 | | {SC_FILE_TYPE_BSO, 0, 3, SC_AC_OP_DELETE}, |
219 | | |
220 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, 1, SC_AC_OP_UPDATE}, |
221 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_CRT, 1, SC_AC_OP_UPDATE}, |
222 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, 2, SC_AC_OP_CRYPTO}, |
223 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_CRT, 2, SC_AC_OP_CRYPTO}, |
224 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, 3, SC_AC_OP_DELETE}, |
225 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_CRT, 3, SC_AC_OP_DELETE}, |
226 | | |
227 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 0, SC_AC_OP_READ}, |
228 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC, 0, SC_AC_OP_READ}, |
229 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 1, SC_AC_OP_UPDATE}, |
230 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC, 1, SC_AC_OP_UPDATE}, |
231 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 2, SC_AC_OP_CRYPTO}, |
232 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC, 2, SC_AC_OP_CRYPTO}, |
233 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 3, SC_AC_OP_DELETE}, |
234 | | {SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC, 3, SC_AC_OP_DELETE}, |
235 | | }; |
236 | | // clang-format on |
237 | | |
238 | | static int epass2003_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu); |
239 | | static int epass2003_select_file(struct sc_card *card, const sc_path_t * in_path, sc_file_t ** file_out); |
240 | | int epass2003_refresh(struct sc_card *card); |
241 | | static int hash_data(struct sc_card *card, const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType); |
242 | | |
243 | | static int |
244 | | epass2003_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2) |
245 | 46.3k | { |
246 | 46.3k | const int err_count = sizeof(epass2003_errors)/sizeof(epass2003_errors[0]); |
247 | 46.3k | int i; |
248 | | |
249 | | /* Handle special cases here */ |
250 | 46.3k | if (sw1 == 0x6C) { |
251 | 496 | sc_log(card->ctx, "Wrong length; correct length is %d", sw2); |
252 | 496 | return SC_ERROR_WRONG_LENGTH; |
253 | 496 | } |
254 | | |
255 | 2.14M | for (i = 0; i < err_count; i++) { |
256 | 2.14M | if (epass2003_errors[i].SWs == ((sw1 << 8) | sw2)) { |
257 | 42.8k | sc_log(card->ctx, "%s", epass2003_errors[i].errorstr); |
258 | 42.8k | return epass2003_errors[i].errorno; |
259 | 42.8k | } |
260 | 2.14M | } |
261 | | |
262 | 2.99k | sc_log(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X", sw1, sw2); |
263 | 2.99k | return SC_ERROR_CARD_CMD_FAILED; |
264 | 45.8k | } |
265 | | |
266 | | static int |
267 | | sc_transmit_apdu_t(sc_card_t *card, sc_apdu_t *apdu) |
268 | 21.9k | { |
269 | 21.9k | size_t resplen = apdu->resplen; |
270 | 21.9k | int r = sc_transmit_apdu(card, apdu); |
271 | 21.9k | if ((0x69 == apdu->sw1 && 0x85 == apdu->sw2) || (0x69 == apdu->sw1 && 0x88 == apdu->sw2)) { |
272 | 711 | epass2003_refresh(card); |
273 | | /* renew old resplen */ |
274 | 711 | apdu->resplen = resplen; |
275 | 711 | r = sc_transmit_apdu(card, apdu); |
276 | 711 | } |
277 | 21.9k | return r; |
278 | 21.9k | } |
279 | | |
280 | | static int |
281 | | openssl_enc(const EVP_CIPHER * cipher, const unsigned char *key, const unsigned char *iv, |
282 | | const unsigned char *input, size_t length, unsigned char *output) |
283 | 12.1k | { |
284 | 12.1k | int r = SC_ERROR_INTERNAL; |
285 | 12.1k | EVP_CIPHER_CTX * ctx = NULL; |
286 | 12.1k | int outl = 0; |
287 | 12.1k | int outl_tmp = 0; |
288 | 12.1k | unsigned char iv_tmp[EVP_MAX_IV_LENGTH] = {0}; |
289 | | |
290 | 12.1k | memcpy(iv_tmp, iv, EVP_MAX_IV_LENGTH); |
291 | 12.1k | ctx = EVP_CIPHER_CTX_new(); |
292 | 12.1k | if (ctx == NULL) |
293 | 0 | goto out; |
294 | | |
295 | 12.1k | if (!EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv_tmp) || !EVP_CIPHER_CTX_set_padding(ctx, 0)) |
296 | 0 | goto out; |
297 | | |
298 | 12.1k | if (!EVP_EncryptUpdate(ctx, output, &outl, input, (int)length)) |
299 | 0 | goto out; |
300 | | |
301 | 12.1k | if (!EVP_EncryptFinal_ex(ctx, output + outl, &outl_tmp)) |
302 | 0 | goto out; |
303 | | |
304 | 12.1k | r = SC_SUCCESS; |
305 | 12.1k | out: |
306 | 12.1k | EVP_CIPHER_CTX_free(ctx); |
307 | 12.1k | return r; |
308 | 12.1k | } |
309 | | |
310 | | static int |
311 | | openssl_dec(const EVP_CIPHER * cipher, const unsigned char *key, const unsigned char *iv, |
312 | | const unsigned char *input, size_t length, unsigned char *output) |
313 | 3.71k | { |
314 | 3.71k | int r = SC_ERROR_INTERNAL; |
315 | 3.71k | EVP_CIPHER_CTX * ctx = NULL; |
316 | 3.71k | int outl = 0; |
317 | 3.71k | int outl_tmp = 0; |
318 | 3.71k | unsigned char iv_tmp[EVP_MAX_IV_LENGTH] = {0}; |
319 | | |
320 | 3.71k | memcpy(iv_tmp, iv, EVP_MAX_IV_LENGTH); |
321 | 3.71k | ctx = EVP_CIPHER_CTX_new(); |
322 | 3.71k | if (ctx == NULL) |
323 | 0 | goto out; |
324 | | |
325 | 3.71k | if (!EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv_tmp) || |
326 | 3.71k | !EVP_CIPHER_CTX_set_padding(ctx, 0)) |
327 | 0 | goto out; |
328 | | |
329 | 3.71k | if (!EVP_DecryptUpdate(ctx, output, &outl, input, (int)length)) |
330 | 0 | goto out; |
331 | | |
332 | 3.71k | if (!EVP_DecryptFinal_ex(ctx, output + outl, &outl_tmp)) |
333 | 89 | goto out; |
334 | | |
335 | 3.62k | r = SC_SUCCESS; |
336 | 3.71k | out: |
337 | 3.71k | EVP_CIPHER_CTX_free(ctx); |
338 | 3.71k | return r; |
339 | 3.62k | } |
340 | | |
341 | | static int |
342 | | aes128_encrypt_cmac_ft(struct sc_card *card, const unsigned char *key, int keysize, |
343 | | const unsigned char *input, size_t length, unsigned char *output,unsigned char *iv) |
344 | 0 | { |
345 | 0 | unsigned char data1[32] = {0}; |
346 | 0 | unsigned char data2[32] = {0}; |
347 | 0 | unsigned char k1Bin[32] = {0}; |
348 | 0 | unsigned char k2Bin[32] = {0}; |
349 | |
|
350 | 0 | unsigned char check = 0; |
351 | 0 | BIGNUM *enc1,*lenc1; |
352 | 0 | BIGNUM *enc2,*lenc2; |
353 | | |
354 | | // k1 |
355 | 0 | int offset = 0; |
356 | 0 | int r = SC_ERROR_INTERNAL; |
357 | 0 | unsigned char out[32] = {0}; |
358 | 0 | unsigned char iv0[EVP_MAX_IV_LENGTH] = {0}; |
359 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-ECB"); |
360 | 0 | r = openssl_enc(alg, key, iv0, data1, 16, out); |
361 | 0 | if (r != SC_SUCCESS) { |
362 | 0 | sc_log_openssl(card->ctx); |
363 | 0 | sc_evp_cipher_free(alg); |
364 | 0 | return r; |
365 | 0 | } |
366 | | |
367 | 0 | check = out[0]; |
368 | 0 | enc1 = BN_new(); |
369 | 0 | lenc1 = BN_new(); |
370 | 0 | BN_bin2bn(out,16,enc1); |
371 | 0 | BN_lshift1(lenc1,enc1); |
372 | 0 | BN_bn2bin(lenc1,k1Bin); |
373 | 0 | if (check & 0x80) { |
374 | 0 | offset = 1; |
375 | 0 | k1Bin[15+offset] ^= 0x87; |
376 | 0 | } |
377 | 0 | BN_free(enc1); |
378 | 0 | BN_free(lenc1); |
379 | | |
380 | | // k2 |
381 | 0 | enc2 = BN_new(); |
382 | 0 | lenc2 = BN_new(); |
383 | 0 | check = k1Bin[offset]; |
384 | 0 | BN_bin2bn(&k1Bin[offset],16,enc2); |
385 | |
|
386 | 0 | offset = 0; |
387 | 0 | BN_lshift1(lenc2,enc2); |
388 | 0 | BN_bn2bin(lenc2,k2Bin); |
389 | 0 | if (check & 0x80) { |
390 | 0 | offset = 1; |
391 | 0 | k2Bin[15+offset] ^= 0x87; |
392 | 0 | } |
393 | 0 | BN_free(enc2); |
394 | 0 | BN_free(lenc2); |
395 | | // padding |
396 | 0 | if (length < 16) { |
397 | 0 | memcpy(&data2[0],input,length); |
398 | 0 | data2[length] = 0x80; |
399 | 0 | } |
400 | | |
401 | | // k2 xor padded data |
402 | 0 | for (int i = 0; i < 16; i++) { |
403 | 0 | data2[i] = data2[i] ^ k2Bin[offset + i]; |
404 | 0 | } |
405 | 0 | r = openssl_enc(alg, key, iv, data2, 16, output); |
406 | 0 | sc_evp_cipher_free(alg); |
407 | 0 | if (r != SC_SUCCESS) |
408 | 0 | sc_log_openssl(card->ctx); |
409 | 0 | return r; |
410 | 0 | } |
411 | | |
412 | | static int |
413 | | aes128_encrypt_cmac(struct sc_card *card, const unsigned char *key, int keysize, |
414 | | const unsigned char *input, size_t length, unsigned char *output) |
415 | 763 | { |
416 | 763 | size_t mactlen = 0; |
417 | 763 | int r = SC_ERROR_INTERNAL; |
418 | 763 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
419 | 763 | CMAC_CTX *ctx = CMAC_CTX_new(); |
420 | 763 | if (ctx == NULL) { |
421 | 0 | return SC_ERROR_INTERNAL; |
422 | 0 | } |
423 | | |
424 | 763 | if (!CMAC_Init(ctx, key, keysize / 8, EVP_aes_128_cbc(), NULL)) { |
425 | 0 | goto err; |
426 | 0 | } |
427 | 763 | if (!CMAC_Update(ctx, input, length)) { |
428 | 0 | goto err; |
429 | 0 | } |
430 | 763 | if (!CMAC_Final(ctx, output, &mactlen)) { |
431 | 0 | goto err; |
432 | 0 | } |
433 | 763 | r = SC_SUCCESS; |
434 | 763 | err: |
435 | 763 | CMAC_CTX_free(ctx); |
436 | | #else |
437 | | EVP_MAC *mac = EVP_MAC_fetch(card->ctx->ossl3ctx->libctx, "cmac", NULL); |
438 | | if (mac == NULL) { |
439 | | return r; |
440 | | } |
441 | | |
442 | | OSSL_PARAM params[2] = {0}; |
443 | | params[0] = OSSL_PARAM_construct_utf8_string("cipher","aes-128-cbc", 0); |
444 | | params[1] = OSSL_PARAM_construct_end(); |
445 | | |
446 | | EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac); |
447 | | if (ctx == NULL) { |
448 | | EVP_MAC_CTX_free(ctx); |
449 | | sc_log_openssl(card->ctx); |
450 | | return r; |
451 | | } |
452 | | if (!EVP_MAC_init(ctx, (const unsigned char *)key, keysize / 8, params)) { |
453 | | sc_log_openssl(card->ctx); |
454 | | goto err; |
455 | | } |
456 | | if (!EVP_MAC_update(ctx, input, length)) { |
457 | | sc_log_openssl(card->ctx); |
458 | | goto err; |
459 | | } |
460 | | if (!EVP_MAC_final(ctx, output, &mactlen, 16)) { |
461 | | sc_log_openssl(card->ctx); |
462 | | goto err; |
463 | | } |
464 | | r = SC_SUCCESS; |
465 | | err: |
466 | | EVP_MAC_CTX_free(ctx); |
467 | | EVP_MAC_free(mac); |
468 | | #endif |
469 | 763 | return r; |
470 | 763 | } |
471 | | |
472 | | static int |
473 | | aes128_encrypt_ecb(struct sc_card *card, const unsigned char *key, int keysize, |
474 | | const unsigned char *input, size_t length, unsigned char *output) |
475 | 140 | { |
476 | 140 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
477 | 140 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-ECB"); |
478 | 140 | int r; |
479 | 140 | r = openssl_enc(alg, key, iv, input, length, output); |
480 | 140 | sc_evp_cipher_free(alg); |
481 | 140 | if (r != SC_SUCCESS) |
482 | 0 | sc_log_openssl(card->ctx); |
483 | 140 | return r; |
484 | 140 | } |
485 | | |
486 | | |
487 | | static int |
488 | | aes128_encrypt_cbc(struct sc_card *card, const unsigned char *key, int keysize, unsigned char iv[16], |
489 | | const unsigned char *input, size_t length, unsigned char *output) |
490 | 822 | { |
491 | 822 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-CBC"); |
492 | 822 | int r; |
493 | 822 | r = openssl_enc(alg, key, iv, input, length, output); |
494 | 822 | sc_evp_cipher_free(alg); |
495 | 822 | if (r != SC_SUCCESS) |
496 | 0 | sc_log_openssl(card->ctx); |
497 | 822 | return r; |
498 | 822 | } |
499 | | |
500 | | |
501 | | static int |
502 | | aes128_decrypt_cbc(struct sc_card *card, const unsigned char *key, int keysize, unsigned char iv[16], |
503 | | const unsigned char *input, size_t length, unsigned char *output) |
504 | 141 | { |
505 | 141 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-CBC"); |
506 | 141 | int r; |
507 | 141 | r = openssl_dec(alg, key, iv, input, length, output); |
508 | 141 | sc_evp_cipher_free(alg); |
509 | 141 | if (r != SC_SUCCESS) |
510 | 89 | sc_log_openssl(card->ctx); |
511 | 141 | return r; |
512 | 141 | } |
513 | | |
514 | | |
515 | | static int |
516 | | des3_encrypt_ecb(struct sc_card *card, const unsigned char *key, int keysize, |
517 | | const unsigned char *input, int length, unsigned char *output) |
518 | 522 | { |
519 | 522 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
520 | 522 | unsigned char bKey[24] = {0}; |
521 | 522 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-EDE3"); |
522 | 522 | int r; |
523 | | |
524 | 522 | if (keysize == 16) { |
525 | 522 | memcpy(&bKey[0], key, 16); |
526 | 522 | memcpy(&bKey[16], key, 8); |
527 | 522 | } else { |
528 | 0 | memcpy(&bKey[0], key, 24); |
529 | 0 | } |
530 | | |
531 | 522 | r = openssl_enc(alg, bKey, iv, input, length, output); |
532 | 522 | sc_evp_cipher_free(alg); |
533 | 522 | if (r != SC_SUCCESS) |
534 | 0 | sc_log_openssl(card->ctx); |
535 | 522 | return r; |
536 | 522 | } |
537 | | |
538 | | |
539 | | static int |
540 | | des3_encrypt_cbc(struct sc_card *card, const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], |
541 | | const unsigned char *input, size_t length, unsigned char *output) |
542 | 3.53k | { |
543 | 3.53k | unsigned char bKey[24] = {0}; |
544 | 3.53k | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-EDE3-CBC"); |
545 | 3.53k | int r; |
546 | | |
547 | 3.53k | if (keysize == 16) { |
548 | 3.53k | memcpy(&bKey[0], key, 16); |
549 | 3.53k | memcpy(&bKey[16], key, 8); |
550 | 3.53k | } else { |
551 | 0 | memcpy(&bKey[0], key, 24); |
552 | 0 | } |
553 | | |
554 | 3.53k | r = openssl_enc(EVP_des_ede3_cbc(), bKey, iv, input, length, output); |
555 | 3.53k | sc_evp_cipher_free(alg); |
556 | 3.53k | if (r != SC_SUCCESS) |
557 | 0 | sc_log_openssl(card->ctx); |
558 | 3.53k | return r; |
559 | 3.53k | } |
560 | | |
561 | | |
562 | | static int |
563 | | des3_decrypt_cbc(struct sc_card *card, const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], |
564 | | const unsigned char *input, size_t length, unsigned char *output) |
565 | 0 | { |
566 | 0 | unsigned char bKey[24] = {0}; |
567 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-EDE3-CBC"); |
568 | 0 | int r; |
569 | |
|
570 | 0 | if (keysize == 16) { |
571 | 0 | memcpy(&bKey[0], key, 16); |
572 | 0 | memcpy(&bKey[16], key, 8); |
573 | 0 | } else { |
574 | 0 | memcpy(&bKey[0], key, 24); |
575 | 0 | } |
576 | |
|
577 | 0 | r = openssl_dec(alg, bKey, iv, input, length, output); |
578 | 0 | sc_evp_cipher_free(alg); |
579 | 0 | if (r != SC_SUCCESS) |
580 | 0 | sc_log_openssl(card->ctx); |
581 | 0 | return r; |
582 | 0 | } |
583 | | |
584 | | |
585 | | static int |
586 | | des_encrypt_cbc(struct sc_card *card, const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], |
587 | | const unsigned char *input, size_t length, unsigned char *output) |
588 | 7.15k | { |
589 | 7.15k | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-CBC"); |
590 | 7.15k | int r; |
591 | | |
592 | 7.15k | r = openssl_enc(alg, key, iv, input, length, output); |
593 | 7.15k | sc_evp_cipher_free(alg); |
594 | 7.15k | if (r != SC_SUCCESS) |
595 | 0 | sc_log_openssl(card->ctx); |
596 | 7.15k | return r; |
597 | 7.15k | } |
598 | | |
599 | | |
600 | | static int |
601 | | des_decrypt_cbc(struct sc_card *card, const unsigned char *key, int keysize, unsigned char iv[EVP_MAX_IV_LENGTH], |
602 | | const unsigned char *input, size_t length, unsigned char *output) |
603 | 3.57k | { |
604 | 3.57k | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-CBC"); |
605 | 3.57k | int r; |
606 | | |
607 | 3.57k | r = openssl_dec(alg, key, iv, input, length, output); |
608 | 3.57k | sc_evp_cipher_free(alg); |
609 | 3.57k | if (r != SC_SUCCESS) |
610 | 0 | sc_log_openssl(card->ctx); |
611 | 3.57k | return r; |
612 | 3.57k | } |
613 | | |
614 | | |
615 | | static int |
616 | | openssl_dig(const EVP_MD * digest, const unsigned char *input, size_t length, |
617 | | unsigned char *output) |
618 | 20 | { |
619 | 20 | int r = 0; |
620 | 20 | EVP_MD_CTX *ctx = NULL; |
621 | 20 | unsigned outl = 0; |
622 | | |
623 | 20 | ctx = EVP_MD_CTX_create(); |
624 | 20 | if (ctx == NULL) { |
625 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
626 | 0 | goto err; |
627 | 0 | } |
628 | | |
629 | 20 | EVP_MD_CTX_init(ctx); |
630 | 20 | if (!EVP_DigestInit_ex(ctx, digest, NULL) || |
631 | 20 | !EVP_DigestUpdate(ctx, input, length)) { |
632 | 0 | r = SC_ERROR_INTERNAL; |
633 | 0 | goto err; |
634 | 0 | } |
635 | | |
636 | 20 | if (!EVP_DigestFinal_ex(ctx, output, &outl)) { |
637 | 0 | r = SC_ERROR_INTERNAL; |
638 | 0 | goto err; |
639 | 0 | } |
640 | 20 | r = SC_SUCCESS; |
641 | 20 | err: |
642 | 20 | if (ctx) |
643 | 20 | EVP_MD_CTX_destroy(ctx); |
644 | | |
645 | 20 | return r; |
646 | 20 | } |
647 | | |
648 | | |
649 | | static int |
650 | | sha1_digest(struct sc_card *card, const unsigned char *input, size_t length, unsigned char *output) |
651 | 20 | { |
652 | 20 | EVP_MD *md = sc_evp_md(card->ctx, "SHA1"); |
653 | 20 | int r; |
654 | | |
655 | 20 | r = openssl_dig(md, input, length, output); |
656 | 20 | sc_evp_md_free(md); |
657 | 20 | if (r != SC_SUCCESS) |
658 | 0 | sc_log_openssl(card->ctx); |
659 | 20 | return r; |
660 | 20 | } |
661 | | |
662 | | static int |
663 | | sha256_digest(struct sc_card *card, const unsigned char *input, size_t length, unsigned char *output) |
664 | 0 | { |
665 | 0 | EVP_MD *md = sc_evp_md(card->ctx, "SHA256"); |
666 | 0 | int r; |
667 | |
|
668 | 0 | r = openssl_dig(md, input, length, output); |
669 | 0 | sc_evp_md_free(md); |
670 | 0 | if (r != SC_SUCCESS) |
671 | 0 | sc_log_openssl(card->ctx); |
672 | 0 | return r; |
673 | 0 | } |
674 | | |
675 | | |
676 | | static int |
677 | | gen_init_key(struct sc_card *card, unsigned char *key_enc, unsigned char *key_mac, |
678 | | unsigned char *result, unsigned char key_type) |
679 | 4.04k | { |
680 | 4.04k | int r; |
681 | 4.04k | struct sc_apdu apdu; |
682 | 4.04k | unsigned char data[256] = {0}; |
683 | 4.04k | unsigned char tmp_sm; |
684 | 4.04k | unsigned char isFips; |
685 | 4.04k | unsigned long blocksize = 0; |
686 | 4.04k | unsigned char cryptogram[256] = {0}; /* host cryptogram */ |
687 | 4.04k | unsigned char iv[16] = {0}; |
688 | 4.04k | epass2003_exdata *exdata = NULL; |
689 | | |
690 | 4.04k | if (!card->drv_data) |
691 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
692 | | |
693 | 4.04k | exdata = (epass2003_exdata *)card->drv_data; |
694 | 4.04k | isFips = exdata->bFipsCertification; |
695 | | |
696 | 4.04k | LOG_FUNC_CALLED(card->ctx); |
697 | | |
698 | 4.04k | if (1 != RAND_bytes(g_random, sizeof(g_random))) |
699 | 0 | return SC_ERROR_INTERNAL; |
700 | | |
701 | 4.04k | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x50, 0x00, 0x00); |
702 | 4.04k | apdu.cla = 0x80; |
703 | 4.04k | apdu.lc = apdu.datalen = sizeof(g_random); |
704 | 4.04k | apdu.data = g_random; /* host random */ |
705 | 4.04k | if (isFips) |
706 | 380 | apdu.le = apdu.resplen = 29; |
707 | 3.66k | else |
708 | 3.66k | apdu.le = apdu.resplen = 28; |
709 | | |
710 | 4.04k | apdu.resp = result; /* card random is result[12~19] */ |
711 | | |
712 | 4.04k | tmp_sm = exdata->sm; |
713 | 4.04k | exdata->sm = SM_PLAIN; |
714 | 4.04k | r = epass2003_transmit_apdu(card, &apdu); |
715 | 4.04k | exdata->sm = tmp_sm; |
716 | 4.04k | LOG_TEST_RET(card->ctx, r, "APDU gen_init_key failed"); |
717 | | |
718 | 3.95k | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
719 | 3.95k | LOG_TEST_RET(card->ctx, r, "gen_init_key failed"); |
720 | | |
721 | | /* Step 1 - Generate Derivation data */ |
722 | 416 | if (isFips) { |
723 | 85 | memset(data, 0x00, 15); |
724 | 85 | data[11] = 0x04; |
725 | 85 | data[14] = 0x80; |
726 | 85 | data[15] = 0x01; |
727 | 85 | memcpy(&data[16], g_random, 8); |
728 | 85 | memcpy(&data[24], &result[12 + 1], 8); |
729 | 331 | } else { |
730 | 331 | memcpy(data, &result[16], 4); |
731 | 331 | memcpy(&data[4], g_random, 4); |
732 | 331 | memcpy(&data[8], &result[12], 4); |
733 | 331 | memcpy(&data[12], &g_random[4], 4); |
734 | 331 | } |
735 | | |
736 | | /* Step 2,3 - Create S-ENC/S-MAC Session Key */ |
737 | 416 | if (KEY_TYPE_AES == key_type) { |
738 | 155 | if (isFips) { |
739 | 85 | r = aes128_encrypt_cmac(card, key_enc, 128, data, 32, exdata->sk_enc); |
740 | 85 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac enc failed"); |
741 | 85 | memset(&data[11], 0x06, 1); |
742 | 85 | r = aes128_encrypt_cmac(card, key_mac, 128, data, 32, exdata->sk_mac); |
743 | 85 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac mac failed"); |
744 | 85 | } else { |
745 | 70 | r = aes128_encrypt_ecb(card, key_enc, 16, data, 16, exdata->sk_enc); |
746 | 70 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_ecb enc failed"); |
747 | 70 | r = aes128_encrypt_ecb(card, key_mac, 16, data, 16, exdata->sk_mac); |
748 | 70 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_ecb mac failed"); |
749 | 70 | } |
750 | 261 | } else { |
751 | 261 | r = des3_encrypt_ecb(card, key_enc, 16, data, 16, exdata->sk_enc); |
752 | 261 | LOG_TEST_RET(card->ctx, r, "des3_encrypt_ecb failed"); |
753 | 261 | r = des3_encrypt_ecb(card, key_mac, 16, data, 16, exdata->sk_mac); |
754 | 261 | LOG_TEST_RET(card->ctx, r, "des3_encrypt_ecb failed"); |
755 | 261 | } |
756 | | |
757 | 416 | if (isFips) { |
758 | 85 | data[11] = 0x00; |
759 | 85 | data[14] = 0x40; |
760 | 331 | } else { |
761 | 331 | memcpy(data, g_random, 8); |
762 | 331 | memcpy(&data[8], &result[12], 8); |
763 | 331 | data[16] = 0x80; |
764 | 331 | blocksize = (key_type == KEY_TYPE_AES ? 16 : 8); |
765 | 331 | memset(&data[17], 0x00, blocksize - 1); |
766 | 331 | } |
767 | | |
768 | | /* calculate host cryptogram */ |
769 | 416 | if (KEY_TYPE_AES == key_type) { |
770 | 155 | if (isFips) { |
771 | 85 | r = aes128_encrypt_cmac(card, exdata->sk_enc, 128, data, 32, cryptogram); |
772 | 85 | } else { |
773 | 70 | r = aes128_encrypt_cbc(card, exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram); |
774 | 70 | } |
775 | 261 | } else { |
776 | 261 | r = des3_encrypt_cbc(card, exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram); |
777 | 261 | } |
778 | | |
779 | 416 | LOG_TEST_RET(card->ctx, r, "calculate host cryptogram failed"); |
780 | | |
781 | | /* verify card cryptogram */ |
782 | 416 | if (isFips) { |
783 | 85 | if (0 != memcmp(&cryptogram[0], &result[20+1], 8)) |
784 | 85 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED); |
785 | 331 | } else { |
786 | 331 | if (0 != memcmp(&cryptogram[16], &result[20], 8)) |
787 | 331 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED); |
788 | 331 | } |
789 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
790 | 0 | } |
791 | | |
792 | | |
793 | | static int |
794 | | verify_init_key(struct sc_card *card, unsigned char *ran_key, unsigned char key_type) |
795 | 0 | { |
796 | 0 | int r; |
797 | 0 | struct sc_apdu apdu; |
798 | 0 | unsigned long blocksize = (key_type == KEY_TYPE_AES ? 16 : 8); |
799 | 0 | unsigned char data[256] = {0}; |
800 | 0 | unsigned char cryptogram[256] = {0}; /* host cryptogram */ |
801 | 0 | unsigned char iv[16] = {0}; |
802 | 0 | unsigned char mac[256] = {0}; |
803 | 0 | unsigned long i; |
804 | 0 | unsigned char tmp_sm; |
805 | 0 | unsigned char isFips; |
806 | 0 | epass2003_exdata *exdata = NULL; |
807 | |
|
808 | 0 | if (!card->drv_data) |
809 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
810 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
811 | 0 | isFips = exdata->bFipsCertification; |
812 | |
|
813 | 0 | LOG_FUNC_CALLED(card->ctx); |
814 | |
|
815 | 0 | if (isFips) { |
816 | 0 | memset(data,0x00,15); |
817 | 0 | data[11] = 0x01; |
818 | 0 | data[14] = 0x40; |
819 | 0 | data[15] = 0x01; |
820 | 0 | memcpy(&data[16], g_random, 8); |
821 | 0 | memcpy(&data[24], ran_key, 8); |
822 | 0 | } else { |
823 | 0 | memcpy(data, ran_key, 8); |
824 | 0 | memcpy(&data[8], g_random, 8); |
825 | 0 | data[16] = 0x80; |
826 | 0 | memset(&data[17], 0x00, blocksize - 1); |
827 | 0 | memset(iv, 0, 16); |
828 | 0 | } |
829 | | |
830 | | /* calculate host cryptogram */ |
831 | 0 | if (KEY_TYPE_AES == key_type) { |
832 | 0 | if (isFips) { |
833 | 0 | r = aes128_encrypt_cmac(card, exdata->sk_enc, 128, data, 32, cryptogram); |
834 | 0 | } else { |
835 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_enc, 16, iv, data, 16 + blocksize,cryptogram); |
836 | 0 | } |
837 | 0 | } else { |
838 | 0 | r = des3_encrypt_cbc(card, exdata->sk_enc, 16, iv, data, 16 + blocksize,cryptogram); |
839 | 0 | } |
840 | |
|
841 | 0 | LOG_TEST_RET(card->ctx, r, "calculate host cryptogram failed"); |
842 | | |
843 | 0 | memset(data, 0, sizeof(data)); |
844 | 0 | memcpy(data, "\x84\x82\x03\x00\x10", 5); |
845 | 0 | if (isFips) { |
846 | 0 | memcpy(&data[5], &cryptogram[0], 8); |
847 | 0 | } else { |
848 | 0 | memcpy(&data[5], &cryptogram[16], 8); |
849 | 0 | memcpy(&data[13], "\x80\x00\x00", 3); |
850 | 0 | } |
851 | | |
852 | | /* calculate mac icv */ |
853 | 0 | memset(iv, 0x00, 16); |
854 | 0 | if (KEY_TYPE_AES == key_type) { |
855 | 0 | if (isFips) { |
856 | 0 | r = aes128_encrypt_cmac(card, exdata->sk_mac, 128, data, 13, mac); |
857 | 0 | } else { |
858 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_mac, 16, iv, data, 16, mac); |
859 | 0 | } |
860 | 0 | i = 0; |
861 | 0 | } else { |
862 | 0 | r = des3_encrypt_cbc(card, exdata->sk_mac, 16, iv, data, 16, mac); |
863 | 0 | i = 8; |
864 | 0 | } |
865 | |
|
866 | 0 | LOG_TEST_RET(card->ctx, r, "calculate mac icv failed"); |
867 | | /* save mac icv */ |
868 | 0 | memset(exdata->icv_mac, 0x00, 16); |
869 | 0 | memcpy(exdata->icv_mac, &mac[i], 8); |
870 | | |
871 | | /* verify host cryptogram */ |
872 | 0 | if (isFips) { |
873 | 0 | memcpy(data, &cryptogram[0], 8); |
874 | 0 | } else { |
875 | 0 | memcpy(data, &cryptogram[16], 8); |
876 | 0 | } |
877 | 0 | memcpy(&data[8], &mac[i], 8); |
878 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x03, 0x00); |
879 | 0 | apdu.cla = 0x84; |
880 | 0 | apdu.lc = apdu.datalen = 16; |
881 | 0 | apdu.data = data; |
882 | 0 | tmp_sm = exdata->sm; |
883 | 0 | exdata->sm = SM_PLAIN; |
884 | 0 | r = epass2003_transmit_apdu(card, &apdu); |
885 | 0 | exdata->sm = tmp_sm; |
886 | 0 | LOG_TEST_RET(card->ctx, r, "APDU verify_init_key failed"); |
887 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
888 | 0 | LOG_TEST_RET(card->ctx, r, "verify_init_key failed"); |
889 | 0 | return r; |
890 | 0 | } |
891 | | |
892 | | |
893 | | static int |
894 | | mutual_auth(struct sc_card *card, unsigned char *key_enc, |
895 | | unsigned char *key_mac) |
896 | 4.04k | { |
897 | 4.04k | struct sc_context *ctx = card->ctx; |
898 | 4.04k | int r; |
899 | 4.04k | unsigned char result[256] = {0}; |
900 | 4.04k | unsigned char ran_key[8] = {0}; |
901 | 4.04k | epass2003_exdata *exdata = NULL; |
902 | | |
903 | 4.04k | if (!card->drv_data) |
904 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
905 | 4.04k | exdata = (epass2003_exdata *)card->drv_data; |
906 | | |
907 | 4.04k | LOG_FUNC_CALLED(ctx); |
908 | | |
909 | 4.04k | r = gen_init_key(card, key_enc, key_mac, result, exdata->smtype); |
910 | 4.04k | LOG_TEST_RET(ctx, r, "gen_init_key failed"); |
911 | 0 | if (exdata->bFipsCertification) { |
912 | 0 | memcpy(ran_key, &result[12+1], 8); |
913 | 0 | } else { |
914 | 0 | memcpy(ran_key, &result[12], 8); |
915 | 0 | } |
916 | |
|
917 | 0 | r = verify_init_key(card, ran_key, exdata->smtype); |
918 | 0 | LOG_TEST_RET(ctx, r, "verify_init_key failed"); |
919 | | |
920 | 0 | LOG_FUNC_RETURN(ctx, r); |
921 | 0 | } |
922 | | |
923 | | |
924 | | int |
925 | | epass2003_refresh(struct sc_card *card) |
926 | 4.93k | { |
927 | 4.93k | int r = SC_SUCCESS; |
928 | 4.93k | epass2003_exdata *exdata = NULL; |
929 | | |
930 | 4.93k | if (!card->drv_data) |
931 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
932 | | |
933 | 4.93k | exdata = (epass2003_exdata *)card->drv_data; |
934 | | |
935 | 4.93k | if (exdata->sm) { |
936 | 4.04k | card->sm_ctx.sm_mode = 0; |
937 | 4.04k | r = mutual_auth(card, g_init_key_enc, g_init_key_mac); |
938 | 4.04k | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
939 | 4.04k | LOG_TEST_RET(card->ctx, r, "mutual_auth failed"); |
940 | 4.04k | } |
941 | | |
942 | 881 | return r; |
943 | 4.93k | } |
944 | | |
945 | | |
946 | | /* Data(TLV)=0x87|L|0x01+Cipher */ |
947 | | static int |
948 | | construct_data_tlv(struct sc_card *card, struct sc_apdu *apdu, unsigned char *apdu_buf, |
949 | | unsigned char *data_tlv, size_t * data_tlv_len, const unsigned char key_type) |
950 | 3.82k | { |
951 | 3.82k | size_t block_size = (KEY_TYPE_AES == key_type ? 16 : 8); |
952 | 3.82k | unsigned char pad[4096] = {0}; |
953 | 3.82k | size_t pad_len; |
954 | 3.82k | size_t tlv_more; /* increased tlv length */ |
955 | 3.82k | unsigned char iv[16] = {0}; |
956 | 3.82k | epass2003_exdata *exdata = NULL; |
957 | 3.82k | int r = 0; |
958 | | |
959 | 3.82k | if (!card->drv_data) |
960 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
961 | | |
962 | 3.82k | exdata = (epass2003_exdata *)card->drv_data; |
963 | | |
964 | | /* padding */ |
965 | 3.82k | apdu_buf[block_size] = 0x87; |
966 | 3.82k | memcpy(pad, apdu->data, apdu->lc); |
967 | 3.82k | pad[apdu->lc] = 0x80; |
968 | 3.82k | if ((apdu->lc + 1) % block_size) |
969 | 3.80k | pad_len = ((apdu->lc + 1) / block_size + 1) * block_size; |
970 | 19 | else |
971 | 19 | pad_len = apdu->lc + 1; |
972 | | |
973 | | /* encode Lc' */ |
974 | 3.82k | if (pad_len > 0x7E) { |
975 | | /* Lc' > 0x7E, use extended APDU */ |
976 | 12 | apdu_buf[block_size + 1] = 0x82; |
977 | 12 | apdu_buf[block_size + 2] = (unsigned char)((pad_len + 1) / 0x100); |
978 | 12 | apdu_buf[block_size + 3] = (unsigned char)((pad_len + 1) % 0x100); |
979 | 12 | apdu_buf[block_size + 4] = 0x01; |
980 | 12 | tlv_more = 5; |
981 | 3.81k | } else { |
982 | 3.81k | apdu_buf[block_size + 1] = (unsigned char)pad_len + 1; |
983 | 3.81k | apdu_buf[block_size + 2] = 0x01; |
984 | 3.81k | tlv_more = 3; |
985 | 3.81k | } |
986 | 3.82k | memcpy(data_tlv, &apdu_buf[block_size], tlv_more); |
987 | | |
988 | | /* encrypt Data */ |
989 | 3.82k | if (KEY_TYPE_AES == key_type) { |
990 | 556 | r = aes128_encrypt_cbc(card, exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more); |
991 | 556 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed"); |
992 | 3.27k | } else { |
993 | 3.27k | r = des3_encrypt_cbc(card, exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more); |
994 | 3.27k | LOG_TEST_RET(card->ctx, r, "des3_encrypt_cbc failed"); |
995 | 3.27k | } |
996 | | |
997 | 3.82k | memcpy(data_tlv + tlv_more, apdu_buf + block_size + tlv_more, pad_len); |
998 | 3.82k | *data_tlv_len = tlv_more + pad_len; |
999 | 3.82k | return 0; |
1000 | 3.82k | } |
1001 | | |
1002 | | |
1003 | | /* Le(TLV)=0x97|L|Le */ |
1004 | | static int |
1005 | | construct_le_tlv(struct sc_apdu *apdu, unsigned char *apdu_buf, size_t data_tlv_len, |
1006 | | unsigned char *le_tlv, size_t * le_tlv_len, const unsigned char key_type) |
1007 | 4.15k | { |
1008 | 4.15k | size_t block_size = (KEY_TYPE_AES == key_type ? 16 : 8); |
1009 | | |
1010 | 4.15k | *(apdu_buf + block_size + data_tlv_len) = 0x97; |
1011 | 4.15k | if (apdu->le > 0x7F) { |
1012 | | /* Le' > 0x7E, use extended APDU */ |
1013 | 58 | *(apdu_buf + block_size + data_tlv_len + 1) = 2; |
1014 | 58 | *(apdu_buf + block_size + data_tlv_len + 2) = (unsigned char)(apdu->le / 0x100); |
1015 | 58 | *(apdu_buf + block_size + data_tlv_len + 3) = (unsigned char)(apdu->le % 0x100); |
1016 | 58 | memcpy(le_tlv, apdu_buf + block_size + data_tlv_len, 4); |
1017 | 58 | *le_tlv_len = 4; |
1018 | 4.09k | } else { |
1019 | 4.09k | *(apdu_buf + block_size + data_tlv_len + 1) = 1; |
1020 | 4.09k | *(apdu_buf + block_size + data_tlv_len + 2) = (unsigned char)apdu->le; |
1021 | 4.09k | memcpy(le_tlv, apdu_buf + block_size + data_tlv_len, 3); |
1022 | 4.09k | *le_tlv_len = 3; |
1023 | 4.09k | } |
1024 | 4.15k | return 0; |
1025 | 4.15k | } |
1026 | | |
1027 | | |
1028 | | /* MAC(TLV)=0x8e|0x08|MAC */ |
1029 | | static int |
1030 | | construct_mac_tlv(struct sc_card *card, unsigned char *apdu_buf, size_t data_tlv_len, size_t le_tlv_len, |
1031 | | unsigned char *mac_tlv, size_t * mac_tlv_len, const unsigned char key_type) |
1032 | 4.19k | { |
1033 | 4.19k | size_t block_size = (KEY_TYPE_AES == key_type ? 16 : 8); |
1034 | 4.19k | unsigned char mac[4096] = {0}; |
1035 | 4.19k | size_t mac_len; |
1036 | 4.19k | unsigned char icv[16] = {0}; |
1037 | 4.19k | int r ; |
1038 | 4.19k | int i = (KEY_TYPE_AES == key_type ? 15 : 7); |
1039 | 4.19k | epass2003_exdata *exdata = NULL; |
1040 | | |
1041 | 4.19k | if (!card->drv_data) |
1042 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1043 | | |
1044 | 4.19k | exdata = (epass2003_exdata *)card->drv_data; |
1045 | | |
1046 | 4.19k | if (0 == data_tlv_len && 0 == le_tlv_len) { |
1047 | 0 | mac_len = block_size; |
1048 | 4.19k | } else { |
1049 | | /* padding */ |
1050 | 4.19k | *(apdu_buf + block_size + data_tlv_len + le_tlv_len) = 0x80; |
1051 | 4.19k | if ((data_tlv_len + le_tlv_len + 1) % block_size) { |
1052 | 4.14k | mac_len = (((data_tlv_len + le_tlv_len + 1) / block_size) + |
1053 | 4.14k | 1) * block_size + block_size; |
1054 | 4.14k | } else { |
1055 | 49 | mac_len = data_tlv_len + le_tlv_len + 1 + block_size; |
1056 | 49 | } |
1057 | 4.19k | memset((apdu_buf + block_size + data_tlv_len + le_tlv_len + 1), |
1058 | 4.19k | 0, (mac_len - (data_tlv_len + le_tlv_len + 1))); |
1059 | 4.19k | } |
1060 | | |
1061 | | /* increase icv */ |
1062 | 4.19k | for (; i >= 0; i--) { |
1063 | 4.19k | if (exdata->icv_mac[i] == 0xff) { |
1064 | 0 | exdata->icv_mac[i] = 0; |
1065 | 4.19k | } else { |
1066 | 4.19k | exdata->icv_mac[i]++; |
1067 | 4.19k | break; |
1068 | 4.19k | } |
1069 | 4.19k | } |
1070 | | |
1071 | | /* calculate MAC */ |
1072 | 4.19k | memset(icv, 0, sizeof(icv)); |
1073 | 4.19k | memcpy(icv, exdata->icv_mac, 16); |
1074 | 4.19k | if (KEY_TYPE_AES == key_type) { |
1075 | 698 | if (exdata->bFipsCertification) { |
1076 | 8.63k | for (int i = 0; i < 16; i++) { |
1077 | 8.12k | apdu_buf[i] = apdu_buf[i] ^ icv[i]; |
1078 | 8.12k | } |
1079 | 508 | r = aes128_encrypt_cmac(card, exdata->sk_mac, 128, apdu_buf, data_tlv_len + le_tlv_len + block_size, mac); |
1080 | 508 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac failed"); |
1081 | 508 | memcpy(mac_tlv + 2, &mac[0 /*ulmacLen-16*/], 8); |
1082 | 2.54k | for (int j = 0; j < 4; j++) { |
1083 | 2.03k | apdu_buf[j] = apdu_buf[j] ^ icv[j]; |
1084 | 2.03k | } |
1085 | 508 | } else { |
1086 | 190 | r = aes128_encrypt_cbc(card, exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac); |
1087 | 190 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed"); |
1088 | 190 | memcpy(mac_tlv + 2, &mac[mac_len - 16], 8); |
1089 | 190 | } |
1090 | 3.49k | } else { |
1091 | 3.49k | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
1092 | 3.49k | unsigned char tmp[8] = {0}; |
1093 | 3.49k | r = des_encrypt_cbc(card, exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac); |
1094 | 3.49k | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc 1 failed"); |
1095 | 3.49k | r = des_decrypt_cbc(card, &exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp); |
1096 | 3.49k | LOG_TEST_RET(card->ctx, r, "des_decrypt_cbc failed"); |
1097 | 3.49k | memset(iv, 0x00, sizeof iv); |
1098 | 3.49k | r = des_encrypt_cbc(card, exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2); |
1099 | 3.49k | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc 2 failed"); |
1100 | 3.49k | } |
1101 | | |
1102 | 4.19k | *mac_tlv_len = 2 + 8; |
1103 | 4.19k | return 0; |
1104 | 4.19k | } |
1105 | | |
1106 | | /* MAC(TLV case 1) */ |
1107 | | static int |
1108 | | construct_mac_tlv_case1(struct sc_card *card, unsigned char *apdu_buf, size_t data_tlv_len, size_t le_tlv_len, |
1109 | | unsigned char *mac_tlv, size_t * mac_tlv_len, const unsigned char key_type) |
1110 | 0 | { |
1111 | 0 | int r; |
1112 | 0 | size_t block_size = 4; |
1113 | 0 | unsigned char mac[4096] = {0}; |
1114 | 0 | size_t mac_len; |
1115 | 0 | int i = (KEY_TYPE_AES == key_type ? 15 : 7); |
1116 | 0 | unsigned char icv[16] = {0}; |
1117 | |
|
1118 | 0 | epass2003_exdata *exdata = NULL; |
1119 | |
|
1120 | 0 | if (!card->drv_data) |
1121 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1122 | | |
1123 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1124 | |
|
1125 | 0 | if (0 == data_tlv_len && 0 == le_tlv_len) { |
1126 | 0 | mac_len = block_size; |
1127 | 0 | } else { |
1128 | | /* padding */ |
1129 | 0 | *(apdu_buf + block_size + data_tlv_len + le_tlv_len) = 0x80; |
1130 | 0 | if ((data_tlv_len + le_tlv_len + 1) % block_size) { |
1131 | 0 | mac_len = (((data_tlv_len + le_tlv_len + 1) / block_size) + 1) * block_size + block_size; |
1132 | 0 | } else { |
1133 | 0 | mac_len = data_tlv_len + le_tlv_len + 1 + block_size; |
1134 | 0 | } |
1135 | 0 | } |
1136 | | /* increase icv */ |
1137 | 0 | for (; i >= 0; i--) { |
1138 | 0 | if (exdata->icv_mac[i] == 0xff) { |
1139 | 0 | exdata->icv_mac[i] = 0; |
1140 | 0 | } else { |
1141 | 0 | exdata->icv_mac[i]++; |
1142 | 0 | break; |
1143 | 0 | } |
1144 | 0 | } |
1145 | | |
1146 | | /* calculate MAC */ |
1147 | 0 | memset(icv, 0, sizeof(icv)); |
1148 | 0 | memcpy(icv, exdata->icv_mac, 16); |
1149 | 0 | if (KEY_TYPE_AES == key_type) { |
1150 | 0 | if (exdata->bFipsCertification) { |
1151 | 0 | r = aes128_encrypt_cmac_ft(card, exdata->sk_mac, 128, apdu_buf, data_tlv_len + le_tlv_len + block_size, mac, &icv[0]); |
1152 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac_ft failed"); |
1153 | 0 | memcpy(mac_tlv + 2, &mac[0 /*ulmacLen-16*/], 8); |
1154 | 0 | } else { |
1155 | 0 | if (mac_len < 16) |
1156 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "incorrect mac length"); |
1157 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac); |
1158 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed"); |
1159 | 0 | memcpy(mac_tlv + 2, &mac[mac_len - 16], 8); |
1160 | 0 | } |
1161 | 0 | } else { |
1162 | 0 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
1163 | 0 | unsigned char tmp[8] = {0}; |
1164 | 0 | if (mac_len < 8) |
1165 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "incorrect mac length"); |
1166 | 0 | r = des_encrypt_cbc(card, exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac); |
1167 | 0 | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc failed"); |
1168 | 0 | r = des_decrypt_cbc(card, &exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp); |
1169 | 0 | LOG_TEST_RET(card->ctx, r, "des_decrypt_cbc failed"); |
1170 | 0 | memset(iv, 0x00, sizeof iv); |
1171 | 0 | r = des_encrypt_cbc(card, exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2); |
1172 | 0 | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc failed"); |
1173 | 0 | } |
1174 | | |
1175 | 0 | *mac_tlv_len = 2 + 8; |
1176 | 0 | return 0; |
1177 | 0 | } |
1178 | | |
1179 | | /* According to GlobalPlatform Card Specification's SCP01 |
1180 | | * encode APDU from |
1181 | | * CLA INS P1 P2 [Lc] Data [Le] |
1182 | | * to |
1183 | | * CLA INS P1 P2 Lc' Data' [Le] |
1184 | | * where |
1185 | | * Data'=Data(TLV)+Le(TLV)+MAC(TLV) */ |
1186 | | static int |
1187 | | encode_apdu(struct sc_card *card, struct sc_apdu *plain, struct sc_apdu *sm, |
1188 | | unsigned char *apdu_buf, size_t * apdu_buf_len) |
1189 | 4.19k | { |
1190 | 4.19k | size_t block_size = 0; |
1191 | 4.19k | unsigned char dataTLV[4096] = {0}; |
1192 | 4.19k | size_t data_tlv_len = 0; |
1193 | 4.19k | unsigned char le_tlv[256] = {0}; |
1194 | 4.19k | size_t le_tlv_len = 0; |
1195 | 4.19k | size_t mac_tlv_len = 10; |
1196 | 4.19k | size_t tmp_lc = 0; |
1197 | 4.19k | size_t tmp_le = 0; |
1198 | 4.19k | unsigned char mac_tlv[256] = {0}; |
1199 | 4.19k | epass2003_exdata *exdata = NULL; |
1200 | | |
1201 | 4.19k | mac_tlv[0] = 0x8E; |
1202 | 4.19k | mac_tlv[1] = 8; |
1203 | | /* size_t plain_le = 0; */ |
1204 | 4.19k | if (!card->drv_data) |
1205 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1206 | 4.19k | exdata = (epass2003_exdata*)card->drv_data; |
1207 | 4.19k | block_size = (KEY_TYPE_DES == exdata->smtype ? 16 : 8); |
1208 | | |
1209 | 4.19k | sm->cse = SC_APDU_CASE_4_SHORT; |
1210 | 4.19k | apdu_buf[0] = (unsigned char)plain->cla; |
1211 | 4.19k | apdu_buf[1] = (unsigned char)plain->ins; |
1212 | 4.19k | apdu_buf[2] = (unsigned char)plain->p1; |
1213 | 4.19k | apdu_buf[3] = (unsigned char)plain->p2; |
1214 | | /* plain_le = plain->le; */ |
1215 | | /* padding */ |
1216 | 4.19k | if (exdata->bFipsCertification && plain->lc == 0 && apdu_buf[1] == 0x82 && apdu_buf[2] == 0x01) { |
1217 | 0 | apdu_buf[4] = 0x00; |
1218 | 4.19k | } else { |
1219 | 4.19k | apdu_buf[4] = 0x80; |
1220 | 4.19k | } |
1221 | 4.19k | memset(&apdu_buf[5], 0x00, block_size - 5); |
1222 | | |
1223 | | /* Data -> Data' */ |
1224 | 4.19k | if (plain->lc != 0) |
1225 | 3.82k | if (0 != construct_data_tlv(card, plain, apdu_buf, dataTLV, &data_tlv_len, exdata->smtype)) |
1226 | 0 | return -1; |
1227 | | |
1228 | 4.19k | if (plain->le != 0 || (plain->le == 0 && plain->resplen != 0)) |
1229 | 4.15k | if (0 != construct_le_tlv(plain, apdu_buf, data_tlv_len, le_tlv, |
1230 | 4.15k | &le_tlv_len, exdata->smtype)) |
1231 | 0 | return -1; |
1232 | | |
1233 | 4.19k | if (exdata->bFipsCertification && plain->lc == 0 && apdu_buf[1] == 0x82 && apdu_buf[2] == 0x01) { |
1234 | 0 | if (0 != construct_mac_tlv_case1(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype)) |
1235 | 0 | return -1; |
1236 | 4.19k | } else { |
1237 | 4.19k | if (0 != construct_mac_tlv(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype)) |
1238 | 0 | return -1; |
1239 | 4.19k | } |
1240 | | |
1241 | 4.19k | memset(apdu_buf + 4, 0, *apdu_buf_len - 4); |
1242 | 4.19k | sm->lc = sm->datalen = data_tlv_len + le_tlv_len + mac_tlv_len; |
1243 | 4.19k | if (sm->lc > 0xFF) { |
1244 | 0 | sm->cse = SC_APDU_CASE_4_EXT; |
1245 | 0 | apdu_buf[4] = (unsigned char)((sm->lc) / 0x10000); |
1246 | 0 | apdu_buf[5] = (unsigned char)(((sm->lc) / 0x100) % 0x100); |
1247 | 0 | apdu_buf[6] = (unsigned char)((sm->lc) % 0x100); |
1248 | 0 | tmp_lc = 3; |
1249 | 4.19k | } else { |
1250 | 4.19k | apdu_buf[4] = (unsigned char)sm->lc; |
1251 | 4.19k | tmp_lc = 1; |
1252 | 4.19k | } |
1253 | | |
1254 | 4.19k | memcpy(apdu_buf + 4 + tmp_lc, dataTLV, data_tlv_len); |
1255 | 4.19k | memcpy(apdu_buf + 4 + tmp_lc + data_tlv_len, le_tlv, le_tlv_len); |
1256 | 4.19k | memcpy(apdu_buf + 4 + tmp_lc + data_tlv_len + le_tlv_len, mac_tlv, mac_tlv_len); |
1257 | 4.19k | memcpy((unsigned char *)sm->data, apdu_buf + 4 + tmp_lc, sm->datalen); |
1258 | 4.19k | *apdu_buf_len = 0; |
1259 | | |
1260 | 4.19k | if (4 == le_tlv_len) { |
1261 | 58 | sm->cse = SC_APDU_CASE_4_EXT; |
1262 | 58 | *(apdu_buf + 4 + tmp_lc + sm->lc) = (unsigned char)(plain->le / 0x100); |
1263 | 58 | *(apdu_buf + 4 + tmp_lc + sm->lc + 1) = (unsigned char)(plain->le % 0x100); |
1264 | 58 | tmp_le = 2; |
1265 | 4.13k | } else if (3 == le_tlv_len) { |
1266 | 4.09k | *(apdu_buf + 4 + tmp_lc + sm->lc) = (unsigned char)plain->le; |
1267 | 4.09k | tmp_le = 1; |
1268 | 4.09k | } |
1269 | | |
1270 | 4.19k | *apdu_buf_len += 4 + tmp_lc + data_tlv_len + le_tlv_len + mac_tlv_len + tmp_le; |
1271 | | /* sm->le = calc_le(plain_le); */ |
1272 | 4.19k | return 0; |
1273 | 4.19k | } |
1274 | | |
1275 | | |
1276 | | static int |
1277 | | epass2003_sm_wrap_apdu(struct sc_card *card, struct sc_apdu *plain, struct sc_apdu *sm) |
1278 | 13.3k | { |
1279 | 13.3k | unsigned char buf[4096] = {0}; /* APDU buffer */ |
1280 | 13.3k | size_t buf_len = sizeof(buf); |
1281 | 13.3k | epass2003_exdata *exdata = NULL; |
1282 | | |
1283 | 13.3k | if (!card->drv_data) |
1284 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1285 | | |
1286 | 13.3k | exdata = (epass2003_exdata *)card->drv_data; |
1287 | | |
1288 | 13.3k | LOG_FUNC_CALLED(card->ctx); |
1289 | | |
1290 | 13.3k | if (exdata->sm) |
1291 | 4.19k | plain->cla |= 0x0C; |
1292 | | |
1293 | 13.3k | sm->cse = plain->cse; |
1294 | 13.3k | sm->cla = plain->cla; |
1295 | 13.3k | sm->ins = plain->ins; |
1296 | 13.3k | sm->p1 = plain->p1; |
1297 | 13.3k | sm->p2 = plain->p2; |
1298 | 13.3k | sm->lc = plain->lc; |
1299 | 13.3k | sm->le = plain->le; |
1300 | 13.3k | sm->control = plain->control; |
1301 | 13.3k | sm->flags = plain->flags; |
1302 | | |
1303 | 13.3k | switch (sm->cla & 0x0C) { |
1304 | 9.18k | case 0x00: |
1305 | 9.18k | case 0x04: |
1306 | 9.18k | sm->datalen = plain->datalen; |
1307 | 9.18k | memcpy((void *)sm->data, plain->data, plain->datalen); |
1308 | 9.18k | sm->resplen = plain->resplen; |
1309 | 9.18k | memcpy(sm->resp, plain->resp, plain->resplen); |
1310 | 9.18k | break; |
1311 | 4.19k | case 0x0C: |
1312 | 4.19k | memset(buf, 0, sizeof(buf)); |
1313 | 4.19k | if (0 != encode_apdu(card, plain, sm, buf, &buf_len)) |
1314 | 0 | return SC_ERROR_CARD_CMD_FAILED; |
1315 | 4.19k | break; |
1316 | 4.19k | default: |
1317 | 0 | return SC_ERROR_INCORRECT_PARAMETERS; |
1318 | 13.3k | } |
1319 | | |
1320 | 13.3k | return SC_SUCCESS; |
1321 | 13.3k | } |
1322 | | |
1323 | | static int |
1324 | | epass2003_check_response_mac_and_sw(struct sc_card *card, struct sc_apdu *sm) |
1325 | 4.19k | { |
1326 | 4.19k | unsigned char iv[16]; |
1327 | 4.19k | unsigned char *data = NULL, *mac = NULL; |
1328 | 4.19k | size_t blocksize, mac_len; |
1329 | 4.19k | int ret = -1; |
1330 | 4.19k | size_t taglen; |
1331 | 4.19k | const u8 *tag; |
1332 | 4.19k | epass2003_exdata *exdata; |
1333 | 4.19k | unsigned char *in = sm->resp; |
1334 | 4.19k | unsigned char *alt_in; |
1335 | 4.19k | size_t inlen = sm->resplen; |
1336 | 4.19k | size_t len_correction; |
1337 | | |
1338 | | /* card/ctx/drv_data is already checked by caller */ |
1339 | 4.19k | exdata = (epass2003_exdata *)card->drv_data; |
1340 | | |
1341 | | /* The SM must contain at least TLV encoded SW and MAC fields. */ |
1342 | 4.19k | if (inlen < 14 ) |
1343 | 3.10k | return ret; |
1344 | | |
1345 | | /* compare BER-TLV encoded SW (TAG 0x99) and raw SW */ |
1346 | 1.09k | alt_in = in; |
1347 | 1.09k | tag = sc_asn1_find_tag(card->ctx, alt_in, inlen, 0x99, &taglen); |
1348 | 1.09k | if (tag == NULL || taglen != 2) { |
1349 | | /* |
1350 | | * It seems that the EPASS2003 firmware has some problem with BER-TLV encoding. |
1351 | | * Instead of (correct) TLV 87 81 81 [01 .. ..] incorrect TLV 87 81 [01 .. ..] |
1352 | | * is returned. There seems to be some proprietary fix for the faulty encoding |
1353 | | * in the decrypt_response() function, similar fix here: |
1354 | | */ |
1355 | 558 | if (0x01 == in[2] && 0x82 != in[1]) { |
1356 | 341 | sc_log(card->ctx, "Workaround, wrong BER-TLV ?"); |
1357 | 341 | len_correction = in[1] + 2; |
1358 | 341 | if (inlen < len_correction) |
1359 | 69 | return ret; |
1360 | 272 | inlen -= len_correction; |
1361 | 272 | alt_in += len_correction; |
1362 | 272 | tag = sc_asn1_find_tag(card->ctx, alt_in, inlen, 0x99, &taglen); |
1363 | 272 | if (tag == NULL || taglen != 2) |
1364 | 233 | return ret; |
1365 | 272 | } else { |
1366 | 217 | return ret; |
1367 | 217 | } |
1368 | 558 | } |
1369 | 571 | if (sm->sw1 != tag[0] || sm->sw2 != tag[1]) |
1370 | 130 | return ret; |
1371 | | |
1372 | | /* no documentation/real hardware to test, the response is accepted without MAC check */ |
1373 | 441 | if (exdata->bFipsCertification) { |
1374 | 314 | sc_log(card->ctx, "Warning, MAC is not checked"); |
1375 | 314 | return 0; |
1376 | 314 | } |
1377 | 127 | tag = sc_asn1_find_tag(card->ctx, alt_in, inlen, 0x8e, &taglen); |
1378 | 127 | if (tag == NULL || taglen != 8) |
1379 | 40 | return ret; |
1380 | | |
1381 | 87 | if (KEY_TYPE_AES == exdata->smtype) |
1382 | 6 | blocksize = 16; |
1383 | 81 | else |
1384 | 81 | blocksize = 8; |
1385 | | |
1386 | 87 | mac_len = tag - in - 2; |
1387 | 87 | if (NULL == (data = calloc(1, mac_len + blocksize))) |
1388 | 0 | goto end; |
1389 | 87 | if (NULL == (mac = malloc(mac_len + blocksize))) |
1390 | 0 | goto end; |
1391 | | |
1392 | | /* copy response to buffer and append padding */ |
1393 | 87 | memcpy(data, in, mac_len); |
1394 | 87 | data[mac_len++] = 0x80; |
1395 | | |
1396 | 87 | if (mac_len % blocksize) |
1397 | 78 | mac_len += (blocksize - (mac_len % blocksize)); |
1398 | | |
1399 | | /* calculate MAC */ |
1400 | 87 | memcpy(iv, exdata->icv_mac, blocksize); |
1401 | | |
1402 | 87 | if (KEY_TYPE_AES == exdata->smtype) { |
1403 | 6 | if (aes128_encrypt_cbc(card, exdata->sk_mac, 16, iv, data, mac_len, mac)) |
1404 | 0 | goto end; |
1405 | 81 | } else { |
1406 | 81 | uint8_t tmp[8]; |
1407 | 81 | uint8_t iv0[EVP_MAX_IV_LENGTH]; |
1408 | 81 | if (des_encrypt_cbc(card, exdata->sk_mac, 8, iv, data, mac_len, mac)) |
1409 | 0 | goto end; |
1410 | 81 | memset(iv0, 0, EVP_MAX_IV_LENGTH); |
1411 | 81 | if (des_decrypt_cbc(card, &exdata->sk_mac[8], 8, iv0, &mac[mac_len - 8], 8, tmp)) |
1412 | 0 | goto end; |
1413 | 81 | memset(iv0, 0, EVP_MAX_IV_LENGTH); |
1414 | 81 | if (des_encrypt_cbc(card, exdata->sk_mac, 8, iv0, tmp, 8, &mac[mac_len - 8])) |
1415 | 0 | goto end; |
1416 | 81 | } |
1417 | | /* compare MAC */ |
1418 | 87 | if (!memcmp(tag, mac + mac_len - blocksize, 8)) |
1419 | 21 | ret = 0; |
1420 | 87 | end: |
1421 | 87 | if (data) |
1422 | 87 | free(data); |
1423 | 87 | if (mac) |
1424 | 87 | free(mac); |
1425 | 87 | return ret; |
1426 | 87 | } |
1427 | | |
1428 | | /* According to GlobalPlatform Card Specification's SCP01 |
1429 | | * decrypt APDU response from |
1430 | | * ResponseData' SW1 SW2 |
1431 | | * to |
1432 | | * ResponseData SW1 SW2 |
1433 | | * where |
1434 | | * ResponseData'=Data(TLV)+SW12(TLV)+MAC(TLV) |
1435 | | * where |
1436 | | * Data(TLV)=0x87|L|Cipher |
1437 | | * SW12(TLV)=0x99|0x02|SW1+SW2 |
1438 | | * MAC(TLV)=0x8e|0x08|MAC */ |
1439 | | static int |
1440 | | decrypt_response(struct sc_card *card, unsigned char *in, size_t inlen, unsigned char *out, size_t * out_len) |
1441 | 295 | { |
1442 | 295 | size_t cipher_len; |
1443 | 295 | size_t i; |
1444 | 295 | unsigned char iv[16] = {0}; |
1445 | 295 | unsigned char plaintext[4096] = {0}; |
1446 | 295 | epass2003_exdata *exdata = NULL; |
1447 | | |
1448 | 295 | if (!card->drv_data) |
1449 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1450 | | |
1451 | 295 | exdata = (epass2003_exdata *)card->drv_data; |
1452 | | |
1453 | | /* no cipher */ |
1454 | 295 | if (in[0] == 0x99) |
1455 | 48 | return 0; |
1456 | | |
1457 | | /* parse cipher length */ |
1458 | 247 | if (0x01 == in[2] && 0x82 != in[1]) { |
1459 | 130 | cipher_len = in[1]; |
1460 | 130 | i = 3; |
1461 | 130 | } else if (0x01 == in[3] && 0x81 == in[1]) { |
1462 | 10 | cipher_len = in[2]; |
1463 | 10 | i = 4; |
1464 | 107 | } else if (0x01 == in[4] && 0x82 == in[1]) { |
1465 | 87 | cipher_len = in[2] * 0x100; |
1466 | 87 | cipher_len += in[3]; |
1467 | 87 | i = 5; |
1468 | 87 | } else { |
1469 | 20 | return -1; |
1470 | 20 | } |
1471 | | |
1472 | 227 | if (cipher_len < 2 || i + cipher_len > inlen || cipher_len > sizeof plaintext) |
1473 | 86 | return -1; |
1474 | | |
1475 | | /* decrypt */ |
1476 | 141 | if (KEY_TYPE_AES == exdata->smtype) |
1477 | 141 | aes128_decrypt_cbc(card, exdata->sk_enc, 16, iv, &in[i], cipher_len - 1, plaintext); |
1478 | 0 | else |
1479 | 0 | des3_decrypt_cbc(card, exdata->sk_enc, 16, iv, &in[i], cipher_len - 1, plaintext); |
1480 | | |
1481 | | /* unpadding */ |
1482 | 11.6k | while (0x80 != plaintext[cipher_len - 2] && (cipher_len > 2)) |
1483 | 11.4k | cipher_len--; |
1484 | | |
1485 | 141 | if (2 == cipher_len || *out_len < cipher_len - 2) |
1486 | 76 | return -1; |
1487 | | |
1488 | 65 | memcpy(out, plaintext, cipher_len - 2); |
1489 | 65 | *out_len = cipher_len - 2; |
1490 | 65 | return 0; |
1491 | 141 | } |
1492 | | |
1493 | | |
1494 | | static int |
1495 | | epass2003_sm_unwrap_apdu(struct sc_card *card, struct sc_apdu *sm, struct sc_apdu *plain) |
1496 | 13.3k | { |
1497 | 13.3k | int r; |
1498 | 13.3k | size_t len = 0; |
1499 | 13.3k | epass2003_exdata *exdata = NULL; |
1500 | | |
1501 | 13.3k | if (!card->drv_data) |
1502 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1503 | | |
1504 | 13.3k | exdata = (epass2003_exdata *)card->drv_data; |
1505 | | |
1506 | 13.3k | LOG_FUNC_CALLED(card->ctx); |
1507 | | |
1508 | | /* verify MAC, and check if SW1,2 match SW1,2 encapsulated in SM */ |
1509 | 13.3k | if (exdata->sm) { |
1510 | 4.19k | if (epass2003_check_response_mac_and_sw(card, sm)) { |
1511 | 3.85k | sc_log(card->ctx, "MAC or SW incorrect"); |
1512 | 3.85k | return SC_ERROR_CARD_CMD_FAILED; |
1513 | 3.85k | } |
1514 | 4.19k | } |
1515 | 9.51k | r = sc_check_sw(card, sm->sw1, sm->sw2); |
1516 | 9.51k | if (r == SC_SUCCESS) { |
1517 | 6.70k | if (exdata->sm) { |
1518 | 295 | len = plain->resplen; |
1519 | 295 | if (0 != decrypt_response(card, sm->resp, sm->resplen, plain->resp, &len)) |
1520 | 182 | return SC_ERROR_CARD_CMD_FAILED; |
1521 | 6.41k | } else { |
1522 | 6.41k | memcpy(plain->resp, sm->resp, sm->resplen); |
1523 | 6.41k | len = sm->resplen; |
1524 | 6.41k | } |
1525 | 6.70k | } |
1526 | | |
1527 | 9.33k | plain->resplen = len; |
1528 | 9.33k | plain->sw1 = sm->sw1; |
1529 | 9.33k | plain->sw2 = sm->sw2; |
1530 | | |
1531 | 9.33k | sc_log(card->ctx, |
1532 | 9.33k | "unwrapped APDU: resplen %"SC_FORMAT_LEN_SIZE_T"u, SW %02X%02X", |
1533 | 9.33k | plain->resplen, plain->sw1, plain->sw2); |
1534 | 9.33k | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1535 | 9.33k | } |
1536 | | |
1537 | | |
1538 | | static int |
1539 | | epass2003_sm_free_wrapped_apdu(struct sc_card *card, |
1540 | | struct sc_apdu *plain, struct sc_apdu **sm_apdu) |
1541 | 13.3k | { |
1542 | 13.3k | struct sc_context *ctx = card->ctx; |
1543 | 13.3k | int rv = SC_SUCCESS; |
1544 | | |
1545 | 13.3k | LOG_FUNC_CALLED(ctx); |
1546 | 13.3k | if (!sm_apdu) |
1547 | 13.3k | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1548 | 13.3k | if (!(*sm_apdu)) |
1549 | 13.3k | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1550 | | |
1551 | | |
1552 | 13.3k | if (plain) |
1553 | 13.3k | rv = epass2003_sm_unwrap_apdu(card, *sm_apdu, plain); |
1554 | | |
1555 | 13.3k | if ((*sm_apdu)->data) { |
1556 | 13.3k | unsigned char * p = (unsigned char *)((*sm_apdu)->data); |
1557 | 13.3k | free(p); |
1558 | 13.3k | } |
1559 | 13.3k | if ((*sm_apdu)->resp) { |
1560 | 13.3k | free((*sm_apdu)->resp); |
1561 | 13.3k | } |
1562 | | |
1563 | 13.3k | free(*sm_apdu); |
1564 | 13.3k | *sm_apdu = NULL; |
1565 | | |
1566 | 13.3k | LOG_FUNC_RETURN(ctx, rv); |
1567 | 13.3k | } |
1568 | | |
1569 | | |
1570 | | static int |
1571 | | epass2003_sm_get_wrapped_apdu(struct sc_card *card, |
1572 | | struct sc_apdu *plain, struct sc_apdu **sm_apdu) |
1573 | 13.3k | { |
1574 | 13.3k | struct sc_context *ctx = card->ctx; |
1575 | 13.3k | struct sc_apdu *apdu = NULL; |
1576 | 13.3k | int rv; |
1577 | | |
1578 | 13.3k | LOG_FUNC_CALLED(ctx); |
1579 | 13.3k | if (!plain || !sm_apdu) |
1580 | 13.3k | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1581 | | |
1582 | 13.3k | *sm_apdu = NULL; |
1583 | | //construct new SM apdu from original apdu |
1584 | 13.3k | apdu = calloc(1, sizeof(struct sc_apdu)); |
1585 | 13.3k | if (!apdu) { |
1586 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1587 | 0 | goto err; |
1588 | 0 | } |
1589 | 13.3k | apdu->data = calloc (1, SC_MAX_EXT_APDU_BUFFER_SIZE); |
1590 | 13.3k | if (!apdu->data) { |
1591 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1592 | 0 | goto err; |
1593 | 0 | } |
1594 | 13.3k | apdu->resp = calloc (1, SC_MAX_EXT_APDU_BUFFER_SIZE); |
1595 | 13.3k | if (!apdu->resp) { |
1596 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1597 | 0 | goto err; |
1598 | 0 | } |
1599 | 13.3k | apdu->datalen = SC_MAX_EXT_APDU_BUFFER_SIZE; |
1600 | 13.3k | apdu->resplen = SC_MAX_EXT_APDU_BUFFER_SIZE; |
1601 | | |
1602 | 13.3k | rv = epass2003_sm_wrap_apdu(card, plain, apdu); |
1603 | 13.3k | if (rv) { |
1604 | 0 | rv = epass2003_sm_free_wrapped_apdu(card, NULL, &apdu); |
1605 | 0 | if (rv < 0) |
1606 | 0 | goto err; |
1607 | 0 | } |
1608 | | |
1609 | 13.3k | *sm_apdu = apdu; |
1610 | 13.3k | apdu = NULL; |
1611 | 13.3k | err: |
1612 | 13.3k | if (apdu) { |
1613 | 0 | free((unsigned char *) apdu->data); |
1614 | 0 | free(apdu->resp); |
1615 | 0 | free(apdu); |
1616 | 0 | apdu = NULL; |
1617 | 0 | } |
1618 | 13.3k | LOG_FUNC_RETURN(ctx, rv); |
1619 | 13.3k | } |
1620 | | |
1621 | | |
1622 | | static int |
1623 | | epass2003_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) |
1624 | 4.04k | { |
1625 | 4.04k | int r; |
1626 | | |
1627 | 4.04k | LOG_FUNC_CALLED(card->ctx); |
1628 | | |
1629 | 4.04k | r = sc_transmit_apdu_t(card, apdu); |
1630 | 4.04k | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1631 | | |
1632 | 3.95k | return r; |
1633 | 4.04k | } |
1634 | | |
1635 | | |
1636 | | static int |
1637 | | get_data(struct sc_card *card, unsigned char type, unsigned char *data, size_t datalen) |
1638 | 4.67k | { |
1639 | 4.67k | int r; |
1640 | 4.67k | struct sc_apdu apdu; |
1641 | 4.67k | unsigned char resp[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1642 | 4.67k | size_t resplen = SC_MAX_APDU_BUFFER_SIZE; |
1643 | 4.67k | epass2003_exdata *exdata = NULL; |
1644 | | |
1645 | 4.67k | if (!card->drv_data) |
1646 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1647 | | |
1648 | 4.67k | exdata = (epass2003_exdata *)card->drv_data; |
1649 | | |
1650 | 4.67k | LOG_FUNC_CALLED(card->ctx); |
1651 | | |
1652 | 4.67k | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, type); |
1653 | 4.67k | apdu.resp = resp; |
1654 | 4.67k | apdu.le = 0; |
1655 | 4.67k | apdu.resplen = resplen; |
1656 | 4.67k | if (0x86 == type) { |
1657 | | /* No SM temporarily */ |
1658 | 4.36k | unsigned char tmp_sm = exdata->sm; |
1659 | 4.36k | exdata->sm = SM_PLAIN; |
1660 | 4.36k | r = sc_transmit_apdu(card, &apdu); |
1661 | 4.36k | exdata->sm = tmp_sm; |
1662 | 4.36k | } else { |
1663 | 309 | r = sc_transmit_apdu_t(card, &apdu); |
1664 | 309 | } |
1665 | 4.67k | LOG_TEST_RET(card->ctx, r, "APDU get_data failed"); |
1666 | 4.62k | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1667 | 4.62k | LOG_TEST_RET(card->ctx, r, "get_data failed"); |
1668 | | |
1669 | 4.31k | memcpy(data, resp, datalen); |
1670 | 4.31k | return r; |
1671 | 4.62k | } |
1672 | | |
1673 | | /* card driver functions */ |
1674 | | |
1675 | | static int epass2003_match_card(struct sc_card *card) |
1676 | 65.4k | { |
1677 | 65.4k | int r; |
1678 | | |
1679 | 65.4k | LOG_FUNC_CALLED(card->ctx); |
1680 | 65.4k | r = _sc_match_atr(card, epass2003_atrs, &card->type); |
1681 | 65.4k | if (r < 0) |
1682 | 61.1k | return 0; |
1683 | | |
1684 | 4.36k | return 1; |
1685 | 65.4k | } |
1686 | | |
1687 | | |
1688 | | static int |
1689 | | epass2003_init(struct sc_card *card) |
1690 | 4.36k | { |
1691 | 4.36k | unsigned int flags; |
1692 | 4.36k | unsigned int ext_flags; |
1693 | 4.36k | unsigned char data[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1694 | 4.36k | size_t datalen = SC_MAX_APDU_BUFFER_SIZE; |
1695 | 4.36k | epass2003_exdata *exdata = NULL; |
1696 | 4.36k | void *old_drv_data = card->drv_data; |
1697 | | |
1698 | 4.36k | LOG_FUNC_CALLED(card->ctx); |
1699 | | |
1700 | 4.36k | card->name = "epass2003"; |
1701 | 4.36k | card->cla = 0x00; |
1702 | 4.36k | exdata = (epass2003_exdata *)calloc(1, sizeof(epass2003_exdata)); |
1703 | 4.36k | if (!exdata) |
1704 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1705 | | |
1706 | 4.36k | card->drv_data = exdata; |
1707 | | |
1708 | 4.36k | exdata->sm = SM_SCP01; |
1709 | | |
1710 | | /* decide FIPS/Non-FIPS mode */ |
1711 | 4.36k | if (SC_SUCCESS != get_data(card, 0x86, data, datalen)) { |
1712 | 143 | free(exdata); |
1713 | 143 | card->drv_data = old_drv_data; |
1714 | 143 | return SC_ERROR_INVALID_CARD; |
1715 | 143 | } |
1716 | | |
1717 | 4.21k | if (memcmp(&data[32], "\x87\x01\x01", 3) == 0 && memcmp(&data[0], "\x80\x01\x01", 3) == 0) { |
1718 | 321 | exdata->bFipsCertification = 0x01; |
1719 | 3.89k | } else { |
1720 | 3.89k | exdata->bFipsCertification = 0x00; |
1721 | 3.89k | } |
1722 | | |
1723 | 4.21k | if (0x01 == data[2]) |
1724 | 470 | exdata->smtype = KEY_TYPE_AES; |
1725 | 3.74k | else |
1726 | 3.74k | exdata->smtype = KEY_TYPE_DES; |
1727 | | |
1728 | 4.21k | if (0x84 == data[14]) { |
1729 | 747 | if (0x00 == data[16]) { |
1730 | 727 | exdata->sm = SM_PLAIN; |
1731 | 727 | } |
1732 | 747 | } |
1733 | | |
1734 | | /* mutual authentication */ |
1735 | 4.21k | card->max_recv_size = 0xD8; |
1736 | 4.21k | card->max_send_size = 0xE8; |
1737 | | |
1738 | 4.21k | card->sm_ctx.ops.open = epass2003_refresh; |
1739 | 4.21k | card->sm_ctx.ops.get_sm_apdu = epass2003_sm_get_wrapped_apdu; |
1740 | 4.21k | card->sm_ctx.ops.free_sm_apdu = epass2003_sm_free_wrapped_apdu; |
1741 | | |
1742 | | /* FIXME (VT): rather then set/unset 'g_sm', better to implement filter for APDUs to be wrapped */ |
1743 | 4.21k | epass2003_refresh(card); |
1744 | | |
1745 | 4.21k | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
1746 | | |
1747 | 4.21k | flags = SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE; |
1748 | | |
1749 | 4.21k | _sc_card_add_rsa_alg(card, 512, flags, 0); |
1750 | 4.21k | _sc_card_add_rsa_alg(card, 768, flags, 0); |
1751 | 4.21k | _sc_card_add_rsa_alg(card, 1024, flags, 0); |
1752 | 4.21k | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
1753 | | |
1754 | | //set EC Alg Flags |
1755 | 4.21k | flags = SC_ALGORITHM_ONBOARD_KEY_GEN|SC_ALGORITHM_ECDSA_HASH_SHA1|SC_ALGORITHM_ECDSA_HASH_SHA256|SC_ALGORITHM_ECDSA_HASH_NONE|SC_ALGORITHM_ECDSA_RAW; |
1756 | 4.21k | ext_flags = 0; |
1757 | 4.21k | _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); |
1758 | | |
1759 | 4.21k | card->caps = SC_CARD_CAP_RNG | SC_CARD_CAP_APDU_EXT; |
1760 | | |
1761 | 4.21k | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1762 | 4.21k | } |
1763 | | |
1764 | | static int |
1765 | | epass2003_finish(sc_card_t *card) |
1766 | 4.21k | { |
1767 | 4.21k | epass2003_exdata *exdata = (epass2003_exdata *)card->drv_data; |
1768 | | |
1769 | 4.21k | if (exdata) |
1770 | 4.21k | free(exdata); |
1771 | 4.21k | return SC_SUCCESS; |
1772 | 4.21k | } |
1773 | | |
1774 | | /* COS implement SFI as lower 5 bits of FID, and not allow same SFI at the |
1775 | | * same DF, so use hook functions to increase/decrease FID by 0x20 */ |
1776 | | static int |
1777 | | epass2003_hook_path(struct sc_path *path, int inc) |
1778 | 24.2k | { |
1779 | 24.2k | u8 fid_h = 0; |
1780 | 24.2k | u8 fid_l = 0; |
1781 | | |
1782 | 24.2k | if (!path || path->len < 2) |
1783 | 83 | return -1; |
1784 | 24.1k | fid_h = path->value[path->len - 2]; |
1785 | 24.1k | fid_l = path->value[path->len - 1]; |
1786 | | |
1787 | 24.1k | switch (fid_h) { |
1788 | 1.65k | case 0x29: |
1789 | 1.78k | case 0x30: |
1790 | 1.93k | case 0x31: |
1791 | 2.08k | case 0x32: |
1792 | 2.21k | case 0x33: |
1793 | 2.36k | case 0x34: |
1794 | 2.36k | if (inc) |
1795 | 1.28k | fid_l = fid_l * FID_STEP; |
1796 | 1.07k | else |
1797 | 1.07k | fid_l = fid_l / FID_STEP; |
1798 | 2.36k | path->value[path->len - 1] = fid_l; |
1799 | 2.36k | return 1; |
1800 | 21.7k | default: |
1801 | 21.7k | break; |
1802 | 24.1k | } |
1803 | 21.7k | return 0; |
1804 | 24.1k | } |
1805 | | |
1806 | | |
1807 | | static int |
1808 | | epass2003_hook_file(struct sc_file *file, int inc) |
1809 | 6.67k | { |
1810 | 6.67k | int fidl = file->id & 0xff; |
1811 | 6.67k | int fidh = file->id & 0xff00; |
1812 | 6.67k | int rv = 0; |
1813 | | |
1814 | 6.67k | rv = epass2003_hook_path(&file->path, inc); |
1815 | | |
1816 | 6.67k | if (rv > 0) { |
1817 | 1.18k | if (inc) |
1818 | 114 | file->id = fidh + fidl * FID_STEP; |
1819 | 1.07k | else |
1820 | 1.07k | file->id = fidh + fidl / FID_STEP; |
1821 | 1.18k | } |
1822 | 6.67k | if (rv < 0) |
1823 | 83 | return rv; |
1824 | 6.59k | return SC_SUCCESS; |
1825 | 6.67k | } |
1826 | | |
1827 | | |
1828 | | static int |
1829 | | epass2003_select_fid_(struct sc_card *card, sc_path_t * in_path, sc_file_t ** file_out) |
1830 | 17.4k | { |
1831 | 17.4k | struct sc_apdu apdu; |
1832 | 17.4k | u8 buf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1833 | 17.4k | u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; |
1834 | 17.4k | int r; |
1835 | 17.4k | size_t pathlen; |
1836 | 17.4k | sc_file_t *file = NULL; |
1837 | | |
1838 | 17.4k | r = epass2003_hook_path(in_path, 1); |
1839 | 17.4k | LOG_TEST_RET(card->ctx, r, "Can not hook path"); |
1840 | | |
1841 | 17.4k | memcpy(path, in_path->value, in_path->len); |
1842 | 17.4k | pathlen = in_path->len; |
1843 | | |
1844 | 17.4k | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00); |
1845 | | |
1846 | 17.4k | switch (in_path->type) { |
1847 | 17.4k | case SC_PATH_TYPE_FILE_ID: |
1848 | 17.4k | apdu.p1 = 0; |
1849 | 17.4k | if (pathlen != 2) |
1850 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1851 | 17.4k | break; |
1852 | 17.4k | default: |
1853 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1854 | 17.4k | } |
1855 | 17.4k | apdu.p2 = 0; /* first record, return FCI */ |
1856 | 17.4k | apdu.lc = pathlen; |
1857 | 17.4k | apdu.data = path; |
1858 | 17.4k | apdu.datalen = pathlen; |
1859 | | |
1860 | 17.4k | if (file_out != NULL) { |
1861 | 17.4k | apdu.resp = buf; |
1862 | 17.4k | apdu.resplen = sizeof(buf); |
1863 | 17.4k | apdu.le = 0; |
1864 | 17.4k | } else { |
1865 | 0 | apdu.cse = (apdu.lc == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT; |
1866 | 0 | } |
1867 | | |
1868 | 17.4k | if (path[0] == 0x29) { /* TODO:0x29 accords with FID prefix in profile */ |
1869 | | /* Not allowed to select private key file, so fake fci. */ |
1870 | | /* 62 16 82 02 11 00 83 02 29 00 85 02 08 00 86 08 FF 90 90 90 FF FF FF FF */ |
1871 | 741 | apdu.resplen = 0x18; |
1872 | 741 | memcpy(apdu.resp, |
1873 | 741 | "\x6f\x16\x82\x02\x11\x00\x83\x02\x29\x00\x85\x02\x08\x00\x86\x08\xff\x90\x90\x90\xff\xff\xff\xff", |
1874 | 741 | apdu.resplen); |
1875 | 741 | apdu.resp[9] = path[1]; |
1876 | 741 | apdu.sw1 = 0x90; |
1877 | 741 | apdu.sw2 = 0x00; |
1878 | 741 | } |
1879 | 16.7k | else { |
1880 | 16.7k | r = sc_transmit_apdu_t(card, &apdu); |
1881 | 16.7k | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1882 | 16.7k | } |
1883 | | |
1884 | 13.7k | if (file_out == NULL) { |
1885 | 0 | if (apdu.sw1 == 0x61) |
1886 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
1887 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
1888 | 0 | } |
1889 | | |
1890 | 13.7k | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1891 | 13.7k | if (r) |
1892 | 13.7k | LOG_FUNC_RETURN(card->ctx, r); |
1893 | 6.87k | if (apdu.resplen < 2) |
1894 | 6.87k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1895 | | |
1896 | 6.33k | switch (apdu.resp[0]) { |
1897 | 6.05k | case 0x6F: |
1898 | 6.05k | file = sc_file_new(); |
1899 | 6.05k | if (file == NULL) |
1900 | 6.05k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
1901 | 6.05k | file->path = *in_path; |
1902 | 6.05k | if (card->ops->process_fci == NULL) { |
1903 | 0 | sc_file_free(file); |
1904 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1905 | 0 | } |
1906 | | |
1907 | 6.05k | if ((size_t) apdu.resp[1] + 2 <= apdu.resplen) |
1908 | 5.06k | card->ops->process_fci(card, file, apdu.resp + 2, apdu.resp[1]); |
1909 | 6.05k | epass2003_hook_file(file, 0); |
1910 | 6.05k | *file_out = file; |
1911 | 6.05k | break; |
1912 | 96 | case 0x00: /* proprietary coding */ |
1913 | 96 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1914 | 0 | break; |
1915 | 180 | default: |
1916 | 180 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1917 | 6.33k | } |
1918 | 6.05k | return 0; |
1919 | 6.33k | } |
1920 | | |
1921 | | |
1922 | | static int |
1923 | | epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_lo, |
1924 | | sc_file_t ** file_out) |
1925 | 17.4k | { |
1926 | 17.4k | int r; |
1927 | 17.4k | sc_file_t *file = NULL; |
1928 | 17.4k | sc_path_t path; |
1929 | | |
1930 | 17.4k | memset(&path, 0, sizeof(path)); |
1931 | 17.4k | path.type = SC_PATH_TYPE_FILE_ID; |
1932 | 17.4k | path.value[0] = id_hi; |
1933 | 17.4k | path.value[1] = id_lo; |
1934 | 17.4k | path.len = 2; |
1935 | | |
1936 | 17.4k | r = epass2003_select_fid_(card, &path, &file); |
1937 | 17.4k | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1938 | | |
1939 | 6.05k | if (file_out) { |
1940 | 1.31k | *file_out = file; |
1941 | 4.74k | } else { |
1942 | 4.74k | sc_file_free(file); |
1943 | 4.74k | } |
1944 | | |
1945 | 6.05k | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1946 | 6.05k | } |
1947 | | |
1948 | | |
1949 | | static int |
1950 | | epass2003_select_aid(struct sc_card *card, const sc_path_t * in_path, sc_file_t ** file_out) |
1951 | 7.83k | { |
1952 | 7.83k | int r = 0; |
1953 | | |
1954 | 7.83k | r = iso_ops->select_file(card, in_path, file_out); |
1955 | 7.83k | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1956 | | |
1957 | 1.04k | if (file_out) { |
1958 | 75 | sc_file_t *file = *file_out; |
1959 | | |
1960 | 75 | file->type = SC_FILE_TYPE_DF; |
1961 | 75 | file->ef_structure = SC_FILE_EF_UNKNOWN; |
1962 | 75 | file->path.len = 0; |
1963 | 75 | file->size = 0; |
1964 | | /* AID */ |
1965 | 75 | memcpy(file->name, in_path->value, in_path->len); |
1966 | 75 | file->namelen = in_path->len; |
1967 | 75 | file->id = 0x0000; |
1968 | 75 | } |
1969 | | |
1970 | 1.04k | LOG_FUNC_RETURN(card->ctx, r); |
1971 | 1.04k | } |
1972 | | |
1973 | | |
1974 | | static int |
1975 | | epass2003_select_path(struct sc_card *card, const u8 pathbuf[16], const size_t len, |
1976 | | sc_file_t ** file_out) |
1977 | 13.4k | { |
1978 | 13.4k | u8 n_pathbuf[SC_MAX_PATH_SIZE]; |
1979 | 13.4k | const u8 *path = pathbuf; |
1980 | 13.4k | size_t pathlen = len; |
1981 | 13.4k | unsigned int i; |
1982 | 13.4k | int r; |
1983 | | |
1984 | 13.4k | if (pathlen % 2 != 0 || pathlen > 6 || pathlen <= 0) |
1985 | 13.4k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1986 | | |
1987 | | /* if pathlen == 6 then the first FID must be MF (== 3F00) */ |
1988 | 13.3k | if (pathlen == 6 && (path[0] != 0x3f || path[1] != 0x00)) |
1989 | 13.3k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1990 | | |
1991 | | /* unify path (the first FID should be MF) */ |
1992 | 13.2k | if (path[0] != 0x3f || path[1] != 0x00) { |
1993 | 1.20k | n_pathbuf[0] = 0x3f; |
1994 | 1.20k | n_pathbuf[1] = 0x00; |
1995 | 1.20k | memcpy(n_pathbuf + 2, path, pathlen); |
1996 | 1.20k | path = n_pathbuf; |
1997 | 1.20k | pathlen += 2; |
1998 | 1.20k | } |
1999 | | |
2000 | 17.0k | for (i = 0; i < pathlen - 2; i += 2) { |
2001 | 13.8k | r = epass2003_select_fid(card, path[i], path[i + 1], NULL); |
2002 | 13.8k | LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed"); |
2003 | 13.8k | } |
2004 | | |
2005 | 3.21k | return epass2003_select_fid(card, path[pathlen - 2], path[pathlen - 1], file_out); |
2006 | 13.2k | } |
2007 | | |
2008 | | |
2009 | | static int |
2010 | | epass2003_select_file(struct sc_card *card, const sc_path_t * in_path, |
2011 | | sc_file_t ** file_out) |
2012 | 21.9k | { |
2013 | 21.9k | LOG_FUNC_CALLED(card->ctx); |
2014 | | |
2015 | 21.9k | switch (in_path->type) { |
2016 | 718 | case SC_PATH_TYPE_FILE_ID: |
2017 | 718 | if (in_path->len != 2) |
2018 | 718 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2019 | 404 | return epass2003_select_fid(card, in_path->value[0], in_path->value[1], file_out); |
2020 | 7.83k | case SC_PATH_TYPE_DF_NAME: |
2021 | 7.83k | return epass2003_select_aid(card, in_path, file_out); |
2022 | 13.4k | case SC_PATH_TYPE_PATH: |
2023 | 13.4k | return epass2003_select_path(card, in_path->value, in_path->len, file_out); |
2024 | 0 | default: |
2025 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2026 | 21.9k | } |
2027 | 21.9k | } |
2028 | | |
2029 | | static int |
2030 | | epass2003_set_security_env(struct sc_card *card, const sc_security_env_t * env, int se_num) |
2031 | 0 | { |
2032 | 0 | struct sc_apdu apdu; |
2033 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2034 | 0 | u8 *p; |
2035 | 0 | unsigned short fid = 0; |
2036 | 0 | int r, locked = 0; |
2037 | 0 | epass2003_exdata *exdata = NULL; |
2038 | |
|
2039 | 0 | if (!card->drv_data) |
2040 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2041 | | |
2042 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
2043 | |
|
2044 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); |
2045 | |
|
2046 | 0 | p = sbuf; |
2047 | 0 | *p++ = 0x80; /* algorithm reference */ |
2048 | 0 | *p++ = 0x01; |
2049 | 0 | *p++ = 0x84; |
2050 | |
|
2051 | 0 | *p++ = 0x81; |
2052 | 0 | *p++ = 0x02; |
2053 | |
|
2054 | 0 | fid = 0x2900; |
2055 | 0 | fid += (unsigned short)(0x20 * (env->key_ref[0] & 0xff)); |
2056 | 0 | *p++ = fid >> 8; |
2057 | 0 | *p++ = fid & 0xff; |
2058 | 0 | r = (int)(p - sbuf); |
2059 | 0 | apdu.lc = r; |
2060 | 0 | apdu.datalen = r; |
2061 | 0 | apdu.data = sbuf; |
2062 | |
|
2063 | 0 | if (env->algorithm == SC_ALGORITHM_EC) { |
2064 | 0 | apdu.p2 = 0xB6; |
2065 | 0 | exdata->currAlg = SC_ALGORITHM_EC; |
2066 | 0 | if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA1) { |
2067 | 0 | sbuf[2] = 0x91; |
2068 | 0 | exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA1; |
2069 | 0 | } else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA256) { |
2070 | 0 | sbuf[2] = 0x92; |
2071 | 0 | exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA256; |
2072 | 0 | } else { |
2073 | 0 | sbuf[2] = 0x92; |
2074 | 0 | exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_NONE; |
2075 | 0 | } |
2076 | 0 | } else if (env->algorithm == SC_ALGORITHM_RSA) { |
2077 | 0 | exdata->currAlg = SC_ALGORITHM_RSA; |
2078 | 0 | apdu.p2 = 0xB8; |
2079 | 0 | sc_log(card->ctx, "setenv RSA Algorithm alg_flags = %0lx\n", env->algorithm_flags); |
2080 | 0 | } else { |
2081 | 0 | sc_log(card->ctx, "%0lx Alg Not Supported!", env->algorithm); |
2082 | 0 | } |
2083 | |
|
2084 | 0 | if (se_num > 0) { |
2085 | 0 | r = sc_lock(card); |
2086 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
2087 | 0 | locked = 1; |
2088 | 0 | } |
2089 | 0 | if (apdu.datalen != 0) { |
2090 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2091 | 0 | if (r) { |
2092 | 0 | sc_log(card->ctx, "%s: APDU transmit failed", sc_strerror(r)); |
2093 | 0 | goto err; |
2094 | 0 | } |
2095 | | |
2096 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2097 | 0 | if (r) { |
2098 | 0 | sc_log(card->ctx, "%s: Card returned error", sc_strerror(r)); |
2099 | 0 | goto err; |
2100 | 0 | } |
2101 | 0 | } |
2102 | 0 | if (se_num <= 0) |
2103 | 0 | return 0; |
2104 | | |
2105 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num); |
2106 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2107 | 0 | sc_unlock(card); |
2108 | |
|
2109 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2110 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
2111 | | |
2112 | 0 | err: |
2113 | 0 | if (locked) |
2114 | 0 | sc_unlock(card); |
2115 | 0 | return r; |
2116 | 0 | } |
2117 | | |
2118 | | |
2119 | | static int |
2120 | | epass2003_restore_security_env(struct sc_card *card, int se_num) |
2121 | 0 | { |
2122 | 0 | LOG_FUNC_CALLED(card->ctx); |
2123 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2124 | 0 | } |
2125 | | |
2126 | | |
2127 | | static int epass2003_decipher(struct sc_card *card, const u8 * data, size_t datalen, |
2128 | | u8 * out, size_t outlen) |
2129 | 0 | { |
2130 | 0 | int r; |
2131 | 0 | struct sc_apdu apdu; |
2132 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2133 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2134 | 0 | epass2003_exdata *exdata = NULL; |
2135 | |
|
2136 | 0 | LOG_FUNC_CALLED(card->ctx); |
2137 | |
|
2138 | 0 | if (!card->drv_data) |
2139 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2140 | | |
2141 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
2142 | |
|
2143 | 0 | if (exdata->currAlg == SC_ALGORITHM_EC) { |
2144 | 0 | if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_SHA1) { |
2145 | 0 | r = hash_data(card, data, datalen, sbuf, SC_ALGORITHM_ECDSA_HASH_SHA1); |
2146 | 0 | LOG_TEST_RET(card->ctx, r, "hash_data failed"); |
2147 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0x2A, 0x9E, 0x9A); |
2148 | 0 | apdu.data = sbuf; |
2149 | 0 | apdu.lc = 0x14; |
2150 | 0 | apdu.datalen = 0x14; |
2151 | 0 | } else if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_SHA256) { |
2152 | 0 | r = hash_data(card, data, datalen, sbuf, SC_ALGORITHM_ECDSA_HASH_SHA256); |
2153 | 0 | LOG_TEST_RET(card->ctx, r, "hash_data failed"); |
2154 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0x2A, 0x9E, 0x9A); |
2155 | 0 | apdu.data = sbuf; |
2156 | 0 | apdu.lc = 0x20; |
2157 | 0 | apdu.datalen = 0x20; |
2158 | 0 | } else if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_NONE) { |
2159 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3,0x2A, 0x9E, 0x9A); |
2160 | 0 | apdu.data = data; |
2161 | 0 | apdu.lc = datalen; |
2162 | 0 | apdu.datalen = datalen; |
2163 | 0 | } else { |
2164 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2165 | 0 | } |
2166 | 0 | apdu.resp = rbuf; |
2167 | 0 | apdu.resplen = sizeof(rbuf); |
2168 | 0 | apdu.le = 0; |
2169 | |
|
2170 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2171 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2172 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
2173 | 0 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
2174 | 0 | memcpy(out, apdu.resp, len); |
2175 | 0 | LOG_FUNC_RETURN(card->ctx, (int)len); |
2176 | 0 | } |
2177 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
2178 | 0 | } else if (exdata->currAlg == SC_ALGORITHM_RSA) { |
2179 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); |
2180 | 0 | apdu.resp = rbuf; |
2181 | 0 | apdu.resplen = sizeof(rbuf); |
2182 | 0 | apdu.le = 0; |
2183 | |
|
2184 | 0 | memcpy(sbuf, data, datalen); |
2185 | 0 | apdu.data = sbuf; |
2186 | 0 | apdu.lc = datalen; |
2187 | 0 | apdu.datalen = datalen; |
2188 | 0 | } else { |
2189 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); |
2190 | 0 | apdu.resp = rbuf; |
2191 | 0 | apdu.resplen = sizeof(rbuf); |
2192 | 0 | apdu.le = 256; |
2193 | |
|
2194 | 0 | memcpy(sbuf, data, datalen); |
2195 | 0 | apdu.data = sbuf; |
2196 | 0 | apdu.lc = datalen; |
2197 | 0 | apdu.datalen = datalen; |
2198 | 0 | } |
2199 | | |
2200 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2201 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2202 | | |
2203 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
2204 | 0 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
2205 | 0 | memcpy(out, apdu.resp, len); |
2206 | 0 | LOG_FUNC_RETURN(card->ctx, (int)len); |
2207 | 0 | } |
2208 | | |
2209 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
2210 | 0 | } |
2211 | | |
2212 | | |
2213 | | static int |
2214 | | acl_to_ac_byte(struct sc_card *card, const struct sc_acl_entry *e) |
2215 | 1.08k | { |
2216 | 1.08k | if (e == NULL) |
2217 | 0 | return SC_ERROR_OBJECT_NOT_FOUND; |
2218 | | |
2219 | 1.08k | switch (e->method) { |
2220 | 974 | case SC_AC_NONE: |
2221 | 974 | LOG_FUNC_RETURN(card->ctx, EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE); |
2222 | 14 | case SC_AC_NEVER: |
2223 | 14 | LOG_FUNC_RETURN(card->ctx, EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_NOONE); |
2224 | 97 | default: |
2225 | 97 | LOG_FUNC_RETURN(card->ctx, EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_USER); |
2226 | 1.08k | } |
2227 | | |
2228 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS); |
2229 | 0 | } |
2230 | | |
2231 | | /* Use epass2003 sec_attr to add acl entries */ |
2232 | | int |
2233 | | sec_attr_to_entry(struct sc_card *card, sc_file_t *file, int index) |
2234 | 13.7k | { |
2235 | 13.7k | int i; |
2236 | 13.7k | int found = 0; |
2237 | | |
2238 | 13.7k | unsigned int method; |
2239 | 13.7k | unsigned long keyref; |
2240 | | |
2241 | 13.7k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
2242 | | |
2243 | 13.7k | switch (file->sec_attr[index]) { |
2244 | 3.94k | case (EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE): |
2245 | 3.94k | method = SC_AC_NONE; |
2246 | 3.94k | keyref = SC_AC_KEY_REF_NONE; |
2247 | 3.94k | break; |
2248 | 1.69k | case (EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_USER): |
2249 | 1.69k | method = SC_AC_CHV; |
2250 | 1.69k | keyref = 1; |
2251 | 1.69k | break; |
2252 | 8.11k | default: |
2253 | 8.11k | sc_log(card->ctx, "Unknown value 0x%2.2x in file->sec_attr[%d]", file->sec_attr[index], index); |
2254 | 8.11k | method = SC_AC_NEVER; |
2255 | 8.11k | keyref = SC_AC_KEY_REF_NONE; |
2256 | 8.11k | break; |
2257 | 13.7k | } |
2258 | | |
2259 | 467k | for (i = 0; i < (int)(sizeof(sec_attr_to_acl_entry) / sizeof(sec_attr_to_acl_entries_t)); i++) { |
2260 | 453k | const sec_attr_to_acl_entries_t *e = &sec_attr_to_acl_entry[i]; |
2261 | | |
2262 | 453k | if (index == e->index && file->type == e->file_type |
2263 | 12.1k | && file->ef_structure == e->file_ef_structure) { |
2264 | | /* may add multiple entries */ |
2265 | 842 | sc_file_add_acl_entry(file, e->op, method, keyref); |
2266 | 842 | found++; |
2267 | 842 | } |
2268 | 453k | } |
2269 | 13.7k | if (found != 1) { |
2270 | 13.3k | sc_log(card->ctx,"found %d entries ", found); |
2271 | 13.3k | } |
2272 | | |
2273 | 13.7k | return 0; |
2274 | 13.7k | } |
2275 | | |
2276 | | static int |
2277 | | epass2003_process_fci(struct sc_card *card, sc_file_t * file, const u8 * buf, size_t buflen) |
2278 | 5.06k | { |
2279 | 5.06k | sc_context_t *ctx = card->ctx; |
2280 | 5.06k | size_t taglen, len = buflen; |
2281 | 5.06k | const u8 *tag = NULL, *p = buf; |
2282 | | |
2283 | 5.06k | sc_log(ctx, "processing FCI bytes"); |
2284 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); |
2285 | 5.06k | if (tag != NULL && taglen == 2) { |
2286 | 991 | file->id = (tag[0] << 8) | tag[1]; |
2287 | 991 | sc_log(ctx, " file identifier: 0x%02X%02X", tag[0], tag[1]); |
2288 | 991 | } |
2289 | | |
2290 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen); |
2291 | 5.06k | if (tag != NULL && taglen > 0 && taglen < 3) { |
2292 | 438 | file->size = tag[0]; |
2293 | 438 | if (taglen == 2) |
2294 | 355 | file->size = (file->size << 8) + tag[1]; |
2295 | 438 | sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", |
2296 | 438 | file->size); |
2297 | 438 | } |
2298 | | |
2299 | 5.06k | if (tag == NULL) { |
2300 | 4.43k | tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen); |
2301 | 4.43k | if (tag != NULL && taglen >= 2) { |
2302 | 172 | int bytes = (tag[0] << 8) + tag[1]; |
2303 | | |
2304 | 172 | sc_log(ctx, " bytes in file: %d", bytes); |
2305 | 172 | file->size = bytes; |
2306 | 172 | } |
2307 | 4.43k | } |
2308 | | |
2309 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); |
2310 | 5.06k | if (tag != NULL) { |
2311 | 2.28k | if (taglen > 0) { |
2312 | 2.20k | unsigned char byte = tag[0]; |
2313 | 2.20k | const char *type; |
2314 | | |
2315 | 2.20k | if (byte == 0x38) { |
2316 | 109 | type = "DF"; |
2317 | 109 | file->type = SC_FILE_TYPE_DF; |
2318 | 2.09k | } else if (0x01 <= byte && byte <= 0x07) { |
2319 | 759 | type = "working EF"; |
2320 | 759 | file->type = SC_FILE_TYPE_WORKING_EF; |
2321 | 759 | switch (byte) { |
2322 | 158 | case 0x01: |
2323 | 158 | file->ef_structure = SC_FILE_EF_TRANSPARENT; |
2324 | 158 | break; |
2325 | 182 | case 0x02: |
2326 | 182 | file->ef_structure = SC_FILE_EF_LINEAR_FIXED; |
2327 | 182 | break; |
2328 | 227 | case 0x04: |
2329 | 227 | file->ef_structure = SC_FILE_EF_LINEAR_FIXED; |
2330 | 227 | break; |
2331 | 192 | default: |
2332 | 192 | break; |
2333 | 759 | } |
2334 | | |
2335 | 1.33k | } else if (0x10 == byte) { |
2336 | 59 | type = "BSO"; |
2337 | 59 | file->type = SC_FILE_TYPE_BSO; |
2338 | 1.27k | } else if (0x11 <= byte) { |
2339 | 1.14k | type = "internal EF"; |
2340 | 1.14k | file->type = SC_FILE_TYPE_INTERNAL_EF; |
2341 | 1.14k | switch (byte) { |
2342 | 798 | case 0x11: |
2343 | 798 | break; |
2344 | 66 | case 0x12: |
2345 | 66 | break; |
2346 | 285 | default: |
2347 | 285 | break; |
2348 | 1.14k | } |
2349 | 1.14k | } else { |
2350 | 125 | type = "unknown"; |
2351 | 125 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
2352 | 125 | } |
2353 | 2.20k | sc_log(ctx, "type %s, EF structure %d", type, byte); |
2354 | 2.20k | } |
2355 | 2.28k | } |
2356 | | |
2357 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); |
2358 | 5.06k | if (tag != NULL && taglen > 0 && taglen <= 16) { |
2359 | 219 | memcpy(file->name, tag, taglen); |
2360 | 219 | file->namelen = taglen; |
2361 | | |
2362 | 219 | sc_log_hex(ctx, "File name", file->name, file->namelen); |
2363 | 219 | if (!file->type) |
2364 | 130 | file->type = SC_FILE_TYPE_DF; |
2365 | 219 | } |
2366 | | |
2367 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen); |
2368 | 5.06k | if (tag != NULL && taglen) |
2369 | 922 | sc_file_set_prop_attr(file, tag, taglen); |
2370 | 4.14k | else |
2371 | 4.14k | file->prop_attr_len = 0; |
2372 | | |
2373 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen); |
2374 | 5.06k | if (tag != NULL && taglen) |
2375 | 82 | sc_file_set_prop_attr(file, tag, taglen); |
2376 | | |
2377 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen); |
2378 | 5.06k | if (tag != NULL && taglen) { |
2379 | 1.45k | unsigned int i; |
2380 | 1.45k | sc_file_set_sec_attr(file, tag, taglen); |
2381 | 21.3k | for (i = 0; i< taglen; i++) |
2382 | 19.9k | if (tag[i] != 0xff) /* skip unused entries */ |
2383 | 13.7k | sec_attr_to_entry(card, file, i); |
2384 | 1.45k | } |
2385 | | |
2386 | 5.06k | tag = sc_asn1_find_tag(ctx, p, len, 0x8A, &taglen); |
2387 | 5.06k | if (tag != NULL && taglen == 1) { |
2388 | 453 | if (tag[0] == 0x01) |
2389 | 103 | file->status = SC_FILE_STATUS_CREATION; |
2390 | 350 | else if (tag[0] == 0x07 || tag[0] == 0x05) |
2391 | 121 | file->status = SC_FILE_STATUS_ACTIVATED; |
2392 | 229 | else if (tag[0] == 0x06 || tag[0] == 0x04) |
2393 | 125 | file->status = SC_FILE_STATUS_INVALIDATED; |
2394 | 453 | } |
2395 | 5.06k | file->magic = SC_FILE_MAGIC; |
2396 | | |
2397 | 5.06k | return 0; |
2398 | 5.06k | } |
2399 | | |
2400 | | |
2401 | | static int |
2402 | | epass2003_construct_fci(struct sc_card *card, const sc_file_t * file, |
2403 | | u8 * out, size_t * outlen) |
2404 | 402 | { |
2405 | 402 | u8 *p = out; |
2406 | 402 | u8 buf[64]; |
2407 | 402 | unsigned char ops[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
2408 | 402 | int rv; |
2409 | 402 | unsigned ii; |
2410 | | |
2411 | 402 | if (*outlen < 2) |
2412 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
2413 | | |
2414 | 402 | *p++ = 0x62; |
2415 | 402 | p++; |
2416 | 402 | if (file->type == SC_FILE_TYPE_WORKING_EF) { |
2417 | 38 | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
2418 | 35 | buf[0] = (file->size >> 8) & 0xFF; |
2419 | 35 | buf[1] = file->size & 0xFF; |
2420 | 35 | sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p); |
2421 | 35 | } |
2422 | 38 | } |
2423 | 402 | if (file->type == SC_FILE_TYPE_DF) { |
2424 | 23 | buf[0] = 0x38; |
2425 | 23 | buf[1] = 0x00; |
2426 | 23 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2427 | 23 | } |
2428 | 379 | else if (file->type == SC_FILE_TYPE_WORKING_EF) { |
2429 | 38 | buf[0] = file->ef_structure & 7; |
2430 | 38 | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
2431 | 35 | buf[1] = 0x00; |
2432 | 35 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2433 | 35 | } else if (file->ef_structure == SC_FILE_EF_LINEAR_FIXED || |
2434 | 3 | file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE) { |
2435 | 0 | buf[1] = 0x00; |
2436 | 0 | buf[2] = 0x00; |
2437 | 0 | buf[3] = 0x40; /* record length */ |
2438 | 0 | buf[4] = 0x00; /* record count */ |
2439 | 0 | sc_asn1_put_tag(0x82, buf, 5, p, *outlen - (p - out), &p); |
2440 | 3 | } else { |
2441 | 3 | return SC_ERROR_NOT_SUPPORTED; |
2442 | 3 | } |
2443 | | |
2444 | 38 | } |
2445 | 341 | else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
2446 | 295 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || |
2447 | 223 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { |
2448 | 223 | buf[0] = 0x11; |
2449 | 223 | buf[1] = 0x00; |
2450 | 223 | } else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2451 | 69 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2452 | 69 | buf[0] = 0x12; |
2453 | 69 | buf[1] = 0x00; |
2454 | 69 | } else { |
2455 | 3 | return SC_ERROR_NOT_SUPPORTED; |
2456 | 3 | } |
2457 | 292 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2458 | 292 | } else if (file->type == SC_FILE_TYPE_BSO) { |
2459 | 1 | buf[0] = 0x10; |
2460 | 1 | buf[1] = 0x00; |
2461 | 1 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2462 | 1 | } |
2463 | | |
2464 | 396 | buf[0] = (file->id >> 8) & 0xFF; |
2465 | 396 | buf[1] = file->id & 0xFF; |
2466 | 396 | sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p); |
2467 | 396 | if (file->type == SC_FILE_TYPE_DF) { |
2468 | 23 | if (file->namelen != 0) { |
2469 | 11 | sc_asn1_put_tag(0x84, file->name, file->namelen, p, *outlen - (p - out), &p); |
2470 | 12 | } else { |
2471 | 12 | return SC_ERROR_INVALID_ARGUMENTS; |
2472 | 12 | } |
2473 | 23 | } |
2474 | 384 | if (file->type == SC_FILE_TYPE_DF) { |
2475 | 11 | unsigned char data[2] = {0x00, 0x7F}; |
2476 | | /* 127 files at most */ |
2477 | 11 | sc_asn1_put_tag(0x85, data, sizeof(data), p, *outlen - (p - out), &p); |
2478 | 373 | } else if (file->type == SC_FILE_TYPE_BSO) { |
2479 | 1 | buf[0] = file->size & 0xff; |
2480 | 1 | sc_asn1_put_tag(0x85, buf, 1, p, *outlen - (p - out), &p); |
2481 | 372 | } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
2482 | 292 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || |
2483 | 170 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2484 | 138 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT || |
2485 | 292 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2486 | 292 | buf[0] = (file->size >> 8) & 0xFF; |
2487 | 292 | buf[1] = file->size & 0xFF; |
2488 | 292 | sc_asn1_put_tag(0x85, buf, 2, p, *outlen - (p - out), &p); |
2489 | 292 | } |
2490 | 292 | } |
2491 | 384 | if (file->sec_attr_len) { |
2492 | 0 | memcpy(buf, file->sec_attr, file->sec_attr_len); |
2493 | 0 | sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p); |
2494 | |
|
2495 | 384 | } else { |
2496 | 384 | sc_log(card->ctx, "SC_FILE_ACL"); |
2497 | 384 | if (file->type == SC_FILE_TYPE_DF) { |
2498 | 11 | ops[0] = SC_AC_OP_LIST_FILES; |
2499 | 11 | ops[1] = SC_AC_OP_CREATE; |
2500 | 11 | ops[3] = SC_AC_OP_DELETE; |
2501 | 373 | } else if (file->type == SC_FILE_TYPE_WORKING_EF) { |
2502 | 35 | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
2503 | 35 | ops[0] = SC_AC_OP_READ; |
2504 | 35 | ops[1] = SC_AC_OP_UPDATE; |
2505 | 35 | ops[3] = SC_AC_OP_DELETE; |
2506 | 35 | } else if (file->ef_structure == SC_FILE_EF_LINEAR_FIXED || |
2507 | 0 | file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE) { |
2508 | 0 | ops[0] = SC_AC_OP_READ; |
2509 | 0 | ops[1] = SC_AC_OP_UPDATE; |
2510 | 0 | ops[2] = SC_AC_OP_WRITE; |
2511 | 0 | ops[3] = SC_AC_OP_DELETE; |
2512 | 0 | } else { |
2513 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2514 | 0 | } |
2515 | 338 | } else if (file->type == SC_FILE_TYPE_BSO) { |
2516 | 1 | ops[0] = SC_AC_OP_UPDATE; |
2517 | 1 | ops[3] = SC_AC_OP_DELETE; |
2518 | 337 | } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
2519 | 292 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || |
2520 | 223 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { |
2521 | 223 | ops[1] = SC_AC_OP_UPDATE; |
2522 | 223 | ops[2] = SC_AC_OP_CRYPTO; |
2523 | 223 | ops[3] = SC_AC_OP_DELETE; |
2524 | 223 | } else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2525 | 69 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2526 | 69 | ops[0] = SC_AC_OP_READ; |
2527 | 69 | ops[1] = SC_AC_OP_UPDATE; |
2528 | 69 | ops[2] = SC_AC_OP_CRYPTO; |
2529 | 69 | ops[3] = SC_AC_OP_DELETE; |
2530 | 69 | } |
2531 | 292 | } else { |
2532 | 45 | return SC_ERROR_NOT_SUPPORTED; |
2533 | 45 | } |
2534 | | |
2535 | 3.05k | for (ii = 0; ii < sizeof(ops); ii++) { |
2536 | 2.71k | const struct sc_acl_entry *entry; |
2537 | | |
2538 | 2.71k | buf[ii] = 0xFF; |
2539 | 2.71k | if (ops[ii] == 0xFF) |
2540 | 1.62k | continue; |
2541 | 1.08k | entry = sc_file_get_acl_entry(file, ops[ii]); |
2542 | | |
2543 | 1.08k | rv = acl_to_ac_byte(card, entry); |
2544 | 1.08k | LOG_TEST_RET(card->ctx, rv, "Invalid ACL"); |
2545 | | |
2546 | 1.08k | buf[ii] = rv; |
2547 | 1.08k | } |
2548 | 339 | sc_asn1_put_tag(0x86, buf, sizeof(ops), p, *outlen - (p - out), &p); |
2549 | 339 | if (file->size == 256) { |
2550 | 139 | out[4]= 0x13; |
2551 | 139 | } |
2552 | 339 | } |
2553 | | |
2554 | | /* VT ??? */ |
2555 | 339 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2556 | 307 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2557 | 69 | unsigned char data[2] = {0x00, 0x66}; |
2558 | 69 | sc_asn1_put_tag(0x87, data, sizeof(data), p, *outlen - (p - out), &p); |
2559 | 69 | if (file->size == 256) { |
2560 | 37 | out[4] = 0x14; |
2561 | 37 | } |
2562 | 69 | } |
2563 | | |
2564 | 339 | out[1] = p - out - 2; |
2565 | | |
2566 | 339 | *outlen = p - out; |
2567 | 339 | return 0; |
2568 | 384 | } |
2569 | | |
2570 | | |
2571 | | static int |
2572 | | epass2003_create_file(struct sc_card *card, sc_file_t * file) |
2573 | 402 | { |
2574 | 402 | int r; |
2575 | 402 | size_t len; |
2576 | 402 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2577 | 402 | struct sc_apdu apdu; |
2578 | | |
2579 | 402 | len = SC_MAX_APDU_BUFFER_SIZE; |
2580 | | |
2581 | 402 | epass2003_hook_file(file, 1); |
2582 | | |
2583 | 402 | if (card->ops->construct_fci == NULL) |
2584 | 402 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2585 | | |
2586 | 402 | r = epass2003_construct_fci(card, file, sbuf, &len); |
2587 | 402 | LOG_TEST_RET(card->ctx, r, "construct_fci() failed"); |
2588 | | |
2589 | 339 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); |
2590 | 339 | apdu.lc = len; |
2591 | 339 | apdu.datalen = len; |
2592 | 339 | apdu.data = sbuf; |
2593 | | |
2594 | 339 | r = sc_transmit_apdu_t(card, &apdu); |
2595 | 339 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2596 | 336 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2597 | 336 | LOG_TEST_RET(card->ctx, r, "APDU sw1/2 wrong"); |
2598 | | |
2599 | 218 | epass2003_hook_file(file, 0); |
2600 | 218 | return r; |
2601 | 336 | } |
2602 | | |
2603 | | |
2604 | | static int |
2605 | | epass2003_delete_file(struct sc_card *card, const sc_path_t * path) |
2606 | 428 | { |
2607 | 428 | int r; |
2608 | 428 | u8 sbuf[2]; |
2609 | 428 | struct sc_apdu apdu; |
2610 | | |
2611 | 428 | LOG_FUNC_CALLED(card->ctx); |
2612 | | |
2613 | 428 | r = sc_select_file(card, path, NULL); |
2614 | 428 | LOG_TEST_RET(card->ctx, r, "Can not select file"); |
2615 | 89 | r = epass2003_hook_path((struct sc_path *)path, 1); |
2616 | 89 | LOG_TEST_RET(card->ctx, r, "Can not hook path"); |
2617 | | |
2618 | 89 | sbuf[0] = path->value[path->len - 2]; |
2619 | 89 | sbuf[1] = path->value[path->len - 1]; |
2620 | 89 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00); |
2621 | 89 | apdu.lc = 2; |
2622 | 89 | apdu.datalen = 2; |
2623 | 89 | apdu.data = sbuf; |
2624 | | |
2625 | 89 | r = sc_transmit_apdu_t(card, &apdu); |
2626 | 89 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2627 | 86 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2628 | 86 | LOG_TEST_RET(card->ctx, r, "Delete file failed"); |
2629 | | |
2630 | 50 | LOG_FUNC_RETURN(card->ctx, r); |
2631 | 50 | } |
2632 | | |
2633 | | static int |
2634 | | epass2003_list_files(struct sc_card *card, unsigned char *buf, size_t buflen) |
2635 | 361 | { |
2636 | 361 | struct sc_apdu apdu; |
2637 | 361 | unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2638 | 361 | int r; |
2639 | | |
2640 | 361 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
2641 | 361 | sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x34, 0x00, 0x00); |
2642 | 361 | apdu.cla = 0x80; |
2643 | 361 | apdu.le = 0; |
2644 | 361 | apdu.resplen = sizeof(rbuf); |
2645 | 361 | apdu.resp = rbuf; |
2646 | | |
2647 | 361 | r = sc_transmit_apdu_t(card, &apdu); |
2648 | 361 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2649 | | |
2650 | 77 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2651 | 77 | LOG_TEST_RET(card->ctx, r, "Card returned error"); |
2652 | | |
2653 | 47 | if (apdu.resplen == 0x100 && rbuf[0] == 0 && rbuf[1] == 0) |
2654 | 47 | LOG_FUNC_RETURN(card->ctx, 0); |
2655 | | |
2656 | 46 | buflen = buflen < apdu.resplen ? buflen : apdu.resplen; |
2657 | 46 | memcpy(buf, rbuf, buflen); |
2658 | | |
2659 | 46 | LOG_FUNC_RETURN(card->ctx, (int)buflen); |
2660 | 46 | } |
2661 | | |
2662 | | |
2663 | | static int |
2664 | | internal_write_rsa_key_factor(struct sc_card *card, unsigned short fid, u8 factor, |
2665 | | sc_pkcs15_bignum_t data) |
2666 | 0 | { |
2667 | 0 | int r; |
2668 | 0 | struct sc_apdu apdu; |
2669 | 0 | u8 sbuff[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0}; |
2670 | |
|
2671 | 0 | LOG_FUNC_CALLED(card->ctx); |
2672 | |
|
2673 | 0 | sbuff[0] = ((fid & 0xff00) >> 8); |
2674 | 0 | sbuff[1] = (fid & 0x00ff); |
2675 | 0 | memcpy(&sbuff[2], data.data, data.len); |
2676 | | // sc_mem_reverse(&sbuff[2], data.len); |
2677 | |
|
2678 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xe7, factor, 0x00); |
2679 | 0 | apdu.cla = 0x80; |
2680 | 0 | apdu.lc = apdu.datalen = 2 + data.len; |
2681 | 0 | apdu.data = sbuff; |
2682 | |
|
2683 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2684 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2685 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2686 | 0 | LOG_TEST_RET(card->ctx, r, "Write rsa key factor failed"); |
2687 | | |
2688 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2689 | 0 | } |
2690 | | |
2691 | | |
2692 | | static int |
2693 | | internal_write_rsa_key(struct sc_card *card, unsigned short fid, struct sc_pkcs15_prkey_rsa *rsa) |
2694 | 0 | { |
2695 | 0 | int r; |
2696 | |
|
2697 | 0 | LOG_FUNC_CALLED(card->ctx); |
2698 | |
|
2699 | 0 | r = internal_write_rsa_key_factor(card, fid, 0x02, rsa->modulus); |
2700 | 0 | LOG_TEST_RET(card->ctx, r, "write n failed"); |
2701 | 0 | r = internal_write_rsa_key_factor(card, fid, 0x03, rsa->d); |
2702 | 0 | LOG_TEST_RET(card->ctx, r, "write d failed"); |
2703 | | |
2704 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2705 | 0 | } |
2706 | | |
2707 | | |
2708 | | static int |
2709 | | hash_data(struct sc_card *card, const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType) |
2710 | 20 | { |
2711 | | |
2712 | 20 | if ((NULL == data) || (NULL == hash)) |
2713 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2714 | | |
2715 | 20 | if (mechanismType & SC_ALGORITHM_ECDSA_HASH_SHA1) { |
2716 | 20 | unsigned char data_hash[24] = {0}; |
2717 | 20 | size_t len = 0; |
2718 | | |
2719 | 20 | sha1_digest(card, data, datalen, data_hash); |
2720 | 20 | len = REVERSE_ORDER4(datalen); |
2721 | 20 | memcpy(&data_hash[20], &len, 4); |
2722 | 20 | memcpy(hash, data_hash, 24); |
2723 | 20 | } else if (mechanismType & SC_ALGORITHM_ECDSA_HASH_SHA256) { |
2724 | 0 | unsigned char data_hash[36] = {0}; |
2725 | 0 | size_t len = 0; |
2726 | |
|
2727 | 0 | sha256_digest(card, data, datalen, data_hash); |
2728 | 0 | len = REVERSE_ORDER4(datalen); |
2729 | 0 | memcpy(&data_hash[32], &len, 4); |
2730 | 0 | memcpy(hash, data_hash, 36); |
2731 | 0 | } else { |
2732 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2733 | 0 | } |
2734 | | |
2735 | 20 | return SC_SUCCESS; |
2736 | 20 | } |
2737 | | |
2738 | | |
2739 | | static int |
2740 | | install_secret_key(struct sc_card *card, unsigned char ktype, unsigned char kid, |
2741 | | unsigned char useac, unsigned char modifyac, unsigned char EC, |
2742 | | unsigned char *data, unsigned long dataLen) |
2743 | 20 | { |
2744 | 20 | int r; |
2745 | 20 | struct sc_apdu apdu; |
2746 | 20 | unsigned char isapp = 0x00; /* appendable */ |
2747 | 20 | unsigned char tmp_data[256] = {0}; |
2748 | | |
2749 | 20 | tmp_data[0] = ktype; |
2750 | 20 | tmp_data[1] = kid; |
2751 | 20 | tmp_data[2] = useac; |
2752 | 20 | tmp_data[3] = modifyac; |
2753 | 20 | tmp_data[8] = 0xFF; |
2754 | | |
2755 | 20 | if (0x04 == ktype || 0x06 == ktype) { |
2756 | 20 | tmp_data[4] = EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_SO; |
2757 | 20 | tmp_data[5] = EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_SO; |
2758 | 20 | tmp_data[7] = (kid == PIN_ID[0] ? EPASS2003_AC_USER : EPASS2003_AC_SO); |
2759 | 20 | tmp_data[9] = (EC << 4) | EC; |
2760 | 20 | } |
2761 | | |
2762 | 20 | memcpy(&tmp_data[10], data, dataLen); |
2763 | 20 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xe3, isapp, 0x00); |
2764 | 20 | apdu.cla = 0x80; |
2765 | 20 | apdu.lc = apdu.datalen = 10 + dataLen; |
2766 | 20 | apdu.data = tmp_data; |
2767 | | |
2768 | 20 | r = sc_transmit_apdu_t(card, &apdu); |
2769 | 20 | LOG_TEST_RET(card->ctx, r, "APDU install_secret_key failed"); |
2770 | 19 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2771 | 19 | LOG_TEST_RET(card->ctx, r, "install_secret_key failed"); |
2772 | | |
2773 | 5 | return r; |
2774 | 19 | } |
2775 | | |
2776 | | |
2777 | | static int |
2778 | | internal_install_pre(struct sc_card *card) |
2779 | 0 | { |
2780 | 0 | int r; |
2781 | | /* init key for enc */ |
2782 | 0 | r = install_secret_key(card, 0x01, 0x00, |
2783 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2784 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2785 | 0 | 0, g_init_key_enc, 16); |
2786 | 0 | LOG_TEST_RET(card->ctx, r, "Install init key failed"); |
2787 | | |
2788 | | /* init key for mac */ |
2789 | 0 | r = install_secret_key(card, 0x02, 0x00, |
2790 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2791 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2792 | 0 | 0, g_init_key_mac, 16); |
2793 | 0 | LOG_TEST_RET(card->ctx, r, "Install init key failed"); |
2794 | | |
2795 | 0 | return r; |
2796 | 0 | } |
2797 | | |
2798 | | |
2799 | | /* use external auth secret as pin */ |
2800 | | static int |
2801 | | internal_install_pin(struct sc_card *card, sc_epass2003_wkey_data * pin) |
2802 | 20 | { |
2803 | 20 | int r; |
2804 | 20 | unsigned char hash[HASH_LEN] = {0}; |
2805 | | |
2806 | 20 | r = hash_data(card, pin->key_data.es_secret.key_val, pin->key_data.es_secret.key_len, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); |
2807 | 20 | LOG_TEST_RET(card->ctx, r, "hash data failed"); |
2808 | | |
2809 | 20 | r = install_secret_key(card, 0x04, pin->key_data.es_secret.kid, |
2810 | 20 | pin->key_data.es_secret.ac[0], |
2811 | 20 | pin->key_data.es_secret.ac[1], |
2812 | 20 | pin->key_data.es_secret.EC, hash, HASH_LEN); |
2813 | 20 | LOG_TEST_RET(card->ctx, r, "Install failed"); |
2814 | | |
2815 | 5 | return r; |
2816 | 20 | } |
2817 | | |
2818 | | |
2819 | | static int |
2820 | | epass2003_write_key(struct sc_card *card, sc_epass2003_wkey_data * data) |
2821 | 20 | { |
2822 | 20 | LOG_FUNC_CALLED(card->ctx); |
2823 | | |
2824 | 20 | if (data->type & SC_EPASS2003_KEY) { |
2825 | 0 | if (data->type == SC_EPASS2003_KEY_RSA) |
2826 | 0 | return internal_write_rsa_key(card, data->key_data.es_key.fid, |
2827 | 0 | data->key_data.es_key.rsa); |
2828 | 0 | else |
2829 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2830 | 20 | } else if (data->type & SC_EPASS2003_SECRET) { |
2831 | 20 | if (data->type == SC_EPASS2003_SECRET_PRE) |
2832 | 0 | return internal_install_pre(card); |
2833 | 20 | else if (data->type == SC_EPASS2003_SECRET_PIN) |
2834 | 20 | return internal_install_pin(card, data); |
2835 | 0 | else |
2836 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2837 | 20 | } else { |
2838 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2839 | 0 | } |
2840 | | |
2841 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2842 | 0 | } |
2843 | | |
2844 | | |
2845 | | static int |
2846 | | epass2003_gen_key(struct sc_card *card, sc_epass2003_gen_key_data * data) |
2847 | 52 | { |
2848 | 52 | int r; |
2849 | 52 | size_t len = data->key_length; |
2850 | 52 | struct sc_apdu apdu; |
2851 | 52 | u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0}; |
2852 | 52 | u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0}; |
2853 | | |
2854 | 52 | LOG_FUNC_CALLED(card->ctx); |
2855 | | |
2856 | 52 | if (len == 256) { |
2857 | 30 | sbuf[0] = 0x02; |
2858 | 30 | } else { |
2859 | 22 | sbuf[0] = 0x01; |
2860 | 22 | } |
2861 | 52 | sbuf[1] = (u8) ((len >> 8) & 0xff); |
2862 | 52 | sbuf[2] = (u8) (len & 0xff); |
2863 | 52 | sbuf[3] = (u8) ((data->prkey_id >> 8) & 0xFF); |
2864 | 52 | sbuf[4] = (u8) ((data->prkey_id) & 0xFF); |
2865 | 52 | sbuf[5] = (u8) ((data->pukey_id >> 8) & 0xFF); |
2866 | 52 | sbuf[6] = (u8) ((data->pukey_id) & 0xFF); |
2867 | | |
2868 | | /* generate key */ |
2869 | 52 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00); |
2870 | 52 | apdu.lc = apdu.datalen = 7; |
2871 | 52 | apdu.data = sbuf; |
2872 | | |
2873 | 52 | r = sc_transmit_apdu_t(card, &apdu); |
2874 | 52 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2875 | 50 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2876 | 50 | LOG_TEST_RET(card->ctx, r, "generate key pair failed"); |
2877 | | |
2878 | | /* read public key */ |
2879 | 37 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xb4, 0x02, 0x00); |
2880 | 37 | if (len == 256) { |
2881 | 21 | apdu.p1 = 0x00; |
2882 | 21 | } |
2883 | | |
2884 | 37 | apdu.cla = 0x80; |
2885 | 37 | apdu.lc = apdu.datalen = 2; |
2886 | 37 | apdu.data = &sbuf[5]; |
2887 | 37 | apdu.resp = rbuf; |
2888 | 37 | apdu.resplen = sizeof(rbuf); |
2889 | 37 | apdu.le = 0x00; |
2890 | | |
2891 | 37 | r = sc_transmit_apdu_t(card, &apdu); |
2892 | 37 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2893 | 36 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2894 | 36 | LOG_TEST_RET(card->ctx, r, "get pukey failed"); |
2895 | | |
2896 | 30 | if (len < apdu.resplen) |
2897 | 30 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2898 | | |
2899 | 25 | if (256 == len) { /* ECC 256 bit */ |
2900 | 17 | size_t xCoordinateLen = rbuf[1]; |
2901 | 17 | size_t yCoordinateLen; |
2902 | 17 | unsigned char *tmp; |
2903 | | |
2904 | 17 | if (2 + xCoordinateLen + 1 > apdu.resplen) { |
2905 | 3 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); |
2906 | 3 | } |
2907 | 14 | yCoordinateLen = rbuf[2 + xCoordinateLen + 1]; |
2908 | 14 | if (2 + xCoordinateLen + 2 + yCoordinateLen > apdu.resplen) { |
2909 | 6 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); |
2910 | 6 | } |
2911 | 8 | data->modulus_len = xCoordinateLen + yCoordinateLen; |
2912 | 8 | tmp = (u8 *)malloc(data->modulus_len); |
2913 | 8 | if (!tmp) { |
2914 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
2915 | 0 | } |
2916 | | |
2917 | 8 | if (0x58 == rbuf[0]) { |
2918 | 3 | memcpy(tmp, &rbuf[2], xCoordinateLen); |
2919 | 5 | } else { |
2920 | 5 | free(tmp); |
2921 | 5 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_VALID); |
2922 | 5 | } |
2923 | 3 | if (0x59 == rbuf[2 + xCoordinateLen]) { |
2924 | 2 | memcpy(tmp + xCoordinateLen, &rbuf[2+xCoordinateLen+2], yCoordinateLen); |
2925 | 2 | } else { |
2926 | 1 | free(tmp); |
2927 | 1 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_VALID); |
2928 | 1 | } |
2929 | | |
2930 | 2 | data->modulus = tmp; |
2931 | 8 | } else { |
2932 | 8 | data->modulus = (u8 *) malloc(len); |
2933 | 8 | if (!data->modulus) { |
2934 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
2935 | 8 | } else { |
2936 | 8 | memcpy(data->modulus, rbuf, len); |
2937 | 8 | } |
2938 | 8 | } |
2939 | 10 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2940 | 10 | } |
2941 | | |
2942 | | |
2943 | | static int |
2944 | | epass2003_erase_card(struct sc_card *card) |
2945 | 17 | { |
2946 | 17 | static const unsigned char install_magic_pin[26] = { |
2947 | | /* compare install_secret_key */ |
2948 | 17 | 0x06, 0x01, 0x10, 0x16, 0x16, 0x16, 0x00, 0x0f, 0xff, 0x66, |
2949 | 17 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2950 | 17 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2951 | 17 | }; |
2952 | 17 | static const unsigned char magic_pin[16] = { |
2953 | 17 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2954 | 17 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2955 | 17 | }; |
2956 | 17 | static const unsigned char mf_path[2] = { 0x3f, 0x00 }; |
2957 | 17 | sc_apdu_t apdu; |
2958 | 17 | int r; |
2959 | | |
2960 | 17 | LOG_FUNC_CALLED(card->ctx); |
2961 | | |
2962 | | /* install magic pin */ |
2963 | 17 | sc_format_apdu(card, &apdu, 0x03, 0xe3, 0x00, 0x00); |
2964 | 17 | apdu.cla = 0x80; |
2965 | 17 | apdu.data = install_magic_pin; |
2966 | 17 | apdu.datalen = apdu.lc = sizeof(install_magic_pin); |
2967 | 17 | r = sc_transmit_apdu(card, &apdu); |
2968 | 17 | LOG_TEST_RET(card->ctx, r, "APDU install magic pin failed"); |
2969 | 16 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2970 | 16 | LOG_TEST_RET(card->ctx, r, "install magic pin failed"); |
2971 | | |
2972 | | /* verify magic pin */ |
2973 | 6 | sc_format_apdu(card, &apdu, 0x03, 0x20, 0x00, 0x01); |
2974 | 6 | apdu.cla = 0; |
2975 | 6 | apdu.data = magic_pin; |
2976 | 6 | apdu.datalen = apdu.lc = sizeof(magic_pin); |
2977 | 6 | r = sc_transmit_apdu(card, &apdu); |
2978 | 6 | LOG_TEST_RET(card->ctx, r, "APDU verify magic pin failed"); |
2979 | 5 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2980 | 5 | LOG_TEST_RET(card->ctx, r, "verify magic pin failed"); |
2981 | | |
2982 | | /* delete MF */ |
2983 | 4 | sc_format_apdu(card, &apdu, 0x03, 0xe4, 0x00, 0x00); |
2984 | 4 | apdu.cla = 0; |
2985 | 4 | apdu.data = mf_path; |
2986 | 4 | apdu.datalen = apdu.lc = sizeof(mf_path); |
2987 | 4 | r = sc_transmit_apdu(card, &apdu); |
2988 | 4 | LOG_TEST_RET(card->ctx, r, "APDU delete MF failed"); |
2989 | 3 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2990 | 3 | LOG_TEST_RET(card->ctx, r, "delete MF failed"); |
2991 | | |
2992 | 1 | LOG_FUNC_RETURN(card->ctx, r); |
2993 | 1 | } |
2994 | | |
2995 | | |
2996 | | static int |
2997 | | epass2003_get_serialnr(struct sc_card *card, sc_serial_number_t * serial) |
2998 | 309 | { |
2999 | 309 | u8 rbuf[8]; |
3000 | 309 | size_t rbuf_len = sizeof(rbuf); |
3001 | | |
3002 | 309 | LOG_FUNC_CALLED(card->ctx); |
3003 | | |
3004 | 309 | if (SC_SUCCESS != get_data(card, 0x80, rbuf, rbuf_len)) |
3005 | 217 | return SC_ERROR_CARD_CMD_FAILED; |
3006 | | |
3007 | 92 | card->serialnr.len = serial->len = 8; |
3008 | 92 | memcpy(card->serialnr.value, rbuf, 8); |
3009 | 92 | memcpy(serial->value, rbuf, 8); |
3010 | | |
3011 | 92 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
3012 | 92 | } |
3013 | | |
3014 | | |
3015 | | static int |
3016 | | epass2003_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr) |
3017 | 1.66k | { |
3018 | 1.66k | LOG_FUNC_CALLED(card->ctx); |
3019 | | |
3020 | 1.66k | sc_log(card->ctx, "cmd is %0lx", cmd); |
3021 | 1.66k | switch (cmd) { |
3022 | 20 | case SC_CARDCTL_ENTERSAFE_WRITE_KEY: |
3023 | 20 | return epass2003_write_key(card, (sc_epass2003_wkey_data *) ptr); |
3024 | 52 | case SC_CARDCTL_ENTERSAFE_GENERATE_KEY: |
3025 | 52 | return epass2003_gen_key(card, (sc_epass2003_gen_key_data *) ptr); |
3026 | 17 | case SC_CARDCTL_ERASE_CARD: |
3027 | 17 | return epass2003_erase_card(card); |
3028 | 309 | case SC_CARDCTL_GET_SERIALNR: |
3029 | 309 | return epass2003_get_serialnr(card, (sc_serial_number_t *) ptr); |
3030 | 1.26k | default: |
3031 | 1.26k | return SC_ERROR_NOT_SUPPORTED; |
3032 | 1.66k | } |
3033 | 1.66k | } |
3034 | | |
3035 | | |
3036 | | static void |
3037 | | internal_sanitize_pin_info(struct sc_pin_cmd_pin *pin, unsigned int num) |
3038 | 618 | { |
3039 | 618 | pin->encoding = SC_PIN_ENCODING_ASCII; |
3040 | 618 | pin->min_length = 4; |
3041 | 618 | pin->max_length = 16; |
3042 | 618 | pin->pad_length = 16; |
3043 | 618 | pin->offset = 5 + num * 16; |
3044 | 618 | pin->pad_char = 0x00; |
3045 | 618 | } |
3046 | | |
3047 | | |
3048 | | static int |
3049 | | get_external_key_maxtries(struct sc_card *card, unsigned char *maxtries) |
3050 | 0 | { |
3051 | 0 | unsigned char maxcounter[2] = {0}; |
3052 | 0 | static const sc_path_t file_path = { |
3053 | 0 | {0x3f, 0x00, 0x50, 0x15, 0x9f, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 6, |
3054 | 0 | 0, |
3055 | 0 | 0, |
3056 | 0 | SC_PATH_TYPE_PATH, |
3057 | 0 | {{0}, 0} |
3058 | 0 | }; |
3059 | 0 | int ret; |
3060 | |
|
3061 | 0 | ret = sc_select_file(card, &file_path, NULL); |
3062 | 0 | LOG_TEST_RET(card->ctx, ret, "select max counter file failed"); |
3063 | | |
3064 | 0 | ret = sc_read_binary(card, 0, maxcounter, 2, 0); |
3065 | 0 | LOG_TEST_RET(card->ctx, ret, "read max counter file failed"); |
3066 | | |
3067 | 0 | *maxtries = maxcounter[0]; |
3068 | 0 | return SC_SUCCESS; |
3069 | 0 | } |
3070 | | |
3071 | | |
3072 | | static int |
3073 | | get_external_key_retries(struct sc_card *card, unsigned char kid, unsigned char *retries) |
3074 | 0 | { |
3075 | 0 | int r; |
3076 | 0 | struct sc_apdu apdu; |
3077 | 0 | unsigned char random[16] = {0}; |
3078 | |
|
3079 | 0 | r = sc_get_challenge(card, random, 8); |
3080 | 0 | LOG_TEST_RET(card->ctx, r, "get challenge get_external_key_retries failed"); |
3081 | | |
3082 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x82, 0x01, 0x80 | kid); |
3083 | 0 | apdu.resp = NULL; |
3084 | 0 | apdu.resplen = 0; |
3085 | |
|
3086 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
3087 | 0 | LOG_TEST_RET(card->ctx, r, "APDU get_external_key_retries failed"); |
3088 | | |
3089 | 0 | if (retries && ((0x63 == (apdu.sw1 & 0xff)) && (0xC0 == (apdu.sw2 & 0xf0)))) { |
3090 | 0 | *retries = (apdu.sw2 & 0x0f); |
3091 | 0 | r = SC_SUCCESS; |
3092 | 0 | } else { |
3093 | 0 | LOG_TEST_RET(card->ctx, r, "get_external_key_retries failed"); |
3094 | 0 | r = SC_ERROR_CARD_CMD_FAILED; |
3095 | 0 | } |
3096 | | |
3097 | 0 | return r; |
3098 | 0 | } |
3099 | | |
3100 | | static int |
3101 | | epass2003_get_challenge(sc_card_t *card, u8 *rnd, size_t len) |
3102 | 1.57k | { |
3103 | 1.57k | u8 rbuf[16]; |
3104 | 1.57k | size_t out_len; |
3105 | 1.57k | int r; |
3106 | | |
3107 | 1.57k | LOG_FUNC_CALLED(card->ctx); |
3108 | | |
3109 | 1.57k | r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); |
3110 | 1.57k | LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); |
3111 | | |
3112 | 1.24k | if (len < (size_t) r) { |
3113 | 2 | out_len = len; |
3114 | 1.24k | } else { |
3115 | 1.24k | out_len = (size_t) r; |
3116 | 1.24k | } |
3117 | 1.24k | memcpy(rnd, rbuf, out_len); |
3118 | | |
3119 | 1.24k | LOG_FUNC_RETURN(card->ctx, (int) out_len); |
3120 | 1.24k | } |
3121 | | |
3122 | | |
3123 | | static int |
3124 | | external_key_auth(struct sc_card *card, unsigned char kid, |
3125 | | unsigned char *data, size_t datalen) |
3126 | 0 | { |
3127 | 0 | int r; |
3128 | 0 | struct sc_apdu apdu; |
3129 | 0 | unsigned char random[16] = {0}; |
3130 | 0 | unsigned char tmp_data[16] = {0}; |
3131 | 0 | unsigned char hash[HASH_LEN] = {0}; |
3132 | 0 | unsigned char iv[16] = {0}; |
3133 | |
|
3134 | 0 | r = sc_get_challenge(card, random, 8); |
3135 | 0 | LOG_TEST_RET(card->ctx, r, "get challenge external_key_auth failed"); |
3136 | | |
3137 | 0 | r = hash_data(card, data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); |
3138 | 0 | LOG_TEST_RET(card->ctx, r, "hash data failed"); |
3139 | | |
3140 | 0 | r = des3_encrypt_cbc(card, hash, HASH_LEN, iv, random, 8, tmp_data); |
3141 | 0 | LOG_TEST_RET(card->ctx, r, "encryption failed"); |
3142 | | |
3143 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x01, 0x80 | kid); |
3144 | 0 | apdu.lc = apdu.datalen = 8; |
3145 | 0 | apdu.data = tmp_data; |
3146 | |
|
3147 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
3148 | 0 | LOG_TEST_RET(card->ctx, r, "APDU external_key_auth failed"); |
3149 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
3150 | 0 | LOG_TEST_RET(card->ctx, r, "external_key_auth failed"); |
3151 | | |
3152 | 0 | return r; |
3153 | 0 | } |
3154 | | |
3155 | | |
3156 | | static int |
3157 | | update_secret_key(struct sc_card *card, unsigned char ktype, unsigned char kid, |
3158 | | const unsigned char *data, unsigned long datalen) |
3159 | 0 | { |
3160 | 0 | int r; |
3161 | 0 | struct sc_apdu apdu; |
3162 | 0 | unsigned char hash[HASH_LEN] = {0}; |
3163 | 0 | unsigned char tmp_data[256] = {0}; |
3164 | 0 | unsigned char maxtries = 0; |
3165 | |
|
3166 | 0 | r = hash_data(card, data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); |
3167 | 0 | LOG_TEST_RET(card->ctx, r, "hash data failed"); |
3168 | | |
3169 | 0 | r = get_external_key_maxtries(card, &maxtries); |
3170 | 0 | LOG_TEST_RET(card->ctx, r, "get max counter failed"); |
3171 | | |
3172 | 0 | tmp_data[0] = (maxtries << 4) | maxtries; |
3173 | 0 | memcpy(&tmp_data[1], hash, HASH_LEN); |
3174 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xe5, ktype, kid); |
3175 | 0 | apdu.cla = 0x80; |
3176 | 0 | apdu.lc = apdu.datalen = 1 + HASH_LEN; |
3177 | 0 | apdu.data = tmp_data; |
3178 | |
|
3179 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
3180 | 0 | LOG_TEST_RET(card->ctx, r, "APDU update_secret_key failed"); |
3181 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
3182 | 0 | LOG_TEST_RET(card->ctx, r, "update_secret_key failed"); |
3183 | | |
3184 | 0 | return r; |
3185 | 0 | } |
3186 | | |
3187 | | /* use external auth secret as pin */ |
3188 | | static int |
3189 | | epass2003_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left) |
3190 | 309 | { |
3191 | 309 | int r; |
3192 | 309 | u8 kid; |
3193 | 309 | u8 retries = 0; |
3194 | 309 | u8 pin_low = 3; |
3195 | 309 | unsigned char maxtries = 0; |
3196 | | |
3197 | 309 | LOG_FUNC_CALLED(card->ctx); |
3198 | | |
3199 | 309 | internal_sanitize_pin_info(&data->pin1, 0); |
3200 | 309 | internal_sanitize_pin_info(&data->pin2, 1); |
3201 | 309 | data->flags |= SC_PIN_CMD_NEED_PADDING; |
3202 | 309 | kid = data->pin_reference; |
3203 | | |
3204 | 309 | if (NULL == (unsigned char *)data->pin1.data || 0 == data->pin1.len) |
3205 | 309 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT); |
3206 | | |
3207 | | /* get pin retries */ |
3208 | 0 | if (data->cmd == SC_PIN_CMD_GET_INFO) { |
3209 | |
|
3210 | 0 | r = get_external_key_retries(card, 0x80 | kid, &retries); |
3211 | 0 | if (r == SC_SUCCESS) { |
3212 | 0 | data->pin1.tries_left = retries; |
3213 | 0 | if (tries_left) |
3214 | 0 | *tries_left = retries; |
3215 | |
|
3216 | 0 | r = get_external_key_maxtries(card, &maxtries); |
3217 | 0 | LOG_TEST_RET(card->ctx, r, "get max counter failed"); |
3218 | | |
3219 | 0 | data->pin1.max_tries = maxtries; |
3220 | 0 | } |
3221 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3222 | 0 | } else if (data->cmd == SC_PIN_CMD_UNBLOCK) { /* verify */ |
3223 | 0 | r = external_key_auth(card, (kid + 1), (unsigned char *)data->pin1.data, |
3224 | 0 | data->pin1.len); |
3225 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3226 | 0 | } else if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) { /* change */ |
3227 | 0 | r = external_key_auth(card, kid, (unsigned char *)data->pin1.data, |
3228 | 0 | data->pin1.len); |
3229 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3230 | | |
3231 | 0 | r = update_secret_key(card, 0x04, kid, data->pin2.data, |
3232 | 0 | (unsigned long)data->pin2.len); |
3233 | 0 | LOG_TEST_RET(card->ctx, r, "change pin failed"); |
3234 | 0 | } else { |
3235 | 0 | r = external_key_auth(card, kid, (unsigned char *)data->pin1.data, |
3236 | 0 | data->pin1.len); |
3237 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3238 | | |
3239 | 0 | r = get_external_key_retries(card, 0x80 | kid, &retries); |
3240 | 0 | if (retries < pin_low) |
3241 | 0 | sc_log(card->ctx, "Verification failed (remaining tries: %d)", retries); |
3242 | |
|
3243 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3244 | 0 | } |
3245 | | |
3246 | 0 | if (r == SC_SUCCESS) { |
3247 | 0 | data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN; |
3248 | 0 | } |
3249 | 0 | return r; |
3250 | 0 | } |
3251 | | |
3252 | | static int |
3253 | | epass2003_logout(struct sc_card *card) |
3254 | 0 | { |
3255 | 0 | epass2003_exdata *exdata = NULL; |
3256 | |
|
3257 | 0 | if (!card->drv_data) |
3258 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
3259 | | |
3260 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
3261 | 0 | if (exdata->sm) { |
3262 | 0 | sc_sm_stop(card); |
3263 | 0 | return epass2003_refresh(card); |
3264 | 0 | } |
3265 | | |
3266 | 0 | return SC_ERROR_NOT_SUPPORTED; |
3267 | 0 | } |
3268 | | |
3269 | | static struct sc_card_driver *sc_get_driver(void) |
3270 | 101k | { |
3271 | 101k | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
3272 | | |
3273 | 101k | if (iso_ops == NULL) |
3274 | 10 | iso_ops = iso_drv->ops; |
3275 | | |
3276 | 101k | epass2003_ops = *iso_ops; |
3277 | | |
3278 | 101k | epass2003_ops.match_card = epass2003_match_card; |
3279 | 101k | epass2003_ops.init = epass2003_init; |
3280 | 101k | epass2003_ops.finish = epass2003_finish; |
3281 | 101k | epass2003_ops.write_binary = NULL; |
3282 | 101k | epass2003_ops.write_record = NULL; |
3283 | 101k | epass2003_ops.select_file = epass2003_select_file; |
3284 | 101k | epass2003_ops.get_response = NULL; |
3285 | 101k | epass2003_ops.restore_security_env = epass2003_restore_security_env; |
3286 | 101k | epass2003_ops.set_security_env = epass2003_set_security_env; |
3287 | 101k | epass2003_ops.decipher = epass2003_decipher; |
3288 | 101k | epass2003_ops.compute_signature = epass2003_decipher; |
3289 | 101k | epass2003_ops.create_file = epass2003_create_file; |
3290 | 101k | epass2003_ops.delete_file = epass2003_delete_file; |
3291 | 101k | epass2003_ops.list_files = epass2003_list_files; |
3292 | 101k | epass2003_ops.card_ctl = epass2003_card_ctl; |
3293 | 101k | epass2003_ops.process_fci = epass2003_process_fci; |
3294 | 101k | epass2003_ops.construct_fci = epass2003_construct_fci; |
3295 | 101k | epass2003_ops.pin_cmd = epass2003_pin_cmd; |
3296 | 101k | epass2003_ops.check_sw = epass2003_check_sw; |
3297 | 101k | epass2003_ops.get_challenge = epass2003_get_challenge; |
3298 | 101k | epass2003_ops.logout = epass2003_logout; |
3299 | 101k | return &epass2003_drv; |
3300 | 101k | } |
3301 | | |
3302 | | struct sc_card_driver *sc_get_epass2003_driver(void) |
3303 | 101k | { |
3304 | 101k | return sc_get_driver(); |
3305 | 101k | } |
3306 | | #endif /* #ifdef ENABLE_OPENSSL */ |
3307 | | #endif /* #ifdef ENABLE_SM */ |