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