/src/opensc/src/libopensc/pkcs15-oberthur.c
Line | Count | Source |
1 | | /* |
2 | | * PKCS15 emulation layer for Oberthur card. |
3 | | * |
4 | | * Copyright (C) 2010, Viktor Tarasov <vtarasov@opentrust.com> |
5 | | * Copyright (C) 2005, Andrea Frigido <andrea@frisoft.it> |
6 | | * Copyright (C) 2005, Sirio Capizzi <graaf@virgilio.it> |
7 | | * Copyright (C) 2004, Antonino Iacono <ant_iacono@tin.it> |
8 | | * Copyright (C) 2003, Olaf Kirch <okir@suse.de> |
9 | | * |
10 | | * This library is free software; you can redistribute it and/or |
11 | | * modify it under the terms of the GNU Lesser General Public |
12 | | * License as published by the Free Software Foundation; either |
13 | | * version 2.1 of the License, or (at your option) any later version. |
14 | | * |
15 | | * This library is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | | * Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; if not, write to the Free Software |
22 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 | | */ |
24 | | |
25 | | #ifdef HAVE_CONFIG_H |
26 | | #include <config.h> |
27 | | #endif |
28 | | |
29 | | #include <stdlib.h> |
30 | | #include <string.h> |
31 | | #include <stdio.h> |
32 | | #include "../common/compat_strlcpy.h" |
33 | | |
34 | | #include "pkcs15.h" |
35 | | #include "log.h" |
36 | | #include "asn1.h" |
37 | | #include "internal.h" |
38 | | |
39 | | #ifdef ENABLE_OPENSSL |
40 | | #include <openssl/bio.h> |
41 | | #include <openssl/x509.h> |
42 | | #include <openssl/x509v3.h> |
43 | | #endif |
44 | | |
45 | 331 | #define OBERTHUR_ATTR_MODIFIABLE 0x0001 |
46 | | #define OBERTHUR_ATTR_TRUSTED 0x0002 |
47 | | #define OBERTHUR_ATTR_LOCAL 0x0004 |
48 | 308 | #define OBERTHUR_ATTR_ENCRYPT 0x0008 |
49 | 308 | #define OBERTHUR_ATTR_DECRYPT 0x0010 |
50 | 308 | #define OBERTHUR_ATTR_SIGN 0x0020 |
51 | 308 | #define OBERTHUR_ATTR_VERIFY 0x0040 |
52 | 308 | #define OBERTHUR_ATTR_RSIGN 0x0080 |
53 | 308 | #define OBERTHUR_ATTR_RVERIFY 0x0100 |
54 | 308 | #define OBERTHUR_ATTR_WRAP 0x0200 |
55 | 308 | #define OBERTHUR_ATTR_UNWRAP 0x0400 |
56 | 308 | #define OBERTHUR_ATTR_DERIVE 0x0800 |
57 | | |
58 | | #define USAGE_PRV_ENC (SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT |\ |
59 | | SC_PKCS15_PRKEY_USAGE_WRAP | SC_PKCS15_PRKEY_USAGE_UNWRAP) |
60 | | #define USAGE_PRV_AUT SC_PKCS15_PRKEY_USAGE_SIGN |
61 | | #define USAGE_PRV_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) |
62 | | #define USAGE_PUB_ENC (SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP) |
63 | | #define USAGE_PUB_AUT SC_PKCS15_PRKEY_USAGE_VERIFY |
64 | | #define USAGE_PUB_SIGN (SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER) |
65 | | |
66 | 22 | #define PIN_DOMAIN_LABEL "SCM" |
67 | | const unsigned char PinDomainID[3] = {0x53, 0x43, 0x4D}; |
68 | | |
69 | 895 | #define AWP_PIN_DF "3F005011" |
70 | | #define AWP_TOKEN_INFO "3F0050111000" |
71 | | #define AWP_PUK_FILE "3F0050112000" |
72 | | #define AWP_CONTAINERS_MS "3F0050113000" |
73 | | #define AWP_OBJECTS_LIST_PUB "3F0050114000" |
74 | 0 | #define AWP_OBJECTS_LIST_PRV "3F0050115000" |
75 | 205 | #define AWP_OBJECTS_DF_PUB "3F0050119001" |
76 | 573 | #define AWP_OBJECTS_DF_PRV "3F0050119002" |
77 | | #define AWP_BASE_RSA_PRV "3F00501190023000" |
78 | | #define AWP_BASE_RSA_PUB "3F00501190011000" |
79 | | #define AWP_BASE_CERTIFICATE "3F00501190012000" |
80 | | |
81 | 62 | #define BASE_ID_PUB_RSA 0x10 |
82 | 36 | #define BASE_ID_CERT 0x20 |
83 | 348 | #define BASE_ID_PRV_RSA 0x30 |
84 | 6 | #define BASE_ID_PRV_DES 0x40 |
85 | 59 | #define BASE_ID_PUB_DATA 0x50 |
86 | 25 | #define BASE_ID_PRV_DATA 0x60 |
87 | 10 | #define BASE_ID_PUB_DES 0x70 |
88 | | |
89 | | static int sc_pkcs15emu_oberthur_add_prvkey(struct sc_pkcs15_card *, unsigned, unsigned); |
90 | | static int sc_pkcs15emu_oberthur_add_pubkey(struct sc_pkcs15_card *, unsigned, unsigned); |
91 | | static int sc_pkcs15emu_oberthur_add_cert(struct sc_pkcs15_card *, unsigned); |
92 | | static int sc_pkcs15emu_oberthur_add_data(struct sc_pkcs15_card *, unsigned, unsigned, int); |
93 | | |
94 | | static int sc_oberthur_parse_tokeninfo (struct sc_pkcs15_card *, unsigned char *, size_t, int); |
95 | | static int sc_oberthur_parse_containers (struct sc_pkcs15_card *, unsigned char *, size_t, int); |
96 | | static int sc_oberthur_parse_publicinfo (struct sc_pkcs15_card *, unsigned char *, size_t, int); |
97 | | static int sc_oberthur_parse_privateinfo (struct sc_pkcs15_card *, unsigned char *, size_t, int); |
98 | | |
99 | | static int sc_awp_parse_df(struct sc_pkcs15_card *, struct sc_pkcs15_df *); |
100 | | static void sc_awp_clear(struct sc_pkcs15_card *); |
101 | | |
102 | | struct crypto_container { |
103 | | unsigned id_pub; |
104 | | unsigned id_prv; |
105 | | unsigned id_cert; |
106 | | }; |
107 | | |
108 | | struct container { |
109 | | char uuid[37]; |
110 | | struct crypto_container exchange; |
111 | | struct crypto_container sign; |
112 | | |
113 | | struct container *next; |
114 | | struct container *prev; |
115 | | }; |
116 | | |
117 | | struct container *Containers = NULL; |
118 | | |
119 | | static struct { |
120 | | const char *name; |
121 | | const char *path; |
122 | | unsigned char *content; |
123 | | size_t len; |
124 | | int (*parser)(struct sc_pkcs15_card *, unsigned char *, size_t, int); |
125 | | int postpone_allowed; |
126 | | } oberthur_infos[] = { |
127 | | /* Never change the following order */ |
128 | | { "Token info", AWP_TOKEN_INFO, NULL, 0, sc_oberthur_parse_tokeninfo, 0}, |
129 | | { "Containers MS", AWP_CONTAINERS_MS, NULL, 0, sc_oberthur_parse_containers, 0}, |
130 | | { "Public objects list", AWP_OBJECTS_LIST_PUB, NULL, 0, sc_oberthur_parse_publicinfo, 0}, |
131 | | { "Private objects list", AWP_OBJECTS_LIST_PRV, NULL, 0, sc_oberthur_parse_privateinfo, 1}, |
132 | | { NULL, NULL, NULL, 0, NULL, 0} |
133 | | }; |
134 | | |
135 | | |
136 | | static unsigned |
137 | | sc_oberthur_decode_usage(unsigned flags) |
138 | 308 | { |
139 | 308 | unsigned ret = 0; |
140 | | |
141 | 308 | if (flags & OBERTHUR_ATTR_ENCRYPT) |
142 | 258 | ret |= SC_PKCS15_PRKEY_USAGE_ENCRYPT; |
143 | 308 | if (flags & OBERTHUR_ATTR_DECRYPT) |
144 | 250 | ret |= SC_PKCS15_PRKEY_USAGE_DECRYPT; |
145 | 308 | if (flags & OBERTHUR_ATTR_SIGN) |
146 | 43 | ret |= SC_PKCS15_PRKEY_USAGE_SIGN; |
147 | 308 | if (flags & OBERTHUR_ATTR_RSIGN) |
148 | 254 | ret |= SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; |
149 | 308 | if (flags & OBERTHUR_ATTR_WRAP) |
150 | 291 | ret |= SC_PKCS15_PRKEY_USAGE_WRAP; |
151 | 308 | if (flags & OBERTHUR_ATTR_UNWRAP) |
152 | 16 | ret |= SC_PKCS15_PRKEY_USAGE_UNWRAP; |
153 | 308 | if (flags & OBERTHUR_ATTR_VERIFY) |
154 | 259 | ret |= SC_PKCS15_PRKEY_USAGE_VERIFY; |
155 | 308 | if (flags & OBERTHUR_ATTR_RVERIFY) |
156 | 14 | ret |= SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER; |
157 | 308 | if (flags & OBERTHUR_ATTR_DERIVE) |
158 | 13 | ret |= SC_PKCS15_PRKEY_USAGE_DERIVE; |
159 | 308 | return ret; |
160 | 308 | } |
161 | | |
162 | | |
163 | | static int |
164 | | sc_oberthur_get_friends (unsigned int id, struct crypto_container *ccont) |
165 | 338 | { |
166 | 338 | struct container *cont; |
167 | | |
168 | 31.6k | for (cont = Containers; cont; cont = cont->next) { |
169 | 31.6k | if (cont->exchange.id_pub == id || cont->exchange.id_prv == id || cont->exchange.id_cert == id) { |
170 | 301 | if (ccont) |
171 | 301 | memcpy(ccont, &cont->exchange, sizeof(struct crypto_container)); |
172 | 301 | break; |
173 | 301 | } |
174 | | |
175 | 31.3k | if (cont->sign.id_pub == id || cont->sign.id_prv == id || cont->sign.id_cert == id) { |
176 | 10 | if (ccont) |
177 | 10 | memcpy(ccont, &cont->sign, sizeof(struct crypto_container)); |
178 | 10 | break; |
179 | 10 | } |
180 | 31.3k | } |
181 | | |
182 | 338 | return cont ? 0 : SC_ERROR_TEMPLATE_NOT_FOUND; |
183 | 338 | } |
184 | | |
185 | | |
186 | | static int |
187 | | sc_oberthur_get_certificate_authority(sc_context_t *ctx, struct sc_pkcs15_der *der, int *out_authority) |
188 | 3 | { |
189 | 3 | #ifdef ENABLE_OPENSSL |
190 | 3 | X509 *x; |
191 | 3 | BUF_MEM buf_mem; |
192 | 3 | BIO *bio = NULL; |
193 | 3 | BASIC_CONSTRAINTS *bs = NULL; |
194 | | |
195 | 3 | if (!der) |
196 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
197 | | |
198 | 3 | buf_mem.data = malloc(der->len); |
199 | 3 | if (!buf_mem.data) |
200 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
201 | | |
202 | 3 | memcpy(buf_mem.data, der->value, der->len); |
203 | 3 | buf_mem.max = buf_mem.length = der->len; |
204 | | |
205 | 3 | bio = BIO_new(BIO_s_mem()); |
206 | 3 | if (!bio) { |
207 | 0 | free(buf_mem.data); |
208 | 0 | sc_log_openssl(ctx); |
209 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
210 | 0 | } |
211 | | |
212 | 3 | BIO_set_mem_buf(bio, &buf_mem, BIO_NOCLOSE); |
213 | 3 | x = d2i_X509_bio(bio, 0); |
214 | 3 | free(buf_mem.data); |
215 | 3 | BIO_free(bio); |
216 | 3 | if (!x) { |
217 | 3 | sc_log_openssl(ctx); |
218 | 3 | return SC_ERROR_INVALID_DATA; |
219 | 3 | } |
220 | | |
221 | 0 | bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL); |
222 | 0 | if (out_authority) |
223 | 0 | *out_authority = (bs && bs->ca); |
224 | |
|
225 | 0 | X509_free(x); |
226 | |
|
227 | 0 | return SC_SUCCESS; |
228 | | #else |
229 | | return SC_ERROR_NOT_SUPPORTED; |
230 | | #endif |
231 | 3 | } |
232 | | |
233 | | |
234 | | static int |
235 | | sc_oberthur_read_file(struct sc_pkcs15_card *p15card, const char *in_path, |
236 | | unsigned char **out, size_t *out_len, |
237 | | int verify_pin) |
238 | 2.21k | { |
239 | 2.21k | struct sc_context *ctx = p15card->card->ctx; |
240 | 2.21k | struct sc_card *card = p15card->card; |
241 | 2.21k | struct sc_file *file = NULL; |
242 | 2.21k | struct sc_path path; |
243 | 2.21k | size_t sz; |
244 | 2.21k | int rv; |
245 | | |
246 | 2.21k | LOG_FUNC_CALLED(ctx); |
247 | 2.21k | if (!in_path || !out || !out_len) |
248 | 2.21k | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot read oberthur file"); |
249 | | |
250 | 2.21k | sc_log(ctx, "read file '%s'; verify_pin:%i", in_path, verify_pin); |
251 | | |
252 | 2.21k | *out = NULL; |
253 | 2.21k | *out_len = 0; |
254 | | |
255 | 2.21k | sc_format_path(in_path, &path); |
256 | 2.21k | rv = sc_select_file(card, &path, &file); |
257 | 2.21k | if (rv != SC_SUCCESS) { |
258 | 124 | sc_file_free(file); |
259 | 124 | LOG_TEST_RET(ctx, rv, "Cannot select oberthur file to read"); |
260 | 124 | } |
261 | | |
262 | 2.09k | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) |
263 | 99 | sz = file->size; |
264 | 1.99k | else |
265 | 1.99k | sz = (file->record_length + 2) * file->record_count; |
266 | | |
267 | 2.09k | *out = calloc(1, sz); |
268 | 2.09k | if (*out == NULL) { |
269 | 0 | sc_file_free(file); |
270 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot read oberthur file"); |
271 | 0 | } |
272 | | |
273 | 2.09k | if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { |
274 | 99 | rv = sc_read_binary(card, 0, *out, sz, 0); |
275 | 99 | } |
276 | 1.99k | else { |
277 | 1.99k | unsigned int rec; |
278 | 1.99k | size_t offs = 0; |
279 | 1.99k | size_t rec_len = file->record_length; |
280 | | |
281 | 176k | for (rec = 1; ; rec++) { |
282 | 176k | if (rec > file->record_count) { |
283 | 1.96k | rv = 0; |
284 | 1.96k | break; |
285 | 1.96k | } |
286 | 174k | rv = sc_read_record(card, rec, 0, *out + offs + 2, rec_len, SC_RECORD_BY_REC_NR); |
287 | 174k | if (rv == SC_ERROR_RECORD_NOT_FOUND) { |
288 | 1 | rv = 0; |
289 | 1 | break; |
290 | 1 | } |
291 | 174k | else if (rv < 0) { |
292 | 30 | break; |
293 | 30 | } |
294 | | |
295 | 174k | rec_len = rv; |
296 | | |
297 | 174k | *(*out + offs) = 'R'; |
298 | 174k | *(*out + offs + 1) = rv; |
299 | | |
300 | 174k | offs += rv + 2; |
301 | 174k | } |
302 | | |
303 | 1.99k | sz = offs; |
304 | 1.99k | } |
305 | | |
306 | 2.09k | sc_log(ctx, "read oberthur file result %i", rv); |
307 | 2.09k | if (verify_pin && rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { |
308 | 3 | struct sc_pkcs15_object *objs[0x10], *pin_obj = NULL; |
309 | 3 | const struct sc_acl_entry *acl = sc_file_get_acl_entry(file, SC_AC_OP_READ); |
310 | 3 | int ii, nobjs; |
311 | | |
312 | 3 | if (acl == NULL) { |
313 | 1 | sc_file_free(file); |
314 | 1 | free(*out); |
315 | 1 | *out = NULL; |
316 | 1 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); |
317 | 1 | } |
318 | | |
319 | 2 | nobjs = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 0x10); |
320 | 2 | if (nobjs < 1) { |
321 | 0 | sc_file_free(file); |
322 | 0 | free(*out); |
323 | 0 | *out = NULL; |
324 | 0 | LOG_TEST_RET(ctx, SC_ERROR_DATA_OBJECT_NOT_FOUND, |
325 | 0 | "Cannot read oberthur file: get AUTH objects error"); |
326 | 0 | } |
327 | | |
328 | 3 | for (ii = 0; ii < nobjs; ii++) { |
329 | 2 | struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) objs[ii]->data; |
330 | 2 | sc_log(ctx, "compare PIN/ACL refs:%i/%i, method:%i/%i", |
331 | 2 | auth_info->attrs.pin.reference, acl->key_ref, auth_info->auth_method, acl->method); |
332 | 2 | if (auth_info->attrs.pin.reference == (int)acl->key_ref && auth_info->auth_method == (unsigned)acl->method) { |
333 | 1 | pin_obj = objs[ii]; |
334 | 1 | break; |
335 | 1 | } |
336 | 2 | } |
337 | | |
338 | 2 | if (!pin_obj || !pin_obj->content.value) { |
339 | 2 | rv = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; |
340 | 2 | } |
341 | 0 | else { |
342 | 0 | rv = sc_pkcs15_verify_pin(p15card, pin_obj, pin_obj->content.value, pin_obj->content.len); |
343 | 0 | if (!rv) |
344 | 0 | rv = sc_oberthur_read_file(p15card, in_path, out, out_len, 0); |
345 | 0 | } |
346 | 2 | } |
347 | | |
348 | 2.09k | sc_file_free(file); |
349 | | |
350 | 2.09k | if (rv < 0) { |
351 | 30 | free(*out); |
352 | 30 | *out = NULL; |
353 | 30 | *out_len = 0; |
354 | 30 | } |
355 | | |
356 | 2.09k | *out_len = sz; |
357 | | |
358 | 2.09k | LOG_FUNC_RETURN(ctx, rv); |
359 | 2.09k | } |
360 | | |
361 | | |
362 | | static int |
363 | | sc_oberthur_parse_tokeninfo (struct sc_pkcs15_card *p15card, |
364 | | unsigned char *buff, size_t len, int postpone_allowed) |
365 | 493 | { |
366 | 493 | struct sc_context *ctx = p15card->card->ctx; |
367 | 493 | char label[0x21]; |
368 | 493 | unsigned flags; |
369 | 493 | int ii; |
370 | | |
371 | 493 | LOG_FUNC_CALLED(ctx); |
372 | 493 | if (!buff || len < 0x24) |
373 | 493 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot parse token info"); |
374 | | |
375 | 469 | memset(label, 0, sizeof(label)); |
376 | | |
377 | 469 | memcpy(label, buff, 0x20); |
378 | 469 | ii = 0x20; |
379 | 542 | while (*(label + --ii)==' ' && ii) |
380 | 73 | ; |
381 | 469 | *(label + ii + 1) = '\0'; |
382 | | |
383 | 469 | flags = *(buff + 0x22) * 0x100 + *(buff + 0x23); |
384 | | |
385 | 469 | set_string(&p15card->tokeninfo->label, label); |
386 | 469 | set_string(&p15card->tokeninfo->manufacturer_id, "Oberthur/OpenSC"); |
387 | | |
388 | 469 | if (flags & 0x01) |
389 | 4 | p15card->tokeninfo->flags |= SC_PKCS15_TOKEN_PRN_GENERATION; |
390 | | |
391 | 469 | sc_log(ctx, "label %s", p15card->tokeninfo->label); |
392 | 469 | sc_log(ctx, "manufacturer_id %s", p15card->tokeninfo->manufacturer_id); |
393 | | |
394 | 469 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
395 | 469 | } |
396 | | |
397 | | |
398 | | static int |
399 | | sc_oberthur_parse_containers (struct sc_pkcs15_card *p15card, |
400 | | unsigned char *buff, size_t len, int postpone_allowed) |
401 | 445 | { |
402 | 445 | struct sc_context *ctx = p15card->card->ctx; |
403 | 445 | size_t offs; |
404 | | |
405 | 445 | LOG_FUNC_CALLED(ctx); |
406 | | |
407 | 22.3k | while (Containers) { |
408 | 21.9k | struct container *next = Containers->next; |
409 | | |
410 | 21.9k | free (Containers); |
411 | 21.9k | Containers = next; |
412 | 21.9k | } |
413 | | |
414 | 22.3k | for (offs=0; offs + 2 + 2+2+2 + 2+2+2 + 2+36 <= len;) { |
415 | 21.9k | struct container *cont; |
416 | 21.9k | unsigned char *ptr = buff + offs + 2; |
417 | | |
418 | 21.9k | sc_log(ctx, "parse contaniers offs:%zu, len:%zu", offs, len); |
419 | 21.9k | if (*(buff + offs) != 'R') |
420 | 3 | return SC_ERROR_INVALID_DATA; |
421 | | |
422 | 21.9k | cont = (struct container *)calloc(1, sizeof(struct container)); |
423 | 21.9k | if (!cont) |
424 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
425 | | |
426 | 21.9k | cont->exchange.id_pub = *ptr * 0x100 + *(ptr + 1); ptr += 2; |
427 | 21.9k | cont->exchange.id_prv = *ptr * 0x100 + *(ptr + 1); ptr += 2; |
428 | 21.9k | cont->exchange.id_cert = *ptr * 0x100 + *(ptr + 1); ptr += 2; |
429 | | |
430 | 21.9k | cont->sign.id_pub = *ptr * 0x100 + *(ptr + 1); ptr += 2; |
431 | 21.9k | cont->sign.id_prv = *ptr * 0x100 + *(ptr + 1); ptr += 2; |
432 | 21.9k | cont->sign.id_cert = *ptr * 0x100 + *(ptr + 1); ptr += 2; |
433 | | |
434 | 21.9k | memcpy(cont->uuid, ptr + 2, 36); |
435 | 21.9k | sc_log(ctx, "UUID: %s; 0x%X, 0x%X, 0x%X", cont->uuid, |
436 | 21.9k | cont->exchange.id_pub, cont->exchange.id_prv, cont->exchange.id_cert); |
437 | | |
438 | 21.9k | if (!Containers) { |
439 | 246 | Containers = cont; |
440 | 246 | } |
441 | 21.6k | else { |
442 | 21.6k | cont->next = Containers; |
443 | 21.6k | Containers->prev = (void *)cont; |
444 | 21.6k | Containers = cont; |
445 | 21.6k | } |
446 | | |
447 | 21.9k | offs += *(buff + offs + 1) + 2; |
448 | 21.9k | } |
449 | | |
450 | 442 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
451 | 442 | } |
452 | | |
453 | | |
454 | | static int |
455 | | sc_oberthur_parse_publicinfo (struct sc_pkcs15_card *p15card, |
456 | | unsigned char *buff, size_t len, int postpone_allowed) |
457 | 423 | { |
458 | 423 | struct sc_context *ctx = p15card->card->ctx; |
459 | 423 | size_t ii; |
460 | 423 | int rv; |
461 | | |
462 | 423 | LOG_FUNC_CALLED(ctx); |
463 | 27.4k | for (ii=0; ii+5<=len; ii+=5) { |
464 | 27.1k | unsigned int file_id, size; |
465 | | |
466 | 27.1k | if(*(buff+ii) != 0xFF) |
467 | 26.9k | continue; |
468 | | |
469 | 182 | file_id = 0x100 * *(buff+ii + 1) + *(buff+ii + 2); |
470 | 182 | size = 0x100 * *(buff+ii + 3) + *(buff+ii + 4); |
471 | 182 | sc_log(ctx, "add public object(file-id:%04X,size:%X)", file_id, size); |
472 | | |
473 | 182 | switch (*(buff+ii + 1)) { |
474 | 62 | case BASE_ID_PUB_RSA : |
475 | 62 | rv = sc_pkcs15emu_oberthur_add_pubkey(p15card, file_id, size); |
476 | 62 | LOG_TEST_RET(ctx, rv, "Cannot parse public key info"); |
477 | 13 | break; |
478 | 36 | case BASE_ID_CERT : |
479 | 36 | rv = sc_pkcs15emu_oberthur_add_cert(p15card, file_id); |
480 | 36 | LOG_TEST_RET(ctx, rv, "Cannot parse certificate info"); |
481 | 0 | break; |
482 | 10 | case BASE_ID_PUB_DES : |
483 | 10 | break; |
484 | 59 | case BASE_ID_PUB_DATA : |
485 | 59 | rv = sc_pkcs15emu_oberthur_add_data(p15card, file_id, size, 0); |
486 | 59 | LOG_TEST_RET(ctx, rv, "Cannot parse data info"); |
487 | 18 | break; |
488 | 18 | default: |
489 | 15 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Public object parse error"); |
490 | 182 | } |
491 | 182 | } |
492 | | |
493 | 282 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
494 | 282 | } |
495 | | |
496 | | |
497 | | static int |
498 | | sc_oberthur_parse_privateinfo (struct sc_pkcs15_card *p15card, |
499 | | unsigned char *buff, size_t len, int postpone_allowed) |
500 | 253 | { |
501 | 253 | struct sc_context *ctx = p15card->card->ctx; |
502 | 253 | size_t ii; |
503 | 253 | int rv; |
504 | 253 | int no_more_private_keys = 0, no_more_private_data = 0; |
505 | | |
506 | 253 | LOG_FUNC_CALLED(ctx); |
507 | | |
508 | 32.4k | for (ii=0; ii+5<=len; ii+=5) { |
509 | 32.3k | unsigned int file_id, size; |
510 | | |
511 | 32.3k | if(*(buff+ii) != 0xFF) |
512 | 31.9k | continue; |
513 | | |
514 | 386 | file_id = 0x100 * *(buff+ii + 1) + *(buff+ii + 2); |
515 | 386 | size = 0x100 * *(buff+ii + 3) + *(buff+ii + 4); |
516 | 386 | sc_log(ctx, "add private object (file-id:%04X, size:%X)", file_id, size); |
517 | | |
518 | 386 | switch (*(buff+ii + 1)) { |
519 | 348 | case BASE_ID_PRV_RSA : |
520 | 348 | if (no_more_private_keys) |
521 | 10 | break; |
522 | | |
523 | 338 | rv = sc_pkcs15emu_oberthur_add_prvkey(p15card, file_id, size); |
524 | 338 | if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed) { |
525 | 5 | struct sc_path path; |
526 | | |
527 | 5 | sc_log(ctx, "postpone adding of the private keys"); |
528 | 5 | sc_format_path("5011A5A5", &path); |
529 | 5 | rv = sc_pkcs15_add_df(p15card, SC_PKCS15_PRKDF, &path); |
530 | 5 | LOG_TEST_RET(ctx, rv, "Add PrkDF error"); |
531 | 5 | no_more_private_keys = 1; |
532 | 5 | } |
533 | 338 | LOG_TEST_RET(ctx, rv, "Cannot parse private key info"); |
534 | 254 | break; |
535 | 254 | case BASE_ID_PRV_DES : |
536 | 6 | break; |
537 | 25 | case BASE_ID_PRV_DATA : |
538 | 25 | sc_log(ctx, "*(buff+ii + 1):%X", *(buff+ii + 1)); |
539 | 25 | if (no_more_private_data) |
540 | 10 | break; |
541 | | |
542 | 15 | rv = sc_pkcs15emu_oberthur_add_data(p15card, file_id, size, 1); |
543 | 15 | if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed) { |
544 | 4 | struct sc_path path; |
545 | | |
546 | 4 | sc_log(ctx, "postpone adding of the private data"); |
547 | 4 | sc_format_path("5011A6A6", &path); |
548 | 4 | rv = sc_pkcs15_add_df(p15card, SC_PKCS15_DODF, &path); |
549 | 4 | LOG_TEST_RET(ctx, rv, "Add DODF error"); |
550 | 4 | no_more_private_data = 1; |
551 | 4 | } |
552 | 15 | LOG_TEST_RET(ctx, rv, "Cannot parse private data info"); |
553 | 9 | break; |
554 | 9 | default: |
555 | 7 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Private object parse error"); |
556 | 386 | } |
557 | 386 | } |
558 | | |
559 | 156 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
560 | 156 | } |
561 | | |
562 | | |
563 | | /* Public key info: |
564 | | * flags:2, |
565 | | * CN(len:2,value:<variable length>), |
566 | | * ID(len:2,value:(SHA1 value)), |
567 | | * StartDate(Ascii:8) |
568 | | * EndDate(Ascii:8) |
569 | | * ??(0x00:2) |
570 | | */ |
571 | | static int |
572 | | sc_pkcs15emu_oberthur_add_pubkey(struct sc_pkcs15_card *p15card, |
573 | | unsigned int file_id, unsigned int size) |
574 | 62 | { |
575 | 62 | struct sc_context *ctx = p15card->card->ctx; |
576 | 62 | struct sc_pkcs15_pubkey_info key_info; |
577 | 62 | struct sc_pkcs15_object key_obj; |
578 | 62 | char ch_tmp[0x100]; |
579 | 62 | unsigned char *info_blob = NULL; |
580 | 62 | size_t len, info_len, offs; |
581 | 62 | unsigned flags; |
582 | 62 | int rv; |
583 | | |
584 | 62 | LOG_FUNC_CALLED(ctx); |
585 | 62 | sc_log(ctx, "public key(file-id:%04X,size:%X)", file_id, size); |
586 | | |
587 | 62 | memset(&key_info, 0, sizeof(key_info)); |
588 | 62 | memset(&key_obj, 0, sizeof(key_obj)); |
589 | | |
590 | 62 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100); |
591 | 62 | rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); |
592 | 62 | LOG_TEST_RET(ctx, rv, "Failed to add public key: read oberthur file error"); |
593 | | |
594 | | /* Flags */ |
595 | 60 | offs = 2; |
596 | 60 | if (offs > info_len) { |
597 | 1 | free(info_blob); |
598 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'tag'"); |
599 | 1 | } |
600 | 59 | flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); |
601 | 59 | key_info.usage = sc_oberthur_decode_usage(flags); |
602 | 59 | if (flags & OBERTHUR_ATTR_MODIFIABLE) |
603 | 22 | key_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE; |
604 | 59 | sc_log(ctx, "Public key key-usage:%04X", key_info.usage); |
605 | | |
606 | | /* Label */ |
607 | 59 | if (offs + 2 > info_len) { |
608 | 1 | free(info_blob); |
609 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'Label'"); |
610 | 1 | } |
611 | 58 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
612 | 58 | if (offs + 2 + len > info_len) { |
613 | 10 | free(info_blob); |
614 | 10 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalid 'Label' length"); |
615 | 48 | } else if (len) { |
616 | 32 | if (len > sizeof(key_obj.label) - 1) |
617 | 13 | len = sizeof(key_obj.label) - 1; |
618 | 32 | memcpy(key_obj.label, info_blob + offs + 2, len); |
619 | 32 | } |
620 | 48 | offs += 2 + len; |
621 | | |
622 | | /* ID */ |
623 | 48 | if (offs + 2 > info_len) { |
624 | 1 | free(info_blob); |
625 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'ID'"); |
626 | 1 | } |
627 | 47 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
628 | 47 | if (len == 0 |
629 | 32 | || len > sizeof(key_info.id.value) |
630 | 34 | || offs + 2 + len > info_len) { |
631 | 34 | free(info_blob); |
632 | 34 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalid 'ID' length"); |
633 | 34 | } |
634 | 13 | memcpy(key_info.id.value, info_blob + offs + 2, len); |
635 | 13 | key_info.id.len = len; |
636 | | |
637 | 13 | free(info_blob); |
638 | | |
639 | | /* Ignore Start/End dates */ |
640 | | |
641 | 13 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id); |
642 | 13 | sc_format_path(ch_tmp, &key_info.path); |
643 | | |
644 | 13 | key_info.native = 1; |
645 | 13 | key_info.key_reference = file_id & 0xFF; |
646 | 13 | key_info.modulus_length = size; |
647 | | |
648 | 13 | rv = sc_pkcs15emu_add_rsa_pubkey(p15card, &key_obj, &key_info); |
649 | | |
650 | 13 | LOG_FUNC_RETURN(ctx, rv); |
651 | 13 | } |
652 | | |
653 | | |
654 | | /* Certificate info: |
655 | | * flags:2, |
656 | | * Label(len:2,value:), |
657 | | * ID(len:2,value:(SHA1 value)), |
658 | | * Subject in ASN.1(len:2,value:) |
659 | | * Issuer in ASN.1(len:2,value:) |
660 | | * Serial encoded in LV or ASN.1 FIXME |
661 | | */ |
662 | | static int |
663 | | sc_pkcs15emu_oberthur_add_cert(struct sc_pkcs15_card *p15card, unsigned int file_id) |
664 | 36 | { |
665 | 36 | struct sc_context *ctx = p15card->card->ctx; |
666 | 36 | struct sc_pkcs15_cert_info cinfo; |
667 | 36 | struct sc_pkcs15_object cobj; |
668 | 36 | unsigned char *info_blob = NULL, *cert_blob = NULL; |
669 | 36 | size_t info_len, cert_len, len, offs; |
670 | 36 | unsigned flags; |
671 | 36 | int rv; |
672 | 36 | char ch_tmp[0x20]; |
673 | | |
674 | 36 | LOG_FUNC_CALLED(ctx); |
675 | 36 | sc_log(ctx, "add certificate(file-id:%04X)", file_id); |
676 | | |
677 | 36 | memset(&cinfo, 0, sizeof(cinfo)); |
678 | 36 | memset(&cobj, 0, sizeof(cobj)); |
679 | | |
680 | 36 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100); |
681 | 36 | rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); |
682 | 36 | LOG_TEST_RET(ctx, rv, "Failed to add certificate: read oberthur file error"); |
683 | | |
684 | 35 | if (info_len < 2) { |
685 | 1 | free(info_blob); |
686 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'tag'"); |
687 | 1 | } |
688 | 34 | flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); |
689 | 34 | offs = 2; |
690 | | |
691 | | /* Label */ |
692 | 34 | if (offs + 2 > info_len) { |
693 | 1 | free(info_blob); |
694 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'CN'"); |
695 | 1 | } |
696 | 33 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
697 | 33 | if (len + offs + 2 > info_len) { |
698 | 3 | free(info_blob); |
699 | 3 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid 'CN' length"); |
700 | 30 | } else if (len) { |
701 | 19 | if (len > sizeof(cobj.label) - 1) |
702 | 16 | len = sizeof(cobj.label) - 1; |
703 | 19 | memcpy(cobj.label, info_blob + offs + 2, len); |
704 | 19 | } |
705 | 30 | offs += 2 + len; |
706 | | |
707 | | /* ID */ |
708 | 30 | if (offs + 2 > info_len) { |
709 | 1 | free(info_blob); |
710 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'ID'"); |
711 | 1 | } |
712 | 29 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
713 | 29 | if (len + offs + 2 > info_len) { |
714 | 11 | free(info_blob); |
715 | 11 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid 'ID' length"); |
716 | 18 | } else if (len > sizeof(cinfo.id.value)) { |
717 | 1 | free(info_blob); |
718 | 1 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add certificate: invalid 'ID' length"); |
719 | 1 | } |
720 | 17 | memcpy(cinfo.id.value, info_blob + offs + 2, len); |
721 | 17 | cinfo.id.len = len; |
722 | | |
723 | 17 | free(info_blob); |
724 | | |
725 | | /* Ignore subject, issuer and serial */ |
726 | | |
727 | 17 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id); |
728 | 17 | sc_format_path(ch_tmp, &cinfo.path); |
729 | 17 | rv = sc_oberthur_read_file(p15card, ch_tmp, &cert_blob, &cert_len, 1); |
730 | 17 | LOG_TEST_RET(ctx, rv, "Failed to add certificate: read certificate error"); |
731 | | |
732 | 3 | cinfo.value.value = cert_blob; |
733 | 3 | cinfo.value.len = cert_len; |
734 | | |
735 | 3 | rv = sc_oberthur_get_certificate_authority(ctx, &cinfo.value, &cinfo.authority); |
736 | 3 | if (rv != SC_SUCCESS) { |
737 | 3 | free(cinfo.value.value); |
738 | 3 | LOG_TEST_RET(ctx, rv, "Failed to add certificate: get certificate attributes error"); |
739 | 3 | } |
740 | | |
741 | 0 | if (flags & OBERTHUR_ATTR_MODIFIABLE) |
742 | 0 | cobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE; |
743 | |
|
744 | 0 | rv = sc_pkcs15emu_add_x509_cert(p15card, &cobj, &cinfo); |
745 | |
|
746 | 0 | LOG_FUNC_RETURN(p15card->card->ctx, rv); |
747 | 0 | } |
748 | | |
749 | | |
750 | | /* Private key info: |
751 | | * flags:2, |
752 | | * CN(len:2,value:), |
753 | | * ID(len:2,value:(SHA1 value)), |
754 | | * StartDate(Ascii:8) |
755 | | * EndDate(Ascii:8) |
756 | | * Subject in ASN.1(len:2,value:) |
757 | | * modulus(value:) |
758 | | * exponent(length:1, value:3) |
759 | | */ |
760 | | static int |
761 | | sc_pkcs15emu_oberthur_add_prvkey(struct sc_pkcs15_card *p15card, |
762 | | unsigned int file_id, unsigned int size) |
763 | 338 | { |
764 | 338 | struct sc_context *ctx = p15card->card->ctx; |
765 | 338 | struct sc_pkcs15_prkey_info kinfo; |
766 | 338 | struct sc_pkcs15_object kobj; |
767 | 338 | struct crypto_container ccont; |
768 | 338 | unsigned char *info_blob = NULL; |
769 | 338 | size_t info_len = 0; |
770 | 338 | unsigned flags; |
771 | 338 | size_t offs, len; |
772 | 338 | char ch_tmp[0x100]; |
773 | 338 | int rv; |
774 | | |
775 | 338 | LOG_FUNC_CALLED(ctx); |
776 | 338 | sc_log(ctx, "add private key(file-id:%04X,size:%04X)", file_id, size); |
777 | | |
778 | 338 | memset(&kinfo, 0, sizeof(kinfo)); |
779 | 338 | memset(&kobj, 0, sizeof(kobj)); |
780 | 338 | memset(&ccont, 0, sizeof(ccont)); |
781 | | |
782 | 338 | rv = sc_oberthur_get_friends (file_id, &ccont); |
783 | 338 | LOG_TEST_RET(ctx, rv, "Failed to add private key: get friends error"); |
784 | | |
785 | 311 | if (ccont.id_cert) { |
786 | 7 | struct sc_pkcs15_object *objs[32]; |
787 | 7 | int ii; |
788 | | |
789 | 7 | sc_log(ctx, "friend certificate %04X", ccont.id_cert); |
790 | 7 | rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, objs, 32); |
791 | 7 | LOG_TEST_RET(ctx, rv, "Failed to add private key: get certificates error"); |
792 | | |
793 | 7 | for (ii=0; ii<rv; ii++) { |
794 | 0 | struct sc_pkcs15_cert_info *cert = (struct sc_pkcs15_cert_info *)objs[ii]->data; |
795 | 0 | struct sc_path path = cert->path; |
796 | 0 | unsigned int id = path.value[path.len - 2] * 0x100 + path.value[path.len - 1]; |
797 | |
|
798 | 0 | if (id == ccont.id_cert) { |
799 | 0 | strlcpy(kobj.label, objs[ii]->label, sizeof(kobj.label)); |
800 | 0 | break; |
801 | 0 | } |
802 | 0 | } |
803 | | |
804 | 7 | if (ii == rv) |
805 | 7 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Failed to add private key: friend not found"); |
806 | 7 | } |
807 | | |
808 | 304 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PRV, file_id | 0x100); |
809 | 304 | rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); |
810 | 304 | LOG_TEST_RET(ctx, rv, "Failed to add private key: read oberthur file error"); |
811 | | |
812 | 287 | if (info_len < 2) { |
813 | 3 | free(info_blob); |
814 | 3 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'tag'"); |
815 | 3 | } |
816 | 284 | flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); |
817 | 284 | offs = 2; |
818 | | |
819 | | /* CN */ |
820 | 284 | if (offs + 2 > info_len) { |
821 | 1 | free(info_blob); |
822 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'CN'"); |
823 | 1 | } |
824 | 283 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
825 | 283 | if (len + offs + 2 > info_len) { |
826 | 12 | free(info_blob); |
827 | 12 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid 'CN' length"); |
828 | 12 | } |
829 | 271 | if (len && !strlen(kobj.label)) { |
830 | 42 | if (len > sizeof(kobj.label) - 1) |
831 | 1 | len = sizeof(kobj.label) - 1; |
832 | 42 | strncpy(kobj.label, (char *)(info_blob + offs + 2), len); |
833 | 42 | } |
834 | 271 | offs += 2 + len; |
835 | | |
836 | | /* ID */ |
837 | 271 | if (offs + 2 > info_len) { |
838 | 1 | free(info_blob); |
839 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'ID'"); |
840 | 1 | } |
841 | 270 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
842 | 270 | if (!len) { |
843 | 1 | free(info_blob); |
844 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: zero length ID"); |
845 | 269 | } else if (len + offs + 2 > info_len) { |
846 | 14 | free(info_blob); |
847 | 14 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid 'ID' length"); |
848 | 255 | } else if (len > sizeof(kinfo.id.value)) { |
849 | 1 | free(info_blob); |
850 | 1 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add private key: invalid ID length"); |
851 | 1 | } |
852 | 254 | memcpy(kinfo.id.value, info_blob + offs + 2, len); |
853 | 254 | kinfo.id.len = len; |
854 | 254 | offs += 2 + len; |
855 | | |
856 | | /* Ignore Start/End dates */ |
857 | 254 | offs += 16; |
858 | | |
859 | | /* Subject encoded in ASN1 */ |
860 | 254 | if (offs + 2 > info_len) { |
861 | 1 | free(info_blob); |
862 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'subject'"); |
863 | 1 | } |
864 | 253 | len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
865 | 253 | if (len + offs + 2 > info_len) { |
866 | 4 | free(info_blob); |
867 | 4 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid 'subject' length"); |
868 | 249 | } else if (len) { |
869 | 241 | kinfo.subject.value = malloc(len); |
870 | 241 | if (!kinfo.subject.value) { |
871 | 0 | free(info_blob); |
872 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Failed to add private key: memory allocation error"); |
873 | 0 | } |
874 | 241 | kinfo.subject.len = len; |
875 | 241 | memcpy(kinfo.subject.value, info_blob + offs + 2, len); |
876 | 241 | } |
877 | | |
878 | | /* Modulus and exponent are ignored */ |
879 | | |
880 | 249 | free(info_blob); |
881 | | |
882 | 249 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PRV, file_id); |
883 | 249 | sc_format_path(ch_tmp, &kinfo.path); |
884 | 249 | sc_log(ctx, "Private key info path %s", ch_tmp); |
885 | | |
886 | 249 | kinfo.modulus_length = size; |
887 | 249 | kinfo.native = 1; |
888 | 249 | kinfo.key_reference = file_id & 0xFF; |
889 | | |
890 | 249 | kinfo.usage = sc_oberthur_decode_usage(flags); |
891 | 249 | kobj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
892 | 249 | if (flags & OBERTHUR_ATTR_MODIFIABLE) |
893 | 10 | kobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE; |
894 | | |
895 | 249 | kobj.auth_id.len = sizeof(PinDomainID) > sizeof(kobj.auth_id.value) |
896 | 249 | ? sizeof(kobj.auth_id.value) : sizeof(PinDomainID); |
897 | 249 | memcpy(kobj.auth_id.value, PinDomainID, kobj.auth_id.len); |
898 | | |
899 | 249 | sc_log(ctx, "Parsed private key(reference:%i,usage:%X,flags:%X)", kinfo.key_reference, kinfo.usage, kobj.flags); |
900 | | |
901 | 249 | rv = sc_pkcs15emu_add_rsa_prkey(p15card, &kobj, &kinfo); |
902 | 249 | LOG_FUNC_RETURN(ctx, rv); |
903 | 249 | } |
904 | | |
905 | | |
906 | | static int |
907 | | sc_pkcs15emu_oberthur_add_data(struct sc_pkcs15_card *p15card, |
908 | | unsigned int file_id, unsigned int size, int private) |
909 | 74 | { |
910 | 74 | struct sc_context *ctx = p15card->card->ctx; |
911 | 74 | struct sc_pkcs15_data_info dinfo; |
912 | 74 | struct sc_pkcs15_object dobj; |
913 | 74 | unsigned flags; |
914 | 74 | unsigned char *info_blob = NULL, *label = NULL, *app = NULL, *oid = NULL; |
915 | 74 | size_t info_len, label_len, app_len, oid_len, offs; |
916 | 74 | char ch_tmp[0x100]; |
917 | 74 | int rv; |
918 | | |
919 | 74 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
920 | 74 | sc_log(ctx, "Add data(file-id:%04X,size:%i,is-private:%i)", file_id, size, private); |
921 | 74 | memset(&dinfo, 0, sizeof(dinfo)); |
922 | 74 | memset(&dobj, 0, sizeof(dobj)); |
923 | | |
924 | 74 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", private ? AWP_OBJECTS_DF_PRV : AWP_OBJECTS_DF_PUB, file_id | 0x100); |
925 | | |
926 | 74 | rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); |
927 | 74 | LOG_TEST_RET(ctx, rv, "Failed to add data: read oberthur file error"); |
928 | | |
929 | 64 | if (info_len < 2) { |
930 | 1 | free(info_blob); |
931 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'tag'"); |
932 | 1 | } |
933 | 63 | flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); |
934 | 63 | offs = 2; |
935 | | |
936 | | /* Label */ |
937 | 63 | if (offs + 2 > info_len) { |
938 | 1 | free(info_blob); |
939 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: no 'label'"); |
940 | 1 | } |
941 | 62 | label = info_blob + offs + 2; |
942 | 62 | label_len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
943 | 62 | if (offs + 2 + label_len > info_len) { |
944 | 8 | free(info_blob); |
945 | 8 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid length of 'label' received"); |
946 | 8 | } |
947 | 54 | if (label_len > sizeof(dobj.label) - 1) |
948 | 5 | label_len = sizeof(dobj.label) - 1; |
949 | 54 | offs += 2 + *(info_blob + offs + 1); |
950 | | |
951 | | /* Application */ |
952 | 54 | if (offs + 2 > info_len) { |
953 | 1 | free(info_blob); |
954 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: no 'application'"); |
955 | 1 | } |
956 | 53 | app = info_blob + offs + 2; |
957 | 53 | app_len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
958 | 53 | if (offs + 2 + app_len > info_len) { |
959 | 9 | free(info_blob); |
960 | 9 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid length of 'application' received"); |
961 | 9 | } |
962 | 44 | if (app_len > sizeof(dinfo.app_label) - 1) |
963 | 2 | app_len = sizeof(dinfo.app_label) - 1; |
964 | 44 | offs += 2 + app_len; |
965 | | |
966 | | /* OID encode like DER(ASN.1(oid)) */ |
967 | 44 | if (offs + 2 > info_len) { |
968 | 1 | free(info_blob); |
969 | 1 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: no 'OID'"); |
970 | 1 | } |
971 | 43 | oid_len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; |
972 | 43 | if (offs + 2 + oid_len > info_len) { |
973 | 17 | free(info_blob); |
974 | 17 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Invalid length of 'oid' received"); |
975 | 17 | } |
976 | 26 | if (oid_len > 2) { |
977 | 4 | oid = info_blob + offs + 2; |
978 | 4 | if (*oid != 0x06 || (*(oid + 1) != oid_len - 2)) { |
979 | 3 | free(info_blob); |
980 | 3 | LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: invalid 'OID' format"); |
981 | 3 | } |
982 | 1 | oid += 2; |
983 | 1 | oid_len -= 2; |
984 | 1 | } |
985 | | |
986 | 23 | snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", private ? AWP_OBJECTS_DF_PRV : AWP_OBJECTS_DF_PUB, file_id); |
987 | | |
988 | 23 | sc_format_path(ch_tmp, &dinfo.path); |
989 | | |
990 | 23 | memcpy(dobj.label, label, label_len); |
991 | 23 | memcpy(dinfo.app_label, app, app_len); |
992 | 23 | if (oid_len) |
993 | 4 | sc_asn1_decode_object_id(oid, oid_len, &dinfo.app_oid); |
994 | | |
995 | 23 | if (flags & OBERTHUR_ATTR_MODIFIABLE) |
996 | 12 | dobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE; |
997 | | |
998 | 23 | if (private) { |
999 | 5 | dobj.auth_id.len = sizeof(PinDomainID) > sizeof(dobj.auth_id.value) |
1000 | 5 | ? sizeof(dobj.auth_id.value) : sizeof(PinDomainID); |
1001 | 5 | memcpy(dobj.auth_id.value, PinDomainID, dobj.auth_id.len); |
1002 | | |
1003 | 5 | dobj.flags |= SC_PKCS15_CO_FLAG_PRIVATE; |
1004 | 5 | } |
1005 | | |
1006 | 23 | rv = sc_pkcs15emu_add_data_object(p15card, &dobj, &dinfo); |
1007 | | |
1008 | 23 | free(info_blob); |
1009 | 23 | LOG_FUNC_RETURN(p15card->card->ctx, rv); |
1010 | 23 | } |
1011 | | |
1012 | | |
1013 | | static int |
1014 | | sc_pkcs15emu_oberthur_init(struct sc_pkcs15_card * p15card) |
1015 | 873 | { |
1016 | 873 | struct sc_context *ctx = p15card->card->ctx; |
1017 | 873 | struct sc_pkcs15_auth_info auth_info; |
1018 | 873 | struct sc_pkcs15_object obj; |
1019 | 873 | struct sc_card *card = p15card->card; |
1020 | 873 | struct sc_path path; |
1021 | 873 | int rv, ii, tries_left; |
1022 | 873 | char serial[0x10]; |
1023 | 873 | unsigned char sopin_reference = 0x04; |
1024 | | |
1025 | 873 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1026 | 873 | sc_bin_to_hex(card->serialnr.value, card->serialnr.len, serial, sizeof(serial), 0); |
1027 | 873 | set_string(&p15card->tokeninfo->serial_number, serial); |
1028 | | |
1029 | 873 | p15card->ops.parse_df = sc_awp_parse_df; |
1030 | 873 | p15card->ops.clear = sc_awp_clear; |
1031 | | |
1032 | 873 | sc_log(ctx, "Oberthur init: serial %s", p15card->tokeninfo->serial_number); |
1033 | | |
1034 | 873 | sc_format_path(AWP_PIN_DF, &path); |
1035 | 873 | rv = sc_select_file(card, &path, NULL); |
1036 | 873 | LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot select PIN dir"); |
1037 | | |
1038 | 567 | tries_left = -1; |
1039 | 567 | rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left); |
1040 | 567 | if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT) { |
1041 | 37 | sopin_reference = 0x84; |
1042 | 37 | rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left); |
1043 | 37 | } |
1044 | 567 | if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT) |
1045 | 567 | LOG_TEST_GOTO_ERR(ctx, rv, "Invalid state of SO-PIN"); |
1046 | | |
1047 | | /* add PIN */ |
1048 | 543 | memset(&auth_info, 0, sizeof(auth_info)); |
1049 | 543 | memset(&obj, 0, sizeof(obj)); |
1050 | | |
1051 | 543 | auth_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
1052 | 543 | auth_info.auth_method = SC_AC_CHV; |
1053 | 543 | auth_info.auth_id.len = 1; |
1054 | 543 | auth_info.auth_id.value[0] = 0xFF; |
1055 | 543 | auth_info.attrs.pin.min_length = 4; |
1056 | 543 | auth_info.attrs.pin.max_length = 64; |
1057 | 543 | auth_info.attrs.pin.stored_length = 64; |
1058 | 543 | auth_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; |
1059 | 543 | auth_info.attrs.pin.reference = sopin_reference; |
1060 | 543 | auth_info.attrs.pin.pad_char = 0xFF; |
1061 | 543 | auth_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE |
1062 | 543 | | SC_PKCS15_PIN_FLAG_INITIALIZED |
1063 | 543 | | SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
1064 | 543 | | SC_PKCS15_PIN_FLAG_SO_PIN; |
1065 | 543 | auth_info.tries_left = tries_left; |
1066 | 543 | auth_info.logged_in = SC_PIN_STATE_UNKNOWN; |
1067 | | |
1068 | 543 | strncpy(obj.label, "SO PIN", SC_PKCS15_MAX_LABEL_SIZE-1); |
1069 | 543 | obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE; |
1070 | | |
1071 | 543 | sc_log(ctx, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label, |
1072 | 543 | sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference); |
1073 | 543 | rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info); |
1074 | 543 | LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot add PIN object"); |
1075 | | |
1076 | 543 | tries_left = -1; |
1077 | 543 | rv = sc_verify(card, SC_AC_CHV, 0x81, (unsigned char *)"", 0, &tries_left); |
1078 | 543 | if (rv == SC_ERROR_PIN_CODE_INCORRECT) { |
1079 | | /* add PIN */ |
1080 | 22 | memset(&auth_info, 0, sizeof(auth_info)); |
1081 | 22 | memset(&obj, 0, sizeof(obj)); |
1082 | | |
1083 | 22 | auth_info.auth_id.len = sizeof(PinDomainID) > sizeof(auth_info.auth_id.value) |
1084 | 22 | ? sizeof(auth_info.auth_id.value) : sizeof(PinDomainID); |
1085 | 22 | memcpy(auth_info.auth_id.value, PinDomainID, auth_info.auth_id.len); |
1086 | 22 | auth_info.auth_method = SC_AC_CHV; |
1087 | | |
1088 | 22 | auth_info.attrs.pin.min_length = 4; |
1089 | 22 | auth_info.attrs.pin.max_length = 64; |
1090 | 22 | auth_info.attrs.pin.stored_length = 64; |
1091 | 22 | auth_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; |
1092 | 22 | auth_info.attrs.pin.reference = 0x81; |
1093 | 22 | auth_info.attrs.pin.pad_char = 0xFF; |
1094 | 22 | auth_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE |
1095 | 22 | | SC_PKCS15_PIN_FLAG_INITIALIZED |
1096 | 22 | | SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
1097 | 22 | | SC_PKCS15_PIN_FLAG_LOCAL; |
1098 | 22 | auth_info.tries_left = tries_left; |
1099 | | |
1100 | 22 | strncpy(obj.label, PIN_DOMAIN_LABEL, SC_PKCS15_MAX_LABEL_SIZE-1); |
1101 | 22 | obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE; |
1102 | 22 | if (sopin_reference == 0x84) { |
1103 | | /* |
1104 | | * auth_pin_reset_oberthur_style() in card-oberthur.c |
1105 | | * always uses PUK with reference 0x84 for |
1106 | | * unblocking of User PIN |
1107 | | */ |
1108 | 3 | obj.auth_id.len = 1; |
1109 | 3 | obj.auth_id.value[0] = 0xFF; |
1110 | 3 | } |
1111 | | |
1112 | 22 | sc_format_path(AWP_PIN_DF, &auth_info.path); |
1113 | 22 | auth_info.path.type = SC_PATH_TYPE_PATH; |
1114 | | |
1115 | 22 | sc_log(ctx, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label, |
1116 | 22 | sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference); |
1117 | 22 | rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info); |
1118 | 22 | LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot add PIN object"); |
1119 | 22 | } |
1120 | 521 | else if (rv != SC_ERROR_DATA_OBJECT_NOT_FOUND) { |
1121 | 520 | LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot verify PIN"); |
1122 | 520 | } |
1123 | | |
1124 | 1.88k | for (ii=0; oberthur_infos[ii].name; ii++) { |
1125 | 1.72k | sc_log(ctx, "Oberthur init: read %s file", oberthur_infos[ii].name); |
1126 | 1.72k | free(oberthur_infos[ii].content); |
1127 | 1.72k | rv = sc_oberthur_read_file(p15card, oberthur_infos[ii].path, |
1128 | 1.72k | &oberthur_infos[ii].content, &oberthur_infos[ii].len, 1); |
1129 | 1.72k | LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: read oberthur file error"); |
1130 | | |
1131 | 1.61k | sc_log(ctx, "Oberthur init: parse %s file, content length %zu", |
1132 | 1.61k | oberthur_infos[ii].name, oberthur_infos[ii].len); |
1133 | 1.61k | rv = oberthur_infos[ii].parser(p15card, oberthur_infos[ii].content, oberthur_infos[ii].len, |
1134 | 1.61k | oberthur_infos[ii].postpone_allowed); |
1135 | 1.61k | LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: parse error"); |
1136 | 1.61k | } |
1137 | | |
1138 | 156 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1139 | | |
1140 | 717 | err: |
1141 | 717 | sc_pkcs15_card_clear(p15card); |
1142 | 717 | LOG_FUNC_RETURN(ctx, rv); |
1143 | 717 | } |
1144 | | |
1145 | | |
1146 | | static int |
1147 | | oberthur_detect_card(struct sc_pkcs15_card * p15card) |
1148 | 10.2k | { |
1149 | 10.2k | struct sc_card *card = p15card->card; |
1150 | | |
1151 | 10.2k | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
1152 | 10.2k | if (p15card->card->type != SC_CARD_TYPE_OBERTHUR_64K) |
1153 | 10.2k | LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_WRONG_CARD); |
1154 | 873 | LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS); |
1155 | 873 | } |
1156 | | |
1157 | | |
1158 | | int |
1159 | | sc_pkcs15emu_oberthur_init_ex(struct sc_pkcs15_card * p15card, struct sc_aid *aid) |
1160 | 10.2k | { |
1161 | 10.2k | int rv; |
1162 | | |
1163 | 10.2k | LOG_FUNC_CALLED(p15card->card->ctx); |
1164 | 10.2k | rv = oberthur_detect_card(p15card); |
1165 | 10.2k | if (!rv) |
1166 | 873 | rv = sc_pkcs15emu_oberthur_init(p15card); |
1167 | | |
1168 | 10.2k | LOG_FUNC_RETURN(p15card->card->ctx, rv); |
1169 | 10.2k | } |
1170 | | |
1171 | | |
1172 | | static int |
1173 | | sc_awp_parse_df(struct sc_pkcs15_card *p15card, struct sc_pkcs15_df *df) |
1174 | 0 | { |
1175 | 0 | struct sc_context *ctx = p15card->card->ctx; |
1176 | 0 | unsigned char *buf = NULL; |
1177 | 0 | size_t buf_len; |
1178 | 0 | int rv; |
1179 | |
|
1180 | 0 | LOG_FUNC_CALLED(ctx); |
1181 | 0 | if (df->type != SC_PKCS15_PRKDF && df->type != SC_PKCS15_DODF) |
1182 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); |
1183 | | |
1184 | 0 | if (df->enumerated) |
1185 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1186 | | |
1187 | 0 | rv = sc_oberthur_read_file(p15card, AWP_OBJECTS_LIST_PRV, &buf, &buf_len, 1); |
1188 | 0 | LOG_TEST_RET(ctx, rv, "Parse DF: read private objects info failed"); |
1189 | | |
1190 | 0 | rv = sc_oberthur_parse_privateinfo(p15card, buf, buf_len, 0); |
1191 | |
|
1192 | 0 | if (buf) |
1193 | 0 | free(buf); |
1194 | |
|
1195 | 0 | if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) |
1196 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
1197 | | |
1198 | 0 | LOG_TEST_RET(ctx, rv, "Parse DF: private info parse error"); |
1199 | 0 | df->enumerated = 1; |
1200 | |
|
1201 | 0 | LOG_FUNC_RETURN(ctx, rv); |
1202 | 0 | } |
1203 | | |
1204 | | |
1205 | | static void |
1206 | | sc_awp_clear(struct sc_pkcs15_card *p15card) |
1207 | 1.59k | { |
1208 | 1.59k | LOG_FUNC_CALLED(p15card->card->ctx); |
1209 | 1.59k | } |