/src/opensc/src/libopensc/card-entersafe.c
Line | Count | Source |
1 | | /* |
2 | | * This library is free software; you can redistribute it and/or |
3 | | * modify it under the terms of the GNU Lesser General Public |
4 | | * License as published by the Free Software Foundation; either |
5 | | * version 2.1 of the License, or (at your option) any later version. |
6 | | * |
7 | | * This library is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
10 | | * Lesser General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU Lesser General Public |
13 | | * License along with this library; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
15 | | */ |
16 | | |
17 | | /* Initially written by Weitao Sun (weitao@ftsafe.com) 2008 */ |
18 | | |
19 | | #ifdef HAVE_CONFIG_H |
20 | | #include "config.h" |
21 | | #endif |
22 | | #ifdef ENABLE_OPENSSL /* empty file without openssl */ |
23 | | |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | |
27 | | #include <openssl/evp.h> |
28 | | |
29 | | #include "internal.h" |
30 | | #include "asn1.h" |
31 | | #include "cardctl.h" |
32 | | |
33 | | static const struct sc_atr_table entersafe_atrs[] = { |
34 | | { |
35 | | "3b:0f:00:65:46:53:05:19:05:71:df:00:00:00:00:00:00", |
36 | | "ff:ff:ff:ff:ff:ff:ff:00:ff:ff:ff:00:00:00:00:00:00", |
37 | | "ePass3000", SC_CARD_TYPE_ENTERSAFE_3K, 0, NULL }, |
38 | | { |
39 | | "3b:9f:95:81:31:fe:9f:00:65:46:53:05:30:06:71:df:00:00:00:80:6a:82:5e", |
40 | | "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:FF:FF:FF:FF:FF:FF:00:00:00:00", |
41 | | "FTCOS/PK-01C", SC_CARD_TYPE_ENTERSAFE_FTCOS_PK_01C, 0, NULL }, |
42 | | { |
43 | | "3b:fc:18:00:00:81:31:80:45:90:67:46:4a:00:64:18:14:00:00:00:00:02", |
44 | | "ff:00:00:00:00:00:00:00:00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:00", |
45 | | "EJAVA/PK-01C", SC_CARD_TYPE_ENTERSAFE_EJAVA_PK_01C, 0, NULL }, |
46 | | { |
47 | | "3b:7c:18:00:00:90:67:46:4a:20:28:8c:58:00:00:00:00", |
48 | | "ff:00:00:00:00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff", |
49 | | "EJAVA/PK-01C-T0",SC_CARD_TYPE_ENTERSAFE_EJAVA_PK_01C_T0,0,NULL}, |
50 | | { |
51 | | "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:21:28:8C:58:00:00:00:00:B7", |
52 | | "ff:00:00:00:00:00:00:00:00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:00", |
53 | | "EJAVA/H10CR/PK-01C-T1",SC_CARD_TYPE_ENTERSAFE_EJAVA_H10CR_PK_01C_T1,0,NULL}, |
54 | | { |
55 | | "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:20:25:c3:30:00:00:00:00", |
56 | | "ff:00:00:00:00:00:00:00:00:ff:ff:ff:ff:00:00:00:00:00:00:00:00", |
57 | | "EJAVA/D11CR/PK-01C-T1",SC_CARD_TYPE_ENTERSAFE_EJAVA_D11CR_PK_01C_T1,0,NULL}, |
58 | | { |
59 | | "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:00:6A:04:24:00:00:00:00:20", |
60 | | "ff:00:00:00:00:00:00:00:00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:00", |
61 | | "EJAVA/C21C/PK-01C-T1",SC_CARD_TYPE_ENTERSAFE_EJAVA_C21C_PK_01C_T1,0,NULL}, |
62 | | { |
63 | | "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:00:68:08:04:00:00:00:00:0E", |
64 | | "ff:00:00:00:00:00:00:00:00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:00", |
65 | | "EJAVA/A22CR/PK-01C-T1",SC_CARD_TYPE_ENTERSAFE_EJAVA_A22CR_PK_01C_T1,0,NULL}, |
66 | | { |
67 | | "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:10:27:61:30:00:00:00:00:0C", |
68 | | "ff:00:00:00:00:00:00:00:00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:00", |
69 | | "EJAVA/A40CR/PK-01C-T1",SC_CARD_TYPE_ENTERSAFE_EJAVA_A40CR_PK_01C_T1,0,NULL}, |
70 | | { |
71 | | "3b:fc:18:00:00:81:31:80:45:90:67:46:4a:00:68:08:06:00:00:00:00:0c", |
72 | | "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:FF:FF:FF:FF:FF:FF:00:00:00", |
73 | | "FTCOS/PK-01C", SC_CARD_TYPE_ENTERSAFE_FTCOS_PK_01C, 0, NULL }, |
74 | | { NULL, NULL, NULL, 0, 0, NULL } |
75 | | }; |
76 | | |
77 | | static struct sc_card_operations entersafe_ops; |
78 | | static struct sc_card_operations *iso_ops = NULL; |
79 | | |
80 | | static struct sc_card_driver entersafe_drv = { |
81 | | "entersafe", |
82 | | "entersafe", |
83 | | &entersafe_ops, |
84 | | NULL, 0, NULL |
85 | | }; |
86 | | |
87 | | static u8 trans_code_3k[] = |
88 | | { |
89 | | 0x01, 0x02, 0x03, 0x04, |
90 | | 0x05, 0x06, 0x07, 0x08, |
91 | | }; |
92 | | |
93 | | static u8 trans_code_ftcos_pk_01c[] = |
94 | | { |
95 | | 0x92, 0x34, 0x2E, 0xEF, |
96 | | 0x23, 0x40, 0x4F, 0xD1, |
97 | | }; |
98 | | |
99 | | static u8 init_key[] = |
100 | | { |
101 | | 1, 2, 3, 4, |
102 | | 5, 6, 7, 8, |
103 | | 9, 10, 11, 12, |
104 | | 13, 14, 15, 16, |
105 | | }; |
106 | | |
107 | | static u8 key_maintain[] = |
108 | | { |
109 | | 0x12, 0x34, 0x56, 0x78, |
110 | | 0x21, 0x43, 0x65, 0x87, |
111 | | 0x11, 0x22, 0xaa, 0xbb, |
112 | | 0x33, 0x44, 0xcd, 0xef |
113 | | }; |
114 | | |
115 | | static void entersafe_reverse_buffer(u8* buff, size_t size) |
116 | 0 | { |
117 | 0 | u8 t; |
118 | 0 | u8 *end = buff + size - 1; |
119 | |
|
120 | 0 | while (buff < end) { |
121 | 0 | t = *buff; |
122 | 0 | *buff = *end; |
123 | 0 | *end = t; |
124 | 0 | ++buff; |
125 | 0 | --end; |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | | static int entersafe_select_file(sc_card_t *card, |
130 | | const sc_path_t *in_path, |
131 | | sc_file_t **file_out); |
132 | | |
133 | | /* the entersafe part */ |
134 | | static int entersafe_match_card(sc_card_t *card) |
135 | 9.77k | { |
136 | 9.77k | int i; |
137 | 9.77k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
138 | | |
139 | 9.77k | i = _sc_match_atr(card, entersafe_atrs, &card->type); |
140 | 9.77k | if (i < 0) |
141 | 9.61k | return 0; |
142 | | |
143 | 159 | return 1; |
144 | 9.77k | } |
145 | | |
146 | | static int entersafe_init(sc_card_t *card) |
147 | 159 | { |
148 | 159 | unsigned int flags; |
149 | | |
150 | 159 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
151 | | |
152 | 159 | card->name = "entersafe"; |
153 | 159 | card->cla = 0x00; |
154 | 159 | card->drv_data = NULL; |
155 | | |
156 | 159 | flags = SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE; |
157 | | |
158 | 159 | _sc_card_add_rsa_alg(card, 512, flags, 0); |
159 | 159 | _sc_card_add_rsa_alg(card, 768, flags, 0); |
160 | 159 | _sc_card_add_rsa_alg(card, 1024, flags, 0); |
161 | 159 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
162 | | |
163 | 159 | card->caps = SC_CARD_CAP_RNG; |
164 | | |
165 | | /* we need read_binary&friends with max 224 bytes per read */ |
166 | 159 | card->max_send_size = 224; |
167 | 159 | card->max_recv_size = 224; |
168 | 159 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
169 | 159 | } |
170 | | |
171 | | static int entersafe_gen_random(sc_card_t *card, u8 *buff, size_t size) |
172 | 0 | { |
173 | 0 | int r = SC_SUCCESS; |
174 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
175 | 0 | sc_apdu_t apdu; |
176 | |
|
177 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
178 | |
|
179 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); |
180 | 0 | apdu.resp = rbuf; |
181 | 0 | apdu.le = size; |
182 | 0 | apdu.resplen = sizeof(rbuf); |
183 | |
|
184 | 0 | r = sc_transmit_apdu(card, &apdu); |
185 | 0 | LOG_TEST_RET(card->ctx, r, "entersafe gen random failed"); |
186 | | |
187 | 0 | if (apdu.resplen != size) |
188 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
189 | 0 | memcpy(buff, rbuf, size); |
190 | |
|
191 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
192 | 0 | } |
193 | | |
194 | | static int entersafe_cipher_apdu(sc_card_t *card, sc_apdu_t *apdu, |
195 | | u8 *key, size_t keylen, |
196 | | u8 *buff, size_t buffsize) |
197 | 0 | { |
198 | 0 | EVP_CIPHER_CTX *ctx = NULL; |
199 | 0 | EVP_CIPHER *alg = NULL; |
200 | |
|
201 | 0 | u8 iv[8] = {0}; |
202 | 0 | int len; |
203 | |
|
204 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
205 | |
|
206 | 0 | assert(card); |
207 | 0 | assert(apdu); |
208 | 0 | assert(key); |
209 | 0 | assert(buff); |
210 | | |
211 | | /* padding as 0x80 0x00 0x00...... */ |
212 | 0 | memset(buff, 0, buffsize); |
213 | 0 | buff[0] = apdu->lc; |
214 | 0 | memcpy(buff + 1, apdu->data, apdu->lc); |
215 | 0 | buff[apdu->lc + 1] = 0x80; |
216 | |
|
217 | 0 | ctx = EVP_CIPHER_CTX_new(); |
218 | 0 | if (ctx == NULL) { |
219 | 0 | sc_log_openssl(card->ctx); |
220 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
221 | 0 | } |
222 | 0 | EVP_CIPHER_CTX_set_padding(ctx, 0); |
223 | |
|
224 | 0 | if (keylen == 8) { |
225 | 0 | alg = sc_evp_cipher(card->ctx, "DES-ECB"); |
226 | 0 | } else if (keylen == 16) { |
227 | 0 | alg = sc_evp_cipher(card->ctx, "DES-EDE"); |
228 | 0 | } else { |
229 | 0 | EVP_CIPHER_CTX_free(ctx); |
230 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
231 | 0 | } |
232 | | |
233 | 0 | if (EVP_EncryptInit_ex(ctx, alg, NULL, key, iv) != 1) { |
234 | 0 | sc_log_openssl(card->ctx); |
235 | 0 | sc_evp_cipher_free(alg); |
236 | 0 | EVP_CIPHER_CTX_free(ctx); |
237 | 0 | sc_log(card->ctx, "entersafe encryption error."); |
238 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
239 | 0 | } |
240 | | |
241 | 0 | len = (int)apdu->lc; |
242 | 0 | if (!EVP_EncryptUpdate(ctx, buff, &len, buff, (int)buffsize)) { |
243 | 0 | sc_log_openssl(card->ctx); |
244 | 0 | sc_evp_cipher_free(alg); |
245 | 0 | EVP_CIPHER_CTX_free(ctx); |
246 | 0 | sc_log(card->ctx, "entersafe encryption error."); |
247 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
248 | 0 | } |
249 | 0 | apdu->lc = len; |
250 | |
|
251 | 0 | sc_evp_cipher_free(alg); |
252 | 0 | EVP_CIPHER_CTX_free(ctx); |
253 | |
|
254 | 0 | if (apdu->lc != buffsize) { |
255 | 0 | sc_log(card->ctx, "entersafe build cipher apdu failed."); |
256 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INTERNAL); |
257 | 0 | } |
258 | | |
259 | 0 | apdu->data = buff; |
260 | 0 | apdu->datalen = apdu->lc; |
261 | |
|
262 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
263 | 0 | } |
264 | | |
265 | | static int entersafe_mac_apdu(sc_card_t *card, sc_apdu_t *apdu, |
266 | | u8 * key,size_t keylen, |
267 | | u8 * buff,size_t buffsize) |
268 | 0 | { |
269 | 0 | int r; |
270 | 0 | u8 iv[8]; |
271 | 0 | u8 *tmp = NULL, *tmp_rounded = NULL; |
272 | 0 | size_t tmpsize = 0, tmpsize_rounded = 0; |
273 | 0 | int outl = 0; |
274 | 0 | EVP_CIPHER_CTX *ctx = NULL; |
275 | 0 | EVP_CIPHER *alg = NULL; |
276 | |
|
277 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
278 | |
|
279 | 0 | assert(card); |
280 | 0 | assert(apdu); |
281 | 0 | assert(key); |
282 | 0 | assert(buff); |
283 | |
|
284 | 0 | if (apdu->cse != SC_APDU_CASE_3_SHORT) |
285 | 0 | return SC_ERROR_INTERNAL; |
286 | 0 | if (keylen != 8 && keylen != 16) |
287 | 0 | return SC_ERROR_INTERNAL; |
288 | | |
289 | 0 | r = entersafe_gen_random(card, iv, sizeof(iv)); |
290 | 0 | LOG_TEST_RET(card->ctx, r, "entersafe gen random failed"); |
291 | | |
292 | | /* encode the APDU in the buffer */ |
293 | 0 | if ((r = sc_apdu_get_octets(card->ctx, apdu, &tmp, &tmpsize, SC_PROTO_RAW)) != SC_SUCCESS) |
294 | 0 | goto out; |
295 | | |
296 | | /* round to 8 */ |
297 | 0 | tmpsize_rounded = (tmpsize / 8 + 1) * 8; |
298 | |
|
299 | 0 | tmp_rounded = malloc(tmpsize_rounded); |
300 | 0 | if (tmp_rounded == NULL) { |
301 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
302 | 0 | goto out; |
303 | 0 | } |
304 | | |
305 | | /* build content and padded buffer by 0x80 0x00 0x00..... */ |
306 | 0 | memset(tmp_rounded, 0, tmpsize_rounded); |
307 | 0 | memcpy(tmp_rounded, tmp, tmpsize); |
308 | 0 | tmp_rounded[4] += 4; |
309 | 0 | tmp_rounded[tmpsize] = 0x80; |
310 | | |
311 | | /* block_size-1 blocks*/ |
312 | 0 | ctx = EVP_CIPHER_CTX_new(); |
313 | 0 | if (ctx == NULL) { |
314 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
315 | 0 | sc_log_openssl(card->ctx); |
316 | 0 | goto out; |
317 | 0 | } |
318 | 0 | EVP_CIPHER_CTX_set_padding(ctx, 0); |
319 | 0 | alg = sc_evp_cipher(card->ctx, "DES-CBC"); |
320 | 0 | if (!alg || |
321 | 0 | EVP_EncryptInit_ex(ctx, alg, NULL, key, iv) != 1) { |
322 | 0 | r = SC_ERROR_INTERNAL; |
323 | 0 | sc_log_openssl(card->ctx); |
324 | 0 | goto out; |
325 | 0 | } |
326 | | |
327 | 0 | if (tmpsize_rounded > 8) { |
328 | 0 | if (!EVP_EncryptUpdate(ctx, tmp_rounded, &outl, tmp_rounded, (int)tmpsize_rounded - 8)) { |
329 | 0 | r = SC_ERROR_INTERNAL; |
330 | 0 | sc_log_openssl(card->ctx); |
331 | 0 | goto out; |
332 | 0 | } |
333 | 0 | } |
334 | | /* last block */ |
335 | 0 | if (keylen == 8) { |
336 | 0 | if (!EVP_EncryptUpdate(ctx, tmp_rounded + outl, &outl, tmp_rounded + outl, 8)) { |
337 | 0 | r = SC_ERROR_INTERNAL; |
338 | 0 | sc_log_openssl(card->ctx); |
339 | 0 | goto out; |
340 | 0 | } |
341 | 0 | } else { |
342 | 0 | if (EVP_EncryptInit_ex(ctx, EVP_des_ede_cbc(), NULL, key, tmp_rounded + outl - 8) != 1 || |
343 | 0 | !EVP_EncryptUpdate(ctx, tmp_rounded + outl, &outl, tmp_rounded + outl, 8)) { |
344 | 0 | r = SC_ERROR_INTERNAL; |
345 | 0 | sc_log_openssl(card->ctx); |
346 | 0 | goto out; |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | 0 | memcpy(buff, apdu->data, apdu->lc); |
351 | | /* use first 4 bytes of last block as mac value*/ |
352 | 0 | memcpy(buff + apdu->lc, tmp_rounded + tmpsize_rounded - 8, 4); |
353 | 0 | apdu->data = buff; |
354 | 0 | apdu->lc += 4; |
355 | 0 | apdu->datalen = apdu->lc; |
356 | |
|
357 | 0 | out: |
358 | 0 | free(tmp); |
359 | 0 | free(tmp_rounded); |
360 | 0 | sc_evp_cipher_free(alg); |
361 | 0 | EVP_CIPHER_CTX_free(ctx); |
362 | |
|
363 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
364 | 0 | } |
365 | | |
366 | | static int entersafe_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu, |
367 | | u8 * key, size_t keylen, |
368 | | int cipher, int mac) |
369 | 2.76k | { |
370 | 2.76k | u8 *cipher_data = NULL, *mac_data = NULL; |
371 | 2.76k | size_t cipher_data_size, mac_data_size, blocks; |
372 | 2.76k | int r = SC_SUCCESS; |
373 | 2.76k | u8 *sbuf = NULL; |
374 | 2.76k | size_t ssize = 0; |
375 | | |
376 | 2.76k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
377 | | |
378 | 2.76k | assert(card); |
379 | 2.76k | assert(apdu); |
380 | | |
381 | 2.76k | if ((cipher || mac) && (!key || (keylen != 8 && keylen != 16))) |
382 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
383 | | |
384 | 2.76k | r = sc_apdu_get_octets(card->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW); |
385 | 2.76k | if (r == SC_SUCCESS) |
386 | 2.76k | sc_apdu_log(card->ctx, sbuf, ssize, 1); |
387 | 2.76k | if (sbuf) |
388 | 2.76k | free(sbuf); |
389 | | |
390 | 2.76k | if (cipher) { |
391 | 0 | blocks = (apdu->lc + 2) / 8 + 1; |
392 | 0 | cipher_data_size = blocks * 8; |
393 | 0 | cipher_data = malloc(cipher_data_size); |
394 | 0 | if (!cipher_data) { |
395 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
396 | 0 | goto out; |
397 | 0 | } |
398 | | |
399 | 0 | if ((r = entersafe_cipher_apdu(card, apdu, key, keylen, cipher_data, cipher_data_size)) < 0) |
400 | 0 | goto out; |
401 | 0 | } |
402 | 2.76k | if (mac) { |
403 | 0 | mac_data_size = apdu->lc + 4; |
404 | 0 | mac_data = malloc(mac_data_size); |
405 | 0 | if (!mac_data) { |
406 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
407 | 0 | goto out; |
408 | 0 | } |
409 | 0 | r = entersafe_mac_apdu(card, apdu, key, keylen, mac_data, mac_data_size); |
410 | 0 | if (r < 0) |
411 | 0 | goto out; |
412 | 0 | } |
413 | | |
414 | 2.76k | r = sc_transmit_apdu(card, apdu); |
415 | | |
416 | 2.76k | out: |
417 | 2.76k | free(cipher_data); |
418 | 2.76k | free(mac_data); |
419 | | |
420 | 2.76k | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
421 | 2.76k | } |
422 | | |
423 | | static int entersafe_read_binary(sc_card_t *card, |
424 | | unsigned int idx, u8 *buf, size_t count, |
425 | | unsigned long *flags) |
426 | 2.62k | { |
427 | 2.62k | sc_apdu_t apdu; |
428 | 2.62k | u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; |
429 | 2.62k | int r; |
430 | | |
431 | 2.62k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
432 | | |
433 | 2.62k | assert(count <= card->max_recv_size); |
434 | 2.62k | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, (idx >> 8) & 0xFF, idx & 0xFF); |
435 | | |
436 | 2.62k | apdu.cla = idx > 0x7fff ? 0x80 : 0x00; |
437 | 2.62k | apdu.le = count; |
438 | 2.62k | apdu.resplen = count; |
439 | 2.62k | apdu.resp = recvbuf; |
440 | | |
441 | 2.62k | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
442 | 2.62k | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
443 | 2.56k | if (apdu.resplen == 0) |
444 | 122 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
445 | 2.44k | memcpy(buf, recvbuf, apdu.resplen); |
446 | | |
447 | 2.44k | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)apdu.resplen); |
448 | 2.44k | } |
449 | | |
450 | | static int entersafe_update_binary(sc_card_t *card, |
451 | | unsigned int idx, const u8 *buf, |
452 | | size_t count, unsigned long flags) |
453 | 0 | { |
454 | 0 | sc_apdu_t apdu; |
455 | 0 | int r; |
456 | |
|
457 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
458 | |
|
459 | 0 | assert(count <= card->max_send_size); |
460 | |
|
461 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, (idx >> 8) & 0xFF, idx & 0xFF); |
462 | 0 | apdu.cla = idx > 0x7fff ? 0x80 : 0x00; |
463 | 0 | apdu.lc = count; |
464 | 0 | apdu.datalen = count; |
465 | 0 | apdu.data = buf; |
466 | |
|
467 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
468 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
469 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), |
470 | 0 | "Card returned error"); |
471 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)count); |
472 | 0 | } |
473 | | |
474 | | static int entersafe_process_fci(struct sc_card *card, struct sc_file *file, |
475 | | const u8 *buf, size_t buflen) |
476 | 395 | { |
477 | 395 | int r; |
478 | | |
479 | 395 | assert(file); |
480 | 395 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
481 | | |
482 | 395 | r = iso_ops->process_fci(card, file, buf, buflen); |
483 | 395 | LOG_TEST_RET(card->ctx, r, "Process fci failed"); |
484 | | |
485 | 395 | if (file->namelen) { |
486 | 72 | file->type = SC_FILE_TYPE_DF; |
487 | 72 | file->ef_structure = SC_FILE_EF_UNKNOWN; |
488 | 323 | } else { |
489 | 323 | file->type = SC_FILE_TYPE_WORKING_EF; |
490 | 323 | file->ef_structure = SC_FILE_EF_TRANSPARENT; |
491 | 323 | } |
492 | | |
493 | 395 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
494 | 395 | } |
495 | | |
496 | | static int entersafe_select_fid(sc_card_t *card, |
497 | | unsigned int id_hi, unsigned int id_lo, |
498 | | sc_file_t **file_out) |
499 | 894 | { |
500 | 894 | int r; |
501 | 894 | sc_file_t *file = NULL; |
502 | 894 | sc_path_t path; |
503 | | |
504 | 894 | memset(&path, 0, sizeof(sc_path_t)); |
505 | | |
506 | 894 | path.type = SC_PATH_TYPE_FILE_ID; |
507 | 894 | path.value[0] = id_hi; |
508 | 894 | path.value[1] = id_lo; |
509 | 894 | path.len = 2; |
510 | | |
511 | 894 | r = iso_ops->select_file(card, &path, &file); |
512 | 894 | if (r < 0) |
513 | 438 | sc_file_free(file); |
514 | 894 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
515 | | |
516 | 456 | if (file_out) |
517 | 204 | *file_out = file; |
518 | 252 | else |
519 | 252 | sc_file_free(file); |
520 | | |
521 | 456 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
522 | 456 | } |
523 | | |
524 | | static int entersafe_select_aid(sc_card_t *card, |
525 | | const sc_path_t *in_path, |
526 | | sc_file_t **file_out) |
527 | 258 | { |
528 | 258 | int r; |
529 | | |
530 | 258 | r = iso_ops->select_file(card, in_path, file_out); |
531 | 258 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
532 | | |
533 | 21 | if (file_out) { |
534 | 0 | sc_file_t *file = *file_out; |
535 | 0 | assert(file); |
536 | |
|
537 | 0 | file->type = SC_FILE_TYPE_DF; |
538 | 0 | file->ef_structure = SC_FILE_EF_UNKNOWN; |
539 | 0 | file->path.len = 0; |
540 | 0 | file->size = 0; |
541 | | /* AID */ |
542 | 0 | memcpy(file->name, in_path->value, in_path->len); |
543 | 0 | file->namelen = in_path->len; |
544 | 0 | file->id = 0x0000; |
545 | 0 | } |
546 | 21 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
547 | 21 | } |
548 | | |
549 | | static int entersafe_select_path(sc_card_t *card, |
550 | | const u8 pathbuf[16], const size_t len, |
551 | | sc_file_t **file_out) |
552 | 682 | { |
553 | 682 | u8 n_pathbuf[SC_MAX_PATH_SIZE]; |
554 | 682 | const u8 *path = pathbuf; |
555 | 682 | size_t pathlen = len; |
556 | 682 | unsigned int i; |
557 | 682 | int r; |
558 | | |
559 | 682 | if (pathlen % 2 != 0 || pathlen > 6 || pathlen <= 0) |
560 | 29 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
561 | | |
562 | | /* if pathlen == 6 then the first FID must be MF (== 3F00) */ |
563 | 653 | if (pathlen == 6 && (path[0] != 0x3f || path[1] != 0x00)) |
564 | 2 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
565 | | |
566 | | /* unify path (the first FID should be MF) */ |
567 | 651 | if (path[0] != 0x3f || path[1] != 0x00) { |
568 | 15 | n_pathbuf[0] = 0x3f; |
569 | 15 | n_pathbuf[1] = 0x00; |
570 | 15 | memcpy(n_pathbuf + 2, path, pathlen); |
571 | 15 | path = n_pathbuf; |
572 | 15 | pathlen += 2; |
573 | 15 | } |
574 | | |
575 | 893 | for (i = 0; i < pathlen - 2; i += 2) { |
576 | 655 | r = entersafe_select_fid(card, path[i], path[i + 1], NULL); |
577 | 655 | LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed"); |
578 | 655 | } |
579 | 238 | return entersafe_select_fid(card, path[pathlen - 2], path[pathlen - 1], file_out); |
580 | 651 | } |
581 | | |
582 | | static int entersafe_select_file(sc_card_t *card, |
583 | | const sc_path_t *in_path, |
584 | | sc_file_t **file_out) |
585 | 941 | { |
586 | 941 | assert(card); |
587 | 941 | assert(in_path); |
588 | 941 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
589 | | |
590 | 941 | switch (in_path->type) { |
591 | 1 | case SC_PATH_TYPE_FILE_ID: |
592 | 1 | if (in_path->len != 2) |
593 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
594 | 1 | return entersafe_select_fid(card,in_path->value[0], in_path->value[1], file_out); |
595 | 258 | case SC_PATH_TYPE_DF_NAME: |
596 | 258 | return entersafe_select_aid(card, in_path, file_out); |
597 | 682 | case SC_PATH_TYPE_PATH: |
598 | 682 | return entersafe_select_path(card, in_path->value, in_path->len, file_out); |
599 | 0 | default: |
600 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
601 | 941 | } |
602 | 941 | } |
603 | | |
604 | | static int entersafe_create_mf(sc_card_t *card, sc_entersafe_create_data *data) |
605 | 0 | { |
606 | 0 | int r; |
607 | 0 | sc_apdu_t apdu; |
608 | |
|
609 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
610 | |
|
611 | 0 | memcpy(data->data.df.init_key, init_key, sizeof(init_key)); |
612 | |
|
613 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); |
614 | 0 | apdu.cla = 0x84; |
615 | 0 | apdu.data = (u8 *)&data->data.df; |
616 | 0 | apdu.datalen = apdu.lc = sizeof(data->data.df); |
617 | |
|
618 | 0 | switch(card->type) { |
619 | 0 | case SC_CARD_TYPE_ENTERSAFE_3K: |
620 | 0 | r = entersafe_transmit_apdu(card, &apdu, trans_code_3k, sizeof(trans_code_3k), 0, 1); |
621 | 0 | break; |
622 | 0 | case SC_CARD_TYPE_ENTERSAFE_FTCOS_PK_01C: |
623 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_PK_01C: |
624 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_PK_01C_T0: |
625 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_H10CR_PK_01C_T1: |
626 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_D11CR_PK_01C_T1: |
627 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_C21C_PK_01C_T1: |
628 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_A22CR_PK_01C_T1: |
629 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_A40CR_PK_01C_T1: |
630 | 0 | r = entersafe_transmit_apdu(card, &apdu, trans_code_ftcos_pk_01c, sizeof(trans_code_ftcos_pk_01c), 0, 1); |
631 | 0 | break; |
632 | 0 | default: |
633 | 0 | r = SC_ERROR_INTERNAL; |
634 | 0 | break; |
635 | 0 | } |
636 | | |
637 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
638 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
639 | 0 | } |
640 | | |
641 | | static int entersafe_create_df(sc_card_t *card, sc_entersafe_create_data *data) |
642 | 0 | { |
643 | 0 | int r; |
644 | 0 | sc_apdu_t apdu; |
645 | |
|
646 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
647 | |
|
648 | 0 | memcpy(data->data.df.init_key, init_key, sizeof(init_key)); |
649 | |
|
650 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x01, 0x00); |
651 | 0 | apdu.cla = 0x84; |
652 | 0 | apdu.data = (u8 *)&data->data.df; |
653 | 0 | apdu.lc = apdu.datalen = sizeof(data->data.df); |
654 | |
|
655 | 0 | r = entersafe_transmit_apdu(card, &apdu,init_key,sizeof(init_key),0,1); |
656 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
657 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
658 | 0 | } |
659 | | |
660 | | static int entersafe_create_ef(sc_card_t *card, sc_entersafe_create_data *data) |
661 | 0 | { |
662 | 0 | int r; |
663 | 0 | sc_apdu_t apdu; |
664 | |
|
665 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
666 | |
|
667 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x02, 0x00); |
668 | 0 | apdu.cla = 0x84; |
669 | 0 | apdu.data = (u8*)&data->data.ef; |
670 | 0 | apdu.lc = apdu.datalen = sizeof(data->data.ef); |
671 | |
|
672 | 0 | r = entersafe_transmit_apdu(card, &apdu, init_key, sizeof(init_key), 0, 1); |
673 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
674 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
675 | 0 | } |
676 | | |
677 | | static u8 process_acl_entry(sc_file_t *in, unsigned int method, unsigned int in_def) |
678 | 0 | { |
679 | 0 | u8 def = (u8)in_def; |
680 | 0 | const sc_acl_entry_t *entry = sc_file_get_acl_entry(in, method); |
681 | 0 | if (!entry) { |
682 | 0 | return def; |
683 | 0 | } else if (entry->method & SC_AC_CHV) { |
684 | 0 | unsigned int key_ref = entry->key_ref; |
685 | 0 | if (key_ref == SC_AC_KEY_REF_NONE) |
686 | 0 | return def; |
687 | 0 | else |
688 | 0 | return ENTERSAFE_AC_ALWAYS&0x04; |
689 | 0 | } else if (entry->method & SC_AC_NEVER) { |
690 | 0 | return ENTERSAFE_AC_NEVER; |
691 | 0 | } |
692 | 0 | return def; |
693 | 0 | } |
694 | | |
695 | | static int entersafe_create_file(sc_card_t *card, sc_file_t *file) |
696 | 0 | { |
697 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
698 | |
|
699 | 0 | if (file->type == SC_FILE_TYPE_WORKING_EF) { |
700 | 0 | sc_entersafe_create_data data; |
701 | 0 | memset(&data, 0, sizeof(data)); |
702 | |
|
703 | 0 | data.data.ef.file_id[0] = (file->id >> 8) & 0xFF; |
704 | 0 | data.data.ef.file_id[1] = file->id & 0xFF; |
705 | 0 | data.data.ef.size[0] = (file->size >> 8) & 0xFF; |
706 | 0 | data.data.ef.size[1] = file->size & 0xFF; |
707 | 0 | memset(data.data.ef.ac, ENTERSAFE_AC_ALWAYS, sizeof(data.data.ef.ac)); |
708 | 0 | data.data.ef.ac[0] = process_acl_entry(file, SC_AC_OP_READ, ENTERSAFE_AC_ALWAYS); |
709 | 0 | data.data.ef.ac[1] = process_acl_entry(file, SC_AC_OP_UPDATE, ENTERSAFE_AC_ALWAYS); |
710 | |
|
711 | 0 | return entersafe_create_ef(card, &data); |
712 | 0 | } else { |
713 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
714 | 0 | } |
715 | 0 | } |
716 | | |
717 | | static int entersafe_internal_set_security_env(sc_card_t *card, |
718 | | const sc_security_env_t *env, |
719 | | u8 ** data,size_t* size) |
720 | 0 | { |
721 | 0 | sc_apdu_t apdu; |
722 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; |
723 | 0 | u8 *p = sbuf; |
724 | 0 | int r; |
725 | |
|
726 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
727 | |
|
728 | 0 | assert(card != NULL && env != NULL); |
729 | |
|
730 | 0 | switch (env->operation) { |
731 | 0 | case SC_SEC_OPERATION_DECIPHER: |
732 | 0 | case SC_SEC_OPERATION_SIGN: |
733 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0); |
734 | 0 | apdu.p1 = 0x41; |
735 | 0 | apdu.p2 = 0xB8; |
736 | 0 | *p++ = 0x80; |
737 | 0 | *p++ = 0x01; |
738 | 0 | *p++ = 0x80; |
739 | 0 | *p++ = 0x83; |
740 | 0 | *p++ = 0x02; |
741 | 0 | *p++ = env->key_ref[0]; |
742 | 0 | *p++ = 0x22; |
743 | 0 | if (*size > 1024 / 8) { |
744 | 0 | if (*size == 2048 / 8) { |
745 | 0 | *p++ = 0x89; |
746 | 0 | *p++ = 0x40; |
747 | 0 | memcpy(p, *data, 0x40); |
748 | 0 | p += 0x40; |
749 | 0 | *data += 0x40; |
750 | 0 | *size -= 0x40; |
751 | 0 | } else { |
752 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
753 | 0 | } |
754 | 0 | } |
755 | 0 | break; |
756 | 0 | default: |
757 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
758 | 0 | } |
759 | | |
760 | 0 | apdu.le = 0; |
761 | 0 | apdu.lc = apdu.datalen = p - sbuf; |
762 | 0 | apdu.data = sbuf; |
763 | 0 | apdu.resplen = 0; |
764 | |
|
765 | 0 | r = sc_transmit_apdu(card, &apdu); |
766 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
767 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
768 | 0 | } |
769 | | |
770 | | /** |
771 | | * We don't really set the security environment,but cache it.It will be set when |
772 | | * security operation is performed later.Because we may transport partial of |
773 | | * the sign/decipher data within the security environment apdu. |
774 | | */ |
775 | | static int entersafe_set_security_env(sc_card_t *card, |
776 | | const sc_security_env_t *env, |
777 | | int se_num) |
778 | 0 | { |
779 | 0 | assert(card); |
780 | 0 | assert(env); |
781 | |
|
782 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
783 | |
|
784 | 0 | if (card->drv_data) { |
785 | 0 | free(card->drv_data); |
786 | 0 | card->drv_data = 0; |
787 | 0 | } |
788 | |
|
789 | 0 | card->drv_data = calloc(1, sizeof(*env)); |
790 | 0 | if (!card->drv_data) |
791 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_OUT_OF_MEMORY); |
792 | | |
793 | 0 | memcpy(card->drv_data, env, sizeof(*env)); |
794 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
795 | 0 | } |
796 | | |
797 | | static int entersafe_restore_security_env(sc_card_t *card, int se_num) |
798 | 0 | { |
799 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
800 | 0 | return SC_SUCCESS; |
801 | 0 | } |
802 | | |
803 | | |
804 | | static int entersafe_compute_with_prkey(sc_card_t *card, |
805 | | const u8 *data, size_t datalen, |
806 | | u8 *out, size_t outlen) |
807 | 0 | { |
808 | 0 | int r; |
809 | 0 | sc_apdu_t apdu; |
810 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; |
811 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; |
812 | 0 | u8 *p = sbuf; |
813 | 0 | size_t size = datalen; |
814 | |
|
815 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
816 | |
|
817 | 0 | if (!data) |
818 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
819 | | |
820 | 0 | memcpy(p,data,size); |
821 | |
|
822 | 0 | if (!card->drv_data) |
823 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INTERNAL); |
824 | | |
825 | 0 | r = entersafe_internal_set_security_env(card, card->drv_data, &p, &size); |
826 | 0 | LOG_TEST_RET(card->ctx, r, "internal set security env failed"); |
827 | | |
828 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x86, 0x80); |
829 | 0 | apdu.data = p; |
830 | 0 | apdu.lc = size; |
831 | 0 | apdu.datalen = size; |
832 | 0 | apdu.resp = rbuf; |
833 | 0 | apdu.resplen = sizeof(rbuf); |
834 | 0 | apdu.le = 256; |
835 | |
|
836 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
837 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
838 | | |
839 | 0 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
840 | 0 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
841 | 0 | memcpy(out, apdu.resp, len); |
842 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len); |
843 | 0 | } |
844 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
845 | 0 | } |
846 | | |
847 | | static int entersafe_compute_signature(sc_card_t *card, |
848 | | const u8 * data, size_t datalen, |
849 | | u8 * out, size_t outlen) |
850 | 0 | { |
851 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
852 | 0 | return entersafe_compute_with_prkey(card, data, datalen, out, outlen); |
853 | 0 | } |
854 | | |
855 | | static int entersafe_decipher(sc_card_t *card, |
856 | | const u8 *crgram, size_t crgram_len, |
857 | | u8 *out, size_t outlen) |
858 | 0 | { |
859 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
860 | 0 | return entersafe_compute_with_prkey(card, crgram, crgram_len, out, outlen); |
861 | 0 | } |
862 | | |
863 | | static void entersafe_init_pin_info(struct sc_pin_cmd_pin *pin, unsigned int num) |
864 | 8 | { |
865 | 8 | pin->encoding = SC_PIN_ENCODING_ASCII; |
866 | 8 | pin->min_length = 4; |
867 | 8 | pin->max_length = 16; |
868 | 8 | pin->pad_length = 16; |
869 | 8 | pin->offset = 5 + num * 16; |
870 | 8 | pin->pad_char = 0x00; |
871 | 8 | } |
872 | | |
873 | | static int entersafe_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, |
874 | | int *tries_left) |
875 | 4 | { |
876 | 4 | int r; |
877 | 4 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
878 | 4 | entersafe_init_pin_info(&data->pin1, 0); |
879 | 4 | entersafe_init_pin_info(&data->pin2, 1); |
880 | 4 | data->flags |= SC_PIN_CMD_NEED_PADDING; |
881 | | |
882 | 4 | if (data->cmd != SC_PIN_CMD_UNBLOCK) { |
883 | 4 | r = iso_ops->pin_cmd(card, data, tries_left); |
884 | 4 | sc_log(card->ctx, "Verify rv:%i", r); |
885 | 4 | } else { |
886 | 0 | { /*verify*/ |
887 | 0 | sc_apdu_t apdu; |
888 | 0 | u8 sbuf[0x10] = {0}; |
889 | |
|
890 | 0 | memcpy(sbuf, data->pin1.data, data->pin1.len); |
891 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, data->pin_reference + 1); |
892 | 0 | apdu.lc = apdu.datalen = sizeof(sbuf); |
893 | 0 | apdu.data = sbuf; |
894 | |
|
895 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
896 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
897 | 0 | } |
898 | | |
899 | 0 | { /*change*/ |
900 | 0 | sc_apdu_t apdu; |
901 | 0 | u8 sbuf[0x12] = {0}; |
902 | |
|
903 | 0 | sbuf[0] = 0x33; |
904 | 0 | sbuf[1] = 0x00; |
905 | 0 | memcpy(sbuf + 2, data->pin2.data, data->pin2.len); |
906 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF4, 0x0B, data->pin_reference); |
907 | 0 | apdu.cla = 0x84; |
908 | 0 | apdu.lc = apdu.datalen = sizeof(sbuf); |
909 | 0 | apdu.data = sbuf; |
910 | |
|
911 | 0 | r = entersafe_transmit_apdu(card, &apdu, key_maintain, sizeof(key_maintain), 1, 1); |
912 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
913 | 0 | } |
914 | 0 | } |
915 | 4 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
916 | 4 | } |
917 | | |
918 | | static int entersafe_erase_card(sc_card_t *card) |
919 | 0 | { |
920 | 0 | int r; |
921 | 0 | u8 sbuf[2]; |
922 | 0 | sc_apdu_t apdu; |
923 | |
|
924 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
925 | |
|
926 | 0 | sbuf[0] = 0x3f; |
927 | 0 | sbuf[1] = 0x00; |
928 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x00); |
929 | 0 | apdu.lc = 2; |
930 | 0 | apdu.datalen = 2; |
931 | 0 | apdu.data = sbuf; |
932 | |
|
933 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
934 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
935 | | |
936 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xEE, 0x00, 0x00); |
937 | 0 | apdu.cla = 0x84; |
938 | 0 | apdu.lc = 2; |
939 | 0 | apdu.datalen = 2; |
940 | 0 | apdu.data = sbuf; |
941 | |
|
942 | 0 | switch(card->type) { |
943 | 0 | case SC_CARD_TYPE_ENTERSAFE_3K: |
944 | 0 | r = entersafe_transmit_apdu(card, &apdu, trans_code_3k, sizeof(trans_code_3k), 0, 1); |
945 | 0 | break; |
946 | 0 | case SC_CARD_TYPE_ENTERSAFE_FTCOS_PK_01C: |
947 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_PK_01C: |
948 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_PK_01C_T0: |
949 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_H10CR_PK_01C_T1: |
950 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_D11CR_PK_01C_T1: |
951 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_C21C_PK_01C_T1: |
952 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_A22CR_PK_01C_T1: |
953 | 0 | case SC_CARD_TYPE_ENTERSAFE_EJAVA_A40CR_PK_01C_T1: |
954 | 0 | r = entersafe_transmit_apdu(card, &apdu, trans_code_ftcos_pk_01c, sizeof(trans_code_ftcos_pk_01c), 0, 1); |
955 | 0 | break; |
956 | 0 | default: |
957 | 0 | r = SC_ERROR_INTERNAL; |
958 | 0 | break; |
959 | 0 | } |
960 | | |
961 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
962 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
963 | 0 | } |
964 | | |
965 | | static void entersafe_encode_bignum(u8 tag, sc_pkcs15_bignum_t bignum, u8 **ptr) |
966 | 0 | { |
967 | 0 | u8 *p = *ptr; |
968 | |
|
969 | 0 | *p++ = tag; |
970 | 0 | if (bignum.len < 128) { |
971 | 0 | *p++ = (u8)bignum.len; |
972 | 0 | } else { |
973 | 0 | u8 bytes = 1; |
974 | 0 | size_t len = bignum.len; |
975 | 0 | while (len) { |
976 | 0 | len = len >> 8; |
977 | 0 | ++bytes; |
978 | 0 | } |
979 | 0 | bytes &= 0x0F; |
980 | 0 | *p++ = 0x80 | bytes; |
981 | 0 | while (bytes) { |
982 | 0 | *p++ = bignum.len >> ((bytes - 1) * 8); |
983 | 0 | --bytes; |
984 | 0 | } |
985 | 0 | } |
986 | 0 | memcpy(p, bignum.data, bignum.len); |
987 | 0 | entersafe_reverse_buffer(p, bignum.len); |
988 | 0 | p += bignum.len; |
989 | 0 | *ptr = p; |
990 | 0 | } |
991 | | |
992 | | static int entersafe_write_small_rsa_key(sc_card_t *card, u8 key_id, struct sc_pkcs15_prkey_rsa *rsa) |
993 | 0 | { |
994 | 0 | sc_apdu_t apdu; |
995 | 0 | u8 sbuff[SC_MAX_APDU_BUFFER_SIZE]; |
996 | 0 | int r; |
997 | 0 | u8 *p = sbuff; |
998 | |
|
999 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1000 | |
|
1001 | 0 | { /* write prkey */ |
1002 | 0 | *p++ = 0x00; /* EC */ |
1003 | 0 | *p++ = 0x00; /* ver */ |
1004 | 0 | entersafe_encode_bignum('E', rsa->exponent, &p); |
1005 | 0 | entersafe_encode_bignum('D', rsa->d, &p); |
1006 | |
|
1007 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF4, 0x22, key_id); |
1008 | 0 | apdu.cla = 0x84; |
1009 | 0 | apdu.data = sbuff; |
1010 | 0 | apdu.lc = apdu.datalen = p - sbuff; |
1011 | |
|
1012 | 0 | r = entersafe_transmit_apdu(card, &apdu, key_maintain, sizeof(key_maintain), 1, 1); |
1013 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1014 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write prkey failed"); |
1015 | 0 | } |
1016 | | |
1017 | 0 | p = sbuff; |
1018 | 0 | { /* write pukey */ |
1019 | 0 | *p++ = 0x00; /* EC */ |
1020 | 0 | *p++ = 0x00; /* ver */ |
1021 | 0 | entersafe_encode_bignum('E', rsa->exponent, &p); |
1022 | 0 | entersafe_encode_bignum('N', rsa->modulus, &p); |
1023 | |
|
1024 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF4, 0x2A, key_id); |
1025 | 0 | apdu.cla = 0x84; |
1026 | 0 | apdu.data = sbuff; |
1027 | 0 | apdu.lc = apdu.datalen = p - sbuff; |
1028 | |
|
1029 | 0 | r = entersafe_transmit_apdu(card, &apdu, key_maintain, sizeof(key_maintain), 1, 1); |
1030 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1031 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write pukey failed"); |
1032 | 0 | } |
1033 | | |
1034 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1035 | 0 | } |
1036 | | |
1037 | | static int entersafe_write_rsa_key_factor(sc_card_t *card, |
1038 | | u8 key_id,u8 usage, |
1039 | | u8 factor, |
1040 | | sc_pkcs15_bignum_t data) |
1041 | 0 | { |
1042 | 0 | int r; |
1043 | 0 | sc_apdu_t apdu; |
1044 | |
|
1045 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1046 | |
|
1047 | 0 | { /* MSE */ |
1048 | 0 | u8 sbuff[4]; |
1049 | 0 | sbuff[0] = 0x84; |
1050 | 0 | sbuff[1] = 0x02; |
1051 | 0 | sbuff[2] = key_id; |
1052 | 0 | sbuff[3] = usage; |
1053 | |
|
1054 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x01, 0xB8); |
1055 | 0 | apdu.data = sbuff; |
1056 | 0 | apdu.lc = apdu.datalen = 4; |
1057 | |
|
1058 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1059 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1060 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write prkey factor failed(MSE)"); |
1061 | 0 | } |
1062 | | |
1063 | 0 | { /* Write 'x'; */ |
1064 | 0 | u8 sbuff[SC_MAX_APDU_BUFFER_SIZE]; |
1065 | |
|
1066 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, factor, 0x00); |
1067 | |
|
1068 | 0 | memcpy(sbuff, data.data, data.len); |
1069 | 0 | entersafe_reverse_buffer(sbuff, data.len); |
1070 | | /* |
1071 | | * PK01C and PK13C smart card only support 1024 or 2048bit key . |
1072 | | * Size of exponent1 exponent2 coefficient of RSA private key keep the same as size of prime1 |
1073 | | * So check factor is padded with zero or not |
1074 | | */ |
1075 | 0 | switch(factor) { |
1076 | 0 | case 0x3: |
1077 | 0 | case 0x4: |
1078 | 0 | case 0x5: { |
1079 | 0 | size_t i; |
1080 | 0 | if (data.len > 32 && data.len < 64) { |
1081 | 0 | for (i = data.len; i < 64; i++) |
1082 | 0 | sbuff[i] = 0; |
1083 | 0 | data.len = 64; |
1084 | 0 | } else if( data.len > 64 && data.len < 128 ) { |
1085 | 0 | for (i = data.len; i < 128; i++) |
1086 | 0 | sbuff[i] = 0; |
1087 | 0 | data.len = 128; |
1088 | 0 | } |
1089 | 0 | } |
1090 | 0 | break; |
1091 | 0 | default: |
1092 | 0 | break; |
1093 | 0 | } |
1094 | | |
1095 | 0 | apdu.data = sbuff; |
1096 | 0 | apdu.lc = apdu.datalen = data.len; |
1097 | |
|
1098 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1099 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1100 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write prkey factor failed"); |
1101 | 0 | } |
1102 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1103 | 0 | } |
1104 | | |
1105 | | static int entersafe_write_large_rsa_key(sc_card_t *card,u8 key_id,struct sc_pkcs15_prkey_rsa *rsa) |
1106 | 0 | { |
1107 | 0 | int r; |
1108 | |
|
1109 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1110 | |
|
1111 | 0 | { /* write prkey */ |
1112 | 0 | r = entersafe_write_rsa_key_factor(card, key_id, 0x22, 0x01, rsa->p); |
1113 | 0 | LOG_TEST_RET(card->ctx, r, "write p failed"); |
1114 | 0 | r = entersafe_write_rsa_key_factor(card, key_id, 0x22, 0x02, rsa->q); |
1115 | 0 | LOG_TEST_RET(card->ctx, r, "write q failed"); |
1116 | 0 | r = entersafe_write_rsa_key_factor(card, key_id, 0x22, 0x03, rsa->dmp1); |
1117 | 0 | LOG_TEST_RET(card->ctx, r, "write dmp1 failed"); |
1118 | 0 | r = entersafe_write_rsa_key_factor(card, key_id, 0x22, 0x04, rsa->dmq1); |
1119 | 0 | LOG_TEST_RET(card->ctx, r, "write dmq1 failed"); |
1120 | 0 | r = entersafe_write_rsa_key_factor(card, key_id, 0x22, 0x05, rsa->iqmp); |
1121 | 0 | LOG_TEST_RET(card->ctx, r, "write iqmp failed"); |
1122 | 0 | } |
1123 | | |
1124 | 0 | { /* write pukey */ |
1125 | 0 | u8 sbuff[SC_MAX_APDU_BUFFER_SIZE]; |
1126 | 0 | sc_apdu_t apdu; |
1127 | | |
1128 | | /* first 64(0x40) bytes of N */ |
1129 | 0 | sbuff[0] = 0x83; |
1130 | 0 | sbuff[1] = 0x02; |
1131 | 0 | sbuff[2] = key_id; |
1132 | 0 | sbuff[3] = 0x2A; |
1133 | 0 | sbuff[4] = 0x89; |
1134 | 0 | sbuff[5] = 0x40; |
1135 | 0 | memcpy(sbuff + 6, rsa->modulus.data, 0x40); |
1136 | |
|
1137 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x01, 0xB8); |
1138 | 0 | apdu.data = sbuff; |
1139 | 0 | apdu.lc = apdu.datalen = 0x46; |
1140 | |
|
1141 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1142 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1143 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write pukey N(1) failed"); |
1144 | | |
1145 | | /* left 192(0xC0) bytes of N */ |
1146 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x0B, 0x00); |
1147 | 0 | apdu.data = rsa->modulus.data + 0x40; |
1148 | 0 | apdu.lc = apdu.datalen = 0xC0; |
1149 | |
|
1150 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1151 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1152 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write pukey N(2) failed"); |
1153 | | |
1154 | | /* E */ |
1155 | 0 | r = entersafe_write_rsa_key_factor(card, key_id, 0x2A, 0x0D, rsa->exponent); |
1156 | 0 | LOG_TEST_RET(card->ctx, r, "write exponent failed"); |
1157 | 0 | } |
1158 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1159 | 0 | } |
1160 | | |
1161 | | static int entersafe_write_symmetric_key(sc_card_t *card, |
1162 | | u8 key_id, u8 usage, |
1163 | | u8 EC, u8 ver, |
1164 | | u8 *data, size_t len) |
1165 | 0 | { |
1166 | 0 | sc_apdu_t apdu; |
1167 | 0 | u8 sbuff[SC_MAX_APDU_BUFFER_SIZE] = {0}; |
1168 | 0 | int r; |
1169 | |
|
1170 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1171 | |
|
1172 | 0 | if (len > 240) |
1173 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INCORRECT_PARAMETERS); |
1174 | | |
1175 | 0 | sbuff[0] = EC; |
1176 | 0 | sbuff[1] = ver; |
1177 | 0 | memcpy(&sbuff[2], data, len); |
1178 | |
|
1179 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF4, usage, key_id); |
1180 | 0 | apdu.cla = 0x84; |
1181 | 0 | apdu.data = sbuff; |
1182 | 0 | apdu.lc = apdu.datalen = len + 2; |
1183 | |
|
1184 | 0 | r = entersafe_transmit_apdu(card, &apdu, key_maintain, sizeof(key_maintain), 1, 1); |
1185 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1186 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Write prkey failed"); |
1187 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
1188 | 0 | } |
1189 | | |
1190 | | static int entersafe_write_key(sc_card_t *card, sc_entersafe_wkey_data *data) |
1191 | 0 | { |
1192 | 0 | struct sc_pkcs15_prkey_rsa *rsa = data->key_data.rsa; |
1193 | |
|
1194 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1195 | |
|
1196 | 0 | switch(data->usage) { |
1197 | 0 | case 0x22: |
1198 | 0 | if(rsa->modulus.len < 256) |
1199 | 0 | return entersafe_write_small_rsa_key(card,data->key_id, rsa); |
1200 | 0 | else |
1201 | 0 | return entersafe_write_large_rsa_key(card,data->key_id, rsa); |
1202 | 0 | break; |
1203 | 0 | case 0x2A: |
1204 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
1205 | 0 | break; |
1206 | 0 | default: |
1207 | 0 | return entersafe_write_symmetric_key(card,data->key_id,data->usage, |
1208 | 0 | data->key_data.symmetric.EC, |
1209 | 0 | data->key_data.symmetric.ver, |
1210 | 0 | data->key_data.symmetric.key_val, |
1211 | 0 | data->key_data.symmetric.key_len); |
1212 | 0 | break; |
1213 | 0 | } |
1214 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1215 | 0 | } |
1216 | | |
1217 | | static int entersafe_gen_key(sc_card_t *card, sc_entersafe_gen_key_data *data) |
1218 | 0 | { |
1219 | 0 | int r; |
1220 | 0 | size_t len = data->key_length >> 3; |
1221 | 0 | sc_apdu_t apdu; |
1222 | 0 | u8 rbuf[300] = {0}; |
1223 | 0 | u8 sbuf[4], *p; |
1224 | 0 | size_t plen = 0; |
1225 | |
|
1226 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1227 | | |
1228 | | /* MSE */ |
1229 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x01, 0xB8); |
1230 | 0 | apdu.lc = 0x04; |
1231 | 0 | sbuf[0] = 0x83; |
1232 | 0 | sbuf[1] = 0x02; |
1233 | 0 | sbuf[2] = data->key_id; |
1234 | 0 | sbuf[3] = 0x2A; |
1235 | 0 | apdu.data = sbuf; |
1236 | 0 | apdu.datalen = 4; |
1237 | 0 | apdu.lc = 4; |
1238 | 0 | apdu.le = 0; |
1239 | |
|
1240 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1241 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1242 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "EnterSafe set MSE failed"); |
1243 | | |
1244 | | /* generate key */ |
1245 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00); |
1246 | 0 | apdu.le = 0; |
1247 | 0 | sbuf[0] = (u8)(data->key_length >> 8); |
1248 | 0 | sbuf[1] = (u8)(data->key_length); |
1249 | 0 | apdu.data = sbuf; |
1250 | 0 | apdu.lc = 2; |
1251 | 0 | apdu.datalen = 2; |
1252 | |
|
1253 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1254 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1255 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "EnterSafe generate key pair failed"); |
1256 | | |
1257 | | /* read public key via READ PUBLIC KEY */ |
1258 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xE6, 0x2A, data->key_id); |
1259 | 0 | apdu.cla = 0x80; |
1260 | 0 | apdu.resp = rbuf; |
1261 | 0 | apdu.resplen = sizeof(rbuf); |
1262 | 0 | apdu.le = 256; |
1263 | 0 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1264 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1265 | 0 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "EnterSafe get pukey failed"); |
1266 | | |
1267 | 0 | p = rbuf; |
1268 | 0 | plen = apdu.resplen; |
1269 | 0 | if (*p != 'E') { |
1270 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); |
1271 | 0 | } |
1272 | 0 | if ((size_t)(p - rbuf) + 2 + p[1] >= plen) { |
1273 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); |
1274 | 0 | } |
1275 | 0 | p += 2 + p[1]; |
1276 | | /* N */ |
1277 | 0 | if (*p != 'N') { |
1278 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); |
1279 | 0 | } |
1280 | 0 | if ((size_t)(p - rbuf) + 2 >= plen) { |
1281 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); |
1282 | 0 | } |
1283 | 0 | ++p; |
1284 | 0 | if (*p++ > 0x80) { |
1285 | 0 | u8 len_bytes = (*(p - 1)) & 0x0f; |
1286 | 0 | size_t module_len = 0; |
1287 | 0 | if ((size_t)(p - rbuf) + len_bytes >= plen) { |
1288 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); |
1289 | 0 | } |
1290 | 0 | while (len_bytes != 0) { |
1291 | 0 | module_len = module_len << 8; |
1292 | 0 | module_len += *p++; |
1293 | 0 | --len_bytes; |
1294 | 0 | } |
1295 | 0 | } |
1296 | | |
1297 | 0 | if ((p - rbuf) + len >= plen) { |
1298 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA); |
1299 | 0 | } |
1300 | | |
1301 | 0 | data->modulus = malloc(len); |
1302 | 0 | if (!data->modulus) |
1303 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_OUT_OF_MEMORY); |
1304 | 0 | entersafe_reverse_buffer(p, len); |
1305 | 0 | memcpy(data->modulus, p, len); |
1306 | |
|
1307 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1308 | 0 | } |
1309 | | |
1310 | | static int entersafe_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) |
1311 | 136 | { |
1312 | 136 | int r; |
1313 | 136 | sc_apdu_t apdu; |
1314 | 136 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; |
1315 | | |
1316 | 136 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1317 | 136 | assert(serial); |
1318 | | |
1319 | 136 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xEA, 0x00, 0x00); |
1320 | 136 | apdu.cla = 0x80; |
1321 | 136 | apdu.resp = rbuf; |
1322 | 136 | apdu.resplen = sizeof(rbuf); |
1323 | 136 | apdu.le = 0x08; |
1324 | | |
1325 | 136 | r = entersafe_transmit_apdu(card, &apdu, 0, 0, 0, 0); |
1326 | 136 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1327 | 128 | LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "EnterSafe get SN failed"); |
1328 | 9 | if (apdu.resplen != 8) |
1329 | 9 | LOG_TEST_RET(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid length of SN"); |
1330 | | |
1331 | 2 | card->serialnr.len = serial->len = 8; |
1332 | 2 | memcpy(card->serialnr.value, rbuf, 8); |
1333 | 2 | memcpy(serial->value, rbuf, 8); |
1334 | | |
1335 | 2 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1336 | 2 | } |
1337 | | |
1338 | | static int entersafe_preinstall_rsa_2048(sc_card_t *card, u8 key_id) |
1339 | 0 | { |
1340 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; |
1341 | 0 | sc_apdu_t apdu; |
1342 | 0 | int ret = 0; |
1343 | 0 | static u8 const rsa_key_e[] = |
1344 | 0 | { |
1345 | 0 | 'E', 0x04, 0x01, 0x00, 0x01, 0x00 |
1346 | 0 | }; |
1347 | |
|
1348 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1349 | | |
1350 | | /* create rsa item in IKF */ |
1351 | 0 | sbuf[0] = 0x04; /* key len extern */ |
1352 | 0 | sbuf[1] = 0x0a; /* key len */ |
1353 | 0 | sbuf[2] = 0x22; /* USAGE */ |
1354 | 0 | sbuf[3] = 0x34; /* user ac */ |
1355 | 0 | sbuf[4] = 0x04; /* change ac */ |
1356 | 0 | sbuf[5] = 0x34; /* UPDATE AC */ |
1357 | 0 | sbuf[6] = 0x40; /* ALGO */ |
1358 | 0 | sbuf[7] = 0x00; /* EC */ |
1359 | 0 | sbuf[8] = 0x00; /* VER */ |
1360 | 0 | memcpy(&sbuf[9], rsa_key_e, sizeof(rsa_key_e)); |
1361 | 0 | sbuf[9 + sizeof(rsa_key_e) + 0] = 'C'+'R'+'T'; |
1362 | 0 | sbuf[9 + sizeof(rsa_key_e) + 1] = 0x82; |
1363 | 0 | sbuf[9 + sizeof(rsa_key_e) + 2] = 0x04; |
1364 | 0 | sbuf[9 + sizeof(rsa_key_e) + 3] = 0x00; |
1365 | |
|
1366 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF0, 0x00, key_id); |
1367 | 0 | apdu.cla = 0x84; |
1368 | 0 | apdu.data = sbuf; |
1369 | 0 | apdu.lc = apdu.datalen = 9 + sizeof(rsa_key_e) + 4; |
1370 | |
|
1371 | 0 | ret = entersafe_transmit_apdu(card, &apdu, init_key, sizeof(init_key), 0, 1); |
1372 | 0 | LOG_TEST_RET(card->ctx, ret, "Preinstall rsa failed"); |
1373 | | |
1374 | | /* create rsa item in PKF */ |
1375 | 0 | sbuf[0] = 0x01; /* key len extern */ |
1376 | 0 | sbuf[1] = 0x0A; /* key len */ |
1377 | 0 | sbuf[2] = 0x2A; /* USAGE */ |
1378 | 0 | sbuf[3] = ENTERSAFE_AC_ALWAYS; /* user ac */ |
1379 | 0 | sbuf[4] = 0x04; /* change ac */ |
1380 | 0 | sbuf[5] = ENTERSAFE_AC_ALWAYS; /* UPDATE AC */ |
1381 | 0 | sbuf[6] = 0x40; /* ALGO */ |
1382 | 0 | sbuf[7] = 0x00; /* EC */ |
1383 | 0 | sbuf[8] = 0x00; /* VER */ |
1384 | 0 | memcpy(&sbuf[9], rsa_key_e, sizeof(rsa_key_e)); |
1385 | 0 | sbuf[9 + sizeof(rsa_key_e) + 0] = 'N'; |
1386 | 0 | sbuf[9 + sizeof(rsa_key_e) + 1] = 0x82; |
1387 | 0 | sbuf[9 + sizeof(rsa_key_e) + 2] = 0x01; |
1388 | 0 | sbuf[9 + sizeof(rsa_key_e) + 3] = 0x00; |
1389 | |
|
1390 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF0, 0x00, key_id); |
1391 | 0 | apdu.cla = 0x84; |
1392 | 0 | apdu.data = sbuf; |
1393 | 0 | apdu.lc = apdu.datalen = 9 + sizeof(rsa_key_e) + 4; |
1394 | |
|
1395 | 0 | ret = entersafe_transmit_apdu(card, &apdu, init_key, sizeof(init_key), 0, 1); |
1396 | 0 | LOG_TEST_RET(card->ctx, ret, "Preinstall rsa failed"); |
1397 | | |
1398 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1399 | 0 | } |
1400 | | |
1401 | | static int entersafe_preinstall_keys(sc_card_t *card, int (*install_rsa)(sc_card_t *, u8)) |
1402 | 0 | { |
1403 | 0 | int r; |
1404 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; |
1405 | 0 | sc_apdu_t apdu; |
1406 | |
|
1407 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1408 | |
|
1409 | 0 | { /* RSA */ |
1410 | 0 | u8 rsa_index; |
1411 | 0 | for (rsa_index = ENTERSAFE_MIN_KEY_ID; rsa_index <= ENTERSAFE_MAX_KEY_ID; ++rsa_index) { |
1412 | 0 | r = install_rsa(card, rsa_index); |
1413 | 0 | LOG_TEST_RET(card->ctx, r, "Preinstall rsa key failed"); |
1414 | 0 | } |
1415 | 0 | } |
1416 | | |
1417 | 0 | { /* key maintain */ |
1418 | | /* create key maintain*/ |
1419 | 0 | sbuf[0] = 0; /* key len extern */ |
1420 | 0 | sbuf[1] = sizeof(key_maintain); /* key len */ |
1421 | 0 | sbuf[2] = 0x03; /* USAGE */ |
1422 | 0 | sbuf[3] = ENTERSAFE_AC_ALWAYS; /* use AC */ |
1423 | 0 | sbuf[4] = ENTERSAFE_AC_ALWAYS; /* CHANGE AC */ |
1424 | 0 | sbuf[5] = ENTERSAFE_AC_NEVER; /* UPDATE AC */ |
1425 | 0 | sbuf[6] = 0x01; /* ALGO */ |
1426 | 0 | sbuf[7] = 0x00; /* EC */ |
1427 | 0 | sbuf[8] = 0x00; /* VER */ |
1428 | 0 | memcpy(&sbuf[9], key_maintain, sizeof(key_maintain)); |
1429 | |
|
1430 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF0, 0x00, 0x00); |
1431 | 0 | apdu.cla = 0x84; |
1432 | 0 | apdu.data = sbuf; |
1433 | 0 | apdu.lc = apdu.datalen = 0x19; |
1434 | |
|
1435 | 0 | r = entersafe_transmit_apdu(card, &apdu, init_key, sizeof(init_key), 0, 1); |
1436 | 0 | LOG_TEST_RET(card->ctx, r, "Preinstall key maintain failed"); |
1437 | 0 | } |
1438 | | |
1439 | 0 | { /* user PIN */ |
1440 | 0 | memset(sbuf, 0, sizeof(sbuf)); |
1441 | 0 | sbuf[0] = 0; /* key len extern */ |
1442 | 0 | sbuf[1] = 16; /* key len */ |
1443 | 0 | sbuf[2] = 0x0B; /* USAGE */ |
1444 | 0 | sbuf[3] = ENTERSAFE_AC_ALWAYS; /* use AC */ |
1445 | 0 | sbuf[4] = 0X04; /* CHANGE AC */ |
1446 | 0 | sbuf[5] = 0x38; /* UPDATE AC */ |
1447 | 0 | sbuf[6] = 0x01; /* ALGO */ |
1448 | 0 | sbuf[7] = 0xFF; /* EC */ |
1449 | 0 | sbuf[8] = 0x00; /* VER */ |
1450 | |
|
1451 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF0, 0x00, ENTERSAFE_USER_PIN_ID); |
1452 | 0 | apdu.cla = 0x84; |
1453 | 0 | apdu.data = sbuf; |
1454 | 0 | apdu.lc = apdu.datalen = 0x19; |
1455 | |
|
1456 | 0 | r = entersafe_transmit_apdu(card, &apdu, init_key, sizeof(init_key), 0, 1); |
1457 | 0 | LOG_TEST_RET(card->ctx, r, "Preinstall user PIN failed"); |
1458 | 0 | } |
1459 | | |
1460 | 0 | { /* user PUK */ |
1461 | 0 | memset(sbuf, 0, sizeof(sbuf)); |
1462 | 0 | sbuf[0] = 0; /* key len extern */ |
1463 | 0 | sbuf[1] = 16; /* key len */ |
1464 | 0 | sbuf[2] = 0x0B; /* USAGE */ |
1465 | 0 | sbuf[3] = ENTERSAFE_AC_ALWAYS; /* use AC */ |
1466 | 0 | sbuf[4] = 0X08; /* CHANGE AC */ |
1467 | 0 | sbuf[5] = 0xC0; /* UPDATE AC */ |
1468 | 0 | sbuf[6] = 0x01; /* ALGO */ |
1469 | 0 | sbuf[7] = 0xFF; /* EC */ |
1470 | 0 | sbuf[8] = 0x00; /* VER */ |
1471 | |
|
1472 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xF0, 0x00, ENTERSAFE_USER_PIN_ID + 1); |
1473 | 0 | apdu.cla = 0x84; |
1474 | 0 | apdu.data = sbuf; |
1475 | 0 | apdu.lc = apdu.datalen = 0x19; |
1476 | |
|
1477 | 0 | r = entersafe_transmit_apdu(card, &apdu, init_key, sizeof(init_key), 0, 1); |
1478 | 0 | LOG_TEST_RET(card->ctx, r, "Preinstall user PUK failed"); |
1479 | 0 | } |
1480 | | |
1481 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
1482 | 0 | } |
1483 | | |
1484 | | static int entersafe_card_ctl_2048(sc_card_t *card, unsigned long cmd, void *ptr) |
1485 | 136 | { |
1486 | 136 | sc_entersafe_create_data *tmp = (sc_entersafe_create_data *)ptr; |
1487 | | |
1488 | 136 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1489 | | |
1490 | 136 | switch (cmd) { |
1491 | 0 | case SC_CARDCTL_ENTERSAFE_CREATE_FILE: |
1492 | 0 | if (tmp->type == SC_ENTERSAFE_MF_DATA) |
1493 | 0 | return entersafe_create_mf(card, tmp); |
1494 | 0 | else if (tmp->type == SC_ENTERSAFE_DF_DATA) |
1495 | 0 | return entersafe_create_df(card, tmp); |
1496 | 0 | else if (tmp->type == SC_ENTERSAFE_EF_DATA) |
1497 | 0 | return entersafe_create_ef(card, tmp); |
1498 | 0 | else |
1499 | 0 | return SC_ERROR_INTERNAL; |
1500 | 0 | case SC_CARDCTL_ENTERSAFE_WRITE_KEY: |
1501 | 0 | return entersafe_write_key(card, (sc_entersafe_wkey_data *)ptr); |
1502 | 0 | case SC_CARDCTL_ENTERSAFE_GENERATE_KEY: |
1503 | 0 | return entersafe_gen_key(card, (sc_entersafe_gen_key_data *)ptr); |
1504 | 0 | case SC_CARDCTL_ERASE_CARD: |
1505 | 0 | return entersafe_erase_card(card); |
1506 | 136 | case SC_CARDCTL_GET_SERIALNR: |
1507 | 136 | return entersafe_get_serialnr(card, (sc_serial_number_t *)ptr); |
1508 | 0 | case SC_CARDCTL_ENTERSAFE_PREINSTALL_KEYS: |
1509 | 0 | return entersafe_preinstall_keys(card, entersafe_preinstall_rsa_2048); |
1510 | 0 | default: |
1511 | 0 | return SC_ERROR_NOT_SUPPORTED; |
1512 | 136 | } |
1513 | 136 | } |
1514 | | |
1515 | | static struct sc_card_driver * sc_get_driver(void) |
1516 | 15.1k | { |
1517 | 15.1k | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
1518 | | |
1519 | 15.1k | if (iso_ops == NULL) |
1520 | 1 | iso_ops = iso_drv->ops; |
1521 | | |
1522 | 15.1k | entersafe_ops = *iso_drv->ops; |
1523 | 15.1k | entersafe_ops.match_card = entersafe_match_card; |
1524 | 15.1k | entersafe_ops.init = entersafe_init; |
1525 | 15.1k | entersafe_ops.read_binary = entersafe_read_binary; |
1526 | 15.1k | entersafe_ops.write_binary = NULL; |
1527 | 15.1k | entersafe_ops.update_binary = entersafe_update_binary; |
1528 | 15.1k | entersafe_ops.select_file = entersafe_select_file; |
1529 | 15.1k | entersafe_ops.restore_security_env = entersafe_restore_security_env; |
1530 | 15.1k | entersafe_ops.set_security_env = entersafe_set_security_env; |
1531 | 15.1k | entersafe_ops.decipher = entersafe_decipher; |
1532 | 15.1k | entersafe_ops.compute_signature = entersafe_compute_signature; |
1533 | 15.1k | entersafe_ops.create_file = entersafe_create_file; |
1534 | 15.1k | entersafe_ops.delete_file = NULL; |
1535 | 15.1k | entersafe_ops.pin_cmd = entersafe_pin_cmd; |
1536 | 15.1k | entersafe_ops.card_ctl = entersafe_card_ctl_2048; |
1537 | 15.1k | entersafe_ops.process_fci = entersafe_process_fci; |
1538 | 15.1k | return &entersafe_drv; |
1539 | 15.1k | } |
1540 | | |
1541 | | struct sc_card_driver * sc_get_entersafe_driver(void) |
1542 | 15.1k | { |
1543 | 15.1k | return sc_get_driver(); |
1544 | 15.1k | } |
1545 | | #endif |