/src/opensc/src/libopensc/card-isoApplet.c
Line | Count | Source |
1 | | /* |
2 | | * Support for the IsoApplet JavaCard Applet. |
3 | | * |
4 | | * Copyright (C) 2014 Philip Wendland <wendlandphilip@gmail.com> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "asn1.h" |
25 | | #include "cardctl.h" |
26 | | #include "internal.h" |
27 | | #include "log.h" |
28 | | #include "opensc.h" |
29 | | #include "pkcs15.h" |
30 | | #include "types.h" |
31 | | |
32 | 0 | #define ISOAPPLET_ALG_REF_ECDSA 0x21 |
33 | 0 | #define ISOAPPLET_ALG_REF_RSA_PAD_PKCS1 0x11 |
34 | 0 | #define ISOAPPLET_ALG_REF_RSA_PAD_PSS 0x12 |
35 | | |
36 | 263 | #define ISOAPPLET_VERSION_V0 0x0006 |
37 | 120 | #define ISOAPPLET_VERSION_V1 0x0100 |
38 | | |
39 | 52 | #define ISOAPPLET_API_FEATURE_EXT_APDU 0x01 |
40 | 52 | #define ISOAPPLET_API_FEATURE_SECURE_RANDOM 0x02 |
41 | 14 | #define ISOAPPLET_API_FEATURE_ECC 0x04 |
42 | 52 | #define ISOAPPLET_API_FEATURE_RSA_PSS 0x08 |
43 | 52 | #define ISOAPPLET_API_FEATURE_RSA_4096 0x20 |
44 | | |
45 | | static const u8 isoApplet_aid[] = {0xf2,0x76,0xa2,0x88,0xbc,0xfb,0xa6,0x9d,0x34,0xf3,0x10,0x01}; |
46 | | |
47 | | struct isoApplet_drv_data |
48 | | { |
49 | | /* Save the current algorithm reference |
50 | | * (ISOAPPLET_ALG_REF_ECDSA, ISOAPPLET_ALG_REF_RSA_PAD_PKCS1) |
51 | | * to be able to distinguish between RSA and ECC operations. |
52 | | * If ECC is being used, the signatures generated by the card |
53 | | * have to be modified. */ |
54 | | unsigned int sec_env_alg_ref; |
55 | | unsigned long sec_env_ec_field_length; |
56 | | unsigned int isoapplet_version; |
57 | | unsigned int isoapplet_features; |
58 | | }; |
59 | 52 | #define DRVDATA(card) ((struct isoApplet_drv_data *) ((card)->drv_data)) |
60 | | |
61 | | /* Operations supported by the applet. */ |
62 | | static struct sc_card_operations isoApplet_ops; |
63 | | |
64 | | /* A reference to the iso7816_* functions. |
65 | | * Initialized in sc_get_driver. */ |
66 | | static const struct sc_card_operations *iso_ops = NULL; |
67 | | |
68 | | /* The description of the driver. */ |
69 | | static struct sc_card_driver isoApplet_drv = |
70 | | { |
71 | | "Javacard with IsoApplet", |
72 | | "isoApplet", |
73 | | &isoApplet_ops, |
74 | | NULL, 0, NULL |
75 | | }; |
76 | | |
77 | | static struct isoapplet_supported_ec_curves { |
78 | | struct sc_object_id oid; |
79 | | size_t size; |
80 | | unsigned int min_applet_version; |
81 | | } ec_curves[] = { |
82 | | {{{1, 2, 840, 10045, 3, 1, 1, -1}}, 192, 0x0000}, /* secp192r1, nistp192, prime192v1, ansiX9p192r1 */ |
83 | | {{{1, 3, 132, 0, 33, -1}}, 224, 0x0000}, /* secp224r1, nistp224 */ |
84 | | {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, 0x0000}, /* secp256r1, nistp256, prime256v1, ansiX9p256r1 */ |
85 | | {{{1, 3, 132, 0, 34, -1}}, 384, 0x0000}, /* secp384r1, nistp384, prime384v1, ansiX9p384r1 */ |
86 | | {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 3, -1}}, 192, 0x0000}, /* brainpoolP192r1 */ |
87 | | {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 5, -1}}, 224, 0x0000}, /* brainpoolP224r1 */ |
88 | | {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256, 0x0000}, /* brainpoolP256r1 */ |
89 | | {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 9, -1}}, 320, 0x0000}, /* brainpoolP320r1 */ |
90 | | {{{1, 3, 132, 0, 31, -1}}, 192, 0x0006}, /* secp192k1 */ |
91 | | {{{1, 3, 132, 0, 10, -1}}, 256, 0x0006}, /* secp256k1 */ |
92 | | {{{-1}}, 0, 0} /* This entry must not be touched. */ |
93 | | }; |
94 | | |
95 | | static int |
96 | | isoApplet_finish(sc_card_t *card) |
97 | 52 | { |
98 | 52 | struct isoApplet_drv_data *drvdata=DRVDATA(card); |
99 | | |
100 | 52 | LOG_FUNC_CALLED(card->ctx); |
101 | 52 | if (drvdata) |
102 | 52 | { |
103 | 52 | free(drvdata); |
104 | 52 | card->drv_data=NULL; |
105 | 52 | } |
106 | 52 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
107 | 52 | } |
108 | | |
109 | | static int |
110 | | isoApplet_match_card(sc_card_t *card) |
111 | 3.71k | { |
112 | 3.71k | int rv; |
113 | | |
114 | 3.71k | rv = iso7816_select_aid(card, isoApplet_aid, sizeof(isoApplet_aid), NULL, NULL); |
115 | 3.71k | if(rv != SC_SUCCESS) |
116 | 3.65k | { |
117 | 3.65k | return 0; |
118 | 3.65k | } |
119 | | |
120 | 68 | return 1; |
121 | 3.71k | } |
122 | | |
123 | | static int |
124 | 68 | isoApplet_get_info(sc_card_t * card, struct isoApplet_drv_data * drvdata) { |
125 | 68 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; |
126 | 68 | int rv; |
127 | 68 | sc_context_t * ctx = card->ctx; |
128 | | |
129 | 68 | rv = sc_get_data(card, 0x0101, rbuf, 3); |
130 | 68 | if(rv == SC_ERROR_INS_NOT_SUPPORTED) { |
131 | | /* INS not supported. This is an older IsoApplet that might return the |
132 | | * applet information upon selection. For backward compatibility, try this. */ |
133 | 5 | size_t rlen = sizeof(rbuf); |
134 | 5 | rv = iso7816_select_aid(card, isoApplet_aid, sizeof(isoApplet_aid), rbuf, &rlen); |
135 | 5 | LOG_TEST_RET(ctx, rv, "Error selecting applet."); |
136 | 3 | rv = (int)rlen; |
137 | 3 | } |
138 | | |
139 | 66 | if (rv < 0) { |
140 | 8 | LOG_TEST_RET(ctx, rv, "Card returned error."); |
141 | 8 | } |
142 | | |
143 | | /* Fill up drvdata */ |
144 | 58 | if(rv >= 3) |
145 | 21 | { |
146 | 21 | drvdata->isoapplet_version = rbuf[0] << 8 | rbuf[1]; |
147 | 21 | drvdata->isoapplet_features = rbuf[2]; |
148 | 21 | } |
149 | | |
150 | 58 | return SC_SUCCESS; |
151 | 66 | } |
152 | | |
153 | | static int |
154 | | isoApplet_init(sc_card_t *card) |
155 | 68 | { |
156 | 68 | int i, r; |
157 | 68 | unsigned int major_version = 0; |
158 | 68 | unsigned long flags = 0; |
159 | 68 | unsigned long ext_flags = 0; |
160 | 68 | struct isoApplet_drv_data *drvdata; |
161 | | |
162 | 68 | LOG_FUNC_CALLED(card->ctx); |
163 | | |
164 | 68 | drvdata=calloc(1, sizeof(*drvdata)); |
165 | 68 | if (!drvdata) |
166 | 68 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
167 | | |
168 | 68 | card->drv_data = drvdata; |
169 | 68 | card->cla = 0x00; |
170 | | |
171 | | /* Obtain applet version and specific features */ |
172 | 68 | r = isoApplet_get_info(card, drvdata); |
173 | 68 | LOG_TEST_GOTO_ERR(card->ctx, r, "Error obtaining information about applet."); |
174 | | |
175 | 58 | major_version = drvdata->isoapplet_version & 0xFF00; |
176 | 58 | if(major_version != (ISOAPPLET_VERSION_V0 & 0xFF00) && major_version != (ISOAPPLET_VERSION_V1 & 0xFF00)) |
177 | 6 | { |
178 | 6 | sc_log(card->ctx, "IsoApplet: Mismatching major API version. Not proceeding. " |
179 | 6 | "API versions: Driver (%04X or %04X), applet (%04X). Please update accordingly.", |
180 | 6 | ISOAPPLET_VERSION_V0, ISOAPPLET_VERSION_V1, drvdata->isoapplet_version); |
181 | 6 | r = SC_ERROR_INVALID_CARD; |
182 | 6 | goto err; |
183 | 6 | } |
184 | 52 | else if(drvdata->isoapplet_version != ISOAPPLET_VERSION_V0 && drvdata->isoapplet_version != ISOAPPLET_VERSION_V1) |
185 | 50 | { |
186 | 50 | sc_log(card->ctx, "IsoApplet: Mismatching minor version. Proceeding anyway. " |
187 | 50 | "API versions: Driver (%04X or %04X), applet (%04X). " |
188 | 50 | "Please update accordingly whenever possible.", |
189 | 50 | ISOAPPLET_VERSION_V0, ISOAPPLET_VERSION_V1, drvdata->isoapplet_version); |
190 | 50 | } |
191 | | |
192 | 52 | if(drvdata->isoapplet_features & ISOAPPLET_API_FEATURE_EXT_APDU) |
193 | 6 | card->caps |= SC_CARD_CAP_APDU_EXT; |
194 | 52 | if(drvdata->isoapplet_features & ISOAPPLET_API_FEATURE_SECURE_RANDOM) |
195 | 7 | card->caps |= SC_CARD_CAP_RNG; |
196 | 52 | if(drvdata->isoapplet_version <= 0x0005 |
197 | 14 | || drvdata->isoapplet_features & ISOAPPLET_API_FEATURE_ECC) |
198 | 45 | { |
199 | | /* There are Java Cards that do not support ECDSA at all. The IsoApplet |
200 | | * started to report this with version 00.06. |
201 | | * |
202 | | * Curves supported by the pkcs15-init driver are indicated per curve. This |
203 | | * should be kept in sync with the explicit parameters in the pkcs15-init |
204 | | * driver. */ |
205 | 45 | flags = 0; |
206 | 45 | if (major_version == (ISOAPPLET_VERSION_V0 & 0xFF00)) { |
207 | 40 | flags |= SC_ALGORITHM_ECDSA_HASH_SHA1; |
208 | 40 | } else { // ISOAPPLET_VERSION_V1 |
209 | 5 | flags |= SC_ALGORITHM_ECDSA_RAW; |
210 | 5 | flags |= SC_ALGORITHM_ECDSA_HASH_NONE; |
211 | 5 | } |
212 | 45 | flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; |
213 | 45 | ext_flags = SC_ALGORITHM_EXT_EC_UNCOMPRESES; |
214 | 45 | ext_flags |= SC_ALGORITHM_EXT_EC_NAMEDCURVE; |
215 | 45 | ext_flags |= SC_ALGORITHM_EXT_EC_F_P; |
216 | 495 | for (i=0; ec_curves[i].oid.value[0] >= 0; i++) |
217 | 450 | { |
218 | 450 | if(drvdata->isoapplet_version >= ec_curves[i].min_applet_version) |
219 | 374 | _sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].oid); |
220 | 450 | } |
221 | 45 | } |
222 | | |
223 | | /* RSA */ |
224 | 52 | flags = 0; |
225 | 52 | flags |= SC_ALGORITHM_RSA_PAD_PKCS1; |
226 | 52 | flags |= SC_ALGORITHM_RSA_HASH_NONE; |
227 | 52 | if(drvdata->isoapplet_features & ISOAPPLET_API_FEATURE_RSA_PSS) { |
228 | 6 | flags |= SC_ALGORITHM_RSA_PAD_PSS; |
229 | 6 | } |
230 | | /* Key-generation: */ |
231 | 52 | flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; |
232 | | /* Modulus lengths: */ |
233 | 52 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
234 | 52 | if (drvdata->isoapplet_features & ISOAPPLET_API_FEATURE_RSA_4096) { |
235 | 7 | _sc_card_add_rsa_alg(card, 4096, flags, 0); |
236 | 7 | } |
237 | | |
238 | 52 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
239 | 16 | err: |
240 | 16 | free(drvdata); |
241 | 16 | LOG_FUNC_RETURN(card->ctx, r); |
242 | 16 | } |
243 | | |
244 | | /* |
245 | | * @brief convert an OpenSC ACL entry to the security condition |
246 | | * byte used by the IsoApplet. |
247 | | * |
248 | | * Used by IsoApplet_create_file to parse OpenSC ACL entries |
249 | | * into ISO 7816-4 Table 20 security condition bytes. |
250 | | * |
251 | | * @param entry The OpenSC ACL entry. |
252 | | * |
253 | | * @return The security condition byte. No restriction (0x00) |
254 | | * if unknown operation. |
255 | | */ |
256 | | static u8 |
257 | | isoApplet_acl_to_security_condition_byte(const sc_acl_entry_t *entry) |
258 | 0 | { |
259 | 0 | if(!entry) |
260 | 0 | return 0x00; |
261 | 0 | switch(entry->method) |
262 | 0 | { |
263 | 0 | case SC_AC_CHV: |
264 | 0 | return 0x90; |
265 | 0 | case SC_AC_NEVER: |
266 | 0 | return 0xFF; |
267 | 0 | case SC_AC_NONE: |
268 | 0 | default: |
269 | 0 | return 0x00; |
270 | 0 | } |
271 | 0 | } |
272 | | |
273 | | /* |
274 | | * The reason for this function is that OpenSC doesn't set any |
275 | | * Security Attribute Tag in the FCI upon file creation if there |
276 | | * is no file->sec_attr. I set the file->sec_attr to a format |
277 | | * understood by the applet (ISO 7816-4 tables 16, 17 and 20). |
278 | | * The iso7816_create_file will then set this as Tag 86 - Sec. |
279 | | * Attr. Prop. Format. |
280 | | * The applet will then be able to set and enforce access rights |
281 | | * for any file created by OpenSC. Without this function, the |
282 | | * applet would not know where to enforce security rules and |
283 | | * when. |
284 | | * |
285 | | * Note: IsoApplet currently only supports a "onepin" option. |
286 | | * |
287 | | * Format of the sec_attr: 8 Bytes: |
288 | | * 7 - ISO 7816-4 table 16 or 17 |
289 | | * 6 to 0 - ISO 7816-4 table 20 |
290 | | */ |
291 | | static int |
292 | | isoApplet_create_file(sc_card_t *card, sc_file_t *file) |
293 | 0 | { |
294 | 0 | int r = 0; |
295 | |
|
296 | 0 | LOG_FUNC_CALLED(card->ctx); |
297 | |
|
298 | 0 | if(file->sec_attr_len == 0) |
299 | 0 | { |
300 | 0 | u8 access_buf[8]; |
301 | 0 | int idx[8], i; |
302 | |
|
303 | 0 | if(file->type == SC_FILE_TYPE_DF) |
304 | 0 | { |
305 | 0 | const int df_idx[8] = /* These are the SC operations. */ |
306 | 0 | { |
307 | 0 | 0, /* Reserved. */ |
308 | 0 | SC_AC_OP_DELETE_SELF, /* b6 */ |
309 | 0 | SC_AC_OP_LOCK, /* b5 */ |
310 | 0 | SC_AC_OP_ACTIVATE, /* b4 */ |
311 | 0 | SC_AC_OP_DEACTIVATE, /* b3 */ |
312 | 0 | SC_AC_OP_CREATE_DF, /* b2 */ |
313 | 0 | SC_AC_OP_CREATE_EF, /* b1 */ |
314 | 0 | SC_AC_OP_DELETE /* b0 */ |
315 | 0 | }; |
316 | 0 | for(i=0; i<8; i++) |
317 | 0 | { |
318 | 0 | idx[i] = df_idx[i]; |
319 | 0 | } |
320 | 0 | } |
321 | 0 | else /* EF */ |
322 | 0 | { |
323 | 0 | const int ef_idx[8] = |
324 | 0 | { |
325 | 0 | 0, /* Reserved. */ |
326 | 0 | SC_AC_OP_DELETE_SELF, /* b6 */ |
327 | 0 | SC_AC_OP_LOCK, /* b5 */ |
328 | 0 | SC_AC_OP_ACTIVATE, /* b4 */ |
329 | 0 | SC_AC_OP_DEACTIVATE, /* b3 */ |
330 | 0 | SC_AC_OP_WRITE, /* b2 */ |
331 | 0 | SC_AC_OP_UPDATE, /* b1 */ |
332 | 0 | SC_AC_OP_READ /* b0 */ |
333 | 0 | }; |
334 | 0 | for(i=0; i<8; i++) |
335 | 0 | { |
336 | 0 | idx[i] = ef_idx[i]; |
337 | 0 | } |
338 | 0 | } |
339 | | /* Now idx contains the operation identifiers. |
340 | | * We now search for the OPs. */ |
341 | 0 | access_buf[0] = 0xFF; /* A security condition byte is present for every OP. (Table 19) */ |
342 | 0 | for(i=1; i<8; i++) |
343 | 0 | { |
344 | 0 | const sc_acl_entry_t *entry; |
345 | 0 | entry = sc_file_get_acl_entry(file, idx[i]); |
346 | 0 | access_buf[i] = isoApplet_acl_to_security_condition_byte(entry); |
347 | 0 | } |
348 | |
|
349 | 0 | r = sc_file_set_sec_attr(file, access_buf, 8); |
350 | 0 | LOG_TEST_RET(card->ctx, r, "Error adding security attribute."); |
351 | 0 | } |
352 | | |
353 | 0 | r = iso_ops->create_file(card, file); |
354 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
355 | 0 | } |
356 | | |
357 | | /* |
358 | | * Add an ACL entry to the OpenSC file struct, according to the operation |
359 | | * and the saByte (Encoded according to IsoApplet FCI proprietary security |
360 | | * information, see also ISO 7816-4 table 20). |
361 | | * |
362 | | * @param[in,out] file |
363 | | * @param[in] operation The OpenSC operation. |
364 | | * @param[in] saByte The security condition byte returned by the applet. |
365 | | */ |
366 | | static int |
367 | | isoApplet_add_sa_to_acl(sc_file_t *file, unsigned int operation, u8 saByte) |
368 | 119 | { |
369 | 119 | int r; |
370 | | |
371 | 119 | switch(saByte) |
372 | 119 | { |
373 | 16 | case 0x90: |
374 | 16 | r = sc_file_add_acl_entry(file, operation, SC_AC_CHV, 1); |
375 | 16 | if(r < 0) |
376 | 0 | return r; |
377 | 16 | break; |
378 | 30 | case 0xFF: |
379 | 30 | r = sc_file_add_acl_entry(file, operation, SC_AC_NEVER, SC_AC_KEY_REF_NONE); |
380 | 30 | if(r < 0) |
381 | 0 | return r; |
382 | 30 | break; |
383 | 30 | case 0x00: |
384 | 23 | r = sc_file_add_acl_entry(file, operation, SC_AC_NONE, SC_AC_KEY_REF_NONE); |
385 | 23 | if(r < 0) |
386 | 0 | return r; |
387 | 23 | break; |
388 | 50 | default: |
389 | 50 | r = sc_file_add_acl_entry(file, operation, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE); |
390 | 50 | if(r < 0) |
391 | 0 | return r; |
392 | 119 | } |
393 | 119 | return SC_SUCCESS; |
394 | 119 | } |
395 | | |
396 | | |
397 | | /* |
398 | | * This function first calls the iso7816.c process_fci() for any other FCI |
399 | | * information and then updates the ACL of the OpenSC file struct according |
400 | | * to the FCI from the applet. |
401 | | */ |
402 | | static int |
403 | | isoApplet_process_fci(sc_card_t *card, sc_file_t *file, |
404 | | const u8 *buf, size_t buflen) |
405 | 44 | { |
406 | 44 | int r; |
407 | 44 | u8 *sa = NULL; |
408 | | |
409 | 44 | LOG_FUNC_CALLED(card->ctx); |
410 | | |
411 | 44 | r = iso_ops->process_fci(card, file, buf, buflen); |
412 | 44 | LOG_TEST_RET(card->ctx, r, "Error while processing the FCI."); |
413 | | /* Construct the ACL from the sec_attr. */ |
414 | 44 | if(file->sec_attr && file->sec_attr_len == 8) |
415 | 32 | { |
416 | 32 | sa = file->sec_attr; |
417 | 32 | if(sa[0] != 0xFF) |
418 | 12 | { |
419 | 12 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, |
420 | 12 | "File security attribute does not contain a ACL byte for every operation."); |
421 | 12 | } |
422 | 20 | if(file->type == SC_FILE_TYPE_DF) |
423 | 7 | { |
424 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DELETE_SELF, sa[1]); |
425 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
426 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_LOCK, sa[2]); |
427 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
428 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_ACTIVATE, sa[3]); |
429 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
430 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DEACTIVATE, sa[4]); |
431 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
432 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_CREATE_DF, sa[5]); |
433 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
434 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_CREATE_EF, sa[6]); |
435 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
436 | 7 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DELETE, sa[7]); |
437 | 7 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
438 | 7 | } |
439 | 13 | else if(file->type == SC_FILE_TYPE_INTERNAL_EF |
440 | 9 | || file->type == SC_FILE_TYPE_WORKING_EF) |
441 | 10 | { |
442 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DELETE_SELF, sa[1]); |
443 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
444 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_LOCK, sa[2]); |
445 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
446 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_ACTIVATE, sa[3]); |
447 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
448 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_DEACTIVATE, sa[4]); |
449 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
450 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_WRITE, sa[5]); |
451 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
452 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_UPDATE, sa[6]); |
453 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
454 | 10 | r = isoApplet_add_sa_to_acl(file, SC_AC_OP_READ, sa[7]); |
455 | 10 | LOG_TEST_RET(card->ctx, r, "Error adding ACL entry."); |
456 | 10 | } |
457 | | |
458 | 20 | } |
459 | | |
460 | 32 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
461 | 32 | } |
462 | | |
463 | | /* |
464 | | * @brief Encode the EC parameters as a concatenation of TLV entries. |
465 | | * |
466 | | * The format is: |
467 | | * 81 - prime |
468 | | * 82 - coefficient A |
469 | | * 83 - coefficient B |
470 | | * 84 - base point G |
471 | | * 85 - order |
472 | | * 87 - cofactor |
473 | | * |
474 | | * @param[in] card |
475 | | * @param[in] params The ECparameters containing the information of the curve. |
476 | | * @param[out] out The array the encoded parameters are written to. |
477 | | * @param[in] out_len The size of out |
478 | | * @param[out] ptr A pointer pointing to the end of the parameters in out |
479 | | * (the first untouched byte behind the parameters). |
480 | | */ |
481 | | static int |
482 | | isoApplet_put_ec_params(sc_card_t *card, sc_cardctl_isoApplet_ec_parameters_t *params, u8 *out, size_t out_len, u8 **ptr) |
483 | 0 | { |
484 | 0 | u8 *p = out; |
485 | 0 | int r; |
486 | |
|
487 | 0 | LOG_FUNC_CALLED(card->ctx); |
488 | |
|
489 | 0 | if(!params |
490 | 0 | || !params->prime.value |
491 | 0 | || !params->coefficientA.value |
492 | 0 | || !params->coefficientB.value |
493 | 0 | || !params->basePointG.value |
494 | 0 | || !params->order.value |
495 | 0 | || !params->coFactor.value) |
496 | 0 | { |
497 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Error: EC params not present."); |
498 | 0 | } |
499 | | |
500 | 0 | if(out == NULL || out_len == 0) |
501 | 0 | { |
502 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Error: Parameter out is NULL or outlen is zero."); |
503 | 0 | } |
504 | | |
505 | 0 | r = sc_asn1_put_tag(0x81, params->prime.value, params->prime.len, p, out_len - (p - out), &p); |
506 | 0 | LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); |
507 | 0 | r = sc_asn1_put_tag(0x82, params->coefficientA.value, params->coefficientA.len, p, out_len - (p - out), &p); |
508 | 0 | LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); |
509 | 0 | r = sc_asn1_put_tag(0x83, params->coefficientB.value, params->coefficientB.len, p, out_len - (p - out), &p); |
510 | 0 | LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); |
511 | 0 | r = sc_asn1_put_tag(0x84, params->basePointG.value, params->basePointG.len, p, out_len - (p - out), &p); |
512 | 0 | LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); |
513 | 0 | r = sc_asn1_put_tag(0x85, params->order.value, params->order.len, p, out_len - (p - out), &p); |
514 | 0 | LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); |
515 | 0 | r = sc_asn1_put_tag(0x87, params->coFactor.value, params->coFactor.len, p, out_len - (p - out), &p); |
516 | 0 | LOG_TEST_RET(card->ctx, r, "Error in handling TLV."); |
517 | | |
518 | 0 | if (ptr != NULL) |
519 | 0 | *ptr = p; |
520 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
521 | 0 | } |
522 | | |
523 | | /* |
524 | | * @brief Generate a private key on the card. |
525 | | */ |
526 | | static int |
527 | | isoApplet_ctl_generate_key(sc_card_t *card, sc_cardctl_isoApplet_genkey_t *args) |
528 | 0 | { |
529 | 0 | int r; |
530 | 0 | sc_apdu_t apdu; |
531 | 0 | u8 rbuf[SC_MAX_EXT_APDU_RESP_SIZE]; |
532 | 0 | u8 sbuf[SC_MAX_EXT_APDU_DATA_SIZE]; |
533 | 0 | u8 *p; |
534 | 0 | const u8 *inner_tag_value; |
535 | 0 | const u8 *outer_tag_value; |
536 | 0 | unsigned int tag; |
537 | 0 | size_t outer_tag_len; |
538 | 0 | size_t inner_tag_len; |
539 | 0 | unsigned int cla; |
540 | 0 | size_t sz; |
541 | |
|
542 | 0 | LOG_FUNC_CALLED(card->ctx); |
543 | | |
544 | | /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ |
545 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); |
546 | |
|
547 | 0 | p = sbuf; |
548 | 0 | *p++ = 0x80; /* algorithm reference */ |
549 | 0 | *p++ = 0x01; |
550 | 0 | *p++ = args->algorithm_ref; |
551 | |
|
552 | 0 | *p++ = 0x84; /* Private key reference */ |
553 | 0 | *p++ = 0x01; |
554 | 0 | *p++ = args->priv_key_ref; |
555 | |
|
556 | 0 | sz = p - sbuf; |
557 | 0 | p = NULL; |
558 | |
|
559 | 0 | apdu.lc = sz; |
560 | 0 | apdu.datalen = sz; |
561 | 0 | apdu.data = sbuf; |
562 | |
|
563 | 0 | r = sc_transmit_apdu(card, &apdu); |
564 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
565 | | |
566 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
567 | 0 | LOG_TEST_RET(card->ctx, r, "Card returned error"); |
568 | | |
569 | | |
570 | | /* GENERATE ASYMMETRIC KEY PAIR |
571 | | * We use a larger buffer here, even if the card does not support extended apdus. |
572 | | * There are two cases: |
573 | | * 1) The card can do ext. apdus: The data fits in one apdu. |
574 | | * 2) The card can't do ext. apdus: sc_transmit_apdu will handle that - the |
575 | | * card will send SW_BYTES_REMAINING, OpenSC will automatically do a |
576 | | * GET RESPONSE to get the remaining data, and will append it to the data |
577 | | * buffer. */ |
578 | 0 | if(args->algorithm_ref == SC_ISOAPPLET_ALG_REF_EC_GEN) |
579 | 0 | { |
580 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x46, 0x00, 0x00); |
581 | 0 | apdu.data = sbuf; |
582 | 0 | p = sbuf; |
583 | 0 | r = isoApplet_put_ec_params(card, &args->pubkey.ec.params, p, sizeof(sbuf), &p); |
584 | 0 | LOG_TEST_RET(card->ctx, r, "Error composing EC params."); |
585 | 0 | apdu.datalen = p - sbuf; |
586 | 0 | apdu.lc = p - sbuf; |
587 | | /* Use APDU chaining if the card does not support extended apdus |
588 | | * and the data does not fit in one short apdu. */ |
589 | 0 | if ((apdu.datalen > 255) && !(card->caps & SC_CARD_CAP_APDU_EXT)) |
590 | 0 | { |
591 | 0 | apdu.flags |= SC_APDU_FLAGS_CHAINING; |
592 | 0 | } |
593 | 0 | } |
594 | 0 | else |
595 | 0 | { |
596 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x46, 0x42, 0x00); |
597 | 0 | } |
598 | | |
599 | 0 | apdu.resp = rbuf; |
600 | 0 | apdu.resplen = sizeof(rbuf); |
601 | 0 | if (card->caps & SC_CARD_CAP_APDU_EXT) { |
602 | 0 | apdu.le = apdu.resplen; |
603 | 0 | } else { |
604 | 0 | apdu.le = 256; |
605 | 0 | } |
606 | 0 | r = sc_transmit_apdu(card, &apdu); |
607 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
608 | | |
609 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
610 | 0 | if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) |
611 | 0 | { |
612 | 0 | sc_log(card->ctx, "Key generation not supported by the card with that particular key type. " |
613 | 0 | "Your card may not support the specified algorithm used by the applet / specified by you. " |
614 | 0 | "In most cases, this happens when trying to generate EC keys not supported by your java card. " |
615 | 0 | "In this case, look for supported field lengths and whether FP and/or F2M are supported."); |
616 | 0 | } |
617 | 0 | LOG_TEST_RET(card->ctx, r, "Card returned error"); |
618 | | |
619 | | /* Parse the public key / response. */ |
620 | 0 | outer_tag_value = apdu.resp; |
621 | 0 | r = sc_asn1_read_tag(&outer_tag_value, apdu.resplen, &cla, &tag, &outer_tag_len); |
622 | 0 | LOG_TEST_RET(card->ctx, r, "Error in ASN1 handling."); |
623 | | /* Interindustry template for nesting one set of public key data objects */ |
624 | 0 | if((tag != 0x1F49) || (cla != 0x60)) |
625 | 0 | { |
626 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, |
627 | 0 | "The data returned by the card is unexpected."); |
628 | 0 | } |
629 | | |
630 | 0 | switch(args->algorithm_ref) |
631 | 0 | { |
632 | | |
633 | 0 | case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: |
634 | 0 | case SC_ISOAPPLET_ALG_REF_RSA_GEN_4096: |
635 | | /* Search for the modulus tag (81). */ |
636 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x81, &inner_tag_len); |
637 | 0 | const size_t expected_modulus_len = args->algorithm_ref == SC_ISOAPPLET_ALG_REF_RSA_GEN_2048 ? 256 : 512; |
638 | 0 | if(inner_tag_value == NULL || inner_tag_len != expected_modulus_len) |
639 | 0 | { |
640 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid modulus."); |
641 | 0 | } |
642 | 0 | if(inner_tag_len > args->pubkey.rsa.modulus.len) |
643 | 0 | { |
644 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); |
645 | 0 | } |
646 | 0 | memcpy(args->pubkey.rsa.modulus.value, inner_tag_value, inner_tag_len); |
647 | 0 | args->pubkey.rsa.modulus.len = inner_tag_len; |
648 | | |
649 | | /* Exponent tag (82) */ |
650 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x82, &inner_tag_len); |
651 | 0 | if(inner_tag_value == NULL || inner_tag_len != 3) |
652 | 0 | { |
653 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid exponent."); |
654 | 0 | } |
655 | 0 | if(inner_tag_len > args->pubkey.rsa.exponent.len) |
656 | 0 | { |
657 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); |
658 | 0 | } |
659 | 0 | if(memcmp(inner_tag_value, "\x01\x00\x01", 3) != 0) |
660 | 0 | { |
661 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, |
662 | 0 | "Key generation error: Unexpected public key exponent."); |
663 | 0 | } |
664 | 0 | memcpy(args->pubkey.rsa.exponent.value, inner_tag_value, inner_tag_len); |
665 | 0 | args->pubkey.rsa.exponent.len = inner_tag_len; |
666 | 0 | p = NULL; |
667 | 0 | break; |
668 | | |
669 | 0 | case SC_ISOAPPLET_ALG_REF_EC_GEN: |
670 | | /* Compare the parameters received from the card to the ones sent to the card. */ |
671 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x81, &inner_tag_len); |
672 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.prime.len |
673 | 0 | || memcmp(inner_tag_value, args->pubkey.ec.params.prime.value, inner_tag_len) != 0) |
674 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid prime."); |
675 | | |
676 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x82, &inner_tag_len); |
677 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coefficientA.len |
678 | 0 | || memcmp(inner_tag_value, args->pubkey.ec.params.coefficientA.value, inner_tag_len) != 0) |
679 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid coefficient A."); |
680 | | |
681 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x83, &inner_tag_len); |
682 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coefficientB.len |
683 | 0 | || memcmp(inner_tag_value, args->pubkey.ec.params.coefficientB.value, inner_tag_len) != 0) |
684 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid coefficient B."); |
685 | | |
686 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x84, &inner_tag_len); |
687 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.basePointG.len |
688 | 0 | || memcmp(inner_tag_value, args->pubkey.ec.params.basePointG.value, inner_tag_len) != 0) |
689 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid base point G."); |
690 | | |
691 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x85, &inner_tag_len); |
692 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.order.len |
693 | 0 | || memcmp(inner_tag_value, args->pubkey.ec.params.order.value, inner_tag_len) != 0) |
694 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid order."); |
695 | | |
696 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x87, &inner_tag_len); |
697 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coFactor.len |
698 | 0 | || memcmp(inner_tag_value, args->pubkey.ec.params.coFactor.value, inner_tag_len) != 0) |
699 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid cofactor."); |
700 | | |
701 | | /* Extract public key */ |
702 | 0 | inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x86, &inner_tag_len); |
703 | 0 | if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.ecPointQ.len) |
704 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid EC point Q."); |
705 | 0 | memcpy(args->pubkey.ec.ecPointQ.value, inner_tag_value, inner_tag_len); |
706 | |
|
707 | 0 | break; |
708 | 0 | default: |
709 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unable to parse public key: Unsupported algorithm."); |
710 | 0 | }/* switch */ |
711 | | |
712 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
713 | 0 | } |
714 | | |
715 | | /* |
716 | | * @brief Use PUT DATA to import a private RSA key. |
717 | | * |
718 | | * For simplicity, command chaining has to be used. One chunk (apdu) must contain |
719 | | * one RSA field (P, Q, etc.). The first apdu must contain the outer tag (7F48). |
720 | | * |
721 | | * @param card |
722 | | * @param rsa The RSA private key to import. |
723 | | * |
724 | | * @return SC_ERROR_INVALID_ARGUMENTS: The RSA key does not contain CRT fields. |
725 | | * other errors: Transmit errors / errors returned by card. |
726 | | */ |
727 | | static int |
728 | | isoApplet_put_data_prkey_rsa(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) |
729 | 0 | { |
730 | 0 | sc_apdu_t apdu; |
731 | 0 | u8 sbuf[SC_MAX_EXT_APDU_DATA_SIZE]; |
732 | 0 | u8 *p = NULL; |
733 | 0 | int r; |
734 | 0 | size_t tags_len; |
735 | |
|
736 | 0 | LOG_FUNC_CALLED(card->ctx); |
737 | |
|
738 | 0 | if(!args->privkey.rsa.p.value |
739 | 0 | || !args->privkey.rsa.q.value |
740 | 0 | || !args->privkey.rsa.iqmp.value |
741 | 0 | || !args->privkey.rsa.dmp1.value |
742 | 0 | || !args->privkey.rsa.dmq1.value) |
743 | 0 | { |
744 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "RSA key is missing information."); |
745 | 0 | } |
746 | | |
747 | | /* Note: The format is according to ISO 2-byte tag 7F48 |
748 | | * "T-L pair to indicate a private key data object" */ |
749 | | |
750 | | /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ |
751 | 0 | tags_len = 0; |
752 | 0 | r = sc_asn1_put_tag(0x92, NULL, args->privkey.rsa.p.len, NULL, 0, NULL); |
753 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
754 | 0 | tags_len += r; |
755 | 0 | r = sc_asn1_put_tag(0x93, NULL, args->privkey.rsa.q.len, NULL, 0, NULL); |
756 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
757 | 0 | tags_len += r; |
758 | 0 | r = sc_asn1_put_tag(0x94, NULL, args->privkey.rsa.iqmp.len, NULL, 0, NULL); |
759 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
760 | 0 | tags_len += r; |
761 | 0 | r = sc_asn1_put_tag(0x95, NULL, args->privkey.rsa.dmp1.len, NULL, 0, NULL); |
762 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
763 | 0 | tags_len += r; |
764 | 0 | r = sc_asn1_put_tag(0x96, NULL, args->privkey.rsa.dmq1.len, NULL, 0, NULL); |
765 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
766 | 0 | tags_len += r; |
767 | | |
768 | | /* Write the outer tag and length information. */ |
769 | 0 | p = sbuf; |
770 | 0 | r = sc_asn1_put_tag(0x7F48, NULL, tags_len, p, sizeof(sbuf), &p); |
771 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
772 | | |
773 | | /* Write inner tags. */ |
774 | | /* p */ |
775 | 0 | r = sc_asn1_put_tag(0x92, args->privkey.rsa.p.value, args->privkey.rsa.p.len, p, sizeof(sbuf) - (p - sbuf), &p); |
776 | 0 | if(r < 0) |
777 | 0 | goto out; |
778 | | /* q */ |
779 | 0 | r = sc_asn1_put_tag(0x93, args->privkey.rsa.q.value, args->privkey.rsa.q.len, p, sizeof(sbuf) - (p - sbuf), &p); |
780 | 0 | if(r < 0) |
781 | 0 | goto out; |
782 | | /* 1/q mod p */ |
783 | 0 | r = sc_asn1_put_tag(0x94, args->privkey.rsa.iqmp.value, args->privkey.rsa.iqmp.len, p, sizeof(sbuf) - (p - sbuf), &p); |
784 | 0 | if(r < 0) |
785 | 0 | goto out; |
786 | | /* d mod (p-1) */ |
787 | 0 | r = sc_asn1_put_tag(0x95, args->privkey.rsa.dmp1.value, args->privkey.rsa.dmp1.len, p, sizeof(sbuf) - (p - sbuf), &p); |
788 | 0 | if(r < 0) |
789 | 0 | goto out; |
790 | | /* d mod (q-1) */ |
791 | 0 | r = sc_asn1_put_tag(0x96, args->privkey.rsa.dmq1.value, args->privkey.rsa.dmq1.len, p, sizeof(sbuf) - (p - sbuf), &p); |
792 | 0 | if(r < 0) |
793 | 0 | goto out; |
794 | | |
795 | | /* Send to card, using chaining or extended APDUs. */ |
796 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); |
797 | 0 | apdu.data = sbuf; |
798 | 0 | apdu.datalen = p - sbuf; |
799 | 0 | apdu.lc = p - sbuf; |
800 | 0 | if ((card->caps & SC_CARD_CAP_APDU_EXT) == 0) |
801 | 0 | { |
802 | | /* The lower layers will automatically do chaining */ |
803 | 0 | apdu.flags |= SC_APDU_FLAGS_CHAINING; |
804 | 0 | } |
805 | 0 | r = sc_transmit_apdu(card, &apdu); |
806 | 0 | if(r < 0) |
807 | 0 | goto out; |
808 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
809 | 0 | if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) |
810 | 0 | { |
811 | 0 | sc_log(card->ctx, "Key import not supported by the card with that particular key type. " |
812 | 0 | "Your card may not support the specified algorithm used by the applet / specified by you. " |
813 | 0 | "In most cases, this happens when trying to import EC keys not supported by your java card. " |
814 | 0 | "In this case, look for supported field lengths and whether FP and/or F2M are supported. " |
815 | 0 | "If you tried to import a private RSA key, check the key length."); |
816 | 0 | } |
817 | 0 | if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) |
818 | 0 | { |
819 | 0 | sc_log(card->ctx, "Key import not allowed by the applet's security policy. " |
820 | 0 | "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," |
821 | 0 | " rebuild and reinstall the applet."); |
822 | 0 | } |
823 | 0 | if(r < 0) |
824 | 0 | goto out; |
825 | | |
826 | 0 | r = SC_SUCCESS; |
827 | 0 | out: |
828 | 0 | sc_mem_clear(sbuf, sizeof(sbuf)); |
829 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
830 | 0 | } |
831 | | |
832 | | /* |
833 | | * @brief Use PUT DATA to import a private EC key. |
834 | | * |
835 | | * Format of transmitted data: |
836 | | * 0xE0 - Private class, constructed encoding, number one. |
837 | | * 0x81 - prime |
838 | | * 0x82 - coefficient A |
839 | | * 0x83 - coefficient B |
840 | | * 0x84 - base point G |
841 | | * 0x85 - order |
842 | | * 0x87 - cofactor |
843 | | * 0x88 - private D (private key) |
844 | | * |
845 | | * @param card |
846 | | * @param ec The EC private key to import. |
847 | | * |
848 | | * @return SC_ERROR_INVALID_ARGUMENTS: Curve parameters or private component is missing. |
849 | | * other errors: Transmit errors / errors returned by card. |
850 | | * ASN1 errors. |
851 | | */ |
852 | | static int |
853 | | isoApplet_put_data_prkey_ec(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) |
854 | 0 | { |
855 | 0 | sc_apdu_t apdu; |
856 | 0 | u8 sbuf[SC_MAX_EXT_APDU_DATA_SIZE]; |
857 | 0 | int r; |
858 | 0 | u8 *p; |
859 | 0 | size_t tags_len; |
860 | |
|
861 | 0 | LOG_FUNC_CALLED(card->ctx); |
862 | |
|
863 | 0 | if(!args->privkey.ec.privateD.value |
864 | 0 | || !args->privkey.ec.params.prime.value |
865 | 0 | || !args->privkey.ec.params.coefficientA.value |
866 | 0 | || !args->privkey.ec.params.coefficientB.value |
867 | 0 | || !args->privkey.ec.params.basePointG.value |
868 | 0 | || !args->privkey.ec.params.order.value |
869 | 0 | || !args->privkey.ec.params.coFactor.value |
870 | 0 | ) |
871 | 0 | { |
872 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Missing information about EC private key."); |
873 | 0 | } |
874 | | |
875 | | /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ |
876 | 0 | tags_len = 0; |
877 | 0 | r = sc_asn1_put_tag(0x81, NULL, args->privkey.ec.params.prime.len, NULL, 0, NULL); |
878 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
879 | 0 | tags_len += r; |
880 | 0 | r = sc_asn1_put_tag(0x82, NULL, args->privkey.ec.params.coefficientA.len, NULL, 0, NULL); |
881 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
882 | 0 | tags_len += r; |
883 | 0 | r = sc_asn1_put_tag(0x83, NULL, args->privkey.ec.params.coefficientB.len, NULL, 0, NULL); |
884 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
885 | 0 | tags_len += r; |
886 | 0 | r = sc_asn1_put_tag(0x84, NULL, args->privkey.ec.params.basePointG.len, NULL, 0, NULL); |
887 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
888 | 0 | tags_len += r; |
889 | 0 | r = sc_asn1_put_tag(0x85, NULL, args->privkey.ec.params.order.len, NULL, 0, NULL); |
890 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
891 | 0 | tags_len += r; |
892 | 0 | r = sc_asn1_put_tag(0x87, NULL, args->privkey.ec.params.coFactor.len, NULL, 0, NULL); |
893 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
894 | 0 | tags_len += r; |
895 | 0 | r = sc_asn1_put_tag(0x88, NULL, args->privkey.ec.privateD.len, NULL, 0, NULL); |
896 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
897 | 0 | tags_len += r; |
898 | | |
899 | | /* Write the outer tag and length information. */ |
900 | 0 | p = sbuf; |
901 | 0 | r = sc_asn1_put_tag(0xE0, NULL, tags_len, p, sizeof(sbuf), &p); |
902 | 0 | LOG_TEST_RET(card->ctx, r, "Error handling TLV."); |
903 | | |
904 | | /* Write inner tags. */ |
905 | 0 | r = isoApplet_put_ec_params(card, &args->privkey.ec.params, p, sizeof(sbuf) - (p - sbuf), &p); |
906 | 0 | if(r < 0) |
907 | 0 | { |
908 | 0 | sc_log(card->ctx, "Error composing EC params."); |
909 | 0 | goto out; |
910 | 0 | } |
911 | 0 | r = sc_asn1_put_tag(0x88, args->privkey.ec.privateD.value, args->privkey.ec.privateD.len, p, sizeof(sbuf) - (p - sbuf), &p); |
912 | 0 | if(r < 0) |
913 | 0 | goto out; |
914 | | |
915 | | /* Send to card. */ |
916 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); |
917 | 0 | apdu.lc = p - sbuf; |
918 | 0 | apdu.datalen = p - sbuf; |
919 | 0 | apdu.data = sbuf; |
920 | 0 | if ((apdu.datalen > 255) && !(card->caps & SC_CARD_CAP_APDU_EXT)) |
921 | 0 | { |
922 | 0 | apdu.flags |= SC_APDU_FLAGS_CHAINING; |
923 | 0 | } |
924 | 0 | r = sc_transmit_apdu(card, &apdu); |
925 | 0 | if(r < 0) |
926 | 0 | { |
927 | 0 | sc_log(card->ctx, "APDU transmit failed"); |
928 | 0 | goto out; |
929 | 0 | } |
930 | | |
931 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
932 | 0 | if(apdu.sw1 == 0x6D && apdu.sw2 == 0x00) |
933 | 0 | { |
934 | 0 | sc_log(card->ctx, "The applet returned that the PUT DATA instruction byte is not supported. " |
935 | 0 | "If you are using an older applet version and are trying to import keys, please update your applet first."); |
936 | 0 | } |
937 | 0 | else if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) |
938 | 0 | { |
939 | 0 | sc_log(card->ctx, "Key import not supported by the card with that particular key type. " |
940 | 0 | "Your card may not support the specified algorithm used by the applet / specified by you. " |
941 | 0 | "In most cases, this happens when trying to import EC keys not supported by your java card. " |
942 | 0 | "In this case, look for supported field lengths and whether FP and/or F2M are supported. " |
943 | 0 | "If you tried to import a private RSA key, check the key length."); |
944 | 0 | } |
945 | 0 | else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) |
946 | 0 | { |
947 | 0 | sc_log(card->ctx, "Key import not allowed by the applet's security policy. " |
948 | 0 | "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," |
949 | 0 | " rebuild and reinstall the applet."); |
950 | 0 | } |
951 | 0 | if(r < 0) |
952 | 0 | { |
953 | 0 | sc_log(card->ctx, "Card returned error"); |
954 | 0 | goto out; |
955 | 0 | } |
956 | | |
957 | 0 | r = SC_SUCCESS; |
958 | 0 | out: |
959 | 0 | sc_mem_clear(sbuf, sizeof(sbuf)); |
960 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
961 | 0 | } |
962 | | |
963 | | /* |
964 | | * @brief Import a private key. |
965 | | */ |
966 | | static int |
967 | | isoApplet_ctl_import_key(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) |
968 | 0 | { |
969 | 0 | int r; |
970 | 0 | size_t sz; |
971 | 0 | sc_apdu_t apdu; |
972 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; |
973 | 0 | u8 *p; |
974 | |
|
975 | 0 | LOG_FUNC_CALLED(card->ctx); |
976 | | |
977 | | /* |
978 | | * Private keys are not stored in the filesystem. |
979 | | * ISO 7816-8 - section C.2 describes: |
980 | | * "Usage of the PUT DATA command for private key import" |
981 | | * The applet uses this PUT DATA to import private keys, if private key import is allowed. |
982 | | * |
983 | | * The first step is to perform a MANAGE SECURITY ENVIRONMENT as it would be done |
984 | | * with on-card key generation. The second step is PUT DATA (instead of |
985 | | * GENERATE ASYMMETRIC KEY PAIR). |
986 | | */ |
987 | | |
988 | | /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ |
989 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); |
990 | |
|
991 | 0 | p = sbuf; |
992 | 0 | *p++ = 0x80; /* algorithm reference */ |
993 | 0 | *p++ = 0x01; |
994 | 0 | *p++ = args->algorithm_ref; |
995 | |
|
996 | 0 | *p++ = 0x84; /* Private key reference */ |
997 | 0 | *p++ = 0x01; |
998 | 0 | *p++ = args->priv_key_ref; |
999 | |
|
1000 | 0 | sz = p - sbuf; |
1001 | 0 | p = NULL; |
1002 | |
|
1003 | 0 | apdu.lc = sz; |
1004 | 0 | apdu.datalen = sz; |
1005 | 0 | apdu.data = sbuf; |
1006 | |
|
1007 | 0 | r = sc_transmit_apdu(card, &apdu); |
1008 | 0 | LOG_TEST_RET(card->ctx, r, "%s: APDU transmit failed"); |
1009 | | |
1010 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1011 | 0 | LOG_TEST_RET(card->ctx, r, "Card returned error"); |
1012 | | |
1013 | | |
1014 | | /* PUT DATA */ |
1015 | 0 | switch(args->algorithm_ref) |
1016 | 0 | { |
1017 | | |
1018 | 0 | case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: |
1019 | 0 | r = isoApplet_put_data_prkey_rsa(card, args); |
1020 | 0 | LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); |
1021 | 0 | break; |
1022 | | |
1023 | 0 | case SC_ISOAPPLET_ALG_REF_EC_GEN: |
1024 | 0 | r = isoApplet_put_data_prkey_ec(card, args); |
1025 | 0 | LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); |
1026 | 0 | break; |
1027 | | |
1028 | 0 | default: |
1029 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unknown algorithm reference."); |
1030 | 0 | } |
1031 | | |
1032 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1033 | 0 | } |
1034 | | |
1035 | | static int |
1036 | | isoApplet_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) |
1037 | 1 | { |
1038 | 1 | int r = 0; |
1039 | | |
1040 | 1 | LOG_FUNC_CALLED(card->ctx); |
1041 | 1 | switch (cmd) |
1042 | 1 | { |
1043 | 0 | case SC_CARDCTL_ISOAPPLET_GENERATE_KEY: |
1044 | 0 | r = isoApplet_ctl_generate_key(card, |
1045 | 0 | (sc_cardctl_isoApplet_genkey_t *) ptr); |
1046 | 0 | break; |
1047 | 0 | case SC_CARDCTL_ISOAPPLET_IMPORT_KEY: |
1048 | 0 | r = isoApplet_ctl_import_key(card, |
1049 | 0 | (sc_cardctl_isoApplet_import_key_t *) ptr); |
1050 | 0 | break; |
1051 | 1 | default: |
1052 | 1 | r = SC_ERROR_NOT_SUPPORTED; |
1053 | 1 | } |
1054 | 1 | LOG_FUNC_RETURN(card->ctx, r); |
1055 | 1 | } |
1056 | | |
1057 | | static int |
1058 | | isoApplet_set_security_env(sc_card_t *card, |
1059 | | const sc_security_env_t *env, int se_num) |
1060 | 0 | { |
1061 | 0 | sc_apdu_t apdu; |
1062 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; |
1063 | 0 | u8 *p; |
1064 | 0 | int r; |
1065 | 0 | size_t sz; |
1066 | 0 | struct isoApplet_drv_data *drvdata = DRVDATA(card); |
1067 | |
|
1068 | 0 | LOG_FUNC_CALLED(card->ctx); |
1069 | |
|
1070 | 0 | if(se_num != 0) |
1071 | 0 | { |
1072 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, |
1073 | 0 | "IsoApplet does not support storing of security environments."); |
1074 | 0 | } |
1075 | 0 | assert(card != NULL && env != NULL); |
1076 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); |
1077 | 0 | switch (env->operation) |
1078 | 0 | { |
1079 | 0 | case SC_SEC_OPERATION_DECIPHER: |
1080 | 0 | apdu.p2 = 0xB8; |
1081 | 0 | break; |
1082 | 0 | case SC_SEC_OPERATION_SIGN: |
1083 | 0 | apdu.p2 = 0xB6; |
1084 | 0 | break; |
1085 | 0 | default: |
1086 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1087 | 0 | } |
1088 | 0 | p = sbuf; |
1089 | |
|
1090 | 0 | if (env->flags & SC_SEC_ENV_ALG_PRESENT) |
1091 | 0 | { |
1092 | |
|
1093 | 0 | switch(env->algorithm) |
1094 | 0 | { |
1095 | | |
1096 | 0 | case SC_ALGORITHM_RSA: |
1097 | 0 | if( env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1 ) |
1098 | 0 | { |
1099 | 0 | drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_RSA_PAD_PKCS1; |
1100 | 0 | } |
1101 | 0 | else if( env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS ) |
1102 | 0 | { |
1103 | 0 | drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_RSA_PAD_PSS; |
1104 | 0 | } |
1105 | 0 | else |
1106 | 0 | { |
1107 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet does not support requested padding/hash combination"); |
1108 | 0 | } |
1109 | 0 | break; |
1110 | | |
1111 | 0 | case SC_ALGORITHM_EC: |
1112 | 0 | drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_ECDSA; |
1113 | 0 | drvdata->sec_env_ec_field_length = env->algorithm_ref; |
1114 | 0 | break; |
1115 | | |
1116 | 0 | default: |
1117 | 0 | LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported algorithm."); |
1118 | 0 | } |
1119 | | |
1120 | 0 | *p++ = 0x80; /* algorithm reference */ |
1121 | 0 | *p++ = 0x01; |
1122 | 0 | *p++ = drvdata->sec_env_alg_ref; |
1123 | 0 | } |
1124 | | |
1125 | 0 | if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) |
1126 | 0 | { |
1127 | 0 | *p++ = 0x81; |
1128 | 0 | *p++ = env->file_ref.len; |
1129 | 0 | assert(sizeof(sbuf) - (p - sbuf) >= env->file_ref.len); |
1130 | 0 | memcpy(p, env->file_ref.value, env->file_ref.len); |
1131 | 0 | p += env->file_ref.len; |
1132 | 0 | } |
1133 | |
|
1134 | 0 | if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) |
1135 | 0 | { |
1136 | 0 | if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) |
1137 | 0 | *p++ = 0x83; |
1138 | 0 | else |
1139 | 0 | *p++ = 0x84; |
1140 | 0 | *p++ = env->key_ref_len; |
1141 | 0 | assert(sizeof(sbuf) - (p - sbuf) >= env->key_ref_len); |
1142 | 0 | memcpy(p, env->key_ref, env->key_ref_len); |
1143 | 0 | p += env->key_ref_len; |
1144 | 0 | } |
1145 | 0 | sz = p - sbuf; |
1146 | 0 | apdu.lc = sz; |
1147 | 0 | apdu.datalen = sz; |
1148 | 0 | apdu.data = sbuf; |
1149 | 0 | r = (int)sz; |
1150 | |
|
1151 | 0 | if (apdu.datalen != 0) |
1152 | 0 | { |
1153 | 0 | r = sc_transmit_apdu(card, &apdu); |
1154 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
1155 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1156 | 0 | LOG_TEST_RET(card->ctx, r, "Card returned error"); |
1157 | 0 | } |
1158 | | |
1159 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1160 | 0 | } |
1161 | | |
1162 | | static int |
1163 | | isoApplet_compute_signature(struct sc_card *card, |
1164 | | const u8 *data, size_t datalen, |
1165 | | u8 *out, size_t outlen) |
1166 | 0 | { |
1167 | 0 | struct sc_context *ctx = card->ctx; |
1168 | 0 | struct isoApplet_drv_data *drvdata = DRVDATA(card); |
1169 | 0 | int r; |
1170 | |
|
1171 | 0 | LOG_FUNC_CALLED(ctx); |
1172 | |
|
1173 | 0 | if (drvdata->sec_env_alg_ref == ISOAPPLET_ALG_REF_RSA_PAD_PSS) { |
1174 | | // For RSA-PSS signature schemes the IsoApplet expects only the hash. |
1175 | 0 | u8 tmp[64]; // large enough for SHA512 |
1176 | 0 | size_t tmplen = sizeof(tmp); |
1177 | 0 | r = sc_pkcs1_strip_digest_info_prefix(NULL, data, datalen, tmp, &tmplen); |
1178 | 0 | if (r == SC_SUCCESS) { |
1179 | 0 | r = iso_ops->compute_signature(card, tmp, tmplen, out, outlen); |
1180 | 0 | } else { |
1181 | | /* No digest info present? Use the value as it is */ |
1182 | 0 | r = iso_ops->compute_signature(card, data, datalen, out, outlen); |
1183 | 0 | } |
1184 | 0 | } else if (drvdata->sec_env_alg_ref == ISOAPPLET_ALG_REF_ECDSA) { |
1185 | | /* |
1186 | | * The card returns ECDSA signatures as an ASN.1 sequence of integers R,S |
1187 | | * while PKCS#11 expects the raw concatenation of R,S for PKCS#11. |
1188 | | * We cannot expect the caller to provide an out buffer that is large enough for the ASN.1 sequence. |
1189 | | * Therefore, we allocate a temporary buffer for the card output, and then convert it to raw R,S. |
1190 | | * The card supports no curves with field sizes larger than 384bit (EC:secp384r1 which yields an ASN.1 |
1191 | | * encoded signature of 104 byte: |
1192 | | * R and S = 384 bit = 48 byte + 1 zero byte if the first bit is set (otherwise they are interpreted as negative). |
1193 | | * Seq-Tag&Len (2 bytes) + R-Tag&Len (2 bytes) + R (49 bytes) + S-Tag&Len (2 bytes) + S (49 bytes) |
1194 | | */ |
1195 | 0 | u8 seqbuf[104]; |
1196 | 0 | size_t seqlen = sizeof(seqbuf); |
1197 | 0 | r = iso_ops->compute_signature(card, data, datalen, seqbuf, seqlen); |
1198 | |
|
1199 | 0 | if (r < 0) { |
1200 | 0 | LOG_FUNC_RETURN(ctx, r); |
1201 | 0 | } |
1202 | | |
1203 | | /* Convert ASN.1 sequence of integers R,S to the raw concatenation of R,S for PKCS#11. */ |
1204 | 0 | size_t len = BYTES4BITS(drvdata->sec_env_ec_field_length) * 2; |
1205 | 0 | if (len > outlen) |
1206 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL); |
1207 | | |
1208 | 0 | r = sc_asn1_sig_value_sequence_to_rs(ctx, seqbuf, r, out, len); |
1209 | 0 | LOG_TEST_RET(ctx, r, "Failed to convert ASN.1 signature to raw RS"); |
1210 | 0 | r = (int)len; |
1211 | 0 | } else { |
1212 | 0 | r = iso_ops->compute_signature(card, data, datalen, out, outlen); |
1213 | 0 | } |
1214 | 0 | LOG_FUNC_RETURN(ctx, r); |
1215 | 0 | } |
1216 | | |
1217 | | static int |
1218 | | isoApplet_get_challenge(struct sc_card *card, u8 *rnd, size_t len) |
1219 | 0 | { |
1220 | 0 | int r; |
1221 | |
|
1222 | 0 | LOG_FUNC_CALLED(card->ctx); |
1223 | |
|
1224 | 0 | if(card->caps & SC_CARD_CAP_RNG) { |
1225 | 0 | r = iso_ops->get_challenge(card, rnd, len); |
1226 | 0 | } else { |
1227 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
1228 | 0 | } |
1229 | |
|
1230 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
1231 | 0 | } |
1232 | | |
1233 | | static int isoApplet_card_reader_lock_obtained(sc_card_t *card, int was_reset) |
1234 | 3.84k | { |
1235 | 3.84k | int r = SC_SUCCESS; |
1236 | | |
1237 | 3.84k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1238 | | |
1239 | 3.84k | if (was_reset > 0) { |
1240 | 0 | r = iso7816_select_aid(card, isoApplet_aid, sizeof(isoApplet_aid), NULL, NULL); |
1241 | 0 | } |
1242 | | |
1243 | 3.84k | LOG_FUNC_RETURN(card->ctx, r); |
1244 | 3.84k | } |
1245 | | |
1246 | | static int isoApplet_logout(sc_card_t *card) |
1247 | 0 | { |
1248 | 0 | return iso7816_select_aid(card, isoApplet_aid, sizeof(isoApplet_aid), NULL, NULL); |
1249 | 0 | } |
1250 | | |
1251 | | static struct sc_card_driver *sc_get_driver(void) |
1252 | 15.2k | { |
1253 | 15.2k | sc_card_driver_t *iso_drv = sc_get_iso7816_driver(); |
1254 | | |
1255 | 15.2k | if(iso_ops == NULL) |
1256 | 1 | { |
1257 | 1 | iso_ops = iso_drv->ops; |
1258 | 1 | } |
1259 | | |
1260 | 15.2k | isoApplet_ops = *iso_drv->ops; |
1261 | | |
1262 | 15.2k | isoApplet_ops.match_card = isoApplet_match_card; |
1263 | 15.2k | isoApplet_ops.init = isoApplet_init; |
1264 | 15.2k | isoApplet_ops.finish = isoApplet_finish; |
1265 | | |
1266 | 15.2k | isoApplet_ops.card_ctl = isoApplet_card_ctl; |
1267 | | |
1268 | 15.2k | isoApplet_ops.create_file = isoApplet_create_file; |
1269 | 15.2k | isoApplet_ops.process_fci = isoApplet_process_fci; |
1270 | 15.2k | isoApplet_ops.set_security_env = isoApplet_set_security_env; |
1271 | 15.2k | isoApplet_ops.compute_signature = isoApplet_compute_signature; |
1272 | 15.2k | isoApplet_ops.get_challenge = isoApplet_get_challenge; |
1273 | 15.2k | isoApplet_ops.card_reader_lock_obtained = isoApplet_card_reader_lock_obtained; |
1274 | 15.2k | isoApplet_ops.logout = isoApplet_logout; |
1275 | | |
1276 | | /* unsupported functions */ |
1277 | 15.2k | isoApplet_ops.write_binary = NULL; |
1278 | 15.2k | isoApplet_ops.read_record = NULL; |
1279 | 15.2k | isoApplet_ops.write_record = NULL; |
1280 | 15.2k | isoApplet_ops.append_record = NULL; |
1281 | 15.2k | isoApplet_ops.update_record = NULL; |
1282 | 15.2k | isoApplet_ops.restore_security_env = NULL; |
1283 | | |
1284 | 15.2k | return &isoApplet_drv; |
1285 | 15.2k | } |
1286 | | |
1287 | | struct sc_card_driver * sc_get_isoApplet_driver(void) |
1288 | 15.2k | { |
1289 | 15.2k | return sc_get_driver(); |
1290 | 15.2k | } |