/src/opensc/src/libopensc/card-gemsafeV1.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 David Mattes (david.mattes@boeing.com) */ |
18 | | /* Portuguese eID card support by Joao Poupino (joao.poupino@ist.utl.pt) */ |
19 | | |
20 | | #ifdef HAVE_CONFIG_H |
21 | | #include "config.h" |
22 | | #endif |
23 | | |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | |
27 | | #include "internal.h" |
28 | | #include "asn1.h" |
29 | | #include "cardctl.h" |
30 | | |
31 | 65 | #define GEMSAFEV1_ALG_REF_FREEFORM 0x12 |
32 | 6 | #define GEMSAFEV3_ALG_REF_FREEFORM 0x02 |
33 | | #define GEMSAFEV3_ALG_REF_SHA1 0x12 |
34 | 6 | #define GEMSAFEV3_ALG_REF_SHA256 0x42 |
35 | | #define MAX_RESP_BUFFER_SIZE 2048 |
36 | | |
37 | | static struct sc_card_operations gemsafe_ops; |
38 | | static struct sc_card_operations *iso_ops = NULL; |
39 | | |
40 | | static struct sc_card_driver gemsafe_drv = { |
41 | | "Gemalto GemSafe V1 applet", |
42 | | "gemsafeV1", |
43 | | &gemsafe_ops, |
44 | | NULL, 0, NULL |
45 | | }; |
46 | | |
47 | | /* Known ATRs */ |
48 | | static const struct sc_atr_table gemsafe_atrs[] = { |
49 | | /* standard version */ |
50 | | {"3B:7B:94:00:00:80:65:B0:83:01:01:74:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
51 | | {"3B:6B:00:00:80:65:B0:83:01:01:74:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
52 | | /* GemSafeXpresso 32K */ |
53 | | {"3b:6d:00:00:80:31:80:65:b0:83:01:02:90:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
54 | | /* fips 140 version */ |
55 | | {"3B:6B:00:00:80:65:B0:83:01:03:74:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
56 | | /* Undefined */ |
57 | | {"3B:7A:94:00:00:80:65:A2:01:01:01:3D:72:D6:43", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
58 | | {"3B:7D:94:00:00:80:31:80:65:B0:83:01:01:90:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
59 | | {"3B:7D:96:00:00:80:31:80:65:B0:83:11:48:C8:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_GENERIC, 0, NULL}, |
60 | | /* Portuguese eID cards */ |
61 | | {"3B:7D:95:00:00:80:31:80:65:B0:83:11:C0:A9:83:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_PTEID, 0, NULL}, |
62 | | {"3B:7D:95:00:00:80:31:80:65:B0:83:11:C0:A9:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_PTEID, 0, NULL}, |
63 | | {"3B:7D:95:00:00:80:31:80:65:B0:83:11:00:C8:83:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_PTEID, 0, NULL}, |
64 | | {"3B:7D:95:00:00:80:31:80:65:B0:83:11:00:C8:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_PTEID, 0, NULL}, |
65 | | {"3B:FF:96:00:00:81:31:80:43:80:31:80:65:B0:85:03:00:EF:12:0F:FF:82:90:00:67", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_PTEID, 0, NULL}, |
66 | | {"3B:FF:96:00:00:81:31:FE:43:80:31:80:65:B0:85:04:01:20:12:0F:FF:82:90:00:D0", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_PTEID, 0, NULL}, |
67 | | /* Swedish eID card */ |
68 | | {"3B:7D:96:00:00:80:31:80:65:B0:83:11:00:C8:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_SEEID, 0, NULL}, |
69 | | /* European Patent Office epoline card*/ |
70 | | {"3b:7d:96:00:00:80:31:80:65:b0:83:02:01:f3:83:00:90:00", NULL, NULL, SC_CARD_TYPE_GEMSAFEV1_SEEID, 0, NULL}, |
71 | | {NULL, NULL, NULL, 0, 0, NULL} |
72 | | }; |
73 | | |
74 | | static const u8 gemsafe_def_aid[] = {0xA0, 0x00, 0x00, 0x00, 0x18, 0x0A, |
75 | | 0x00, 0x00, 0x01, 0x63, 0x42, 0x00}; |
76 | | |
77 | | static const u8 gemsafe_pteid_aid[] = {0x60, 0x46, 0x32, 0xFF, 0x00, 0x00, 0x02}; |
78 | | |
79 | | static const u8 gemsafe_seeid_aid[] = {0xA0, 0x00, 0x00, 0x00, 0x18, 0x0C, |
80 | | 0x00, 0x00, 0x01, 0x63, 0x42, 0x00}; |
81 | | |
82 | | /* |
83 | | static const u8 gemsafe_def_aid[] = {0xA0, 0x00, 0x00, 0x00, 0x63, 0x50, |
84 | | 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35}; |
85 | | */ |
86 | | |
87 | | typedef struct gemsafe_exdata_st { |
88 | | u8 aid[16]; |
89 | | size_t aid_len; |
90 | | } gemsafe_exdata; |
91 | | |
92 | | static int get_conf_aid(sc_card_t *card, u8 *aid, size_t *len) |
93 | 91 | { |
94 | 91 | sc_context_t *ctx = card->ctx; |
95 | 91 | scconf_block *conf_block, **blocks; |
96 | 91 | int i; |
97 | 91 | const char *str_aid; |
98 | | |
99 | 91 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
100 | | |
101 | 91 | conf_block = NULL; |
102 | 182 | for (i = 0; ctx->conf_blocks[i] != NULL; i++) { |
103 | 91 | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], |
104 | 91 | "card", "gemsafeV1"); |
105 | 91 | if (blocks != NULL && blocks[0] != NULL) |
106 | 0 | conf_block = blocks[0]; |
107 | 91 | free(blocks); |
108 | 91 | } |
109 | | |
110 | 91 | if (!conf_block) { |
111 | 91 | sc_log(ctx, "no card specific options configured, trying default AID\n"); |
112 | 91 | return SC_ERROR_INTERNAL; |
113 | 91 | } |
114 | | |
115 | 0 | str_aid = scconf_get_str(conf_block, "aid", NULL); |
116 | 0 | if (!str_aid) { |
117 | 0 | sc_log(ctx, "no aid configured, trying default AID\n"); |
118 | 0 | return SC_ERROR_INTERNAL; |
119 | 0 | } |
120 | 0 | return sc_hex_to_bin(str_aid, aid, len); |
121 | 0 | } |
122 | | |
123 | | static int gemsafe_match_card(sc_card_t *card) |
124 | 14.4k | { |
125 | 14.4k | int i; |
126 | | |
127 | 14.4k | i = _sc_match_atr(card, gemsafe_atrs, &card->type); |
128 | 14.4k | if (i < 0) |
129 | 13.8k | return 0; |
130 | | |
131 | 542 | return 1; |
132 | 14.4k | } |
133 | | |
134 | | static int gemsafe_init(struct sc_card *card) |
135 | 542 | { |
136 | 542 | int r; |
137 | 542 | gemsafe_exdata *exdata = NULL; |
138 | | |
139 | 542 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
140 | | |
141 | 542 | card->name = "GemSAFE V1"; |
142 | 542 | card->cla = 0x00; |
143 | | |
144 | 542 | exdata = (gemsafe_exdata *)calloc(1, sizeof(gemsafe_exdata)); |
145 | 542 | if (!exdata) |
146 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
147 | 542 | exdata->aid_len = sizeof(exdata->aid); |
148 | 542 | if(card->type == SC_CARD_TYPE_GEMSAFEV1_GENERIC) { |
149 | | /* try to get a AID from the config file */ |
150 | 91 | r = get_conf_aid(card, exdata->aid, &exdata->aid_len); |
151 | 91 | if (r < 0) { |
152 | | /* failed, use default value */ |
153 | 91 | memcpy(exdata->aid, gemsafe_def_aid, sizeof(gemsafe_def_aid)); |
154 | 91 | exdata->aid_len = sizeof(gemsafe_def_aid); |
155 | 91 | } |
156 | 451 | } else if (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID) { |
157 | 449 | memcpy(exdata->aid, gemsafe_pteid_aid, sizeof(gemsafe_pteid_aid)); |
158 | 449 | exdata->aid_len = sizeof(gemsafe_pteid_aid); |
159 | 449 | } else if (card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) { |
160 | 2 | memcpy(exdata->aid, gemsafe_seeid_aid, sizeof(gemsafe_seeid_aid)); |
161 | 2 | exdata->aid_len = sizeof(gemsafe_seeid_aid); |
162 | 2 | } |
163 | | |
164 | | /* increase lock_count here to prevent sc_unlock to select |
165 | | * applet twice in gp_select_applet */ |
166 | 542 | card->lock_count++; |
167 | | /* SELECT applet */ |
168 | 542 | r = iso7816_select_aid(card, exdata->aid, exdata->aid_len, NULL, NULL); |
169 | 542 | if (r < 0) { |
170 | 8 | free(exdata); |
171 | 8 | sc_log(card->ctx, "applet selection failed\n"); |
172 | 8 | return SC_ERROR_INVALID_CARD; |
173 | 8 | } |
174 | 534 | card->lock_count--; |
175 | | |
176 | | /* set the supported algorithm */ |
177 | 534 | unsigned long flags; |
178 | | |
179 | 534 | flags = SC_ALGORITHM_RSA_PAD_PKCS1; |
180 | 534 | flags |= SC_ALGORITHM_RSA_PAD_ISO9796; |
181 | 534 | flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; |
182 | 534 | flags |= SC_ALGORITHM_RSA_HASH_NONE; |
183 | | |
184 | | /* GemSAFE V3 cards support SHA256 */ |
185 | 534 | if (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || |
186 | 91 | card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) |
187 | 444 | flags |= SC_ALGORITHM_RSA_HASH_SHA256; |
188 | | |
189 | 534 | _sc_card_add_rsa_alg(card, 512, flags, 0); |
190 | 534 | _sc_card_add_rsa_alg(card, 768, flags, 0); |
191 | 534 | _sc_card_add_rsa_alg(card, 1024, flags, 0); |
192 | 534 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
193 | 534 | _sc_card_add_rsa_alg(card, 3072, flags, 0); |
194 | 534 | _sc_card_add_rsa_alg(card, 4096, flags, 0); |
195 | | |
196 | | /* fake algorithm to persuade register_mechanisms() |
197 | | * to register these hashes */ |
198 | 534 | if (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || |
199 | 444 | card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) { |
200 | 444 | flags = SC_ALGORITHM_RSA_HASH_SHA1; |
201 | 444 | flags |= SC_ALGORITHM_RSA_HASH_MD5; |
202 | 444 | flags |= SC_ALGORITHM_RSA_HASH_MD5_SHA1; |
203 | 444 | flags |= SC_ALGORITHM_RSA_HASH_RIPEMD160; |
204 | | |
205 | 444 | _sc_card_add_rsa_alg(card, 512, flags, 0); |
206 | 444 | } |
207 | | |
208 | 534 | card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; |
209 | 534 | card->drv_data = exdata; |
210 | | |
211 | 534 | return SC_SUCCESS; |
212 | 542 | } |
213 | | |
214 | | static int gemsafe_finish(sc_card_t *card) |
215 | 534 | { |
216 | 534 | gemsafe_exdata *exdata = (gemsafe_exdata *)card->drv_data; |
217 | | |
218 | 534 | if (exdata) |
219 | 534 | free(exdata); |
220 | 534 | return SC_SUCCESS; |
221 | 534 | } |
222 | | |
223 | | static int gemsafe_select_file(struct sc_card *card, const struct sc_path *path, |
224 | | struct sc_file **file_out) |
225 | 4.41k | { |
226 | | /* so far just call the iso select file (but this will change) */ |
227 | 4.41k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
228 | | |
229 | 4.41k | return iso_ops->select_file(card, path, file_out); |
230 | 4.41k | } |
231 | | |
232 | | static int gemsafe_sc2acl(sc_file_t *file, unsigned ops, u8 sc_byte) |
233 | 304 | { |
234 | 304 | int r; |
235 | 304 | unsigned int meth = 0; |
236 | | |
237 | 304 | if (sc_byte == 0xff) { |
238 | 110 | r = sc_file_add_acl_entry(file, ops, SC_AC_NEVER, 0); |
239 | 110 | return r; |
240 | 110 | } |
241 | 194 | if (sc_byte == 0x00) { |
242 | 26 | r = sc_file_add_acl_entry(file, ops, SC_AC_NONE, 0); |
243 | 26 | return r; |
244 | 26 | } |
245 | | |
246 | | /* XXX: OR combination of access rights are currently not supported |
247 | | * hence ignored */ |
248 | 168 | if (sc_byte & 0x40) |
249 | 105 | meth |= SC_AC_PRO; |
250 | 168 | if (sc_byte & 0x20) |
251 | 98 | meth |= SC_AC_AUT | SC_AC_TERM; |
252 | 168 | if (sc_byte & 0x10) |
253 | 69 | meth |= SC_AC_CHV; |
254 | | |
255 | 168 | return sc_file_add_acl_entry(file, ops, meth, sc_byte & 0x0f); |
256 | 194 | } |
257 | | |
258 | | static int gemsafe_setacl(sc_card_t *card, sc_file_t *file, const u8 *data, |
259 | | int is_df) |
260 | 96 | { |
261 | 96 | int r; |
262 | 96 | u8 cond; |
263 | 96 | const u8 *p = data + 1; |
264 | 96 | struct sc_context *ctx = card->ctx; |
265 | | |
266 | 96 | if (is_df) { |
267 | 40 | if (*data & 0x04) /* CREATE DF */ |
268 | 19 | cond = *p++; |
269 | 21 | else |
270 | 21 | cond = 0xff; |
271 | 40 | sc_log(ctx, |
272 | 40 | "DF security byte CREATE DF: %02x\n", cond); |
273 | 40 | r = gemsafe_sc2acl(file, SC_AC_OP_CREATE, cond); |
274 | 40 | if (r < 0) |
275 | 0 | return r; |
276 | 40 | if (*data & 0x02) /* CREATE EF */ |
277 | 28 | cond = *p; |
278 | 12 | else |
279 | 12 | cond = 0xff; |
280 | 40 | sc_log(ctx, |
281 | 40 | "DF security byte CREATE EF: %02x\n", cond); |
282 | | /* XXX: opensc doesn't currently separate access conditions for |
283 | | * CREATE EF and CREATE DF, this should be changed */ |
284 | 40 | r = gemsafe_sc2acl(file, SC_AC_OP_CREATE, cond); |
285 | 40 | if (r < 0) |
286 | 0 | return r; |
287 | 56 | } else { |
288 | | /* XXX: ACTIVATE FILE and DEACTIVATE FILE ac are currently not |
289 | | * supported => ignore them */ |
290 | 56 | if (*data & 0x02) /* UPDATE BINARY, ERASE BINARY */ |
291 | 36 | cond = *p++; |
292 | 20 | else |
293 | 20 | cond = 0xff; |
294 | 56 | sc_log(ctx, |
295 | 56 | "EF security byte UPDATE/ERASE BINARY: %02x\n", cond); |
296 | 56 | r = gemsafe_sc2acl(file, SC_AC_OP_UPDATE, cond); |
297 | 56 | if (r < 0) |
298 | 0 | return r; |
299 | 56 | r = gemsafe_sc2acl(file, SC_AC_OP_WRITE, cond); |
300 | 56 | if (r < 0) |
301 | 0 | return r; |
302 | 56 | r = gemsafe_sc2acl(file, SC_AC_OP_ERASE, cond); |
303 | 56 | if (r < 0) |
304 | 0 | return r; |
305 | 56 | if (*data & 0x01) /* READ BINARY */ |
306 | 43 | cond = *p; |
307 | 13 | else |
308 | 13 | cond = 0xff; |
309 | 56 | sc_log(ctx, |
310 | 56 | "EF security byte READ BINARY: %02x\n", cond); |
311 | 56 | r = gemsafe_sc2acl(file, SC_AC_OP_READ, cond); |
312 | 56 | if (r < 0) |
313 | 0 | return r; |
314 | 56 | } |
315 | | |
316 | 96 | return SC_SUCCESS; |
317 | 96 | } |
318 | | |
319 | | static int gemsafe_process_fci(struct sc_card *card, struct sc_file *file, |
320 | | const u8 *buf, size_t len) |
321 | 528 | { |
322 | 528 | int r; |
323 | 528 | size_t tlen; |
324 | 528 | const u8 *tag = NULL, *p = buf; |
325 | 528 | const char *type; |
326 | 528 | struct sc_context *ctx = card->ctx; |
327 | | |
328 | 528 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
329 | | |
330 | 528 | r = iso_ops->process_fci(card, file, buf, len); |
331 | 528 | if (r < 0) |
332 | 0 | return r; |
333 | 528 | sc_log(ctx, |
334 | 528 | "processing GemSAFE V1 specific FCI information\n"); |
335 | | |
336 | | |
337 | 528 | tag = sc_asn1_find_tag(ctx, p, len, 0x82, &tlen); |
338 | 528 | if (!tag) { |
339 | | /* no FDB => we have a DF */ |
340 | 240 | type = "DF"; |
341 | 240 | file->type = SC_FILE_TYPE_DF; |
342 | 288 | } else { |
343 | 288 | type = "EF"; |
344 | 288 | file->type = SC_FILE_TYPE_WORKING_EF; |
345 | 288 | } |
346 | | |
347 | 528 | sc_log(ctx, "file type: %s\n", type); |
348 | | |
349 | 528 | tag = sc_asn1_find_tag(ctx, p, len, 0x8C, &tlen); |
350 | 528 | if (tag) { |
351 | 96 | r = gemsafe_setacl(card, file, tag, strcmp(type, "DF") ? 0 : 1); |
352 | 96 | if (r < 0) { |
353 | 0 | sc_log(ctx, "unable to set ACL\n"); |
354 | 0 | return SC_ERROR_INTERNAL; |
355 | 0 | } |
356 | 96 | } else |
357 | 432 | sc_log(ctx, "error: AM and SC bytes missing\n"); |
358 | | |
359 | 528 | return SC_SUCCESS; |
360 | 528 | } |
361 | | |
362 | | static u8 gemsafe_flags2algref(struct sc_card *card, const struct sc_security_env *env) |
363 | 77 | { |
364 | 77 | u8 ret = 0; |
365 | | |
366 | 77 | if (env->operation == SC_SEC_OPERATION_SIGN) { |
367 | 44 | if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) |
368 | 6 | ret = GEMSAFEV3_ALG_REF_SHA256; |
369 | 38 | else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01) |
370 | 38 | ret = (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || |
371 | 33 | card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) ? |
372 | 5 | GEMSAFEV3_ALG_REF_FREEFORM : |
373 | 38 | GEMSAFEV1_ALG_REF_FREEFORM; |
374 | 0 | else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796) |
375 | 0 | ret = 0x11; |
376 | 44 | } else if (env->operation == SC_SEC_OPERATION_DECIPHER) { |
377 | 33 | if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02) |
378 | 33 | ret = (card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || |
379 | 32 | card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) ? |
380 | 1 | GEMSAFEV3_ALG_REF_FREEFORM : |
381 | 33 | GEMSAFEV1_ALG_REF_FREEFORM; |
382 | 33 | } |
383 | | |
384 | 77 | return ret; |
385 | 77 | } |
386 | | |
387 | | static int gemsafe_restore_security_env(struct sc_card *card, int se_num) |
388 | 0 | { |
389 | 0 | int r; |
390 | 0 | struct sc_apdu apdu; |
391 | |
|
392 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
393 | |
|
394 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0x73, (u8) se_num); |
395 | |
|
396 | 0 | r = sc_transmit_apdu(card, &apdu); |
397 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
398 | | |
399 | 0 | return sc_check_sw(card, apdu.sw1, apdu.sw2); |
400 | 0 | } |
401 | | |
402 | | |
403 | | static int gemsafe_set_security_env(struct sc_card *card, |
404 | | const struct sc_security_env *env, |
405 | | int se_num) |
406 | 77 | { |
407 | 77 | u8 alg_ref; |
408 | 77 | struct sc_security_env se_env = *env; |
409 | 77 | struct sc_context *ctx = card->ctx; |
410 | | |
411 | 77 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
412 | | |
413 | 77 | if (!(se_env.flags & SC_SEC_ENV_ALG_REF_PRESENT)) { |
414 | | /* set the algorithm reference */ |
415 | 77 | alg_ref = gemsafe_flags2algref(card, &se_env); |
416 | 77 | if (alg_ref) { |
417 | 77 | se_env.algorithm_ref = alg_ref; |
418 | 77 | se_env.flags |= SC_SEC_ENV_ALG_REF_PRESENT; |
419 | 77 | } |
420 | 77 | } |
421 | 77 | if (!(se_env.flags & SC_SEC_ENV_ALG_REF_PRESENT)) |
422 | 0 | sc_log(ctx, "unknown algorithm flags '%lx'\n", se_env.algorithm_flags); |
423 | | |
424 | 77 | se_env.flags &= ~SC_SEC_ENV_FILE_REF_PRESENT; |
425 | 77 | return iso_ops->set_security_env(card, &se_env, se_num); |
426 | 77 | } |
427 | | |
428 | | static int gemsafe_compute_signature(struct sc_card *card, const u8 * data, |
429 | | size_t data_len, u8 * out, size_t outlen) |
430 | 34 | { |
431 | 34 | int r; |
432 | 34 | size_t len; |
433 | 34 | struct sc_apdu apdu; |
434 | 34 | u8 rbuf[MAX_RESP_BUFFER_SIZE]; |
435 | 34 | u8 sbuf[MAX_RESP_BUFFER_SIZE]; |
436 | 34 | sc_context_t *ctx = card->ctx; |
437 | | |
438 | 34 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
439 | | |
440 | | /* the card can sign 36 bytes of free form data */ |
441 | 34 | if (data_len > 36) { |
442 | 2 | sc_log(ctx, |
443 | 2 | "error: input data too long: %"SC_FORMAT_LEN_SIZE_T"u bytes\n", |
444 | 2 | data_len); |
445 | 2 | return SC_ERROR_INVALID_ARGUMENTS; |
446 | 2 | } |
447 | | |
448 | | /* the Portuguese eID card requires a two-phase exchange */ |
449 | | /* and so does the Swedish one */ |
450 | 32 | if(card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || |
451 | 24 | card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) { |
452 | 8 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x90, 0xA0); |
453 | 24 | } else { |
454 | 24 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0xAC); |
455 | 24 | apdu.cla |= 0x80; |
456 | 24 | apdu.resp = rbuf; |
457 | 24 | apdu.resplen = sizeof(rbuf); |
458 | 24 | apdu.le = 256; |
459 | 24 | } |
460 | | /* we sign a digestInfo object => tag 0x90 */ |
461 | 32 | sbuf[0] = 0x90; |
462 | 32 | sbuf[1] = (u8)data_len; |
463 | 32 | memcpy(sbuf + 2, data, data_len); |
464 | 32 | apdu.data = sbuf; |
465 | 32 | apdu.lc = data_len + 2; |
466 | 32 | apdu.datalen = data_len + 2; |
467 | | |
468 | 32 | r = sc_transmit_apdu(card, &apdu); |
469 | 32 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
470 | 31 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
471 | 24 | if(card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID || |
472 | 19 | card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) { |
473 | | /* finalize the exchange */ |
474 | 5 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A, 0x9E, 0x9A); |
475 | 5 | apdu.le = 128; /* 1024 bit keys */ |
476 | 5 | apdu.resp = rbuf; |
477 | 5 | apdu.resplen = sizeof(rbuf); |
478 | 5 | if(card->type == SC_CARD_TYPE_GEMSAFEV1_SEEID) { |
479 | | /* cla 0x80 not supported */ |
480 | 0 | apdu.cla = 0x00; |
481 | 0 | } |
482 | 5 | r = sc_transmit_apdu(card, &apdu); |
483 | 5 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
484 | 4 | if(apdu.sw1 != 0x90 || apdu.sw2 != 0x00) |
485 | 4 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
486 | 4 | } |
487 | 19 | len = apdu.resplen > outlen ? outlen : apdu.resplen; |
488 | | |
489 | 19 | memcpy(out, apdu.resp, len); |
490 | 19 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len); |
491 | 19 | } |
492 | 7 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
493 | 7 | } |
494 | | |
495 | | static int gemsafe_decipher(struct sc_card *card, const u8 * crgram, |
496 | | size_t crgram_len, u8 *out, size_t outlen) |
497 | 26 | { |
498 | 26 | int r; |
499 | 26 | struct sc_apdu apdu; |
500 | 26 | u8 rbuf[MAX_RESP_BUFFER_SIZE]; |
501 | 26 | sc_context_t *ctx = card->ctx; |
502 | | |
503 | 26 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
504 | 26 | if (crgram_len > 255) |
505 | 1 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
506 | | |
507 | 25 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x84); |
508 | 25 | apdu.cla |= 0x80; |
509 | 25 | apdu.resp = rbuf; |
510 | 25 | apdu.resplen = sizeof(rbuf); |
511 | 25 | apdu.le = crgram_len; |
512 | | |
513 | 25 | apdu.data = crgram; |
514 | 25 | apdu.lc = crgram_len; |
515 | 25 | apdu.datalen = crgram_len; |
516 | 25 | r = sc_transmit_apdu(card, &apdu); |
517 | 25 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
518 | 24 | if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { |
519 | 14 | size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; |
520 | | |
521 | 14 | memcpy(out, apdu.resp, len); |
522 | 14 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len); |
523 | 14 | } |
524 | 10 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); |
525 | 10 | } |
526 | | |
527 | | static int gemsafe_get_challenge(sc_card_t *card, u8 *rnd, size_t len) |
528 | 254 | { |
529 | 254 | int prev_cla, r; |
530 | | |
531 | 254 | prev_cla = card->cla; |
532 | 254 | if(card->type == SC_CARD_TYPE_GEMSAFEV1_PTEID) { |
533 | | /* Warning: this depends on iso7816_get_challenge not |
534 | | * changing the value of the card's CLA |
535 | | */ |
536 | 186 | card->cla = 0x80; |
537 | 186 | } |
538 | 254 | r = iso_ops->get_challenge(card, rnd, len); |
539 | | /* Restore the CLA value if needed */ |
540 | 254 | if(card->cla != prev_cla) |
541 | 186 | card->cla = prev_cla; |
542 | | |
543 | 254 | return r; |
544 | 254 | } |
545 | | |
546 | | static int gemsafe_card_reader_lock_obtained(sc_card_t *card, int was_reset) |
547 | 2.19k | { |
548 | 2.19k | int r = SC_SUCCESS; |
549 | 2.19k | gemsafe_exdata *exdata = (gemsafe_exdata *)card->drv_data; |
550 | | |
551 | 2.19k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
552 | | |
553 | 2.19k | if (was_reset > 0 && exdata) { |
554 | 0 | r = iso7816_select_aid(card, exdata->aid, exdata->aid_len, NULL, NULL); |
555 | 0 | } |
556 | | |
557 | 2.19k | LOG_FUNC_RETURN(card->ctx, r); |
558 | 2.19k | } |
559 | | |
560 | | static int gemsafe_logout(sc_card_t *card) |
561 | 0 | { |
562 | 0 | gemsafe_exdata *exdata = (gemsafe_exdata *)card->drv_data; |
563 | |
|
564 | 0 | return iso7816_select_aid(card, exdata->aid, exdata->aid_len, NULL, NULL); |
565 | 0 | } |
566 | | |
567 | | static struct sc_card_driver *sc_get_driver(void) |
568 | 15.4k | { |
569 | 15.4k | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
570 | 15.4k | if (!iso_ops) |
571 | 1 | iso_ops = iso_drv->ops; |
572 | | /* use the standard iso operations as default */ |
573 | 15.4k | gemsafe_ops = *iso_drv->ops; |
574 | | /* gemsafe specific functions */ |
575 | 15.4k | gemsafe_ops.match_card = gemsafe_match_card; |
576 | 15.4k | gemsafe_ops.init = gemsafe_init; |
577 | 15.4k | gemsafe_ops.finish = gemsafe_finish; |
578 | 15.4k | gemsafe_ops.select_file = gemsafe_select_file; |
579 | 15.4k | gemsafe_ops.restore_security_env = gemsafe_restore_security_env; |
580 | 15.4k | gemsafe_ops.set_security_env = gemsafe_set_security_env; |
581 | 15.4k | gemsafe_ops.decipher = gemsafe_decipher; |
582 | 15.4k | gemsafe_ops.compute_signature = gemsafe_compute_signature; |
583 | 15.4k | gemsafe_ops.get_challenge = gemsafe_get_challenge; |
584 | 15.4k | gemsafe_ops.process_fci = gemsafe_process_fci; |
585 | 15.4k | gemsafe_ops.pin_cmd = iso_ops->pin_cmd; |
586 | 15.4k | gemsafe_ops.card_reader_lock_obtained = gemsafe_card_reader_lock_obtained; |
587 | 15.4k | gemsafe_ops.logout = gemsafe_logout; |
588 | | |
589 | 15.4k | return &gemsafe_drv; |
590 | 15.4k | } |
591 | | |
592 | | struct sc_card_driver *sc_get_gemsafeV1_driver(void) |
593 | 15.4k | { |
594 | 15.4k | return sc_get_driver(); |
595 | 15.4k | } |
596 | | |