/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 | 0 | #define KEY_TYPE_AES 0x01 /* FIPS mode */ |
81 | 0 | #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 | 0 | #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 | 0 | #define SM_PLAIN 0x00 |
92 | 0 | #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 | 0 | #define REVERSE_ORDER4(x) ( \ |
118 | 0 | ((unsigned long)x & 0xFF000000)>> 24 | \ |
119 | 0 | ((unsigned long)x & 0x00FF0000)>> 8 | \ |
120 | 0 | ((unsigned long)x & 0x0000FF00)<< 8 | \ |
121 | 0 | ((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 | 0 | { |
246 | 0 | const int err_count = sizeof(epass2003_errors)/sizeof(epass2003_errors[0]); |
247 | 0 | int i; |
248 | | |
249 | | /* Handle special cases here */ |
250 | 0 | if (sw1 == 0x6C) { |
251 | 0 | sc_log(card->ctx, "Wrong length; correct length is %d", sw2); |
252 | 0 | return SC_ERROR_WRONG_LENGTH; |
253 | 0 | } |
254 | | |
255 | 0 | for (i = 0; i < err_count; i++) { |
256 | 0 | if (epass2003_errors[i].SWs == ((sw1 << 8) | sw2)) { |
257 | 0 | sc_log(card->ctx, "%s", epass2003_errors[i].errorstr); |
258 | 0 | return epass2003_errors[i].errorno; |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | 0 | sc_log(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X", sw1, sw2); |
263 | 0 | return SC_ERROR_CARD_CMD_FAILED; |
264 | 0 | } |
265 | | |
266 | | static int |
267 | | sc_transmit_apdu_t(sc_card_t *card, sc_apdu_t *apdu) |
268 | 0 | { |
269 | 0 | size_t resplen = apdu->resplen; |
270 | 0 | int r = sc_transmit_apdu(card, apdu); |
271 | 0 | if ((0x69 == apdu->sw1 && 0x85 == apdu->sw2) || (0x69 == apdu->sw1 && 0x88 == apdu->sw2)) { |
272 | 0 | epass2003_refresh(card); |
273 | | /* renew old resplen */ |
274 | 0 | apdu->resplen = resplen; |
275 | 0 | r = sc_transmit_apdu(card, apdu); |
276 | 0 | } |
277 | 0 | return r; |
278 | 0 | } |
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 | 0 | { |
284 | 0 | int r = SC_ERROR_INTERNAL; |
285 | 0 | EVP_CIPHER_CTX * ctx = NULL; |
286 | 0 | int outl = 0; |
287 | 0 | int outl_tmp = 0; |
288 | 0 | unsigned char iv_tmp[EVP_MAX_IV_LENGTH] = {0}; |
289 | |
|
290 | 0 | memcpy(iv_tmp, iv, EVP_MAX_IV_LENGTH); |
291 | 0 | ctx = EVP_CIPHER_CTX_new(); |
292 | 0 | if (ctx == NULL) |
293 | 0 | goto out; |
294 | | |
295 | 0 | if (!EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv_tmp) || !EVP_CIPHER_CTX_set_padding(ctx, 0)) |
296 | 0 | goto out; |
297 | | |
298 | 0 | if (!EVP_EncryptUpdate(ctx, output, &outl, input, (int)length)) |
299 | 0 | goto out; |
300 | | |
301 | 0 | if (!EVP_EncryptFinal_ex(ctx, output + outl, &outl_tmp)) |
302 | 0 | goto out; |
303 | | |
304 | 0 | r = SC_SUCCESS; |
305 | 0 | out: |
306 | 0 | EVP_CIPHER_CTX_free(ctx); |
307 | 0 | return r; |
308 | 0 | } |
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 | 0 | { |
314 | 0 | int r = SC_ERROR_INTERNAL; |
315 | 0 | EVP_CIPHER_CTX * ctx = NULL; |
316 | 0 | int outl = 0; |
317 | 0 | int outl_tmp = 0; |
318 | 0 | unsigned char iv_tmp[EVP_MAX_IV_LENGTH] = {0}; |
319 | |
|
320 | 0 | memcpy(iv_tmp, iv, EVP_MAX_IV_LENGTH); |
321 | 0 | ctx = EVP_CIPHER_CTX_new(); |
322 | 0 | if (ctx == NULL) |
323 | 0 | goto out; |
324 | | |
325 | 0 | if (!EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv_tmp) || |
326 | 0 | !EVP_CIPHER_CTX_set_padding(ctx, 0)) |
327 | 0 | goto out; |
328 | | |
329 | 0 | if (!EVP_DecryptUpdate(ctx, output, &outl, input, (int)length)) |
330 | 0 | goto out; |
331 | | |
332 | 0 | if (!EVP_DecryptFinal_ex(ctx, output + outl, &outl_tmp)) |
333 | 0 | goto out; |
334 | | |
335 | 0 | r = SC_SUCCESS; |
336 | 0 | out: |
337 | 0 | EVP_CIPHER_CTX_free(ctx); |
338 | 0 | return r; |
339 | 0 | } |
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 | 0 | { |
416 | 0 | size_t mactlen = 0; |
417 | 0 | int r = SC_ERROR_INTERNAL; |
418 | 0 | #if OPENSSL_VERSION_NUMBER < 0x30000000L |
419 | 0 | CMAC_CTX *ctx = CMAC_CTX_new(); |
420 | 0 | if (ctx == NULL) { |
421 | 0 | return SC_ERROR_INTERNAL; |
422 | 0 | } |
423 | | |
424 | 0 | if (!CMAC_Init(ctx, key, keysize / 8, EVP_aes_128_cbc(), NULL)) { |
425 | 0 | goto err; |
426 | 0 | } |
427 | 0 | if (!CMAC_Update(ctx, input, length)) { |
428 | 0 | goto err; |
429 | 0 | } |
430 | 0 | if (!CMAC_Final(ctx, output, &mactlen)) { |
431 | 0 | goto err; |
432 | 0 | } |
433 | 0 | r = SC_SUCCESS; |
434 | 0 | err: |
435 | 0 | 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 | 0 | return r; |
470 | 0 | } |
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 | 0 | { |
476 | 0 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
477 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-ECB"); |
478 | 0 | int r; |
479 | 0 | r = openssl_enc(alg, key, iv, input, length, output); |
480 | 0 | sc_evp_cipher_free(alg); |
481 | 0 | if (r != SC_SUCCESS) |
482 | 0 | sc_log_openssl(card->ctx); |
483 | 0 | return r; |
484 | 0 | } |
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 | 0 | { |
491 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-CBC"); |
492 | 0 | int r; |
493 | 0 | r = openssl_enc(alg, key, iv, input, length, output); |
494 | 0 | sc_evp_cipher_free(alg); |
495 | 0 | if (r != SC_SUCCESS) |
496 | 0 | sc_log_openssl(card->ctx); |
497 | 0 | return r; |
498 | 0 | } |
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 | 0 | { |
505 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "AES-128-CBC"); |
506 | 0 | int r; |
507 | 0 | r = openssl_dec(alg, key, iv, input, length, output); |
508 | 0 | sc_evp_cipher_free(alg); |
509 | 0 | if (r != SC_SUCCESS) |
510 | 0 | sc_log_openssl(card->ctx); |
511 | 0 | return r; |
512 | 0 | } |
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 | 0 | { |
519 | 0 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
520 | 0 | unsigned char bKey[24] = {0}; |
521 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-EDE3"); |
522 | 0 | int r; |
523 | |
|
524 | 0 | if (keysize == 16) { |
525 | 0 | memcpy(&bKey[0], key, 16); |
526 | 0 | memcpy(&bKey[16], key, 8); |
527 | 0 | } else { |
528 | 0 | memcpy(&bKey[0], key, 24); |
529 | 0 | } |
530 | |
|
531 | 0 | r = openssl_enc(alg, bKey, iv, input, length, output); |
532 | 0 | sc_evp_cipher_free(alg); |
533 | 0 | if (r != SC_SUCCESS) |
534 | 0 | sc_log_openssl(card->ctx); |
535 | 0 | return r; |
536 | 0 | } |
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 | 0 | { |
543 | 0 | unsigned char bKey[24] = {0}; |
544 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-EDE3-CBC"); |
545 | 0 | int r; |
546 | |
|
547 | 0 | if (keysize == 16) { |
548 | 0 | memcpy(&bKey[0], key, 16); |
549 | 0 | memcpy(&bKey[16], key, 8); |
550 | 0 | } else { |
551 | 0 | memcpy(&bKey[0], key, 24); |
552 | 0 | } |
553 | |
|
554 | 0 | r = openssl_enc(EVP_des_ede3_cbc(), bKey, iv, input, length, output); |
555 | 0 | sc_evp_cipher_free(alg); |
556 | 0 | if (r != SC_SUCCESS) |
557 | 0 | sc_log_openssl(card->ctx); |
558 | 0 | return r; |
559 | 0 | } |
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 | 0 | { |
589 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-CBC"); |
590 | 0 | int r; |
591 | |
|
592 | 0 | r = openssl_enc(alg, key, iv, input, length, output); |
593 | 0 | sc_evp_cipher_free(alg); |
594 | 0 | if (r != SC_SUCCESS) |
595 | 0 | sc_log_openssl(card->ctx); |
596 | 0 | return r; |
597 | 0 | } |
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 | 0 | { |
604 | 0 | EVP_CIPHER *alg = sc_evp_cipher(card->ctx, "DES-CBC"); |
605 | 0 | int r; |
606 | |
|
607 | 0 | r = openssl_dec(alg, key, iv, input, length, output); |
608 | 0 | sc_evp_cipher_free(alg); |
609 | 0 | if (r != SC_SUCCESS) |
610 | 0 | sc_log_openssl(card->ctx); |
611 | 0 | return r; |
612 | 0 | } |
613 | | |
614 | | |
615 | | static int |
616 | | openssl_dig(const EVP_MD * digest, const unsigned char *input, size_t length, |
617 | | unsigned char *output) |
618 | 0 | { |
619 | 0 | int r = 0; |
620 | 0 | EVP_MD_CTX *ctx = NULL; |
621 | 0 | unsigned outl = 0; |
622 | |
|
623 | 0 | ctx = EVP_MD_CTX_create(); |
624 | 0 | if (ctx == NULL) { |
625 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
626 | 0 | goto err; |
627 | 0 | } |
628 | | |
629 | 0 | EVP_MD_CTX_init(ctx); |
630 | 0 | if (!EVP_DigestInit_ex(ctx, digest, NULL) || |
631 | 0 | !EVP_DigestUpdate(ctx, input, length)) { |
632 | 0 | r = SC_ERROR_INTERNAL; |
633 | 0 | goto err; |
634 | 0 | } |
635 | | |
636 | 0 | if (!EVP_DigestFinal_ex(ctx, output, &outl)) { |
637 | 0 | r = SC_ERROR_INTERNAL; |
638 | 0 | goto err; |
639 | 0 | } |
640 | 0 | r = SC_SUCCESS; |
641 | 0 | err: |
642 | 0 | if (ctx) |
643 | 0 | EVP_MD_CTX_destroy(ctx); |
644 | |
|
645 | 0 | return r; |
646 | 0 | } |
647 | | |
648 | | |
649 | | static int |
650 | | sha1_digest(struct sc_card *card, const unsigned char *input, size_t length, unsigned char *output) |
651 | 0 | { |
652 | 0 | EVP_MD *md = sc_evp_md(card->ctx, "SHA1"); |
653 | 0 | int r; |
654 | |
|
655 | 0 | r = openssl_dig(md, input, length, output); |
656 | 0 | sc_evp_md_free(md); |
657 | 0 | if (r != SC_SUCCESS) |
658 | 0 | sc_log_openssl(card->ctx); |
659 | 0 | return r; |
660 | 0 | } |
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 | 0 | { |
680 | 0 | int r; |
681 | 0 | struct sc_apdu apdu; |
682 | 0 | unsigned char data[256] = {0}; |
683 | 0 | unsigned char tmp_sm; |
684 | 0 | unsigned char isFips; |
685 | 0 | unsigned long blocksize = 0; |
686 | 0 | unsigned char cryptogram[256] = {0}; /* host cryptogram */ |
687 | 0 | unsigned char iv[16] = {0}; |
688 | 0 | epass2003_exdata *exdata = NULL; |
689 | |
|
690 | 0 | if (!card->drv_data) |
691 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
692 | | |
693 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
694 | 0 | isFips = exdata->bFipsCertification; |
695 | |
|
696 | 0 | LOG_FUNC_CALLED(card->ctx); |
697 | |
|
698 | 0 | if (1 != RAND_bytes(g_random, sizeof(g_random))) |
699 | 0 | return SC_ERROR_INTERNAL; |
700 | | |
701 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x50, 0x00, 0x00); |
702 | 0 | apdu.cla = 0x80; |
703 | 0 | apdu.lc = apdu.datalen = sizeof(g_random); |
704 | 0 | apdu.data = g_random; /* host random */ |
705 | 0 | if (isFips) |
706 | 0 | apdu.le = apdu.resplen = 29; |
707 | 0 | else |
708 | 0 | apdu.le = apdu.resplen = 28; |
709 | |
|
710 | 0 | apdu.resp = result; /* card random is result[12~19] */ |
711 | |
|
712 | 0 | tmp_sm = exdata->sm; |
713 | 0 | exdata->sm = SM_PLAIN; |
714 | 0 | r = epass2003_transmit_apdu(card, &apdu); |
715 | 0 | exdata->sm = tmp_sm; |
716 | 0 | LOG_TEST_RET(card->ctx, r, "APDU gen_init_key failed"); |
717 | | |
718 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
719 | 0 | LOG_TEST_RET(card->ctx, r, "gen_init_key failed"); |
720 | | |
721 | | /* Step 1 - Generate Derivation data */ |
722 | 0 | if (isFips) { |
723 | 0 | memset(data, 0x00, 15); |
724 | 0 | data[11] = 0x04; |
725 | 0 | data[14] = 0x80; |
726 | 0 | data[15] = 0x01; |
727 | 0 | memcpy(&data[16], g_random, 8); |
728 | 0 | memcpy(&data[24], &result[12 + 1], 8); |
729 | 0 | } else { |
730 | 0 | memcpy(data, &result[16], 4); |
731 | 0 | memcpy(&data[4], g_random, 4); |
732 | 0 | memcpy(&data[8], &result[12], 4); |
733 | 0 | memcpy(&data[12], &g_random[4], 4); |
734 | 0 | } |
735 | | |
736 | | /* Step 2,3 - Create S-ENC/S-MAC Session Key */ |
737 | 0 | if (KEY_TYPE_AES == key_type) { |
738 | 0 | if (isFips) { |
739 | 0 | r = aes128_encrypt_cmac(card, key_enc, 128, data, 32, exdata->sk_enc); |
740 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac enc failed"); |
741 | 0 | memset(&data[11], 0x06, 1); |
742 | 0 | r = aes128_encrypt_cmac(card, key_mac, 128, data, 32, exdata->sk_mac); |
743 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac mac failed"); |
744 | 0 | } else { |
745 | 0 | r = aes128_encrypt_ecb(card, key_enc, 16, data, 16, exdata->sk_enc); |
746 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_ecb enc failed"); |
747 | 0 | r = aes128_encrypt_ecb(card, key_mac, 16, data, 16, exdata->sk_mac); |
748 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_ecb mac failed"); |
749 | 0 | } |
750 | 0 | } else { |
751 | 0 | r = des3_encrypt_ecb(card, key_enc, 16, data, 16, exdata->sk_enc); |
752 | 0 | LOG_TEST_RET(card->ctx, r, "des3_encrypt_ecb failed"); |
753 | 0 | r = des3_encrypt_ecb(card, key_mac, 16, data, 16, exdata->sk_mac); |
754 | 0 | LOG_TEST_RET(card->ctx, r, "des3_encrypt_ecb failed"); |
755 | 0 | } |
756 | | |
757 | 0 | if (isFips) { |
758 | 0 | data[11] = 0x00; |
759 | 0 | data[14] = 0x40; |
760 | 0 | } else { |
761 | 0 | memcpy(data, g_random, 8); |
762 | 0 | memcpy(&data[8], &result[12], 8); |
763 | 0 | data[16] = 0x80; |
764 | 0 | blocksize = (key_type == KEY_TYPE_AES ? 16 : 8); |
765 | 0 | memset(&data[17], 0x00, blocksize - 1); |
766 | 0 | } |
767 | | |
768 | | /* calculate host cryptogram */ |
769 | 0 | if (KEY_TYPE_AES == key_type) { |
770 | 0 | if (isFips) { |
771 | 0 | r = aes128_encrypt_cmac(card, exdata->sk_enc, 128, data, 32, cryptogram); |
772 | 0 | } else { |
773 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram); |
774 | 0 | } |
775 | 0 | } else { |
776 | 0 | r = des3_encrypt_cbc(card, exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram); |
777 | 0 | } |
778 | |
|
779 | 0 | LOG_TEST_RET(card->ctx, r, "calculate host cryptogram failed"); |
780 | | |
781 | | /* verify card cryptogram */ |
782 | 0 | if (isFips) { |
783 | 0 | if (0 != memcmp(&cryptogram[0], &result[20+1], 8)) |
784 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED); |
785 | 0 | } else { |
786 | 0 | if (0 != memcmp(&cryptogram[16], &result[20], 8)) |
787 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED); |
788 | 0 | } |
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 | 0 | { |
897 | 0 | struct sc_context *ctx = card->ctx; |
898 | 0 | int r; |
899 | 0 | unsigned char result[256] = {0}; |
900 | 0 | unsigned char ran_key[8] = {0}; |
901 | 0 | epass2003_exdata *exdata = NULL; |
902 | |
|
903 | 0 | if (!card->drv_data) |
904 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
905 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
906 | |
|
907 | 0 | LOG_FUNC_CALLED(ctx); |
908 | |
|
909 | 0 | r = gen_init_key(card, key_enc, key_mac, result, exdata->smtype); |
910 | 0 | 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 | 0 | { |
927 | 0 | int r = SC_SUCCESS; |
928 | 0 | epass2003_exdata *exdata = NULL; |
929 | |
|
930 | 0 | if (!card->drv_data) |
931 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
932 | | |
933 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
934 | |
|
935 | 0 | if (exdata->sm) { |
936 | 0 | card->sm_ctx.sm_mode = 0; |
937 | 0 | r = mutual_auth(card, g_init_key_enc, g_init_key_mac); |
938 | 0 | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
939 | 0 | LOG_TEST_RET(card->ctx, r, "mutual_auth failed"); |
940 | 0 | } |
941 | | |
942 | 0 | return r; |
943 | 0 | } |
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 | 0 | { |
951 | 0 | size_t block_size = (KEY_TYPE_AES == key_type ? 16 : 8); |
952 | 0 | unsigned char pad[4096] = {0}; |
953 | 0 | size_t pad_len; |
954 | 0 | size_t tlv_more; /* increased tlv length */ |
955 | 0 | unsigned char iv[16] = {0}; |
956 | 0 | epass2003_exdata *exdata = NULL; |
957 | 0 | int r = 0; |
958 | |
|
959 | 0 | if (!card->drv_data) |
960 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
961 | | |
962 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
963 | | |
964 | | /* we encrypt the pad buffer and then write it to the apdu_buf at offset block_size + tlv_more */ |
965 | 0 | if (apdu->lc >= sizeof(pad) - block_size - 5) |
966 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, |
967 | 0 | "ePass2003 secure messaging APDU data too large"); |
968 | | |
969 | | /* padding */ |
970 | 0 | apdu_buf[block_size] = 0x87; |
971 | 0 | memcpy(pad, apdu->data, apdu->lc); |
972 | 0 | pad[apdu->lc] = 0x80; |
973 | 0 | if ((apdu->lc + 1) % block_size) |
974 | 0 | pad_len = ((apdu->lc + 1) / block_size + 1) * block_size; |
975 | 0 | else |
976 | 0 | pad_len = apdu->lc + 1; |
977 | | |
978 | | /* encode Lc' */ |
979 | 0 | if (pad_len > 0x7E) { |
980 | | /* Lc' > 0x7E, use extended APDU */ |
981 | 0 | apdu_buf[block_size + 1] = 0x82; |
982 | 0 | apdu_buf[block_size + 2] = (unsigned char)((pad_len + 1) / 0x100); |
983 | 0 | apdu_buf[block_size + 3] = (unsigned char)((pad_len + 1) % 0x100); |
984 | 0 | apdu_buf[block_size + 4] = 0x01; |
985 | 0 | tlv_more = 5; |
986 | 0 | } else { |
987 | 0 | apdu_buf[block_size + 1] = (unsigned char)pad_len + 1; |
988 | 0 | apdu_buf[block_size + 2] = 0x01; |
989 | 0 | tlv_more = 3; |
990 | 0 | } |
991 | 0 | memcpy(data_tlv, &apdu_buf[block_size], tlv_more); |
992 | | |
993 | | /* encrypt Data */ |
994 | 0 | if (KEY_TYPE_AES == key_type) { |
995 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more); |
996 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed"); |
997 | 0 | } else { |
998 | 0 | r = des3_encrypt_cbc(card, exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more); |
999 | 0 | LOG_TEST_RET(card->ctx, r, "des3_encrypt_cbc failed"); |
1000 | 0 | } |
1001 | | |
1002 | 0 | memcpy(data_tlv + tlv_more, apdu_buf + block_size + tlv_more, pad_len); |
1003 | 0 | *data_tlv_len = tlv_more + pad_len; |
1004 | 0 | return 0; |
1005 | 0 | } |
1006 | | |
1007 | | |
1008 | | /* Le(TLV)=0x97|L|Le */ |
1009 | | static int |
1010 | | construct_le_tlv(struct sc_apdu *apdu, unsigned char *apdu_buf, size_t data_tlv_len, |
1011 | | unsigned char *le_tlv, size_t * le_tlv_len, const unsigned char key_type) |
1012 | 0 | { |
1013 | 0 | size_t block_size = (KEY_TYPE_AES == key_type ? 16 : 8); |
1014 | |
|
1015 | 0 | *(apdu_buf + block_size + data_tlv_len) = 0x97; |
1016 | 0 | if (apdu->le > 0x7F) { |
1017 | | /* Le' > 0x7E, use extended APDU */ |
1018 | 0 | *(apdu_buf + block_size + data_tlv_len + 1) = 2; |
1019 | 0 | *(apdu_buf + block_size + data_tlv_len + 2) = (unsigned char)(apdu->le / 0x100); |
1020 | 0 | *(apdu_buf + block_size + data_tlv_len + 3) = (unsigned char)(apdu->le % 0x100); |
1021 | 0 | memcpy(le_tlv, apdu_buf + block_size + data_tlv_len, 4); |
1022 | 0 | *le_tlv_len = 4; |
1023 | 0 | } else { |
1024 | 0 | *(apdu_buf + block_size + data_tlv_len + 1) = 1; |
1025 | 0 | *(apdu_buf + block_size + data_tlv_len + 2) = (unsigned char)apdu->le; |
1026 | 0 | memcpy(le_tlv, apdu_buf + block_size + data_tlv_len, 3); |
1027 | 0 | *le_tlv_len = 3; |
1028 | 0 | } |
1029 | 0 | return 0; |
1030 | 0 | } |
1031 | | |
1032 | | |
1033 | | /* MAC(TLV)=0x8e|0x08|MAC */ |
1034 | | static int |
1035 | | construct_mac_tlv(struct sc_card *card, unsigned char *apdu_buf, size_t data_tlv_len, size_t le_tlv_len, |
1036 | | unsigned char *mac_tlv, size_t * mac_tlv_len, const unsigned char key_type) |
1037 | 0 | { |
1038 | 0 | size_t block_size = (KEY_TYPE_AES == key_type ? 16 : 8); |
1039 | 0 | unsigned char mac[4096] = {0}; |
1040 | 0 | size_t mac_len; |
1041 | 0 | unsigned char icv[16] = {0}; |
1042 | 0 | int r ; |
1043 | 0 | int i = (KEY_TYPE_AES == key_type ? 15 : 7); |
1044 | 0 | epass2003_exdata *exdata = NULL; |
1045 | |
|
1046 | 0 | if (!card->drv_data) |
1047 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1048 | | |
1049 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1050 | |
|
1051 | 0 | if (data_tlv_len + le_tlv_len + block_size + 1 > sizeof(mac)) { |
1052 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
1053 | 0 | } |
1054 | | |
1055 | 0 | if (0 == data_tlv_len && 0 == le_tlv_len) { |
1056 | 0 | mac_len = block_size; |
1057 | 0 | } else { |
1058 | | /* padding */ |
1059 | 0 | *(apdu_buf + block_size + data_tlv_len + le_tlv_len) = 0x80; |
1060 | 0 | if ((data_tlv_len + le_tlv_len + 1) % block_size) { |
1061 | 0 | mac_len = (((data_tlv_len + le_tlv_len + 1) / block_size) + |
1062 | 0 | 1) * block_size + block_size; |
1063 | 0 | } else { |
1064 | 0 | mac_len = data_tlv_len + le_tlv_len + 1 + block_size; |
1065 | 0 | } |
1066 | 0 | memset((apdu_buf + block_size + data_tlv_len + le_tlv_len + 1), |
1067 | 0 | 0, (mac_len - (data_tlv_len + le_tlv_len + 1))); |
1068 | 0 | } |
1069 | | |
1070 | | /* increase icv */ |
1071 | 0 | for (; i >= 0; i--) { |
1072 | 0 | if (exdata->icv_mac[i] == 0xff) { |
1073 | 0 | exdata->icv_mac[i] = 0; |
1074 | 0 | } else { |
1075 | 0 | exdata->icv_mac[i]++; |
1076 | 0 | break; |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | | /* calculate MAC */ |
1081 | 0 | memset(icv, 0, sizeof(icv)); |
1082 | 0 | memcpy(icv, exdata->icv_mac, 16); |
1083 | 0 | if (KEY_TYPE_AES == key_type) { |
1084 | 0 | if (exdata->bFipsCertification) { |
1085 | 0 | for (int i = 0; i < 16; i++) { |
1086 | 0 | apdu_buf[i] = apdu_buf[i] ^ icv[i]; |
1087 | 0 | } |
1088 | 0 | r = aes128_encrypt_cmac(card, exdata->sk_mac, 128, apdu_buf, data_tlv_len + le_tlv_len + block_size, mac); |
1089 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac failed"); |
1090 | 0 | memcpy(mac_tlv + 2, &mac[0 /*ulmacLen-16*/], 8); |
1091 | 0 | for (int j = 0; j < 4; j++) { |
1092 | 0 | apdu_buf[j] = apdu_buf[j] ^ icv[j]; |
1093 | 0 | } |
1094 | 0 | } else { |
1095 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac); |
1096 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed"); |
1097 | 0 | memcpy(mac_tlv + 2, &mac[mac_len - 16], 8); |
1098 | 0 | } |
1099 | 0 | } else { |
1100 | 0 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
1101 | 0 | unsigned char tmp[8] = {0}; |
1102 | 0 | r = des_encrypt_cbc(card, exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac); |
1103 | 0 | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc 1 failed"); |
1104 | 0 | r = des_decrypt_cbc(card, &exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp); |
1105 | 0 | LOG_TEST_RET(card->ctx, r, "des_decrypt_cbc failed"); |
1106 | 0 | memset(iv, 0x00, sizeof iv); |
1107 | 0 | r = des_encrypt_cbc(card, exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2); |
1108 | 0 | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc 2 failed"); |
1109 | 0 | } |
1110 | | |
1111 | 0 | *mac_tlv_len = 2 + 8; |
1112 | 0 | return 0; |
1113 | 0 | } |
1114 | | |
1115 | | /* MAC(TLV case 1) */ |
1116 | | static int |
1117 | | construct_mac_tlv_case1(struct sc_card *card, unsigned char *apdu_buf, size_t data_tlv_len, size_t le_tlv_len, |
1118 | | unsigned char *mac_tlv, size_t * mac_tlv_len, const unsigned char key_type) |
1119 | 0 | { |
1120 | 0 | int r; |
1121 | 0 | size_t block_size = 4; |
1122 | 0 | unsigned char mac[4096] = {0}; |
1123 | 0 | size_t mac_len; |
1124 | 0 | int i = (KEY_TYPE_AES == key_type ? 15 : 7); |
1125 | 0 | unsigned char icv[16] = {0}; |
1126 | |
|
1127 | 0 | epass2003_exdata *exdata = NULL; |
1128 | |
|
1129 | 0 | if (!card->drv_data) |
1130 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1131 | | |
1132 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1133 | |
|
1134 | 0 | if (data_tlv_len + le_tlv_len + block_size + 1 > sizeof(mac)) { |
1135 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
1136 | 0 | } |
1137 | | |
1138 | 0 | if (0 == data_tlv_len && 0 == le_tlv_len) { |
1139 | 0 | mac_len = block_size; |
1140 | 0 | } else { |
1141 | | /* padding */ |
1142 | 0 | *(apdu_buf + block_size + data_tlv_len + le_tlv_len) = 0x80; |
1143 | 0 | if ((data_tlv_len + le_tlv_len + 1) % block_size) { |
1144 | 0 | mac_len = (((data_tlv_len + le_tlv_len + 1) / block_size) + 1) * block_size + block_size; |
1145 | 0 | } else { |
1146 | 0 | mac_len = data_tlv_len + le_tlv_len + 1 + block_size; |
1147 | 0 | } |
1148 | 0 | } |
1149 | | /* increase icv */ |
1150 | 0 | for (; i >= 0; i--) { |
1151 | 0 | if (exdata->icv_mac[i] == 0xff) { |
1152 | 0 | exdata->icv_mac[i] = 0; |
1153 | 0 | } else { |
1154 | 0 | exdata->icv_mac[i]++; |
1155 | 0 | break; |
1156 | 0 | } |
1157 | 0 | } |
1158 | | |
1159 | | /* calculate MAC */ |
1160 | 0 | memset(icv, 0, sizeof(icv)); |
1161 | 0 | memcpy(icv, exdata->icv_mac, 16); |
1162 | 0 | if (KEY_TYPE_AES == key_type) { |
1163 | 0 | if (exdata->bFipsCertification) { |
1164 | 0 | r = aes128_encrypt_cmac_ft(card, exdata->sk_mac, 128, apdu_buf, data_tlv_len + le_tlv_len + block_size, mac, &icv[0]); |
1165 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac_ft failed"); |
1166 | 0 | memcpy(mac_tlv + 2, &mac[0 /*ulmacLen-16*/], 8); |
1167 | 0 | } else { |
1168 | 0 | if (mac_len < 16) |
1169 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "incorrect mac length"); |
1170 | 0 | r = aes128_encrypt_cbc(card, exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac); |
1171 | 0 | LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed"); |
1172 | 0 | memcpy(mac_tlv + 2, &mac[mac_len - 16], 8); |
1173 | 0 | } |
1174 | 0 | } else { |
1175 | 0 | unsigned char iv[EVP_MAX_IV_LENGTH] = {0}; |
1176 | 0 | unsigned char tmp[8] = {0}; |
1177 | 0 | if (mac_len < 8) |
1178 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "incorrect mac length"); |
1179 | 0 | r = des_encrypt_cbc(card, exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac); |
1180 | 0 | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc failed"); |
1181 | 0 | r = des_decrypt_cbc(card, &exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp); |
1182 | 0 | LOG_TEST_RET(card->ctx, r, "des_decrypt_cbc failed"); |
1183 | 0 | memset(iv, 0x00, sizeof iv); |
1184 | 0 | r = des_encrypt_cbc(card, exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2); |
1185 | 0 | LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc failed"); |
1186 | 0 | } |
1187 | | |
1188 | 0 | *mac_tlv_len = 2 + 8; |
1189 | 0 | return 0; |
1190 | 0 | } |
1191 | | |
1192 | | /* According to GlobalPlatform Card Specification's SCP01 |
1193 | | * encode APDU from |
1194 | | * CLA INS P1 P2 [Lc] Data [Le] |
1195 | | * to |
1196 | | * CLA INS P1 P2 Lc' Data' [Le] |
1197 | | * where |
1198 | | * Data'=Data(TLV)+Le(TLV)+MAC(TLV) */ |
1199 | | static int |
1200 | | encode_apdu(struct sc_card *card, struct sc_apdu *plain, struct sc_apdu *sm, |
1201 | | unsigned char *apdu_buf, size_t * apdu_buf_len) |
1202 | 0 | { |
1203 | 0 | size_t block_size = 0; |
1204 | 0 | unsigned char dataTLV[4096] = {0}; |
1205 | 0 | size_t data_tlv_len = 0; |
1206 | 0 | unsigned char le_tlv[256] = {0}; |
1207 | 0 | size_t le_tlv_len = 0; |
1208 | 0 | size_t mac_tlv_len = 10; |
1209 | 0 | size_t tmp_lc = 0; |
1210 | 0 | size_t tmp_le = 0; |
1211 | 0 | size_t expected_total_len; |
1212 | 0 | unsigned char mac_tlv[256] = {0}; |
1213 | 0 | epass2003_exdata *exdata = NULL; |
1214 | |
|
1215 | 0 | mac_tlv[0] = 0x8E; |
1216 | 0 | mac_tlv[1] = 8; |
1217 | | /* size_t plain_le = 0; */ |
1218 | 0 | if (!card->drv_data) |
1219 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1220 | 0 | exdata = (epass2003_exdata*)card->drv_data; |
1221 | 0 | block_size = (KEY_TYPE_DES == exdata->smtype ? 16 : 8); |
1222 | |
|
1223 | 0 | sm->cse = SC_APDU_CASE_4_SHORT; |
1224 | 0 | apdu_buf[0] = (unsigned char)plain->cla; |
1225 | 0 | apdu_buf[1] = (unsigned char)plain->ins; |
1226 | 0 | apdu_buf[2] = (unsigned char)plain->p1; |
1227 | 0 | apdu_buf[3] = (unsigned char)plain->p2; |
1228 | | /* plain_le = plain->le; */ |
1229 | | /* padding */ |
1230 | 0 | if (exdata->bFipsCertification && plain->lc == 0 && apdu_buf[1] == 0x82 && apdu_buf[2] == 0x01) { |
1231 | 0 | apdu_buf[4] = 0x00; |
1232 | 0 | } else { |
1233 | 0 | apdu_buf[4] = 0x80; |
1234 | 0 | } |
1235 | 0 | memset(&apdu_buf[5], 0x00, block_size - 5); |
1236 | | |
1237 | | /* Data -> Data' */ |
1238 | 0 | if (plain->lc != 0) |
1239 | 0 | if (0 != construct_data_tlv(card, plain, apdu_buf, dataTLV, &data_tlv_len, exdata->smtype)) |
1240 | 0 | return -1; |
1241 | | |
1242 | 0 | if (plain->le != 0 || (plain->le == 0 && plain->resplen != 0)) |
1243 | 0 | if (0 != construct_le_tlv(plain, apdu_buf, data_tlv_len, le_tlv, |
1244 | 0 | &le_tlv_len, exdata->smtype)) |
1245 | 0 | return -1; |
1246 | | |
1247 | 0 | if (exdata->bFipsCertification && plain->lc == 0 && apdu_buf[1] == 0x82 && apdu_buf[2] == 0x01) { |
1248 | 0 | if (0 != construct_mac_tlv_case1(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype)) |
1249 | 0 | return -1; |
1250 | 0 | } else { |
1251 | 0 | if (0 != construct_mac_tlv(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype)) |
1252 | 0 | return -1; |
1253 | 0 | } |
1254 | | |
1255 | 0 | memset(apdu_buf + 4, 0, *apdu_buf_len - 4); |
1256 | 0 | sm->lc = sm->datalen = data_tlv_len + le_tlv_len + mac_tlv_len; |
1257 | 0 | if (sm->lc > 0xFF) { |
1258 | 0 | sm->cse = SC_APDU_CASE_4_EXT; |
1259 | 0 | apdu_buf[4] = (unsigned char)((sm->lc) / 0x10000); |
1260 | 0 | apdu_buf[5] = (unsigned char)(((sm->lc) / 0x100) % 0x100); |
1261 | 0 | apdu_buf[6] = (unsigned char)((sm->lc) % 0x100); |
1262 | 0 | tmp_lc = 3; |
1263 | 0 | } else { |
1264 | 0 | apdu_buf[4] = (unsigned char)sm->lc; |
1265 | 0 | tmp_lc = 1; |
1266 | 0 | } |
1267 | | |
1268 | | /* 2 is for Le extension in the worst case */ |
1269 | 0 | expected_total_len = 4 + tmp_lc + data_tlv_len + le_tlv_len + mac_tlv_len + 2; |
1270 | |
|
1271 | 0 | if (expected_total_len > *apdu_buf_len) { |
1272 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
1273 | 0 | } |
1274 | | |
1275 | 0 | memcpy(apdu_buf + 4 + tmp_lc, dataTLV, data_tlv_len); |
1276 | 0 | memcpy(apdu_buf + 4 + tmp_lc + data_tlv_len, le_tlv, le_tlv_len); |
1277 | 0 | memcpy(apdu_buf + 4 + tmp_lc + data_tlv_len + le_tlv_len, mac_tlv, mac_tlv_len); |
1278 | 0 | memcpy((unsigned char *)sm->data, apdu_buf + 4 + tmp_lc, sm->datalen); |
1279 | 0 | *apdu_buf_len = 0; |
1280 | |
|
1281 | 0 | if (4 == le_tlv_len) { |
1282 | 0 | sm->cse = SC_APDU_CASE_4_EXT; |
1283 | 0 | *(apdu_buf + 4 + tmp_lc + sm->lc) = (unsigned char)(plain->le / 0x100); |
1284 | 0 | *(apdu_buf + 4 + tmp_lc + sm->lc + 1) = (unsigned char)(plain->le % 0x100); |
1285 | 0 | tmp_le = 2; |
1286 | 0 | } else if (3 == le_tlv_len) { |
1287 | 0 | *(apdu_buf + 4 + tmp_lc + sm->lc) = (unsigned char)plain->le; |
1288 | 0 | tmp_le = 1; |
1289 | 0 | } |
1290 | |
|
1291 | 0 | *apdu_buf_len += 4 + tmp_lc + data_tlv_len + le_tlv_len + mac_tlv_len + tmp_le; |
1292 | | /* sm->le = calc_le(plain_le); */ |
1293 | 0 | return 0; |
1294 | 0 | } |
1295 | | |
1296 | | |
1297 | | static int |
1298 | | epass2003_sm_wrap_apdu(struct sc_card *card, struct sc_apdu *plain, struct sc_apdu *sm) |
1299 | 0 | { |
1300 | 0 | unsigned char buf[4096] = {0}; /* APDU buffer */ |
1301 | 0 | size_t buf_len = sizeof(buf); |
1302 | 0 | epass2003_exdata *exdata = NULL; |
1303 | |
|
1304 | 0 | if (!card->drv_data) |
1305 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1306 | | |
1307 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1308 | |
|
1309 | 0 | LOG_FUNC_CALLED(card->ctx); |
1310 | |
|
1311 | 0 | if (exdata->sm) |
1312 | 0 | plain->cla |= 0x0C; |
1313 | |
|
1314 | 0 | sm->cse = plain->cse; |
1315 | 0 | sm->cla = plain->cla; |
1316 | 0 | sm->ins = plain->ins; |
1317 | 0 | sm->p1 = plain->p1; |
1318 | 0 | sm->p2 = plain->p2; |
1319 | 0 | sm->lc = plain->lc; |
1320 | 0 | sm->le = plain->le; |
1321 | 0 | sm->control = plain->control; |
1322 | 0 | sm->flags = plain->flags; |
1323 | |
|
1324 | 0 | switch (sm->cla & 0x0C) { |
1325 | 0 | case 0x00: |
1326 | 0 | case 0x04: |
1327 | 0 | sm->datalen = plain->datalen; |
1328 | 0 | memcpy((void *)sm->data, plain->data, plain->datalen); |
1329 | 0 | sm->resplen = plain->resplen; |
1330 | 0 | memcpy(sm->resp, plain->resp, plain->resplen); |
1331 | 0 | break; |
1332 | 0 | case 0x0C: |
1333 | 0 | memset(buf, 0, sizeof(buf)); |
1334 | 0 | if (0 != encode_apdu(card, plain, sm, buf, &buf_len)) |
1335 | 0 | return SC_ERROR_CARD_CMD_FAILED; |
1336 | 0 | break; |
1337 | 0 | default: |
1338 | 0 | return SC_ERROR_INCORRECT_PARAMETERS; |
1339 | 0 | } |
1340 | | |
1341 | 0 | return SC_SUCCESS; |
1342 | 0 | } |
1343 | | |
1344 | | static int |
1345 | | epass2003_check_response_mac_and_sw(struct sc_card *card, struct sc_apdu *sm) |
1346 | 0 | { |
1347 | 0 | unsigned char iv[16]; |
1348 | 0 | unsigned char *data = NULL, *mac = NULL; |
1349 | 0 | size_t blocksize, mac_len; |
1350 | 0 | int ret = -1; |
1351 | 0 | size_t taglen; |
1352 | 0 | const u8 *tag; |
1353 | 0 | epass2003_exdata *exdata; |
1354 | 0 | unsigned char *in = sm->resp; |
1355 | 0 | unsigned char *alt_in; |
1356 | 0 | size_t inlen = sm->resplen; |
1357 | 0 | size_t len_correction; |
1358 | | |
1359 | | /* card/ctx/drv_data is already checked by caller */ |
1360 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1361 | | |
1362 | | /* The SM must contain at least TLV encoded SW and MAC fields. */ |
1363 | 0 | if (inlen < 14 ) |
1364 | 0 | return ret; |
1365 | | |
1366 | | /* compare BER-TLV encoded SW (TAG 0x99) and raw SW */ |
1367 | 0 | alt_in = in; |
1368 | 0 | tag = sc_asn1_find_tag(card->ctx, alt_in, inlen, 0x99, &taglen); |
1369 | 0 | if (tag == NULL || taglen != 2) { |
1370 | | /* |
1371 | | * It seems that the EPASS2003 firmware has some problem with BER-TLV encoding. |
1372 | | * Instead of (correct) TLV 87 81 81 [01 .. ..] incorrect TLV 87 81 [01 .. ..] |
1373 | | * is returned. There seems to be some proprietary fix for the faulty encoding |
1374 | | * in the decrypt_response() function, similar fix here: |
1375 | | */ |
1376 | 0 | if (0x01 == in[2] && 0x82 != in[1]) { |
1377 | 0 | sc_log(card->ctx, "Workaround, wrong BER-TLV ?"); |
1378 | 0 | len_correction = in[1] + 2; |
1379 | 0 | if (inlen < len_correction) |
1380 | 0 | return ret; |
1381 | 0 | inlen -= len_correction; |
1382 | 0 | alt_in += len_correction; |
1383 | 0 | tag = sc_asn1_find_tag(card->ctx, alt_in, inlen, 0x99, &taglen); |
1384 | 0 | if (tag == NULL || taglen != 2) |
1385 | 0 | return ret; |
1386 | 0 | } else { |
1387 | 0 | return ret; |
1388 | 0 | } |
1389 | 0 | } |
1390 | 0 | if (sm->sw1 != tag[0] || sm->sw2 != tag[1]) |
1391 | 0 | return ret; |
1392 | | |
1393 | | /* no documentation/real hardware to test, the response is accepted without MAC check */ |
1394 | 0 | if (exdata->bFipsCertification) { |
1395 | 0 | sc_log(card->ctx, "Warning, MAC is not checked"); |
1396 | 0 | return 0; |
1397 | 0 | } |
1398 | 0 | tag = sc_asn1_find_tag(card->ctx, alt_in, inlen, 0x8e, &taglen); |
1399 | 0 | if (tag == NULL || taglen != 8) |
1400 | 0 | return ret; |
1401 | | |
1402 | 0 | if (KEY_TYPE_AES == exdata->smtype) |
1403 | 0 | blocksize = 16; |
1404 | 0 | else |
1405 | 0 | blocksize = 8; |
1406 | |
|
1407 | 0 | mac_len = tag - in - 2; |
1408 | 0 | if (NULL == (data = calloc(1, mac_len + blocksize))) |
1409 | 0 | goto end; |
1410 | 0 | if (NULL == (mac = malloc(mac_len + blocksize))) |
1411 | 0 | goto end; |
1412 | | |
1413 | | /* copy response to buffer and append padding */ |
1414 | 0 | memcpy(data, in, mac_len); |
1415 | 0 | data[mac_len++] = 0x80; |
1416 | |
|
1417 | 0 | if (mac_len % blocksize) |
1418 | 0 | mac_len += (blocksize - (mac_len % blocksize)); |
1419 | | |
1420 | | /* calculate MAC */ |
1421 | 0 | memcpy(iv, exdata->icv_mac, blocksize); |
1422 | |
|
1423 | 0 | if (KEY_TYPE_AES == exdata->smtype) { |
1424 | 0 | if (aes128_encrypt_cbc(card, exdata->sk_mac, 16, iv, data, mac_len, mac)) |
1425 | 0 | goto end; |
1426 | 0 | } else { |
1427 | 0 | uint8_t tmp[8]; |
1428 | 0 | uint8_t iv0[EVP_MAX_IV_LENGTH]; |
1429 | 0 | if (des_encrypt_cbc(card, exdata->sk_mac, 8, iv, data, mac_len, mac)) |
1430 | 0 | goto end; |
1431 | 0 | memset(iv0, 0, EVP_MAX_IV_LENGTH); |
1432 | 0 | if (des_decrypt_cbc(card, &exdata->sk_mac[8], 8, iv0, &mac[mac_len - 8], 8, tmp)) |
1433 | 0 | goto end; |
1434 | 0 | memset(iv0, 0, EVP_MAX_IV_LENGTH); |
1435 | 0 | if (des_encrypt_cbc(card, exdata->sk_mac, 8, iv0, tmp, 8, &mac[mac_len - 8])) |
1436 | 0 | goto end; |
1437 | 0 | } |
1438 | | /* compare MAC */ |
1439 | 0 | if (!memcmp(tag, mac + mac_len - blocksize, 8)) |
1440 | 0 | ret = 0; |
1441 | 0 | end: |
1442 | 0 | if (data) |
1443 | 0 | free(data); |
1444 | 0 | if (mac) |
1445 | 0 | free(mac); |
1446 | 0 | return ret; |
1447 | 0 | } |
1448 | | |
1449 | | /* According to GlobalPlatform Card Specification's SCP01 |
1450 | | * decrypt APDU response from |
1451 | | * ResponseData' SW1 SW2 |
1452 | | * to |
1453 | | * ResponseData SW1 SW2 |
1454 | | * where |
1455 | | * ResponseData'=Data(TLV)+SW12(TLV)+MAC(TLV) |
1456 | | * where |
1457 | | * Data(TLV)=0x87|L|Cipher |
1458 | | * SW12(TLV)=0x99|0x02|SW1+SW2 |
1459 | | * MAC(TLV)=0x8e|0x08|MAC */ |
1460 | | static int |
1461 | | decrypt_response(struct sc_card *card, unsigned char *in, size_t inlen, unsigned char *out, size_t * out_len) |
1462 | 0 | { |
1463 | 0 | unsigned int cla = 0, tag = 0; |
1464 | 0 | const unsigned char *p = in; |
1465 | 0 | size_t cipher_len; |
1466 | 0 | unsigned char iv[16] = {0}; |
1467 | 0 | unsigned char plaintext[4096] = {0}; |
1468 | 0 | epass2003_exdata *exdata = NULL; |
1469 | |
|
1470 | 0 | if (!card->drv_data) |
1471 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1472 | | |
1473 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1474 | |
|
1475 | 0 | if (SC_SUCCESS != sc_asn1_read_tag(&p, inlen, &cla, &tag, &cipher_len) || p == NULL) { |
1476 | 0 | return -1; |
1477 | 0 | } |
1478 | 0 | if ((cla | tag) == 0x99) |
1479 | 0 | return 0; |
1480 | 0 | if ((cla | tag) != 0x87) |
1481 | 0 | return -1; |
1482 | | |
1483 | 0 | if (cipher_len < 2 || cipher_len > sizeof plaintext) |
1484 | 0 | return -1; |
1485 | | |
1486 | | /* Skip the 0x01 separator between tag and ciphertext */ |
1487 | 0 | p++; |
1488 | | /* decrypt */ |
1489 | 0 | if (KEY_TYPE_AES == exdata->smtype) |
1490 | 0 | aes128_decrypt_cbc(card, exdata->sk_enc, 16, iv, p, cipher_len - 1, plaintext); |
1491 | 0 | else |
1492 | 0 | des3_decrypt_cbc(card, exdata->sk_enc, 16, iv, p, cipher_len - 1, plaintext); |
1493 | | |
1494 | | /* unpadding */ |
1495 | 0 | while (0x80 != plaintext[cipher_len - 2] && (cipher_len > 2)) |
1496 | 0 | cipher_len--; |
1497 | |
|
1498 | 0 | if (2 == cipher_len || *out_len < cipher_len - 2) |
1499 | 0 | return -1; |
1500 | | |
1501 | 0 | memcpy(out, plaintext, cipher_len - 2); |
1502 | 0 | *out_len = cipher_len - 2; |
1503 | 0 | return 0; |
1504 | 0 | } |
1505 | | |
1506 | | |
1507 | | static int |
1508 | | epass2003_sm_unwrap_apdu(struct sc_card *card, struct sc_apdu *sm, struct sc_apdu *plain) |
1509 | 0 | { |
1510 | 0 | int r; |
1511 | 0 | size_t len = 0; |
1512 | 0 | epass2003_exdata *exdata = NULL; |
1513 | |
|
1514 | 0 | if (!card->drv_data) |
1515 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1516 | | |
1517 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1518 | |
|
1519 | 0 | LOG_FUNC_CALLED(card->ctx); |
1520 | | |
1521 | | /* verify MAC, and check if SW1,2 match SW1,2 encapsulated in SM */ |
1522 | 0 | if (exdata->sm) { |
1523 | 0 | if (epass2003_check_response_mac_and_sw(card, sm)) { |
1524 | 0 | sc_log(card->ctx, "MAC or SW incorrect"); |
1525 | 0 | return SC_ERROR_CARD_CMD_FAILED; |
1526 | 0 | } |
1527 | 0 | } |
1528 | 0 | r = sc_check_sw(card, sm->sw1, sm->sw2); |
1529 | 0 | if (r == SC_SUCCESS) { |
1530 | 0 | if (exdata->sm) { |
1531 | 0 | len = plain->resplen; |
1532 | 0 | if (0 != decrypt_response(card, sm->resp, sm->resplen, plain->resp, &len)) |
1533 | 0 | return SC_ERROR_CARD_CMD_FAILED; |
1534 | 0 | } else { |
1535 | 0 | memcpy(plain->resp, sm->resp, sm->resplen); |
1536 | 0 | len = sm->resplen; |
1537 | 0 | } |
1538 | 0 | } |
1539 | | |
1540 | 0 | plain->resplen = len; |
1541 | 0 | plain->sw1 = sm->sw1; |
1542 | 0 | plain->sw2 = sm->sw2; |
1543 | |
|
1544 | 0 | sc_log(card->ctx, |
1545 | 0 | "unwrapped APDU: resplen %"SC_FORMAT_LEN_SIZE_T"u, SW %02X%02X", |
1546 | 0 | plain->resplen, plain->sw1, plain->sw2); |
1547 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1548 | 0 | } |
1549 | | |
1550 | | |
1551 | | static int |
1552 | | epass2003_sm_free_wrapped_apdu(struct sc_card *card, |
1553 | | struct sc_apdu *plain, struct sc_apdu **sm_apdu) |
1554 | 0 | { |
1555 | 0 | struct sc_context *ctx = card->ctx; |
1556 | 0 | int rv = SC_SUCCESS; |
1557 | |
|
1558 | 0 | LOG_FUNC_CALLED(ctx); |
1559 | 0 | if (!sm_apdu) |
1560 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1561 | 0 | if (!(*sm_apdu)) |
1562 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1563 | | |
1564 | | |
1565 | 0 | if (plain) |
1566 | 0 | rv = epass2003_sm_unwrap_apdu(card, *sm_apdu, plain); |
1567 | |
|
1568 | 0 | if ((*sm_apdu)->data) { |
1569 | 0 | unsigned char * p = (unsigned char *)((*sm_apdu)->data); |
1570 | 0 | free(p); |
1571 | 0 | } |
1572 | 0 | if ((*sm_apdu)->resp) { |
1573 | 0 | free((*sm_apdu)->resp); |
1574 | 0 | } |
1575 | |
|
1576 | 0 | free(*sm_apdu); |
1577 | 0 | *sm_apdu = NULL; |
1578 | |
|
1579 | 0 | LOG_FUNC_RETURN(ctx, rv); |
1580 | 0 | } |
1581 | | |
1582 | | |
1583 | | static int |
1584 | | epass2003_sm_get_wrapped_apdu(struct sc_card *card, |
1585 | | struct sc_apdu *plain, struct sc_apdu **sm_apdu) |
1586 | 0 | { |
1587 | 0 | struct sc_context *ctx = card->ctx; |
1588 | 0 | struct sc_apdu *apdu = NULL; |
1589 | 0 | int rv; |
1590 | |
|
1591 | 0 | LOG_FUNC_CALLED(ctx); |
1592 | 0 | if (!plain || !sm_apdu) |
1593 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1594 | | |
1595 | 0 | *sm_apdu = NULL; |
1596 | | //construct new SM apdu from original apdu |
1597 | 0 | apdu = calloc(1, sizeof(struct sc_apdu)); |
1598 | 0 | if (!apdu) { |
1599 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1600 | 0 | goto err; |
1601 | 0 | } |
1602 | 0 | apdu->data = calloc (1, SC_MAX_EXT_APDU_BUFFER_SIZE); |
1603 | 0 | if (!apdu->data) { |
1604 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1605 | 0 | goto err; |
1606 | 0 | } |
1607 | 0 | apdu->resp = calloc (1, SC_MAX_EXT_APDU_BUFFER_SIZE); |
1608 | 0 | if (!apdu->resp) { |
1609 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
1610 | 0 | goto err; |
1611 | 0 | } |
1612 | 0 | apdu->datalen = SC_MAX_EXT_APDU_BUFFER_SIZE; |
1613 | 0 | apdu->resplen = SC_MAX_EXT_APDU_BUFFER_SIZE; |
1614 | |
|
1615 | 0 | rv = epass2003_sm_wrap_apdu(card, plain, apdu); |
1616 | 0 | if (rv) { |
1617 | 0 | rv = epass2003_sm_free_wrapped_apdu(card, NULL, &apdu); |
1618 | 0 | if (rv < 0) |
1619 | 0 | goto err; |
1620 | 0 | } |
1621 | | |
1622 | 0 | *sm_apdu = apdu; |
1623 | 0 | apdu = NULL; |
1624 | 0 | err: |
1625 | 0 | if (apdu) { |
1626 | 0 | free((unsigned char *) apdu->data); |
1627 | 0 | free(apdu->resp); |
1628 | 0 | free(apdu); |
1629 | 0 | apdu = NULL; |
1630 | 0 | } |
1631 | 0 | LOG_FUNC_RETURN(ctx, rv); |
1632 | 0 | } |
1633 | | |
1634 | | |
1635 | | static int |
1636 | | epass2003_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu) |
1637 | 0 | { |
1638 | 0 | int r; |
1639 | |
|
1640 | 0 | LOG_FUNC_CALLED(card->ctx); |
1641 | |
|
1642 | 0 | r = sc_transmit_apdu_t(card, apdu); |
1643 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1644 | | |
1645 | 0 | return r; |
1646 | 0 | } |
1647 | | |
1648 | | |
1649 | | static int |
1650 | | get_data(struct sc_card *card, unsigned char type, unsigned char *data, size_t datalen) |
1651 | 0 | { |
1652 | 0 | int r; |
1653 | 0 | struct sc_apdu apdu; |
1654 | 0 | unsigned char resp[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1655 | 0 | size_t resplen = SC_MAX_APDU_BUFFER_SIZE; |
1656 | 0 | epass2003_exdata *exdata = NULL; |
1657 | |
|
1658 | 0 | if (!card->drv_data) |
1659 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1660 | | |
1661 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
1662 | |
|
1663 | 0 | LOG_FUNC_CALLED(card->ctx); |
1664 | |
|
1665 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, type); |
1666 | 0 | apdu.resp = resp; |
1667 | 0 | apdu.le = 0; |
1668 | 0 | apdu.resplen = resplen; |
1669 | 0 | if (0x86 == type) { |
1670 | | /* No SM temporarily */ |
1671 | 0 | unsigned char tmp_sm = exdata->sm; |
1672 | 0 | exdata->sm = SM_PLAIN; |
1673 | 0 | r = sc_transmit_apdu(card, &apdu); |
1674 | 0 | exdata->sm = tmp_sm; |
1675 | 0 | } else { |
1676 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
1677 | 0 | } |
1678 | 0 | LOG_TEST_RET(card->ctx, r, "APDU get_data failed"); |
1679 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1680 | 0 | LOG_TEST_RET(card->ctx, r, "get_data failed"); |
1681 | | |
1682 | 0 | memcpy(data, resp, datalen); |
1683 | 0 | return r; |
1684 | 0 | } |
1685 | | |
1686 | | /* card driver functions */ |
1687 | | |
1688 | | static int epass2003_match_card(struct sc_card *card) |
1689 | 9 | { |
1690 | 9 | int r; |
1691 | | |
1692 | 9 | LOG_FUNC_CALLED(card->ctx); |
1693 | 9 | r = _sc_match_atr(card, epass2003_atrs, &card->type); |
1694 | 9 | if (r < 0) |
1695 | 9 | return 0; |
1696 | | |
1697 | 0 | return 1; |
1698 | 9 | } |
1699 | | |
1700 | | |
1701 | | static int |
1702 | | epass2003_init(struct sc_card *card) |
1703 | 0 | { |
1704 | 0 | unsigned int flags; |
1705 | 0 | unsigned int ext_flags; |
1706 | 0 | unsigned char data[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1707 | 0 | size_t datalen = SC_MAX_APDU_BUFFER_SIZE; |
1708 | 0 | epass2003_exdata *exdata = NULL; |
1709 | 0 | void *old_drv_data = card->drv_data; |
1710 | |
|
1711 | 0 | LOG_FUNC_CALLED(card->ctx); |
1712 | |
|
1713 | 0 | card->name = "epass2003"; |
1714 | 0 | card->cla = 0x00; |
1715 | 0 | exdata = (epass2003_exdata *)calloc(1, sizeof(epass2003_exdata)); |
1716 | 0 | if (!exdata) |
1717 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
1718 | | |
1719 | 0 | card->drv_data = exdata; |
1720 | |
|
1721 | 0 | exdata->sm = SM_SCP01; |
1722 | | |
1723 | | /* decide FIPS/Non-FIPS mode */ |
1724 | 0 | if (SC_SUCCESS != get_data(card, 0x86, data, datalen)) { |
1725 | 0 | free(exdata); |
1726 | 0 | card->drv_data = old_drv_data; |
1727 | 0 | return SC_ERROR_INVALID_CARD; |
1728 | 0 | } |
1729 | | |
1730 | 0 | if (memcmp(&data[32], "\x87\x01\x01", 3) == 0 && memcmp(&data[0], "\x80\x01\x01", 3) == 0) { |
1731 | 0 | exdata->bFipsCertification = 0x01; |
1732 | 0 | } else { |
1733 | 0 | exdata->bFipsCertification = 0x00; |
1734 | 0 | } |
1735 | |
|
1736 | 0 | if (0x01 == data[2]) |
1737 | 0 | exdata->smtype = KEY_TYPE_AES; |
1738 | 0 | else |
1739 | 0 | exdata->smtype = KEY_TYPE_DES; |
1740 | |
|
1741 | 0 | if (0x84 == data[14]) { |
1742 | 0 | if (0x00 == data[16]) { |
1743 | 0 | exdata->sm = SM_PLAIN; |
1744 | 0 | } |
1745 | 0 | } |
1746 | | |
1747 | | /* mutual authentication */ |
1748 | 0 | card->max_recv_size = 0xD8; |
1749 | 0 | card->max_send_size = 0xE8; |
1750 | |
|
1751 | 0 | card->sm_ctx.ops.open = epass2003_refresh; |
1752 | 0 | card->sm_ctx.ops.get_sm_apdu = epass2003_sm_get_wrapped_apdu; |
1753 | 0 | card->sm_ctx.ops.free_sm_apdu = epass2003_sm_free_wrapped_apdu; |
1754 | | |
1755 | | /* FIXME (VT): rather then set/unset 'g_sm', better to implement filter for APDUs to be wrapped */ |
1756 | 0 | epass2003_refresh(card); |
1757 | |
|
1758 | 0 | card->sm_ctx.sm_mode = SM_MODE_TRANSMIT; |
1759 | |
|
1760 | 0 | flags = SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE; |
1761 | |
|
1762 | 0 | _sc_card_add_rsa_alg(card, 512, flags, 0); |
1763 | 0 | _sc_card_add_rsa_alg(card, 768, flags, 0); |
1764 | 0 | _sc_card_add_rsa_alg(card, 1024, flags, 0); |
1765 | 0 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
1766 | | |
1767 | | //set EC Alg Flags |
1768 | 0 | 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; |
1769 | 0 | ext_flags = 0; |
1770 | 0 | _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); |
1771 | |
|
1772 | 0 | card->caps = SC_CARD_CAP_RNG | SC_CARD_CAP_APDU_EXT; |
1773 | |
|
1774 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1775 | 0 | } |
1776 | | |
1777 | | static int |
1778 | | epass2003_finish(sc_card_t *card) |
1779 | 0 | { |
1780 | 0 | epass2003_exdata *exdata = (epass2003_exdata *)card->drv_data; |
1781 | |
|
1782 | 0 | if (exdata) |
1783 | 0 | free(exdata); |
1784 | 0 | return SC_SUCCESS; |
1785 | 0 | } |
1786 | | |
1787 | | /* COS implement SFI as lower 5 bits of FID, and not allow same SFI at the |
1788 | | * same DF, so use hook functions to increase/decrease FID by 0x20 */ |
1789 | | static int |
1790 | | epass2003_hook_path(struct sc_path *path, int inc) |
1791 | 0 | { |
1792 | 0 | u8 fid_h = 0; |
1793 | 0 | u8 fid_l = 0; |
1794 | |
|
1795 | 0 | if (!path || path->len < 2) |
1796 | 0 | return -1; |
1797 | 0 | fid_h = path->value[path->len - 2]; |
1798 | 0 | fid_l = path->value[path->len - 1]; |
1799 | |
|
1800 | 0 | switch (fid_h) { |
1801 | 0 | case 0x29: |
1802 | 0 | case 0x30: |
1803 | 0 | case 0x31: |
1804 | 0 | case 0x32: |
1805 | 0 | case 0x33: |
1806 | 0 | case 0x34: |
1807 | 0 | if (inc) |
1808 | 0 | fid_l = fid_l * FID_STEP; |
1809 | 0 | else |
1810 | 0 | fid_l = fid_l / FID_STEP; |
1811 | 0 | path->value[path->len - 1] = fid_l; |
1812 | 0 | return 1; |
1813 | 0 | default: |
1814 | 0 | break; |
1815 | 0 | } |
1816 | 0 | return 0; |
1817 | 0 | } |
1818 | | |
1819 | | |
1820 | | static int |
1821 | | epass2003_hook_file(struct sc_file *file, int inc) |
1822 | 0 | { |
1823 | 0 | int fidl = file->id & 0xff; |
1824 | 0 | int fidh = file->id & 0xff00; |
1825 | 0 | int rv = 0; |
1826 | |
|
1827 | 0 | rv = epass2003_hook_path(&file->path, inc); |
1828 | |
|
1829 | 0 | if (rv > 0) { |
1830 | 0 | if (inc) |
1831 | 0 | file->id = fidh + fidl * FID_STEP; |
1832 | 0 | else |
1833 | 0 | file->id = fidh + fidl / FID_STEP; |
1834 | 0 | } |
1835 | 0 | if (rv < 0) |
1836 | 0 | return rv; |
1837 | 0 | return SC_SUCCESS; |
1838 | 0 | } |
1839 | | |
1840 | | |
1841 | | static int |
1842 | | epass2003_select_fid_(struct sc_card *card, sc_path_t * in_path, sc_file_t ** file_out) |
1843 | 0 | { |
1844 | 0 | struct sc_apdu apdu; |
1845 | 0 | u8 buf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1846 | 0 | u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; |
1847 | 0 | int r; |
1848 | 0 | size_t pathlen; |
1849 | 0 | sc_file_t *file = NULL; |
1850 | |
|
1851 | 0 | r = epass2003_hook_path(in_path, 1); |
1852 | 0 | LOG_TEST_RET(card->ctx, r, "Can not hook path"); |
1853 | | |
1854 | 0 | memcpy(path, in_path->value, in_path->len); |
1855 | 0 | pathlen = in_path->len; |
1856 | |
|
1857 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00); |
1858 | |
|
1859 | 0 | switch (in_path->type) { |
1860 | 0 | case SC_PATH_TYPE_FILE_ID: |
1861 | 0 | apdu.p1 = 0; |
1862 | 0 | if (pathlen != 2) |
1863 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1864 | 0 | break; |
1865 | 0 | default: |
1866 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1867 | 0 | } |
1868 | 0 | apdu.p2 = 0; /* first record, return FCI */ |
1869 | 0 | apdu.lc = pathlen; |
1870 | 0 | apdu.data = path; |
1871 | 0 | apdu.datalen = pathlen; |
1872 | |
|
1873 | 0 | if (file_out != NULL) { |
1874 | 0 | apdu.resp = buf; |
1875 | 0 | apdu.resplen = sizeof(buf); |
1876 | 0 | apdu.le = 0; |
1877 | 0 | } else { |
1878 | 0 | apdu.cse = (apdu.lc == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT; |
1879 | 0 | } |
1880 | |
|
1881 | 0 | if (path[0] == 0x29) { /* TODO:0x29 accords with FID prefix in profile */ |
1882 | | /* Not allowed to select private key file, so fake fci. */ |
1883 | | /* 62 16 82 02 11 00 83 02 29 00 85 02 08 00 86 08 FF 90 90 90 FF FF FF FF */ |
1884 | 0 | apdu.resplen = 0x18; |
1885 | 0 | memcpy(apdu.resp, |
1886 | 0 | "\x6f\x16\x82\x02\x11\x00\x83\x02\x29\x00\x85\x02\x08\x00\x86\x08\xff\x90\x90\x90\xff\xff\xff\xff", |
1887 | 0 | apdu.resplen); |
1888 | 0 | apdu.resp[9] = path[1]; |
1889 | 0 | apdu.sw1 = 0x90; |
1890 | 0 | apdu.sw2 = 0x00; |
1891 | 0 | } |
1892 | 0 | else { |
1893 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
1894 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1895 | 0 | } |
1896 | | |
1897 | 0 | if (file_out == NULL) { |
1898 | 0 | if (apdu.sw1 == 0x61) |
1899 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
1900 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
1901 | 0 | } |
1902 | | |
1903 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1904 | 0 | if (r) |
1905 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1906 | 0 | if (apdu.resplen < 2) |
1907 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1908 | | |
1909 | 0 | switch (apdu.resp[0]) { |
1910 | 0 | case 0x6F: |
1911 | 0 | file = sc_file_new(); |
1912 | 0 | if (file == NULL) |
1913 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
1914 | 0 | file->path = *in_path; |
1915 | 0 | if (card->ops->process_fci == NULL) { |
1916 | 0 | sc_file_free(file); |
1917 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1918 | 0 | } |
1919 | | |
1920 | 0 | if ((size_t) apdu.resp[1] + 2 <= apdu.resplen) |
1921 | 0 | card->ops->process_fci(card, file, apdu.resp + 2, apdu.resp[1]); |
1922 | 0 | epass2003_hook_file(file, 0); |
1923 | 0 | *file_out = file; |
1924 | 0 | break; |
1925 | 0 | case 0x00: /* proprietary coding */ |
1926 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1927 | 0 | break; |
1928 | 0 | default: |
1929 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1930 | 0 | } |
1931 | 0 | return 0; |
1932 | 0 | } |
1933 | | |
1934 | | |
1935 | | static int |
1936 | | epass2003_select_fid(struct sc_card *card, unsigned int id_hi, unsigned int id_lo, |
1937 | | sc_file_t ** file_out) |
1938 | 0 | { |
1939 | 0 | int r; |
1940 | 0 | sc_file_t *file = NULL; |
1941 | 0 | sc_path_t path; |
1942 | |
|
1943 | 0 | memset(&path, 0, sizeof(path)); |
1944 | 0 | path.type = SC_PATH_TYPE_FILE_ID; |
1945 | 0 | path.value[0] = id_hi; |
1946 | 0 | path.value[1] = id_lo; |
1947 | 0 | path.len = 2; |
1948 | |
|
1949 | 0 | r = epass2003_select_fid_(card, &path, &file); |
1950 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1951 | | |
1952 | 0 | if (file_out) { |
1953 | 0 | *file_out = file; |
1954 | 0 | } else { |
1955 | 0 | sc_file_free(file); |
1956 | 0 | } |
1957 | |
|
1958 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1959 | 0 | } |
1960 | | |
1961 | | |
1962 | | static int |
1963 | | epass2003_select_aid(struct sc_card *card, const sc_path_t * in_path, sc_file_t ** file_out) |
1964 | 0 | { |
1965 | 0 | int r = 0; |
1966 | |
|
1967 | 0 | r = iso_ops->select_file(card, in_path, file_out); |
1968 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1969 | | |
1970 | 0 | if (file_out) { |
1971 | 0 | sc_file_t *file = *file_out; |
1972 | |
|
1973 | 0 | file->type = SC_FILE_TYPE_DF; |
1974 | 0 | file->ef_structure = SC_FILE_EF_UNKNOWN; |
1975 | 0 | file->path.len = 0; |
1976 | 0 | file->size = 0; |
1977 | | /* AID */ |
1978 | 0 | memcpy(file->name, in_path->value, in_path->len); |
1979 | 0 | file->namelen = in_path->len; |
1980 | 0 | file->id = 0x0000; |
1981 | 0 | } |
1982 | |
|
1983 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1984 | 0 | } |
1985 | | |
1986 | | |
1987 | | static int |
1988 | | epass2003_select_path(struct sc_card *card, const u8 pathbuf[16], const size_t len, |
1989 | | sc_file_t ** file_out) |
1990 | 0 | { |
1991 | 0 | u8 n_pathbuf[SC_MAX_PATH_SIZE]; |
1992 | 0 | const u8 *path = pathbuf; |
1993 | 0 | size_t pathlen = len; |
1994 | 0 | unsigned int i; |
1995 | 0 | int r; |
1996 | |
|
1997 | 0 | if (pathlen % 2 != 0 || pathlen > 6 || pathlen <= 0) |
1998 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1999 | | |
2000 | | /* if pathlen == 6 then the first FID must be MF (== 3F00) */ |
2001 | 0 | if (pathlen == 6 && (path[0] != 0x3f || path[1] != 0x00)) |
2002 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2003 | | |
2004 | | /* unify path (the first FID should be MF) */ |
2005 | 0 | if (path[0] != 0x3f || path[1] != 0x00) { |
2006 | 0 | n_pathbuf[0] = 0x3f; |
2007 | 0 | n_pathbuf[1] = 0x00; |
2008 | 0 | memcpy(n_pathbuf + 2, path, pathlen); |
2009 | 0 | path = n_pathbuf; |
2010 | 0 | pathlen += 2; |
2011 | 0 | } |
2012 | |
|
2013 | 0 | for (i = 0; i < pathlen - 2; i += 2) { |
2014 | 0 | r = epass2003_select_fid(card, path[i], path[i + 1], NULL); |
2015 | 0 | LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed"); |
2016 | 0 | } |
2017 | | |
2018 | 0 | return epass2003_select_fid(card, path[pathlen - 2], path[pathlen - 1], file_out); |
2019 | 0 | } |
2020 | | |
2021 | | |
2022 | | static int |
2023 | | epass2003_select_file(struct sc_card *card, const sc_path_t * in_path, |
2024 | | sc_file_t ** file_out) |
2025 | 0 | { |
2026 | 0 | LOG_FUNC_CALLED(card->ctx); |
2027 | |
|
2028 | 0 | switch (in_path->type) { |
2029 | 0 | case SC_PATH_TYPE_FILE_ID: |
2030 | 0 | if (in_path->len != 2) |
2031 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2032 | 0 | return epass2003_select_fid(card, in_path->value[0], in_path->value[1], file_out); |
2033 | 0 | case SC_PATH_TYPE_DF_NAME: |
2034 | 0 | return epass2003_select_aid(card, in_path, file_out); |
2035 | 0 | case SC_PATH_TYPE_PATH: |
2036 | 0 | return epass2003_select_path(card, in_path->value, in_path->len, file_out); |
2037 | 0 | default: |
2038 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2039 | 0 | } |
2040 | 0 | } |
2041 | | |
2042 | | static int |
2043 | | epass2003_set_security_env(struct sc_card *card, const sc_security_env_t * env, int se_num) |
2044 | 0 | { |
2045 | 0 | struct sc_apdu apdu; |
2046 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2047 | 0 | u8 *p; |
2048 | 0 | unsigned short fid = 0; |
2049 | 0 | int r, locked = 0; |
2050 | 0 | epass2003_exdata *exdata = NULL; |
2051 | |
|
2052 | 0 | if (!card->drv_data) |
2053 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2054 | | |
2055 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
2056 | |
|
2057 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); |
2058 | |
|
2059 | 0 | p = sbuf; |
2060 | 0 | *p++ = 0x80; /* algorithm reference */ |
2061 | 0 | *p++ = 0x01; |
2062 | 0 | *p++ = 0x84; |
2063 | |
|
2064 | 0 | *p++ = 0x81; |
2065 | 0 | *p++ = 0x02; |
2066 | |
|
2067 | 0 | fid = 0x2900; |
2068 | 0 | fid += (unsigned short)(0x20 * (env->key_ref[0] & 0xff)); |
2069 | 0 | *p++ = fid >> 8; |
2070 | 0 | *p++ = fid & 0xff; |
2071 | 0 | r = (int)(p - sbuf); |
2072 | 0 | apdu.lc = r; |
2073 | 0 | apdu.datalen = r; |
2074 | 0 | apdu.data = sbuf; |
2075 | |
|
2076 | 0 | if (env->algorithm == SC_ALGORITHM_EC) { |
2077 | 0 | apdu.p2 = 0xB6; |
2078 | 0 | exdata->currAlg = SC_ALGORITHM_EC; |
2079 | 0 | if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA1) { |
2080 | 0 | sbuf[2] = 0x91; |
2081 | 0 | exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA1; |
2082 | 0 | } else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA256) { |
2083 | 0 | sbuf[2] = 0x92; |
2084 | 0 | exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA256; |
2085 | 0 | } else { |
2086 | 0 | sbuf[2] = 0x92; |
2087 | 0 | exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_NONE; |
2088 | 0 | } |
2089 | 0 | } else if (env->algorithm == SC_ALGORITHM_RSA) { |
2090 | 0 | exdata->currAlg = SC_ALGORITHM_RSA; |
2091 | 0 | apdu.p2 = 0xB8; |
2092 | 0 | sc_log(card->ctx, "setenv RSA Algorithm alg_flags = %0lx\n", env->algorithm_flags); |
2093 | 0 | } else { |
2094 | 0 | sc_log(card->ctx, "%0lx Alg Not Supported!", env->algorithm); |
2095 | 0 | } |
2096 | |
|
2097 | 0 | if (se_num > 0) { |
2098 | 0 | r = sc_lock(card); |
2099 | 0 | LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); |
2100 | 0 | locked = 1; |
2101 | 0 | } |
2102 | 0 | if (apdu.datalen != 0) { |
2103 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2104 | 0 | if (r) { |
2105 | 0 | sc_log(card->ctx, "%s: APDU transmit failed", sc_strerror(r)); |
2106 | 0 | goto err; |
2107 | 0 | } |
2108 | | |
2109 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2110 | 0 | if (r) { |
2111 | 0 | sc_log(card->ctx, "%s: Card returned error", sc_strerror(r)); |
2112 | 0 | goto err; |
2113 | 0 | } |
2114 | 0 | } |
2115 | 0 | if (se_num <= 0) |
2116 | 0 | return 0; |
2117 | | |
2118 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num); |
2119 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2120 | 0 | sc_unlock(card); |
2121 | |
|
2122 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2123 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
2124 | | |
2125 | 0 | err: |
2126 | 0 | if (locked) |
2127 | 0 | sc_unlock(card); |
2128 | 0 | return r; |
2129 | 0 | } |
2130 | | |
2131 | | |
2132 | | static int |
2133 | | epass2003_restore_security_env(struct sc_card *card, int se_num) |
2134 | 0 | { |
2135 | 0 | LOG_FUNC_CALLED(card->ctx); |
2136 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2137 | 0 | } |
2138 | | |
2139 | | |
2140 | | static int epass2003_decipher(struct sc_card *card, const u8 * data, size_t datalen, |
2141 | | u8 * out, size_t outlen) |
2142 | 0 | { |
2143 | 0 | int r; |
2144 | 0 | struct sc_apdu apdu; |
2145 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2146 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2147 | 0 | epass2003_exdata *exdata = NULL; |
2148 | |
|
2149 | 0 | LOG_FUNC_CALLED(card->ctx); |
2150 | |
|
2151 | 0 | if (!card->drv_data) |
2152 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2153 | | |
2154 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
2155 | |
|
2156 | 0 | if (exdata->currAlg == SC_ALGORITHM_EC) { |
2157 | 0 | if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_SHA1) { |
2158 | 0 | r = hash_data(card, data, datalen, sbuf, SC_ALGORITHM_ECDSA_HASH_SHA1); |
2159 | 0 | LOG_TEST_RET(card->ctx, r, "hash_data failed"); |
2160 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0x2A, 0x9E, 0x9A); |
2161 | 0 | apdu.data = sbuf; |
2162 | 0 | apdu.lc = 0x14; |
2163 | 0 | apdu.datalen = 0x14; |
2164 | 0 | } else if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_SHA256) { |
2165 | 0 | r = hash_data(card, data, datalen, sbuf, SC_ALGORITHM_ECDSA_HASH_SHA256); |
2166 | 0 | LOG_TEST_RET(card->ctx, r, "hash_data failed"); |
2167 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0x2A, 0x9E, 0x9A); |
2168 | 0 | apdu.data = sbuf; |
2169 | 0 | apdu.lc = 0x20; |
2170 | 0 | apdu.datalen = 0x20; |
2171 | 0 | } else if (exdata->ecAlgFlags & SC_ALGORITHM_ECDSA_HASH_NONE) { |
2172 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3,0x2A, 0x9E, 0x9A); |
2173 | 0 | apdu.data = data; |
2174 | 0 | apdu.lc = datalen; |
2175 | 0 | apdu.datalen = datalen; |
2176 | 0 | } else { |
2177 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2178 | 0 | } |
2179 | 0 | apdu.resp = rbuf; |
2180 | 0 | apdu.resplen = sizeof(rbuf); |
2181 | 0 | apdu.le = 0; |
2182 | |
|
2183 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2184 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2185 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
2186 | 0 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
2187 | 0 | memcpy(out, apdu.resp, len); |
2188 | 0 | LOG_FUNC_RETURN(card->ctx, (int)len); |
2189 | 0 | } |
2190 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
2191 | 0 | } else if (exdata->currAlg == SC_ALGORITHM_RSA) { |
2192 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); |
2193 | 0 | apdu.resp = rbuf; |
2194 | 0 | apdu.resplen = sizeof(rbuf); |
2195 | 0 | apdu.le = 0; |
2196 | |
|
2197 | 0 | memcpy(sbuf, data, datalen); |
2198 | 0 | apdu.data = sbuf; |
2199 | 0 | apdu.lc = datalen; |
2200 | 0 | apdu.datalen = datalen; |
2201 | 0 | } else { |
2202 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); |
2203 | 0 | apdu.resp = rbuf; |
2204 | 0 | apdu.resplen = sizeof(rbuf); |
2205 | 0 | apdu.le = 256; |
2206 | |
|
2207 | 0 | memcpy(sbuf, data, datalen); |
2208 | 0 | apdu.data = sbuf; |
2209 | 0 | apdu.lc = datalen; |
2210 | 0 | apdu.datalen = datalen; |
2211 | 0 | } |
2212 | | |
2213 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2214 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2215 | | |
2216 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
2217 | 0 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
2218 | 0 | memcpy(out, apdu.resp, len); |
2219 | 0 | LOG_FUNC_RETURN(card->ctx, (int)len); |
2220 | 0 | } |
2221 | | |
2222 | 0 | LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
2223 | 0 | } |
2224 | | |
2225 | | |
2226 | | static int |
2227 | | acl_to_ac_byte(struct sc_card *card, const struct sc_acl_entry *e) |
2228 | 0 | { |
2229 | 0 | if (e == NULL) |
2230 | 0 | return SC_ERROR_OBJECT_NOT_FOUND; |
2231 | | |
2232 | 0 | switch (e->method) { |
2233 | 0 | case SC_AC_NONE: |
2234 | 0 | LOG_FUNC_RETURN(card->ctx, EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE); |
2235 | 0 | case SC_AC_NEVER: |
2236 | 0 | LOG_FUNC_RETURN(card->ctx, EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_NOONE); |
2237 | 0 | default: |
2238 | 0 | LOG_FUNC_RETURN(card->ctx, EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_USER); |
2239 | 0 | } |
2240 | | |
2241 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS); |
2242 | 0 | } |
2243 | | |
2244 | | /* Use epass2003 sec_attr to add acl entries */ |
2245 | | int |
2246 | | sec_attr_to_entry(struct sc_card *card, sc_file_t *file, int index) |
2247 | 0 | { |
2248 | 0 | int i; |
2249 | 0 | int found = 0; |
2250 | |
|
2251 | 0 | unsigned int method; |
2252 | 0 | unsigned long keyref; |
2253 | |
|
2254 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
2255 | |
|
2256 | 0 | switch (file->sec_attr[index]) { |
2257 | 0 | case (EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE): |
2258 | 0 | method = SC_AC_NONE; |
2259 | 0 | keyref = SC_AC_KEY_REF_NONE; |
2260 | 0 | break; |
2261 | 0 | case (EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_USER): |
2262 | 0 | method = SC_AC_CHV; |
2263 | 0 | keyref = 1; |
2264 | 0 | break; |
2265 | 0 | default: |
2266 | 0 | sc_log(card->ctx, "Unknown value 0x%2.2x in file->sec_attr[%d]", file->sec_attr[index], index); |
2267 | 0 | method = SC_AC_NEVER; |
2268 | 0 | keyref = SC_AC_KEY_REF_NONE; |
2269 | 0 | break; |
2270 | 0 | } |
2271 | | |
2272 | 0 | for (i = 0; i < (int)(sizeof(sec_attr_to_acl_entry) / sizeof(sec_attr_to_acl_entries_t)); i++) { |
2273 | 0 | const sec_attr_to_acl_entries_t *e = &sec_attr_to_acl_entry[i]; |
2274 | |
|
2275 | 0 | if (index == e->index && file->type == e->file_type |
2276 | 0 | && file->ef_structure == e->file_ef_structure) { |
2277 | | /* may add multiple entries */ |
2278 | 0 | sc_file_add_acl_entry(file, e->op, method, keyref); |
2279 | 0 | found++; |
2280 | 0 | } |
2281 | 0 | } |
2282 | 0 | if (found != 1) { |
2283 | 0 | sc_log(card->ctx,"found %d entries ", found); |
2284 | 0 | } |
2285 | |
|
2286 | 0 | return 0; |
2287 | 0 | } |
2288 | | |
2289 | | static int |
2290 | | epass2003_process_fci(struct sc_card *card, sc_file_t * file, const u8 * buf, size_t buflen) |
2291 | 0 | { |
2292 | 0 | sc_context_t *ctx = card->ctx; |
2293 | 0 | size_t taglen, len = buflen; |
2294 | 0 | const u8 *tag = NULL, *p = buf; |
2295 | |
|
2296 | 0 | sc_log(ctx, "processing FCI bytes"); |
2297 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); |
2298 | 0 | if (tag != NULL && taglen == 2) { |
2299 | 0 | file->id = (tag[0] << 8) | tag[1]; |
2300 | 0 | sc_log(ctx, " file identifier: 0x%02X%02X", tag[0], tag[1]); |
2301 | 0 | } |
2302 | |
|
2303 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen); |
2304 | 0 | if (tag != NULL && taglen > 0 && taglen < 3) { |
2305 | 0 | file->size = tag[0]; |
2306 | 0 | if (taglen == 2) |
2307 | 0 | file->size = (file->size << 8) + tag[1]; |
2308 | 0 | sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", |
2309 | 0 | file->size); |
2310 | 0 | } |
2311 | |
|
2312 | 0 | if (tag == NULL) { |
2313 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen); |
2314 | 0 | if (tag != NULL && taglen >= 2) { |
2315 | 0 | int bytes = (tag[0] << 8) + tag[1]; |
2316 | |
|
2317 | 0 | sc_log(ctx, " bytes in file: %d", bytes); |
2318 | 0 | file->size = bytes; |
2319 | 0 | } |
2320 | 0 | } |
2321 | |
|
2322 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); |
2323 | 0 | if (tag != NULL) { |
2324 | 0 | if (taglen > 0) { |
2325 | 0 | unsigned char byte = tag[0]; |
2326 | 0 | const char *type; |
2327 | |
|
2328 | 0 | if (byte == 0x38) { |
2329 | 0 | type = "DF"; |
2330 | 0 | file->type = SC_FILE_TYPE_DF; |
2331 | 0 | } else if (0x01 <= byte && byte <= 0x07) { |
2332 | 0 | type = "working EF"; |
2333 | 0 | file->type = SC_FILE_TYPE_WORKING_EF; |
2334 | 0 | switch (byte) { |
2335 | 0 | case 0x01: |
2336 | 0 | file->ef_structure = SC_FILE_EF_TRANSPARENT; |
2337 | 0 | break; |
2338 | 0 | case 0x02: |
2339 | 0 | file->ef_structure = SC_FILE_EF_LINEAR_FIXED; |
2340 | 0 | break; |
2341 | 0 | case 0x04: |
2342 | 0 | file->ef_structure = SC_FILE_EF_LINEAR_FIXED; |
2343 | 0 | break; |
2344 | 0 | default: |
2345 | 0 | break; |
2346 | 0 | } |
2347 | |
|
2348 | 0 | } else if (0x10 == byte) { |
2349 | 0 | type = "BSO"; |
2350 | 0 | file->type = SC_FILE_TYPE_BSO; |
2351 | 0 | } else if (0x11 <= byte) { |
2352 | 0 | type = "internal EF"; |
2353 | 0 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
2354 | 0 | switch (byte) { |
2355 | 0 | case 0x11: |
2356 | 0 | break; |
2357 | 0 | case 0x12: |
2358 | 0 | break; |
2359 | 0 | default: |
2360 | 0 | break; |
2361 | 0 | } |
2362 | 0 | } else { |
2363 | 0 | type = "unknown"; |
2364 | 0 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
2365 | 0 | } |
2366 | 0 | sc_log(ctx, "type %s, EF structure %d", type, byte); |
2367 | 0 | } |
2368 | 0 | } |
2369 | | |
2370 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); |
2371 | 0 | if (tag != NULL && taglen > 0 && taglen <= 16) { |
2372 | 0 | memcpy(file->name, tag, taglen); |
2373 | 0 | file->namelen = taglen; |
2374 | |
|
2375 | 0 | sc_log_hex(ctx, "File name", file->name, file->namelen); |
2376 | 0 | if (!file->type) |
2377 | 0 | file->type = SC_FILE_TYPE_DF; |
2378 | 0 | } |
2379 | |
|
2380 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen); |
2381 | 0 | if (tag != NULL && taglen) |
2382 | 0 | sc_file_set_prop_attr(file, tag, taglen); |
2383 | 0 | else |
2384 | 0 | file->prop_attr_len = 0; |
2385 | |
|
2386 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen); |
2387 | 0 | if (tag != NULL && taglen) |
2388 | 0 | sc_file_set_prop_attr(file, tag, taglen); |
2389 | |
|
2390 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen); |
2391 | 0 | if (tag != NULL && taglen) { |
2392 | 0 | unsigned int i; |
2393 | 0 | sc_file_set_sec_attr(file, tag, taglen); |
2394 | 0 | for (i = 0; i< taglen; i++) |
2395 | 0 | if (tag[i] != 0xff) /* skip unused entries */ |
2396 | 0 | sec_attr_to_entry(card, file, i); |
2397 | 0 | } |
2398 | |
|
2399 | 0 | tag = sc_asn1_find_tag(ctx, p, len, 0x8A, &taglen); |
2400 | 0 | if (tag != NULL && taglen == 1) { |
2401 | 0 | if (tag[0] == 0x01) |
2402 | 0 | file->status = SC_FILE_STATUS_CREATION; |
2403 | 0 | else if (tag[0] == 0x07 || tag[0] == 0x05) |
2404 | 0 | file->status = SC_FILE_STATUS_ACTIVATED; |
2405 | 0 | else if (tag[0] == 0x06 || tag[0] == 0x04) |
2406 | 0 | file->status = SC_FILE_STATUS_INVALIDATED; |
2407 | 0 | } |
2408 | 0 | file->magic = SC_FILE_MAGIC; |
2409 | |
|
2410 | 0 | return 0; |
2411 | 0 | } |
2412 | | |
2413 | | |
2414 | | static int |
2415 | | epass2003_construct_fci(struct sc_card *card, const sc_file_t * file, |
2416 | | u8 * out, size_t * outlen) |
2417 | 0 | { |
2418 | 0 | u8 *p = out; |
2419 | 0 | u8 buf[64]; |
2420 | 0 | unsigned char ops[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
2421 | 0 | int rv; |
2422 | 0 | unsigned ii; |
2423 | |
|
2424 | 0 | if (*outlen < 2) |
2425 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
2426 | | |
2427 | 0 | *p++ = 0x62; |
2428 | 0 | p++; |
2429 | 0 | if (file->type == SC_FILE_TYPE_WORKING_EF) { |
2430 | 0 | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
2431 | 0 | buf[0] = (file->size >> 8) & 0xFF; |
2432 | 0 | buf[1] = file->size & 0xFF; |
2433 | 0 | sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p); |
2434 | 0 | } |
2435 | 0 | } |
2436 | 0 | if (file->type == SC_FILE_TYPE_DF) { |
2437 | 0 | buf[0] = 0x38; |
2438 | 0 | buf[1] = 0x00; |
2439 | 0 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2440 | 0 | } |
2441 | 0 | else if (file->type == SC_FILE_TYPE_WORKING_EF) { |
2442 | 0 | buf[0] = file->ef_structure & 7; |
2443 | 0 | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
2444 | 0 | buf[1] = 0x00; |
2445 | 0 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2446 | 0 | } else if (file->ef_structure == SC_FILE_EF_LINEAR_FIXED || |
2447 | 0 | file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE) { |
2448 | 0 | buf[1] = 0x00; |
2449 | 0 | buf[2] = 0x00; |
2450 | 0 | buf[3] = 0x40; /* record length */ |
2451 | 0 | buf[4] = 0x00; /* record count */ |
2452 | 0 | sc_asn1_put_tag(0x82, buf, 5, p, *outlen - (p - out), &p); |
2453 | 0 | } else { |
2454 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2455 | 0 | } |
2456 | |
|
2457 | 0 | } |
2458 | 0 | else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
2459 | 0 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || |
2460 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { |
2461 | 0 | buf[0] = 0x11; |
2462 | 0 | buf[1] = 0x00; |
2463 | 0 | } else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2464 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2465 | 0 | buf[0] = 0x12; |
2466 | 0 | buf[1] = 0x00; |
2467 | 0 | } else { |
2468 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2469 | 0 | } |
2470 | 0 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2471 | 0 | } else if (file->type == SC_FILE_TYPE_BSO) { |
2472 | 0 | buf[0] = 0x10; |
2473 | 0 | buf[1] = 0x00; |
2474 | 0 | sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p); |
2475 | 0 | } |
2476 | | |
2477 | 0 | buf[0] = (file->id >> 8) & 0xFF; |
2478 | 0 | buf[1] = file->id & 0xFF; |
2479 | 0 | sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p); |
2480 | 0 | if (file->type == SC_FILE_TYPE_DF) { |
2481 | 0 | if (file->namelen != 0) { |
2482 | 0 | sc_asn1_put_tag(0x84, file->name, file->namelen, p, *outlen - (p - out), &p); |
2483 | 0 | } else { |
2484 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2485 | 0 | } |
2486 | 0 | } |
2487 | 0 | if (file->type == SC_FILE_TYPE_DF) { |
2488 | 0 | unsigned char data[2] = {0x00, 0x7F}; |
2489 | | /* 127 files at most */ |
2490 | 0 | sc_asn1_put_tag(0x85, data, sizeof(data), p, *outlen - (p - out), &p); |
2491 | 0 | } else if (file->type == SC_FILE_TYPE_BSO) { |
2492 | 0 | buf[0] = file->size & 0xff; |
2493 | 0 | sc_asn1_put_tag(0x85, buf, 1, p, *outlen - (p - out), &p); |
2494 | 0 | } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
2495 | 0 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || |
2496 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2497 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT || |
2498 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2499 | 0 | buf[0] = (file->size >> 8) & 0xFF; |
2500 | 0 | buf[1] = file->size & 0xFF; |
2501 | 0 | sc_asn1_put_tag(0x85, buf, 2, p, *outlen - (p - out), &p); |
2502 | 0 | } |
2503 | 0 | } |
2504 | 0 | if (file->sec_attr_len) { |
2505 | 0 | memcpy(buf, file->sec_attr, file->sec_attr_len); |
2506 | 0 | sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p); |
2507 | |
|
2508 | 0 | } else { |
2509 | 0 | sc_log(card->ctx, "SC_FILE_ACL"); |
2510 | 0 | if (file->type == SC_FILE_TYPE_DF) { |
2511 | 0 | ops[0] = SC_AC_OP_LIST_FILES; |
2512 | 0 | ops[1] = SC_AC_OP_CREATE; |
2513 | 0 | ops[3] = SC_AC_OP_DELETE; |
2514 | 0 | } else if (file->type == SC_FILE_TYPE_WORKING_EF) { |
2515 | 0 | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
2516 | 0 | ops[0] = SC_AC_OP_READ; |
2517 | 0 | ops[1] = SC_AC_OP_UPDATE; |
2518 | 0 | ops[3] = SC_AC_OP_DELETE; |
2519 | 0 | } else if (file->ef_structure == SC_FILE_EF_LINEAR_FIXED || |
2520 | 0 | file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE) { |
2521 | 0 | ops[0] = SC_AC_OP_READ; |
2522 | 0 | ops[1] = SC_AC_OP_UPDATE; |
2523 | 0 | ops[2] = SC_AC_OP_WRITE; |
2524 | 0 | ops[3] = SC_AC_OP_DELETE; |
2525 | 0 | } else { |
2526 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2527 | 0 | } |
2528 | 0 | } else if (file->type == SC_FILE_TYPE_BSO) { |
2529 | 0 | ops[0] = SC_AC_OP_UPDATE; |
2530 | 0 | ops[3] = SC_AC_OP_DELETE; |
2531 | 0 | } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
2532 | 0 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || |
2533 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { |
2534 | 0 | ops[1] = SC_AC_OP_UPDATE; |
2535 | 0 | ops[2] = SC_AC_OP_CRYPTO; |
2536 | 0 | ops[3] = SC_AC_OP_DELETE; |
2537 | 0 | } else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2538 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2539 | 0 | ops[0] = SC_AC_OP_READ; |
2540 | 0 | ops[1] = SC_AC_OP_UPDATE; |
2541 | 0 | ops[2] = SC_AC_OP_CRYPTO; |
2542 | 0 | ops[3] = SC_AC_OP_DELETE; |
2543 | 0 | } |
2544 | 0 | } else { |
2545 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2546 | 0 | } |
2547 | | |
2548 | 0 | for (ii = 0; ii < sizeof(ops); ii++) { |
2549 | 0 | const struct sc_acl_entry *entry; |
2550 | |
|
2551 | 0 | buf[ii] = 0xFF; |
2552 | 0 | if (ops[ii] == 0xFF) |
2553 | 0 | continue; |
2554 | 0 | entry = sc_file_get_acl_entry(file, ops[ii]); |
2555 | |
|
2556 | 0 | rv = acl_to_ac_byte(card, entry); |
2557 | 0 | LOG_TEST_RET(card->ctx, rv, "Invalid ACL"); |
2558 | | |
2559 | 0 | buf[ii] = rv; |
2560 | 0 | } |
2561 | 0 | sc_asn1_put_tag(0x86, buf, sizeof(ops), p, *outlen - (p - out), &p); |
2562 | 0 | if (file->size == 256) { |
2563 | 0 | out[4]= 0x13; |
2564 | 0 | } |
2565 | 0 | } |
2566 | | |
2567 | | /* VT ??? */ |
2568 | 0 | if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || |
2569 | 0 | file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { |
2570 | 0 | unsigned char data[2] = {0x00, 0x66}; |
2571 | 0 | sc_asn1_put_tag(0x87, data, sizeof(data), p, *outlen - (p - out), &p); |
2572 | 0 | if (file->size == 256) { |
2573 | 0 | out[4] = 0x14; |
2574 | 0 | } |
2575 | 0 | } |
2576 | |
|
2577 | 0 | out[1] = p - out - 2; |
2578 | |
|
2579 | 0 | *outlen = p - out; |
2580 | 0 | return 0; |
2581 | 0 | } |
2582 | | |
2583 | | |
2584 | | static int |
2585 | | epass2003_create_file(struct sc_card *card, sc_file_t * file) |
2586 | 0 | { |
2587 | 0 | int r; |
2588 | 0 | size_t len; |
2589 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2590 | 0 | struct sc_apdu apdu; |
2591 | |
|
2592 | 0 | len = SC_MAX_APDU_BUFFER_SIZE; |
2593 | |
|
2594 | 0 | epass2003_hook_file(file, 1); |
2595 | |
|
2596 | 0 | if (card->ops->construct_fci == NULL) |
2597 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2598 | | |
2599 | 0 | r = epass2003_construct_fci(card, file, sbuf, &len); |
2600 | 0 | LOG_TEST_RET(card->ctx, r, "construct_fci() failed"); |
2601 | | |
2602 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); |
2603 | 0 | apdu.lc = len; |
2604 | 0 | apdu.datalen = len; |
2605 | 0 | apdu.data = sbuf; |
2606 | |
|
2607 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2608 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2609 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2610 | 0 | LOG_TEST_RET(card->ctx, r, "APDU sw1/2 wrong"); |
2611 | | |
2612 | 0 | epass2003_hook_file(file, 0); |
2613 | 0 | return r; |
2614 | 0 | } |
2615 | | |
2616 | | |
2617 | | static int |
2618 | | epass2003_delete_file(struct sc_card *card, const sc_path_t * path) |
2619 | 0 | { |
2620 | 0 | int r; |
2621 | 0 | u8 sbuf[2]; |
2622 | 0 | struct sc_apdu apdu; |
2623 | |
|
2624 | 0 | LOG_FUNC_CALLED(card->ctx); |
2625 | |
|
2626 | 0 | r = sc_select_file(card, path, NULL); |
2627 | 0 | LOG_TEST_RET(card->ctx, r, "Can not select file"); |
2628 | 0 | r = epass2003_hook_path((struct sc_path *)path, 1); |
2629 | 0 | LOG_TEST_RET(card->ctx, r, "Can not hook path"); |
2630 | | |
2631 | 0 | sbuf[0] = path->value[path->len - 2]; |
2632 | 0 | sbuf[1] = path->value[path->len - 1]; |
2633 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00); |
2634 | 0 | apdu.lc = 2; |
2635 | 0 | apdu.datalen = 2; |
2636 | 0 | apdu.data = sbuf; |
2637 | |
|
2638 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2639 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2640 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2641 | 0 | LOG_TEST_RET(card->ctx, r, "Delete file failed"); |
2642 | | |
2643 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
2644 | 0 | } |
2645 | | |
2646 | | static int |
2647 | | epass2003_list_files(struct sc_card *card, unsigned char *buf, size_t buflen) |
2648 | 0 | { |
2649 | 0 | struct sc_apdu apdu; |
2650 | 0 | unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
2651 | 0 | int r; |
2652 | |
|
2653 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
2654 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x34, 0x00, 0x00); |
2655 | 0 | apdu.cla = 0x80; |
2656 | 0 | apdu.le = 0; |
2657 | 0 | apdu.resplen = sizeof(rbuf); |
2658 | 0 | apdu.resp = rbuf; |
2659 | |
|
2660 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2661 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2662 | | |
2663 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2664 | 0 | LOG_TEST_RET(card->ctx, r, "Card returned error"); |
2665 | | |
2666 | 0 | if (apdu.resplen == 0x100 && rbuf[0] == 0 && rbuf[1] == 0) |
2667 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
2668 | | |
2669 | 0 | buflen = buflen < apdu.resplen ? buflen : apdu.resplen; |
2670 | 0 | memcpy(buf, rbuf, buflen); |
2671 | |
|
2672 | 0 | LOG_FUNC_RETURN(card->ctx, (int)buflen); |
2673 | 0 | } |
2674 | | |
2675 | | |
2676 | | static int |
2677 | | internal_write_rsa_key_factor(struct sc_card *card, unsigned short fid, u8 factor, |
2678 | | sc_pkcs15_bignum_t data) |
2679 | 0 | { |
2680 | 0 | int r; |
2681 | 0 | struct sc_apdu apdu; |
2682 | 0 | u8 sbuff[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0}; |
2683 | |
|
2684 | 0 | LOG_FUNC_CALLED(card->ctx); |
2685 | |
|
2686 | 0 | sbuff[0] = ((fid & 0xff00) >> 8); |
2687 | 0 | sbuff[1] = (fid & 0x00ff); |
2688 | 0 | memcpy(&sbuff[2], data.data, data.len); |
2689 | | // sc_mem_reverse(&sbuff[2], data.len); |
2690 | |
|
2691 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xe7, factor, 0x00); |
2692 | 0 | apdu.cla = 0x80; |
2693 | 0 | apdu.lc = apdu.datalen = 2 + data.len; |
2694 | 0 | apdu.data = sbuff; |
2695 | |
|
2696 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2697 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2698 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2699 | 0 | LOG_TEST_RET(card->ctx, r, "Write rsa key factor failed"); |
2700 | | |
2701 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2702 | 0 | } |
2703 | | |
2704 | | |
2705 | | static int |
2706 | | internal_write_rsa_key(struct sc_card *card, unsigned short fid, struct sc_pkcs15_prkey_rsa *rsa) |
2707 | 0 | { |
2708 | 0 | int r; |
2709 | |
|
2710 | 0 | LOG_FUNC_CALLED(card->ctx); |
2711 | |
|
2712 | 0 | r = internal_write_rsa_key_factor(card, fid, 0x02, rsa->modulus); |
2713 | 0 | LOG_TEST_RET(card->ctx, r, "write n failed"); |
2714 | 0 | r = internal_write_rsa_key_factor(card, fid, 0x03, rsa->d); |
2715 | 0 | LOG_TEST_RET(card->ctx, r, "write d failed"); |
2716 | | |
2717 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2718 | 0 | } |
2719 | | |
2720 | | |
2721 | | static int |
2722 | | hash_data(struct sc_card *card, const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType) |
2723 | 0 | { |
2724 | |
|
2725 | 0 | if ((NULL == data) || (NULL == hash)) |
2726 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2727 | | |
2728 | 0 | if (mechanismType & SC_ALGORITHM_ECDSA_HASH_SHA1) { |
2729 | 0 | unsigned char data_hash[24] = {0}; |
2730 | 0 | size_t len = 0; |
2731 | |
|
2732 | 0 | sha1_digest(card, data, datalen, data_hash); |
2733 | 0 | len = REVERSE_ORDER4(datalen); |
2734 | 0 | memcpy(&data_hash[20], &len, 4); |
2735 | 0 | memcpy(hash, data_hash, 24); |
2736 | 0 | } else if (mechanismType & SC_ALGORITHM_ECDSA_HASH_SHA256) { |
2737 | 0 | unsigned char data_hash[36] = {0}; |
2738 | 0 | size_t len = 0; |
2739 | |
|
2740 | 0 | sha256_digest(card, data, datalen, data_hash); |
2741 | 0 | len = REVERSE_ORDER4(datalen); |
2742 | 0 | memcpy(&data_hash[32], &len, 4); |
2743 | 0 | memcpy(hash, data_hash, 36); |
2744 | 0 | } else { |
2745 | 0 | return SC_ERROR_NOT_SUPPORTED; |
2746 | 0 | } |
2747 | | |
2748 | 0 | return SC_SUCCESS; |
2749 | 0 | } |
2750 | | |
2751 | | |
2752 | | static int |
2753 | | install_secret_key(struct sc_card *card, unsigned char ktype, unsigned char kid, |
2754 | | unsigned char useac, unsigned char modifyac, unsigned char EC, |
2755 | | unsigned char *data, unsigned long dataLen) |
2756 | 0 | { |
2757 | 0 | int r; |
2758 | 0 | struct sc_apdu apdu; |
2759 | 0 | unsigned char isapp = 0x00; /* appendable */ |
2760 | 0 | unsigned char tmp_data[256] = {0}; |
2761 | |
|
2762 | 0 | tmp_data[0] = ktype; |
2763 | 0 | tmp_data[1] = kid; |
2764 | 0 | tmp_data[2] = useac; |
2765 | 0 | tmp_data[3] = modifyac; |
2766 | 0 | tmp_data[8] = 0xFF; |
2767 | |
|
2768 | 0 | if (0x04 == ktype || 0x06 == ktype) { |
2769 | 0 | tmp_data[4] = EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_SO; |
2770 | 0 | tmp_data[5] = EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_SO; |
2771 | 0 | tmp_data[7] = (kid == PIN_ID[0] ? EPASS2003_AC_USER : EPASS2003_AC_SO); |
2772 | 0 | tmp_data[9] = (EC << 4) | EC; |
2773 | 0 | } |
2774 | |
|
2775 | 0 | memcpy(&tmp_data[10], data, dataLen); |
2776 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xe3, isapp, 0x00); |
2777 | 0 | apdu.cla = 0x80; |
2778 | 0 | apdu.lc = apdu.datalen = 10 + dataLen; |
2779 | 0 | apdu.data = tmp_data; |
2780 | |
|
2781 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2782 | 0 | LOG_TEST_RET(card->ctx, r, "APDU install_secret_key failed"); |
2783 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2784 | 0 | LOG_TEST_RET(card->ctx, r, "install_secret_key failed"); |
2785 | | |
2786 | 0 | return r; |
2787 | 0 | } |
2788 | | |
2789 | | |
2790 | | static int |
2791 | | internal_install_pre(struct sc_card *card) |
2792 | 0 | { |
2793 | 0 | int r; |
2794 | | /* init key for enc */ |
2795 | 0 | r = install_secret_key(card, 0x01, 0x00, |
2796 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2797 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2798 | 0 | 0, g_init_key_enc, 16); |
2799 | 0 | LOG_TEST_RET(card->ctx, r, "Install init key failed"); |
2800 | | |
2801 | | /* init key for mac */ |
2802 | 0 | r = install_secret_key(card, 0x02, 0x00, |
2803 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2804 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE, |
2805 | 0 | 0, g_init_key_mac, 16); |
2806 | 0 | LOG_TEST_RET(card->ctx, r, "Install init key failed"); |
2807 | | |
2808 | 0 | return r; |
2809 | 0 | } |
2810 | | |
2811 | | |
2812 | | /* use external auth secret as pin */ |
2813 | | static int |
2814 | | internal_install_pin(struct sc_card *card, sc_epass2003_wkey_data * pin) |
2815 | 0 | { |
2816 | 0 | int r; |
2817 | 0 | unsigned char hash[HASH_LEN] = {0}; |
2818 | |
|
2819 | 0 | r = hash_data(card, pin->key_data.es_secret.key_val, pin->key_data.es_secret.key_len, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); |
2820 | 0 | LOG_TEST_RET(card->ctx, r, "hash data failed"); |
2821 | | |
2822 | 0 | r = install_secret_key(card, 0x04, pin->key_data.es_secret.kid, |
2823 | 0 | pin->key_data.es_secret.ac[0], |
2824 | 0 | pin->key_data.es_secret.ac[1], |
2825 | 0 | pin->key_data.es_secret.EC, hash, HASH_LEN); |
2826 | 0 | LOG_TEST_RET(card->ctx, r, "Install failed"); |
2827 | | |
2828 | 0 | return r; |
2829 | 0 | } |
2830 | | |
2831 | | |
2832 | | static int |
2833 | | epass2003_write_key(struct sc_card *card, sc_epass2003_wkey_data * data) |
2834 | 0 | { |
2835 | 0 | LOG_FUNC_CALLED(card->ctx); |
2836 | |
|
2837 | 0 | if (data->type & SC_EPASS2003_KEY) { |
2838 | 0 | if (data->type == SC_EPASS2003_KEY_RSA) |
2839 | 0 | return internal_write_rsa_key(card, data->key_data.es_key.fid, |
2840 | 0 | data->key_data.es_key.rsa); |
2841 | 0 | else |
2842 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2843 | 0 | } else if (data->type & SC_EPASS2003_SECRET) { |
2844 | 0 | if (data->type == SC_EPASS2003_SECRET_PRE) |
2845 | 0 | return internal_install_pre(card); |
2846 | 0 | else if (data->type == SC_EPASS2003_SECRET_PIN) |
2847 | 0 | return internal_install_pin(card, data); |
2848 | 0 | else |
2849 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2850 | 0 | } else { |
2851 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2852 | 0 | } |
2853 | | |
2854 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2855 | 0 | } |
2856 | | |
2857 | | |
2858 | | static int |
2859 | | epass2003_gen_key(struct sc_card *card, sc_epass2003_gen_key_data * data) |
2860 | 0 | { |
2861 | 0 | int r; |
2862 | 0 | size_t len = data->key_length; |
2863 | 0 | struct sc_apdu apdu; |
2864 | 0 | u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0}; |
2865 | 0 | u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0}; |
2866 | |
|
2867 | 0 | LOG_FUNC_CALLED(card->ctx); |
2868 | |
|
2869 | 0 | if (len == 256) { |
2870 | 0 | sbuf[0] = 0x02; |
2871 | 0 | } else { |
2872 | 0 | sbuf[0] = 0x01; |
2873 | 0 | } |
2874 | 0 | sbuf[1] = (u8) ((len >> 8) & 0xff); |
2875 | 0 | sbuf[2] = (u8) (len & 0xff); |
2876 | 0 | sbuf[3] = (u8) ((data->prkey_id >> 8) & 0xFF); |
2877 | 0 | sbuf[4] = (u8) ((data->prkey_id) & 0xFF); |
2878 | 0 | sbuf[5] = (u8) ((data->pukey_id >> 8) & 0xFF); |
2879 | 0 | sbuf[6] = (u8) ((data->pukey_id) & 0xFF); |
2880 | | |
2881 | | /* generate key */ |
2882 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00); |
2883 | 0 | apdu.lc = apdu.datalen = 7; |
2884 | 0 | apdu.data = sbuf; |
2885 | |
|
2886 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2887 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2888 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2889 | 0 | LOG_TEST_RET(card->ctx, r, "generate key pair failed"); |
2890 | | |
2891 | | /* read public key */ |
2892 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xb4, 0x02, 0x00); |
2893 | 0 | if (len == 256) { |
2894 | 0 | apdu.p1 = 0x00; |
2895 | 0 | } |
2896 | |
|
2897 | 0 | apdu.cla = 0x80; |
2898 | 0 | apdu.lc = apdu.datalen = 2; |
2899 | 0 | apdu.data = &sbuf[5]; |
2900 | 0 | apdu.resp = rbuf; |
2901 | 0 | apdu.resplen = sizeof(rbuf); |
2902 | 0 | apdu.le = 0x00; |
2903 | |
|
2904 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
2905 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
2906 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2907 | 0 | LOG_TEST_RET(card->ctx, r, "get pukey failed"); |
2908 | | |
2909 | 0 | if (len < apdu.resplen) |
2910 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2911 | | |
2912 | 0 | if (256 == len) { /* ECC 256 bit */ |
2913 | 0 | size_t xCoordinateLen = rbuf[1]; |
2914 | 0 | size_t yCoordinateLen; |
2915 | 0 | unsigned char *tmp; |
2916 | |
|
2917 | 0 | if (2 + xCoordinateLen + 1 > apdu.resplen) { |
2918 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); |
2919 | 0 | } |
2920 | 0 | yCoordinateLen = rbuf[2 + xCoordinateLen + 1]; |
2921 | 0 | if (2 + xCoordinateLen + 2 + yCoordinateLen > apdu.resplen) { |
2922 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA); |
2923 | 0 | } |
2924 | 0 | data->modulus_len = xCoordinateLen + yCoordinateLen; |
2925 | 0 | tmp = (u8 *)malloc(data->modulus_len); |
2926 | 0 | if (!tmp) { |
2927 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
2928 | 0 | } |
2929 | | |
2930 | 0 | if (0x58 == rbuf[0]) { |
2931 | 0 | memcpy(tmp, &rbuf[2], xCoordinateLen); |
2932 | 0 | } else { |
2933 | 0 | free(tmp); |
2934 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_VALID); |
2935 | 0 | } |
2936 | 0 | if (0x59 == rbuf[2 + xCoordinateLen]) { |
2937 | 0 | memcpy(tmp + xCoordinateLen, &rbuf[2+xCoordinateLen+2], yCoordinateLen); |
2938 | 0 | } else { |
2939 | 0 | free(tmp); |
2940 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_VALID); |
2941 | 0 | } |
2942 | | |
2943 | 0 | data->modulus = tmp; |
2944 | 0 | } else { |
2945 | 0 | data->modulus = (u8 *) malloc(len); |
2946 | 0 | if (!data->modulus) { |
2947 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
2948 | 0 | } else { |
2949 | 0 | memcpy(data->modulus, rbuf, len); |
2950 | 0 | } |
2951 | 0 | } |
2952 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
2953 | 0 | } |
2954 | | |
2955 | | |
2956 | | static int |
2957 | | epass2003_erase_card(struct sc_card *card) |
2958 | 0 | { |
2959 | 0 | static const unsigned char install_magic_pin[26] = { |
2960 | | /* compare install_secret_key */ |
2961 | 0 | 0x06, 0x01, 0x10, 0x16, 0x16, 0x16, 0x00, 0x0f, 0xff, 0x66, |
2962 | 0 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2963 | 0 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2964 | 0 | }; |
2965 | 0 | static const unsigned char magic_pin[16] = { |
2966 | 0 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2967 | 0 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
2968 | 0 | }; |
2969 | 0 | static const unsigned char mf_path[2] = { 0x3f, 0x00 }; |
2970 | 0 | sc_apdu_t apdu; |
2971 | 0 | int r; |
2972 | |
|
2973 | 0 | LOG_FUNC_CALLED(card->ctx); |
2974 | | |
2975 | | /* install magic pin */ |
2976 | 0 | sc_format_apdu(card, &apdu, 0x03, 0xe3, 0x00, 0x00); |
2977 | 0 | apdu.cla = 0x80; |
2978 | 0 | apdu.data = install_magic_pin; |
2979 | 0 | apdu.datalen = apdu.lc = sizeof(install_magic_pin); |
2980 | 0 | r = sc_transmit_apdu(card, &apdu); |
2981 | 0 | LOG_TEST_RET(card->ctx, r, "APDU install magic pin failed"); |
2982 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2983 | 0 | LOG_TEST_RET(card->ctx, r, "install magic pin failed"); |
2984 | | |
2985 | | /* verify magic pin */ |
2986 | 0 | sc_format_apdu(card, &apdu, 0x03, 0x20, 0x00, 0x01); |
2987 | 0 | apdu.cla = 0; |
2988 | 0 | apdu.data = magic_pin; |
2989 | 0 | apdu.datalen = apdu.lc = sizeof(magic_pin); |
2990 | 0 | r = sc_transmit_apdu(card, &apdu); |
2991 | 0 | LOG_TEST_RET(card->ctx, r, "APDU verify magic pin failed"); |
2992 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
2993 | 0 | LOG_TEST_RET(card->ctx, r, "verify magic pin failed"); |
2994 | | |
2995 | | /* delete MF */ |
2996 | 0 | sc_format_apdu(card, &apdu, 0x03, 0xe4, 0x00, 0x00); |
2997 | 0 | apdu.cla = 0; |
2998 | 0 | apdu.data = mf_path; |
2999 | 0 | apdu.datalen = apdu.lc = sizeof(mf_path); |
3000 | 0 | r = sc_transmit_apdu(card, &apdu); |
3001 | 0 | LOG_TEST_RET(card->ctx, r, "APDU delete MF failed"); |
3002 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
3003 | 0 | LOG_TEST_RET(card->ctx, r, "delete MF failed"); |
3004 | | |
3005 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
3006 | 0 | } |
3007 | | |
3008 | | |
3009 | | static int |
3010 | | epass2003_get_serialnr(struct sc_card *card, sc_serial_number_t * serial) |
3011 | 0 | { |
3012 | 0 | u8 rbuf[8]; |
3013 | 0 | size_t rbuf_len = sizeof(rbuf); |
3014 | |
|
3015 | 0 | LOG_FUNC_CALLED(card->ctx); |
3016 | |
|
3017 | 0 | if (SC_SUCCESS != get_data(card, 0x80, rbuf, rbuf_len)) |
3018 | 0 | return SC_ERROR_CARD_CMD_FAILED; |
3019 | | |
3020 | 0 | card->serialnr.len = serial->len = 8; |
3021 | 0 | memcpy(card->serialnr.value, rbuf, 8); |
3022 | 0 | memcpy(serial->value, rbuf, 8); |
3023 | |
|
3024 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
3025 | 0 | } |
3026 | | |
3027 | | |
3028 | | static int |
3029 | | epass2003_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr) |
3030 | 0 | { |
3031 | 0 | LOG_FUNC_CALLED(card->ctx); |
3032 | |
|
3033 | 0 | sc_log(card->ctx, "cmd is %0lx", cmd); |
3034 | 0 | switch (cmd) { |
3035 | 0 | case SC_CARDCTL_ENTERSAFE_WRITE_KEY: |
3036 | 0 | return epass2003_write_key(card, (sc_epass2003_wkey_data *) ptr); |
3037 | 0 | case SC_CARDCTL_ENTERSAFE_GENERATE_KEY: |
3038 | 0 | return epass2003_gen_key(card, (sc_epass2003_gen_key_data *) ptr); |
3039 | 0 | case SC_CARDCTL_ERASE_CARD: |
3040 | 0 | return epass2003_erase_card(card); |
3041 | 0 | case SC_CARDCTL_GET_SERIALNR: |
3042 | 0 | return epass2003_get_serialnr(card, (sc_serial_number_t *) ptr); |
3043 | 0 | default: |
3044 | 0 | return SC_ERROR_NOT_SUPPORTED; |
3045 | 0 | } |
3046 | 0 | } |
3047 | | |
3048 | | |
3049 | | static void |
3050 | | internal_sanitize_pin_info(struct sc_pin_cmd_pin *pin, unsigned int num) |
3051 | 0 | { |
3052 | 0 | pin->encoding = SC_PIN_ENCODING_ASCII; |
3053 | 0 | pin->min_length = 4; |
3054 | 0 | pin->max_length = 16; |
3055 | 0 | pin->pad_length = 16; |
3056 | 0 | pin->offset = 5 + num * 16; |
3057 | 0 | pin->pad_char = 0x00; |
3058 | 0 | } |
3059 | | |
3060 | | |
3061 | | static int |
3062 | | get_external_key_maxtries(struct sc_card *card, unsigned char *maxtries) |
3063 | 0 | { |
3064 | 0 | unsigned char maxcounter[2] = {0}; |
3065 | 0 | static const sc_path_t file_path = { |
3066 | 0 | {0x3f, 0x00, 0x50, 0x15, 0x9f, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 6, |
3067 | 0 | 0, |
3068 | 0 | 0, |
3069 | 0 | SC_PATH_TYPE_PATH, |
3070 | 0 | {{0}, 0} |
3071 | 0 | }; |
3072 | 0 | int ret; |
3073 | |
|
3074 | 0 | ret = sc_select_file(card, &file_path, NULL); |
3075 | 0 | LOG_TEST_RET(card->ctx, ret, "select max counter file failed"); |
3076 | | |
3077 | 0 | ret = sc_read_binary(card, 0, maxcounter, 2, 0); |
3078 | 0 | LOG_TEST_RET(card->ctx, ret, "read max counter file failed"); |
3079 | | |
3080 | 0 | *maxtries = maxcounter[0]; |
3081 | 0 | return SC_SUCCESS; |
3082 | 0 | } |
3083 | | |
3084 | | |
3085 | | static int |
3086 | | get_external_key_retries(struct sc_card *card, unsigned char kid, unsigned char *retries) |
3087 | 0 | { |
3088 | 0 | int r; |
3089 | 0 | struct sc_apdu apdu; |
3090 | 0 | unsigned char random[16] = {0}; |
3091 | |
|
3092 | 0 | r = sc_get_challenge(card, random, 8); |
3093 | 0 | LOG_TEST_RET(card->ctx, r, "get challenge get_external_key_retries failed"); |
3094 | | |
3095 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x82, 0x01, 0x80 | kid); |
3096 | 0 | apdu.resp = NULL; |
3097 | 0 | apdu.resplen = 0; |
3098 | |
|
3099 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
3100 | 0 | LOG_TEST_RET(card->ctx, r, "APDU get_external_key_retries failed"); |
3101 | | |
3102 | 0 | if (retries && ((0x63 == (apdu.sw1 & 0xff)) && (0xC0 == (apdu.sw2 & 0xf0)))) { |
3103 | 0 | *retries = (apdu.sw2 & 0x0f); |
3104 | 0 | r = SC_SUCCESS; |
3105 | 0 | } else { |
3106 | 0 | LOG_TEST_RET(card->ctx, r, "get_external_key_retries failed"); |
3107 | 0 | r = SC_ERROR_CARD_CMD_FAILED; |
3108 | 0 | } |
3109 | | |
3110 | 0 | return r; |
3111 | 0 | } |
3112 | | |
3113 | | static int |
3114 | | epass2003_get_challenge(sc_card_t *card, u8 *rnd, size_t len) |
3115 | 0 | { |
3116 | 0 | u8 rbuf[16]; |
3117 | 0 | size_t out_len; |
3118 | 0 | int r; |
3119 | |
|
3120 | 0 | LOG_FUNC_CALLED(card->ctx); |
3121 | |
|
3122 | 0 | r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); |
3123 | 0 | LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); |
3124 | | |
3125 | 0 | if (len < (size_t) r) { |
3126 | 0 | out_len = len; |
3127 | 0 | } else { |
3128 | 0 | out_len = (size_t) r; |
3129 | 0 | } |
3130 | 0 | memcpy(rnd, rbuf, out_len); |
3131 | |
|
3132 | 0 | LOG_FUNC_RETURN(card->ctx, (int) out_len); |
3133 | 0 | } |
3134 | | |
3135 | | |
3136 | | static int |
3137 | | external_key_auth(struct sc_card *card, unsigned char kid, |
3138 | | unsigned char *data, size_t datalen) |
3139 | 0 | { |
3140 | 0 | int r; |
3141 | 0 | struct sc_apdu apdu; |
3142 | 0 | unsigned char random[16] = {0}; |
3143 | 0 | unsigned char tmp_data[16] = {0}; |
3144 | 0 | unsigned char hash[HASH_LEN] = {0}; |
3145 | 0 | unsigned char iv[16] = {0}; |
3146 | |
|
3147 | 0 | r = sc_get_challenge(card, random, 8); |
3148 | 0 | LOG_TEST_RET(card->ctx, r, "get challenge external_key_auth failed"); |
3149 | | |
3150 | 0 | r = hash_data(card, data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); |
3151 | 0 | LOG_TEST_RET(card->ctx, r, "hash data failed"); |
3152 | | |
3153 | 0 | r = des3_encrypt_cbc(card, hash, HASH_LEN, iv, random, 8, tmp_data); |
3154 | 0 | LOG_TEST_RET(card->ctx, r, "encryption failed"); |
3155 | | |
3156 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x01, 0x80 | kid); |
3157 | 0 | apdu.lc = apdu.datalen = 8; |
3158 | 0 | apdu.data = tmp_data; |
3159 | |
|
3160 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
3161 | 0 | LOG_TEST_RET(card->ctx, r, "APDU external_key_auth failed"); |
3162 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
3163 | 0 | LOG_TEST_RET(card->ctx, r, "external_key_auth failed"); |
3164 | | |
3165 | 0 | return r; |
3166 | 0 | } |
3167 | | |
3168 | | |
3169 | | static int |
3170 | | update_secret_key(struct sc_card *card, unsigned char ktype, unsigned char kid, |
3171 | | const unsigned char *data, unsigned long datalen) |
3172 | 0 | { |
3173 | 0 | int r; |
3174 | 0 | struct sc_apdu apdu; |
3175 | 0 | unsigned char hash[HASH_LEN] = {0}; |
3176 | 0 | unsigned char tmp_data[256] = {0}; |
3177 | 0 | unsigned char maxtries = 0; |
3178 | |
|
3179 | 0 | r = hash_data(card, data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); |
3180 | 0 | LOG_TEST_RET(card->ctx, r, "hash data failed"); |
3181 | | |
3182 | 0 | r = get_external_key_maxtries(card, &maxtries); |
3183 | 0 | LOG_TEST_RET(card->ctx, r, "get max counter failed"); |
3184 | | |
3185 | 0 | tmp_data[0] = (maxtries << 4) | maxtries; |
3186 | 0 | memcpy(&tmp_data[1], hash, HASH_LEN); |
3187 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xe5, ktype, kid); |
3188 | 0 | apdu.cla = 0x80; |
3189 | 0 | apdu.lc = apdu.datalen = 1 + HASH_LEN; |
3190 | 0 | apdu.data = tmp_data; |
3191 | |
|
3192 | 0 | r = sc_transmit_apdu_t(card, &apdu); |
3193 | 0 | LOG_TEST_RET(card->ctx, r, "APDU update_secret_key failed"); |
3194 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
3195 | 0 | LOG_TEST_RET(card->ctx, r, "update_secret_key failed"); |
3196 | | |
3197 | 0 | return r; |
3198 | 0 | } |
3199 | | |
3200 | | /* use external auth secret as pin */ |
3201 | | static int |
3202 | | epass2003_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data) |
3203 | 0 | { |
3204 | 0 | int r; |
3205 | 0 | u8 kid; |
3206 | 0 | u8 retries = 0; |
3207 | 0 | u8 pin_low = 3; |
3208 | 0 | unsigned char maxtries = 0; |
3209 | |
|
3210 | 0 | LOG_FUNC_CALLED(card->ctx); |
3211 | |
|
3212 | 0 | internal_sanitize_pin_info(&data->pin1, 0); |
3213 | 0 | internal_sanitize_pin_info(&data->pin2, 1); |
3214 | 0 | data->flags |= SC_PIN_CMD_NEED_PADDING; |
3215 | 0 | kid = data->pin_reference; |
3216 | |
|
3217 | 0 | if (NULL == (unsigned char *)data->pin1.data || 0 == data->pin1.len) |
3218 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT); |
3219 | | |
3220 | | /* get pin retries */ |
3221 | 0 | if (data->cmd == SC_PIN_CMD_GET_INFO) { |
3222 | |
|
3223 | 0 | r = get_external_key_retries(card, 0x80 | kid, &retries); |
3224 | 0 | if (r == SC_SUCCESS) { |
3225 | 0 | data->pin1.tries_left = retries; |
3226 | |
|
3227 | 0 | r = get_external_key_maxtries(card, &maxtries); |
3228 | 0 | LOG_TEST_RET(card->ctx, r, "get max counter failed"); |
3229 | | |
3230 | 0 | data->pin1.max_tries = maxtries; |
3231 | 0 | } |
3232 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3233 | 0 | } else if (data->cmd == SC_PIN_CMD_UNBLOCK) { /* verify */ |
3234 | 0 | r = external_key_auth(card, (kid + 1), (unsigned char *)data->pin1.data, |
3235 | 0 | data->pin1.len); |
3236 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3237 | 0 | } else if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) { /* change */ |
3238 | 0 | r = external_key_auth(card, kid, (unsigned char *)data->pin1.data, |
3239 | 0 | data->pin1.len); |
3240 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3241 | | |
3242 | 0 | r = update_secret_key(card, 0x04, kid, data->pin2.data, |
3243 | 0 | (unsigned long)data->pin2.len); |
3244 | 0 | LOG_TEST_RET(card->ctx, r, "change pin failed"); |
3245 | 0 | } else { |
3246 | 0 | r = external_key_auth(card, kid, (unsigned char *)data->pin1.data, |
3247 | 0 | data->pin1.len); |
3248 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3249 | | |
3250 | 0 | r = get_external_key_retries(card, 0x80 | kid, &retries); |
3251 | 0 | if (retries < pin_low) |
3252 | 0 | sc_log(card->ctx, "Verification failed (remaining tries: %d)", retries); |
3253 | |
|
3254 | 0 | LOG_TEST_RET(card->ctx, r, "verify pin failed"); |
3255 | 0 | } |
3256 | | |
3257 | 0 | if (r == SC_SUCCESS) { |
3258 | 0 | data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN; |
3259 | 0 | } |
3260 | 0 | return r; |
3261 | 0 | } |
3262 | | |
3263 | | static int |
3264 | | epass2003_logout(struct sc_card *card) |
3265 | 0 | { |
3266 | 0 | epass2003_exdata *exdata = NULL; |
3267 | |
|
3268 | 0 | if (!card->drv_data) |
3269 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
3270 | | |
3271 | 0 | exdata = (epass2003_exdata *)card->drv_data; |
3272 | 0 | if (exdata->sm) { |
3273 | 0 | sc_sm_stop(card); |
3274 | 0 | return epass2003_refresh(card); |
3275 | 0 | } |
3276 | | |
3277 | 0 | return SC_ERROR_NOT_SUPPORTED; |
3278 | 0 | } |
3279 | | |
3280 | | static struct sc_card_driver *sc_get_driver(void) |
3281 | 291 | { |
3282 | 291 | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
3283 | | |
3284 | 291 | if (iso_ops == NULL) |
3285 | 1 | iso_ops = iso_drv->ops; |
3286 | | |
3287 | 291 | epass2003_ops = *iso_ops; |
3288 | | |
3289 | 291 | epass2003_ops.match_card = epass2003_match_card; |
3290 | 291 | epass2003_ops.init = epass2003_init; |
3291 | 291 | epass2003_ops.finish = epass2003_finish; |
3292 | 291 | epass2003_ops.write_binary = NULL; |
3293 | 291 | epass2003_ops.write_record = NULL; |
3294 | 291 | epass2003_ops.select_file = epass2003_select_file; |
3295 | 291 | epass2003_ops.get_response = NULL; |
3296 | 291 | epass2003_ops.restore_security_env = epass2003_restore_security_env; |
3297 | 291 | epass2003_ops.set_security_env = epass2003_set_security_env; |
3298 | 291 | epass2003_ops.decipher = epass2003_decipher; |
3299 | 291 | epass2003_ops.compute_signature = epass2003_decipher; |
3300 | 291 | epass2003_ops.create_file = epass2003_create_file; |
3301 | 291 | epass2003_ops.delete_file = epass2003_delete_file; |
3302 | 291 | epass2003_ops.list_files = epass2003_list_files; |
3303 | 291 | epass2003_ops.card_ctl = epass2003_card_ctl; |
3304 | 291 | epass2003_ops.process_fci = epass2003_process_fci; |
3305 | 291 | epass2003_ops.construct_fci = epass2003_construct_fci; |
3306 | 291 | epass2003_ops.pin_cmd = epass2003_pin_cmd; |
3307 | 291 | epass2003_ops.check_sw = epass2003_check_sw; |
3308 | 291 | epass2003_ops.get_challenge = epass2003_get_challenge; |
3309 | 291 | epass2003_ops.logout = epass2003_logout; |
3310 | 291 | return &epass2003_drv; |
3311 | 291 | } |
3312 | | |
3313 | | struct sc_card_driver *sc_get_epass2003_driver(void) |
3314 | 291 | { |
3315 | 291 | return sc_get_driver(); |
3316 | 291 | } |
3317 | | #endif /* #ifdef ENABLE_OPENSSL */ |
3318 | | #endif /* #ifdef ENABLE_SM */ |