/src/opensc/src/pkcs15init/pkcs15-oberthur.c
Line | Count | Source |
1 | | /* |
2 | | * Oberthur specific operation for PKCS #15 initialization |
3 | | * |
4 | | * Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * Copyright (C) 2009 Viktor Tarasov <viktor.tarasov@opentrust.com>, |
6 | | * OpenTrust <www.opentrust.com> |
7 | | * |
8 | | * This library is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public |
10 | | * License as published by the Free Software Foundation; either |
11 | | * version 2.1 of the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with this library; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | #include "pkcs15-oberthur.h" |
24 | | #include <sys/types.h> |
25 | | #include <ctype.h> |
26 | | |
27 | | #include "libopensc/opensc.h" |
28 | | #include "libopensc/cardctl.h" |
29 | | #include "libopensc/log.h" |
30 | | #include "profile.h" |
31 | | #include "pkcs15-init.h" |
32 | | |
33 | 0 | #define COSM_TITLE "OberthurAWP" |
34 | | |
35 | | #define TLV_TYPE_V 0 |
36 | | #define TLV_TYPE_LV 1 |
37 | | #define TLV_TYPE_TLV 2 |
38 | | |
39 | | /* Should be greater then SC_PKCS15_TYPE_CLASS_MASK */ |
40 | 0 | #define SC_DEVICE_SPECIFIC_TYPE 0x1000 |
41 | | |
42 | 0 | #define COSM_TYPE_PRKEY_RSA (SC_DEVICE_SPECIFIC_TYPE | SC_PKCS15_TYPE_PRKEY_RSA) |
43 | 0 | #define COSM_TYPE_PUBKEY_RSA (SC_DEVICE_SPECIFIC_TYPE | SC_PKCS15_TYPE_PUBKEY_RSA) |
44 | | |
45 | 0 | #define COSM_TOKEN_FLAG_PRN_GENERATION 0x01 |
46 | 0 | #define COSM_TOKEN_FLAG_LOGIN_REQUIRED 0x04 |
47 | 0 | #define COSM_TOKEN_FLAG_USER_PIN_INITIALIZED 0x08 |
48 | 0 | #define COSM_TOKEN_FLAG_TOKEN_INITIALIZED 0x0400 |
49 | | |
50 | | static int cosm_create_reference_data(struct sc_profile *, struct sc_pkcs15_card *, |
51 | | struct sc_pkcs15_auth_info *, const unsigned char *, size_t, |
52 | | const unsigned char *, size_t); |
53 | | static int cosm_update_pin(struct sc_profile *, struct sc_pkcs15_card *, |
54 | | struct sc_pkcs15_auth_info *, const unsigned char *, size_t, |
55 | | const unsigned char *, size_t); |
56 | | |
57 | | static int |
58 | | cosm_write_tokeninfo (struct sc_pkcs15_card *p15card, struct sc_profile *profile, |
59 | | char *label, unsigned flags) |
60 | 0 | { |
61 | 0 | struct sc_context *ctx; |
62 | 0 | struct sc_file *file = NULL; |
63 | 0 | int rv; |
64 | 0 | size_t sz; |
65 | 0 | char *buffer = NULL; |
66 | |
|
67 | 0 | if (!p15card || !p15card->card || !profile) |
68 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
69 | | |
70 | 0 | ctx = p15card->card->ctx; |
71 | |
|
72 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
73 | 0 | if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) { |
74 | 0 | rv = SC_ERROR_INCONSISTENT_PROFILE; |
75 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Cannot find "COSM_TITLE"-token-info"); |
76 | 0 | } |
77 | | |
78 | 0 | if (file->size < 16) { |
79 | 0 | rv = SC_ERROR_INCONSISTENT_PROFILE; |
80 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Insufficient size of the "COSM_TITLE"-token-info file"); |
81 | 0 | } |
82 | | |
83 | 0 | buffer = calloc(1, file->size); |
84 | 0 | if (!buffer) { |
85 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
86 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Allocation error in cosm_write_tokeninfo()"); |
87 | 0 | } |
88 | | |
89 | 0 | if (label) |
90 | 0 | strncpy(buffer, label, file->size - 4); |
91 | 0 | else if (p15card->tokeninfo->label) |
92 | 0 | snprintf(buffer, file->size - 4, "%s", p15card->tokeninfo->label); |
93 | 0 | else if (profile->p15_spec && profile->p15_spec->tokeninfo->label) |
94 | 0 | snprintf(buffer, file->size - 4, "%s", profile->p15_spec->tokeninfo->label); |
95 | 0 | else |
96 | 0 | snprintf(buffer, file->size - 4, "OpenSC-Token"); |
97 | |
|
98 | 0 | sz = strlen(buffer); |
99 | 0 | if (sz < file->size - 4) |
100 | 0 | memset(buffer + sz, ' ', file->size - sz); |
101 | |
|
102 | 0 | sc_log(ctx, "cosm_write_tokeninfo() token label '%s'; oberthur flags 0x%X", buffer, flags); |
103 | |
|
104 | 0 | memset(buffer + file->size - 4, 0, 4); |
105 | 0 | *(buffer + file->size - 1) = flags & 0xFF; |
106 | 0 | *(buffer + file->size - 2) = (flags >> 8) & 0xFF; |
107 | |
|
108 | 0 | rv = sc_pkcs15init_update_file(profile, p15card, file, buffer, file->size); |
109 | 0 | if (rv > 0) |
110 | 0 | rv = 0; |
111 | |
|
112 | 0 | err: |
113 | 0 | sc_file_free(file); |
114 | 0 | free(buffer); |
115 | 0 | LOG_FUNC_RETURN(ctx, rv); |
116 | 0 | } |
117 | | |
118 | | |
119 | | int |
120 | | cosm_delete_file(struct sc_pkcs15_card *p15card, struct sc_profile *profile, |
121 | | struct sc_file *df) |
122 | 0 | { |
123 | 0 | struct sc_context *ctx = p15card->card->ctx; |
124 | 0 | struct sc_path path; |
125 | 0 | struct sc_file *parent; |
126 | 0 | int rv = 0; |
127 | |
|
128 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
129 | 0 | sc_log(ctx, "id %04X", df->id); |
130 | 0 | if (df->type==SC_FILE_TYPE_DF) { |
131 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_DELETE); |
132 | 0 | LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE"); |
133 | 0 | } |
134 | | |
135 | | /* Select the parent DF */ |
136 | 0 | path = df->path; |
137 | 0 | if (path.len < 2) { |
138 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
139 | 0 | } |
140 | 0 | path.len -= 2; |
141 | |
|
142 | 0 | rv = sc_select_file(p15card->card, &path, &parent); |
143 | 0 | LOG_TEST_RET(ctx, rv, "Cannot select parent"); |
144 | | |
145 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE); |
146 | 0 | sc_file_free(parent); |
147 | 0 | LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE"); |
148 | | |
149 | 0 | memset(&path, 0, sizeof(path)); |
150 | 0 | path.type = SC_PATH_TYPE_FILE_ID; |
151 | 0 | path.value[0] = df->id >> 8; |
152 | 0 | path.value[1] = df->id & 0xFF; |
153 | 0 | path.len = 2; |
154 | |
|
155 | 0 | rv = sc_delete_file(p15card->card, &path); |
156 | |
|
157 | 0 | LOG_FUNC_RETURN(ctx, rv); |
158 | 0 | } |
159 | | |
160 | | |
161 | | /* |
162 | | * Erase the card |
163 | | */ |
164 | | static int |
165 | | cosm_erase_card(struct sc_profile *profile, struct sc_pkcs15_card *p15card) |
166 | 0 | { |
167 | 0 | struct sc_context *ctx = p15card->card->ctx; |
168 | 0 | struct sc_file *df = profile->df_info->file, *dir; |
169 | 0 | int rv; |
170 | |
|
171 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
172 | | /* Delete EF(DIR). This may not be very nice |
173 | | * against other applications that use this file, but |
174 | | * extremely useful for testing :) |
175 | | * Note we need to delete if before the DF because we create |
176 | | * it *after* the DF. |
177 | | * */ |
178 | 0 | if (sc_profile_get_file(profile, "DIR", &dir) >= 0) { |
179 | 0 | sc_log(ctx, "erase file dir %04X",dir->id); |
180 | 0 | rv = cosm_delete_file(p15card, profile, dir); |
181 | 0 | sc_file_free(dir); |
182 | 0 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
183 | 0 | goto done; |
184 | 0 | } |
185 | | |
186 | 0 | sc_log(ctx, "erase file ddf %04X",df->id); |
187 | 0 | rv = cosm_delete_file(p15card, profile, df); |
188 | 0 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
189 | 0 | goto done; |
190 | | |
191 | 0 | if (sc_profile_get_file(profile, "private-DF", &dir) >= 0) { |
192 | 0 | sc_log(ctx, "erase file dir %04X",dir->id); |
193 | 0 | rv = cosm_delete_file(p15card, profile, dir); |
194 | 0 | sc_file_free(dir); |
195 | 0 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
196 | 0 | goto done; |
197 | 0 | } |
198 | | |
199 | 0 | if (sc_profile_get_file(profile, "public-DF", &dir) >= 0) { |
200 | 0 | sc_log(ctx, "erase file dir %04X",dir->id); |
201 | 0 | rv = cosm_delete_file(p15card, profile, dir); |
202 | 0 | sc_file_free(dir); |
203 | 0 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
204 | 0 | goto done; |
205 | 0 | } |
206 | | |
207 | 0 | rv = sc_profile_get_file(profile, COSM_TITLE"-AppDF", &dir); |
208 | 0 | if (!rv) { |
209 | 0 | sc_log(ctx, "delete %s; r %i", COSM_TITLE"-AppDF", rv); |
210 | 0 | rv = cosm_delete_file(p15card, profile, dir); |
211 | 0 | sc_file_free(dir); |
212 | 0 | } |
213 | |
|
214 | 0 | sc_free_apps(p15card->card); |
215 | 0 | done: |
216 | 0 | if (rv == SC_ERROR_FILE_NOT_FOUND) |
217 | 0 | rv = 0; |
218 | |
|
219 | 0 | LOG_FUNC_RETURN(ctx, rv); |
220 | 0 | } |
221 | | |
222 | | |
223 | | static int |
224 | | cosm_create_dir(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
225 | | struct sc_file *df) |
226 | 0 | { |
227 | 0 | struct sc_context *ctx = p15card->card->ctx; |
228 | 0 | struct sc_file *file = NULL; |
229 | 0 | size_t ii; |
230 | 0 | int rv; |
231 | 0 | static const char *create_dfs[] = { |
232 | 0 | COSM_TITLE"-AppDF", |
233 | 0 | "private-DF", |
234 | 0 | "public-DF", |
235 | 0 | COSM_TITLE"-token-info", |
236 | 0 | COSM_TITLE"-puk-file", |
237 | 0 | COSM_TITLE"-container-list", |
238 | 0 | COSM_TITLE"-public-list", |
239 | 0 | COSM_TITLE"-private-list", |
240 | 0 | NULL |
241 | 0 | }; |
242 | |
|
243 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
244 | | |
245 | | /* Oberthur AWP file system is expected.*/ |
246 | | /* Create private objects DF */ |
247 | 0 | for (ii = 0; create_dfs[ii]; ii++) { |
248 | 0 | if (sc_profile_get_file(profile, create_dfs[ii], &file)) { |
249 | 0 | sc_log(ctx, "Inconsistent profile: cannot find %s", create_dfs[ii]); |
250 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Profile do not contains Oberthur AWP file"); |
251 | 0 | } |
252 | | |
253 | 0 | rv = sc_pkcs15init_create_file(profile, p15card, file); |
254 | 0 | sc_file_free(file); |
255 | 0 | if (rv != SC_ERROR_FILE_ALREADY_EXISTS) |
256 | 0 | LOG_TEST_RET(ctx, rv, "Failed to create Oberthur AWP file"); |
257 | 0 | } |
258 | | |
259 | 0 | rv = cosm_write_tokeninfo(p15card, profile, NULL, |
260 | 0 | COSM_TOKEN_FLAG_TOKEN_INITIALIZED | COSM_TOKEN_FLAG_PRN_GENERATION); |
261 | |
|
262 | 0 | LOG_FUNC_RETURN(ctx, rv); |
263 | 0 | } |
264 | | |
265 | | |
266 | | static int |
267 | | cosm_create_reference_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
268 | | struct sc_pkcs15_auth_info *ainfo, |
269 | | const unsigned char *pin, size_t pin_len, |
270 | | const unsigned char *puk, size_t puk_len ) |
271 | 0 | { |
272 | 0 | struct sc_context *ctx = p15card->card->ctx; |
273 | 0 | struct sc_card *card = p15card->card; |
274 | 0 | struct sc_pkcs15_auth_info profile_auth_pin = {0}, profile_auth_puk = {0}; |
275 | 0 | struct sc_cardctl_oberthur_createpin_info args; |
276 | 0 | int rv; |
277 | 0 | unsigned char oberthur_puk[16] = { |
278 | 0 | 0x6F, 0x47, 0xD9, 0x88, 0x4B, 0x6F, 0x9D, 0xC5, |
279 | 0 | 0x78, 0x33, 0x79, 0x8F, 0x5B, 0x7D, 0xE1, 0xA5 |
280 | 0 | }; |
281 | |
|
282 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
283 | 0 | sc_log(ctx, "pin lens %zu/%zu", pin_len, puk_len); |
284 | 0 | if (!pin || pin_len>0x40) |
285 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
286 | 0 | if (puk && !puk_len) |
287 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
288 | 0 | if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
289 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
290 | | |
291 | 0 | rv = sc_select_file(card, &ainfo->path, NULL); |
292 | 0 | LOG_TEST_RET(ctx, rv, "Cannot select file"); |
293 | | |
294 | 0 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &profile_auth_pin); |
295 | 0 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &profile_auth_puk); |
296 | |
|
297 | 0 | memset(&args, 0, sizeof(args)); |
298 | 0 | args.type = SC_AC_CHV; |
299 | 0 | args.ref = ainfo->attrs.pin.reference; |
300 | 0 | args.pin = pin; |
301 | 0 | args.pin_len = pin_len; |
302 | |
|
303 | 0 | if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)) { |
304 | 0 | args.pin_tries = profile_auth_pin.tries_left; |
305 | 0 | if (profile_auth_puk.tries_left > 0) { |
306 | 0 | args.puk = oberthur_puk; |
307 | 0 | args.puk_len = sizeof(oberthur_puk); |
308 | 0 | args.puk_tries = 5; |
309 | 0 | } |
310 | 0 | } |
311 | 0 | else { |
312 | 0 | args.pin_tries = profile_auth_puk.tries_left; |
313 | 0 | } |
314 | |
|
315 | 0 | rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_CREATE_PIN, &args); |
316 | 0 | LOG_TEST_RET(ctx, rv, "'CREATE_PIN' card specific command failed"); |
317 | | |
318 | 0 | if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) |
319 | 0 | && (profile_auth_puk.tries_left > 0)) { |
320 | 0 | struct sc_file *file = NULL; |
321 | |
|
322 | 0 | if (sc_profile_get_file(profile, COSM_TITLE"-puk-file", &file)) |
323 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Cannot find PUKFILE"); |
324 | | |
325 | 0 | rv = sc_pkcs15init_update_file(profile, p15card, file, oberthur_puk, sizeof(oberthur_puk)); |
326 | 0 | LOG_TEST_RET(ctx, rv, "Failed to update pukfile"); |
327 | | |
328 | 0 | sc_file_free(file); |
329 | 0 | } |
330 | | |
331 | 0 | LOG_FUNC_RETURN(ctx, rv); |
332 | 0 | } |
333 | | |
334 | | |
335 | | /* |
336 | | * Update PIN |
337 | | */ |
338 | | static int |
339 | | cosm_update_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
340 | | struct sc_pkcs15_auth_info *ainfo, const unsigned char *pin, size_t pin_len, |
341 | | const unsigned char *puk, size_t puk_len ) |
342 | 0 | { |
343 | 0 | struct sc_context *ctx = p15card->card->ctx; |
344 | 0 | int rv; |
345 | |
|
346 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
347 | 0 | if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
348 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
349 | | |
350 | 0 | sc_log(ctx, "ref %i; flags 0x%X", ainfo->attrs.pin.reference, ainfo->attrs.pin.flags); |
351 | |
|
352 | 0 | if (ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
353 | 0 | if (ainfo->attrs.pin.reference != 4) |
354 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "cosm_update_pin() invalid SOPIN reference"); |
355 | 0 | sc_log(ctx, "Update SOPIN ignored"); |
356 | 0 | rv = SC_SUCCESS; |
357 | 0 | } |
358 | 0 | else { |
359 | 0 | rv = cosm_create_reference_data(profile, p15card, ainfo, pin, pin_len, puk, puk_len); |
360 | 0 | LOG_TEST_RET(ctx, rv, "cosm_update_pin() failed to change PIN"); |
361 | | |
362 | 0 | rv = cosm_write_tokeninfo(p15card, profile, NULL, |
363 | 0 | COSM_TOKEN_FLAG_TOKEN_INITIALIZED |
364 | 0 | | COSM_TOKEN_FLAG_PRN_GENERATION |
365 | 0 | | COSM_TOKEN_FLAG_LOGIN_REQUIRED |
366 | 0 | | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED); |
367 | 0 | LOG_TEST_RET(ctx, rv, "cosm_update_pin() failed to update tokeninfo"); |
368 | 0 | } |
369 | | |
370 | 0 | LOG_FUNC_RETURN(ctx, rv); |
371 | 0 | } |
372 | | |
373 | | |
374 | | static int |
375 | | cosm_select_pin_reference(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
376 | | struct sc_pkcs15_auth_info *auth_info) |
377 | 0 | { |
378 | 0 | struct sc_context *ctx = p15card->card->ctx; |
379 | 0 | struct sc_pkcs15_pin_attributes *pin_attrs; |
380 | 0 | struct sc_file *pinfile; |
381 | |
|
382 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
383 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
384 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
385 | | |
386 | 0 | pin_attrs = &auth_info->attrs.pin; |
387 | |
|
388 | 0 | sc_log(ctx, "ref %i; flags %X", pin_attrs->reference, pin_attrs->flags); |
389 | 0 | if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) { |
390 | 0 | sc_log(ctx, "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF"); |
391 | 0 | return SC_ERROR_INCONSISTENT_PROFILE; |
392 | 0 | } |
393 | | |
394 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
395 | 0 | auth_info->path = pinfile->path; |
396 | |
|
397 | 0 | sc_file_free(pinfile); |
398 | |
|
399 | 0 | if (pin_attrs->reference <= 0) { |
400 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
401 | 0 | pin_attrs->reference = 4; |
402 | 0 | else if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) |
403 | 0 | pin_attrs->reference = 4; |
404 | 0 | else |
405 | 0 | pin_attrs->reference = 1; |
406 | |
|
407 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
408 | 0 | pin_attrs->reference |= 0x80; |
409 | 0 | } |
410 | |
|
411 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
412 | 0 | } |
413 | | |
414 | | |
415 | | /* |
416 | | * Store a PIN |
417 | | */ |
418 | | static int |
419 | | cosm_create_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
420 | | struct sc_file *df, struct sc_pkcs15_object *pin_obj, |
421 | | const unsigned char *pin, size_t pin_len, |
422 | | const unsigned char *puk, size_t puk_len) |
423 | 0 | { |
424 | 0 | struct sc_context *ctx = p15card->card->ctx; |
425 | 0 | struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data; |
426 | 0 | struct sc_pkcs15_pin_attributes *pin_attrs; |
427 | 0 | struct sc_file *pin_file; |
428 | 0 | int rv = 0; |
429 | |
|
430 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
431 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
432 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
433 | | |
434 | 0 | pin_attrs = &auth_info->attrs.pin; |
435 | |
|
436 | 0 | sc_log(ctx, "create '%.*s'; ref 0x%X; flags %X", (int) sizeof pin_obj->label, pin_obj->label, pin_attrs->reference, pin_attrs->flags); |
437 | 0 | if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pin_file) < 0) |
438 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "\""COSM_TITLE"-AppDF\" not defined"); |
439 | | |
440 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
441 | 0 | auth_info->path = pin_file->path; |
442 | |
|
443 | 0 | sc_file_free(pin_file); |
444 | |
|
445 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
446 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { |
447 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "SOPIN unblocking is not supported"); |
448 | 0 | } |
449 | 0 | else { |
450 | 0 | if (pin_attrs->reference != 4) |
451 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid SOPIN reference"); |
452 | 0 | } |
453 | 0 | } |
454 | 0 | else { |
455 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { |
456 | 0 | if (pin_attrs->reference != 0x84) |
457 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PUK reference"); |
458 | 0 | } |
459 | 0 | else { |
460 | 0 | if (pin_attrs->reference != 0x81) |
461 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PIN reference"); |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | 0 | if (pin && pin_len) { |
466 | 0 | rv = cosm_update_pin(profile, p15card, auth_info, pin, pin_len, puk, puk_len); |
467 | 0 | LOG_TEST_RET(ctx, rv, "Update PIN failed"); |
468 | 0 | } |
469 | | |
470 | 0 | LOG_FUNC_RETURN(ctx, rv); |
471 | 0 | } |
472 | | |
473 | | |
474 | | /* |
475 | | * Allocate a file |
476 | | */ |
477 | | static int |
478 | | cosm_new_file(struct sc_profile *profile, struct sc_card *card, |
479 | | unsigned int type, unsigned int num, struct sc_file **out) |
480 | 0 | { |
481 | 0 | struct sc_file *file; |
482 | 0 | const char *_template = NULL, *desc = NULL; |
483 | 0 | unsigned int structure = 0xFFFFFFFF; |
484 | |
|
485 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
486 | 0 | sc_log(card->ctx, "cosm_new_file() type %X; num %i",type, num); |
487 | 0 | while (1) { |
488 | 0 | switch (type) { |
489 | 0 | case SC_PKCS15_TYPE_PRKEY_RSA: |
490 | 0 | case COSM_TYPE_PRKEY_RSA: |
491 | 0 | desc = "RSA private key"; |
492 | 0 | _template = "template-private-key"; |
493 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
494 | 0 | break; |
495 | 0 | case SC_PKCS15_TYPE_PUBKEY_RSA: |
496 | 0 | case COSM_TYPE_PUBKEY_RSA: |
497 | 0 | desc = "RSA public key"; |
498 | 0 | _template = "template-public-key"; |
499 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC; |
500 | 0 | break; |
501 | 0 | case SC_PKCS15_TYPE_CERT: |
502 | 0 | desc = "certificate"; |
503 | 0 | _template = "template-certificate"; |
504 | 0 | break; |
505 | 0 | case SC_PKCS15_TYPE_DATA_OBJECT: |
506 | 0 | desc = "data object"; |
507 | 0 | _template = "template-public-data"; |
508 | 0 | break; |
509 | 0 | } |
510 | 0 | if (_template) |
511 | 0 | break; |
512 | | /* If this is a specific type such as |
513 | | * SC_PKCS15_TYPE_CERT_FOOBAR, fall back to |
514 | | * the generic class (SC_PKCS15_TYPE_CERT) |
515 | | */ |
516 | 0 | if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) { |
517 | 0 | sc_log(card->ctx, "File type %X not supported by card driver", |
518 | 0 | type); |
519 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
520 | 0 | } |
521 | 0 | type &= SC_PKCS15_TYPE_CLASS_MASK; |
522 | 0 | } |
523 | | |
524 | 0 | sc_log(card->ctx, "cosm_new_file() template %s; num %i",_template, num); |
525 | 0 | if (sc_profile_get_file(profile, _template, &file) < 0) { |
526 | 0 | sc_log(card->ctx, "Profile doesn't define %s template '%s'", |
527 | 0 | desc, _template); |
528 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
529 | 0 | } |
530 | | |
531 | 0 | file->id |= (num & 0xFF); |
532 | 0 | if (file->path.len) { |
533 | 0 | file->path.value[file->path.len - 1] |= (num & 0xFF); |
534 | 0 | } |
535 | 0 | if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
536 | 0 | file->ef_structure = structure; |
537 | 0 | } |
538 | |
|
539 | 0 | sc_log(card->ctx, "cosm_new_file() file size %zu; ef type %i/%i; id %04X", |
540 | 0 | file->size, file->type, file->ef_structure, file->id); |
541 | 0 | *out = file; |
542 | |
|
543 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
544 | 0 | } |
545 | | |
546 | | |
547 | | static int |
548 | | cosm_get_temporary_public_key_file(struct sc_card *card, |
549 | | struct sc_file *prvkey_file, struct sc_file **pubkey_file) |
550 | 0 | { |
551 | 0 | struct sc_context *ctx = card->ctx; |
552 | 0 | const struct sc_acl_entry *entry = NULL; |
553 | 0 | struct sc_file *file = NULL; |
554 | 0 | int rv; |
555 | |
|
556 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
557 | 0 | if (!pubkey_file || !prvkey_file) |
558 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
559 | | |
560 | 0 | file = sc_file_new(); |
561 | 0 | if (!file) |
562 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
563 | | |
564 | 0 | file->status = SC_FILE_STATUS_ACTIVATED; |
565 | 0 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
566 | 0 | file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC; |
567 | 0 | file->id = 0x1012; |
568 | 0 | memcpy(&file->path, &prvkey_file->path, sizeof(file->path)); |
569 | 0 | file->path.value[file->path.len - 2] = 0x10; |
570 | 0 | file->path.value[file->path.len - 1] = 0x12; |
571 | 0 | file->size = prvkey_file->size; |
572 | |
|
573 | 0 | entry = sc_file_get_acl_entry(prvkey_file, SC_AC_OP_UPDATE); |
574 | 0 | if (!entry) { |
575 | 0 | sc_file_free(file); |
576 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Failed to find ACL entry"); |
577 | 0 | } |
578 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, entry->method, entry->key_ref); |
579 | 0 | if (!rv) |
580 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_ENCRYPT, SC_AC_NONE, 0); |
581 | 0 | if (!rv) |
582 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_VERIFY_SIGNATURE, SC_AC_NONE, 0); |
583 | 0 | if (!rv) |
584 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_EXTERNAL_AUTHENTICATE, SC_AC_NONE, 0); |
585 | 0 | if (rv < 0) |
586 | 0 | sc_file_free(file); |
587 | 0 | LOG_TEST_RET(ctx, rv, "Failed to add ACL entry to the temporary public key file"); |
588 | | |
589 | 0 | *pubkey_file = file; |
590 | |
|
591 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
592 | 0 | } |
593 | | |
594 | | |
595 | | static int |
596 | | cosm_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
597 | | struct sc_pkcs15_object *object, |
598 | | struct sc_pkcs15_pubkey *pubkey) |
599 | 0 | { |
600 | 0 | struct sc_context *ctx = p15card->card->ctx; |
601 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
602 | 0 | struct sc_cardctl_oberthur_genkey_info args; |
603 | 0 | struct sc_file *prkf = NULL, *tmpf = NULL; |
604 | 0 | struct sc_path path; |
605 | 0 | int rv = 0; |
606 | |
|
607 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
608 | |
|
609 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA) |
610 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: RSA only supported"); |
611 | | |
612 | 0 | if (key_info->path.len < 4) { |
613 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, |
614 | 0 | "The path needs to be at least four bytes long"); |
615 | 0 | } |
616 | | |
617 | 0 | path = key_info->path; |
618 | 0 | path.len -= 2; |
619 | |
|
620 | 0 | rv = sc_select_file(p15card->card, &path, &tmpf); |
621 | 0 | LOG_TEST_RET(ctx, rv, "Cannot generate key: failed to select private object DF"); |
622 | | |
623 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CRYPTO); |
624 | 0 | if (rv != SC_SUCCESS) { |
625 | 0 | sc_file_free(tmpf); |
626 | 0 | LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CRYPTO' authentication failed"); |
627 | 0 | } |
628 | | |
629 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CREATE); |
630 | 0 | sc_file_free(tmpf); |
631 | 0 | tmpf = NULL; |
632 | 0 | LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CREATE' authentication failed"); |
633 | | |
634 | 0 | rv = sc_select_file(p15card->card, &key_info->path, &prkf); |
635 | 0 | LOG_TEST_RET(ctx, rv, "Failed to generate key: cannot select private key file"); |
636 | | |
637 | | /* In the private key DF create the temporary public RSA file. */ |
638 | 0 | rv = cosm_get_temporary_public_key_file(p15card->card, prkf, &tmpf); |
639 | 0 | if (rv != SC_SUCCESS) { |
640 | 0 | sc_file_free(prkf); |
641 | 0 | LOG_TEST_RET(ctx, rv, "Error while getting temporary public key file"); |
642 | 0 | } |
643 | | |
644 | 0 | rv = sc_pkcs15init_create_file(profile, p15card, tmpf); |
645 | 0 | if (rv != SC_SUCCESS) { |
646 | 0 | sc_file_free(prkf); |
647 | 0 | sc_file_free(tmpf); |
648 | 0 | LOG_TEST_RET(ctx, rv, "cosm_generate_key() failed to create temporary public key EF"); |
649 | 0 | } |
650 | | |
651 | 0 | memset(&args, 0, sizeof(args)); |
652 | 0 | args.id_prv = prkf->id; |
653 | 0 | args.id_pub = tmpf->id; |
654 | 0 | args.exponent = 0x10001; |
655 | 0 | args.key_bits = key_info->modulus_length; |
656 | 0 | args.pubkey_len = key_info->modulus_length / 8; |
657 | 0 | args.pubkey = malloc(key_info->modulus_length / 8); |
658 | 0 | if (!args.pubkey) { |
659 | 0 | sc_file_free(prkf); |
660 | 0 | sc_file_free(tmpf); |
661 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate pubkey"); |
662 | 0 | } |
663 | | |
664 | 0 | rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_GENERATE_KEY, &args); |
665 | 0 | if (rv != SC_SUCCESS) { |
666 | 0 | sc_file_free(prkf); |
667 | 0 | sc_file_free(tmpf); |
668 | 0 | free(args.pubkey); |
669 | 0 | } |
670 | 0 | LOG_TEST_RET(ctx, rv, "cosm_generate_key() CARDCTL_OBERTHUR_GENERATE_KEY failed"); |
671 | | |
672 | | /* extract public key */ |
673 | 0 | pubkey->algorithm = SC_ALGORITHM_RSA; |
674 | 0 | pubkey->u.rsa.modulus.len = key_info->modulus_length / 8; |
675 | 0 | pubkey->u.rsa.modulus.data = malloc(key_info->modulus_length / 8); |
676 | 0 | if (!pubkey->u.rsa.modulus.data) { |
677 | 0 | sc_file_free(prkf); |
678 | 0 | sc_file_free(tmpf); |
679 | 0 | free(args.pubkey); |
680 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate modulus buf"); |
681 | 0 | } |
682 | | |
683 | | /* FIXME and if the exponent length is not 3? */ |
684 | 0 | pubkey->u.rsa.exponent.len = 3; |
685 | 0 | pubkey->u.rsa.exponent.data = malloc(3); |
686 | 0 | if (!pubkey->u.rsa.exponent.data) { |
687 | 0 | sc_file_free(prkf); |
688 | 0 | sc_file_free(tmpf); |
689 | 0 | free(args.pubkey); |
690 | 0 | free(pubkey->u.rsa.modulus.data); |
691 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate exponent buf"); |
692 | 0 | } |
693 | 0 | memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3); |
694 | 0 | memcpy(pubkey->u.rsa.modulus.data, args.pubkey, args.pubkey_len); |
695 | 0 | pubkey->u.rsa.modulus.len = args.pubkey_len; |
696 | |
|
697 | 0 | key_info->key_reference = prkf->path.value[prkf->path.len - 1] & 0xFF; |
698 | 0 | key_info->path = prkf->path; |
699 | |
|
700 | 0 | sc_log(ctx, "cosm_generate_key() now delete temporary public key"); |
701 | 0 | rv = cosm_delete_file(p15card, profile, tmpf); |
702 | |
|
703 | 0 | sc_file_free(tmpf); |
704 | 0 | sc_file_free(prkf); |
705 | 0 | free(args.pubkey); |
706 | |
|
707 | 0 | LOG_FUNC_RETURN(ctx, rv); |
708 | 0 | } |
709 | | |
710 | | |
711 | | /* |
712 | | * Create private key file |
713 | | */ |
714 | | static int |
715 | | cosm_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
716 | | struct sc_pkcs15_object *object) |
717 | 0 | { |
718 | 0 | struct sc_context *ctx = p15card->card->ctx; |
719 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
720 | 0 | struct sc_file *file = NULL; |
721 | 0 | int rv = 0; |
722 | |
|
723 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
724 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA) |
725 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Create key failed: RSA only supported"); |
726 | | |
727 | 0 | if (key_info->path.len < 2) { |
728 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, |
729 | 0 | "The path needs to be at least two bytes long"); |
730 | 0 | } |
731 | | |
732 | 0 | sc_log(ctx, "create private key ID:%s", sc_pkcs15_print_id(&key_info->id)); |
733 | | /* Here, the path of private key file should be defined. |
734 | | * Nevertheless, we need to instantiate private key to get the ACLs. */ |
735 | 0 | rv = cosm_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file); |
736 | 0 | LOG_TEST_RET(ctx, rv, "Cannot create key: failed to allocate new key object"); |
737 | | |
738 | 0 | file->size = key_info->modulus_length; |
739 | 0 | memcpy(&file->path, &key_info->path, sizeof(file->path)); |
740 | 0 | file->id = file->path.value[file->path.len - 2] * 0x100 |
741 | 0 | + file->path.value[file->path.len - 1]; |
742 | |
|
743 | 0 | sc_log(ctx, "Path of private key file to create %s", sc_print_path(&file->path)); |
744 | |
|
745 | 0 | rv = sc_select_file(p15card->card, &file->path, NULL); |
746 | 0 | if (rv == 0) { |
747 | 0 | rv = cosm_delete_file(p15card, profile, file); |
748 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to delete private key file"); |
749 | 0 | } |
750 | 0 | else if (rv != SC_ERROR_FILE_NOT_FOUND) { |
751 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Select private key file error"); |
752 | 0 | } |
753 | | |
754 | 0 | rv = sc_pkcs15init_create_file(profile, p15card, file); |
755 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to create private key file"); |
756 | | |
757 | 0 | key_info->key_reference = file->path.value[file->path.len - 1]; |
758 | |
|
759 | 0 | err: |
760 | 0 | sc_file_free(file); |
761 | |
|
762 | 0 | LOG_FUNC_RETURN(ctx, rv); |
763 | 0 | } |
764 | | |
765 | | |
766 | | /* |
767 | | * Store a private key |
768 | | */ |
769 | | static int |
770 | | cosm_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
771 | | struct sc_pkcs15_object *object, |
772 | | struct sc_pkcs15_prkey *prkey) |
773 | 0 | { |
774 | 0 | struct sc_context *ctx = p15card->card->ctx; |
775 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
776 | 0 | struct sc_file *file = NULL; |
777 | 0 | struct sc_cardctl_oberthur_updatekey_info update_info; |
778 | 0 | int rv = 0; |
779 | |
|
780 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
781 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA || prkey->algorithm != SC_ALGORITHM_RSA) |
782 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Store key failed: RSA only supported"); |
783 | | |
784 | 0 | sc_log(ctx, "store key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), |
785 | 0 | sc_print_path(&key_info->path)); |
786 | |
|
787 | 0 | rv = sc_select_file(p15card->card, &key_info->path, &file); |
788 | 0 | LOG_TEST_RET(ctx, rv, "Cannot store key: select key file failed"); |
789 | | |
790 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
791 | 0 | LOG_TEST_RET(ctx, rv, "No authorisation to store private key"); |
792 | | |
793 | 0 | if (key_info->id.len > sizeof(update_info.id)) |
794 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
795 | | |
796 | 0 | memset(&update_info, 0, sizeof(update_info)); |
797 | 0 | update_info.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
798 | 0 | update_info.data = (void *)&prkey->u.rsa; |
799 | 0 | update_info.data_len = sizeof(void *); |
800 | 0 | update_info.id_len = key_info->id.len; |
801 | 0 | memcpy(update_info.id, key_info->id.value, update_info.id_len); |
802 | |
|
803 | 0 | rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_UPDATE_KEY, &update_info); |
804 | 0 | LOG_TEST_RET(ctx, rv, "Cannot update private key"); |
805 | | |
806 | 0 | sc_file_free(file); |
807 | |
|
808 | 0 | LOG_FUNC_RETURN(ctx, rv); |
809 | 0 | } |
810 | | |
811 | | |
812 | | #ifdef ENABLE_OPENSSL |
813 | | static int |
814 | | cosm_emu_update_dir (struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
815 | | struct sc_app_info *info) |
816 | 0 | { |
817 | 0 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
818 | | /* No DIR file in the native Oberthur card */ |
819 | 0 | SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); |
820 | 0 | } |
821 | | |
822 | | |
823 | | static int |
824 | | cosm_emu_update_any_df(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
825 | | unsigned op, struct sc_pkcs15_object *object) |
826 | 0 | { |
827 | 0 | struct sc_context *ctx = p15card->card->ctx; |
828 | 0 | int rv = SC_ERROR_NOT_SUPPORTED; |
829 | |
|
830 | 0 | SC_FUNC_CALLED(ctx, 1); |
831 | 0 | switch(op) { |
832 | 0 | case SC_AC_OP_ERASE: |
833 | 0 | sc_log(ctx, "Update DF; erase object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type); |
834 | 0 | rv = awp_update_df_delete(p15card, profile, object); |
835 | 0 | break; |
836 | 0 | case SC_AC_OP_CREATE: |
837 | 0 | sc_log(ctx, "Update DF; create object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type); |
838 | 0 | rv = awp_update_df_create(p15card, profile, object); |
839 | 0 | break; |
840 | 0 | } |
841 | 0 | SC_FUNC_RETURN(ctx, 1, rv); |
842 | 0 | } |
843 | | |
844 | | |
845 | | static int |
846 | | cosm_emu_update_tokeninfo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
847 | | struct sc_pkcs15_tokeninfo *tinfo) |
848 | 0 | { |
849 | 0 | struct sc_context *ctx = p15card->card->ctx; |
850 | 0 | struct sc_file *file = NULL; |
851 | 0 | int rv, flags = 0; |
852 | 0 | size_t label_len; |
853 | 0 | unsigned char *buf = NULL; |
854 | |
|
855 | 0 | SC_FUNC_CALLED(ctx, 1); |
856 | |
|
857 | 0 | if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) |
858 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "cannot find "COSM_TITLE"-token-info"); |
859 | | |
860 | 0 | buf = calloc(1, file->size); |
861 | 0 | if (!buf) { |
862 | 0 | sc_file_free(file); |
863 | 0 | SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); |
864 | 0 | } |
865 | | |
866 | 0 | label_len = strlen(tinfo->label) > (file->size - 4) ? (file->size - 4) : strlen(tinfo->label); |
867 | 0 | memcpy(buf, tinfo->label, label_len); |
868 | 0 | memset(buf + label_len, ' ', file->size - 4 - label_len); |
869 | | |
870 | | /* current PKCS#11 flags should be read from the token, |
871 | | * but for simplicity assume that user-pin is already initialised -- Andre 2010-10-05 |
872 | | */ |
873 | 0 | flags = COSM_TOKEN_FLAG_TOKEN_INITIALIZED |
874 | 0 | | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED |
875 | 0 | | COSM_TOKEN_FLAG_LOGIN_REQUIRED |
876 | 0 | | COSM_TOKEN_FLAG_PRN_GENERATION; |
877 | |
|
878 | 0 | memset(buf + file->size - 4, 0, 4); |
879 | 0 | *(buf + file->size - 1) = flags % 0x100; |
880 | 0 | *(buf + file->size - 2) = (flags % 0x10000) / 0x100; |
881 | |
|
882 | 0 | sc_log(ctx, "Update token info (label:'%s',flags:%X,p15card->flags:%X)", buf, flags, p15card->flags); |
883 | 0 | rv = sc_pkcs15init_update_file(profile, p15card, file, buf, file->size); |
884 | 0 | free(buf); |
885 | 0 | sc_file_free(file); |
886 | |
|
887 | 0 | if (rv > 0) |
888 | 0 | rv = 0; |
889 | |
|
890 | 0 | SC_FUNC_RETURN(ctx, 1, rv); |
891 | 0 | } |
892 | | |
893 | | |
894 | | static int |
895 | | cosm_emu_write_info(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
896 | | struct sc_pkcs15_object *pin_obj) |
897 | 0 | { |
898 | 0 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
899 | | /* No OpenSC Info file in the native Oberthur card */ |
900 | 0 | SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); |
901 | 0 | } |
902 | | #endif |
903 | | |
904 | | |
905 | | static struct sc_pkcs15init_operations |
906 | | sc_pkcs15init_oberthur_operations = { |
907 | | cosm_erase_card, |
908 | | NULL, /* init_card */ |
909 | | cosm_create_dir, /* create_dir */ |
910 | | NULL, /* create_domain */ |
911 | | cosm_select_pin_reference, |
912 | | cosm_create_pin, |
913 | | NULL, /* select_key_reference */ |
914 | | cosm_create_key, /* create_key */ |
915 | | cosm_store_key, /* store_key */ |
916 | | cosm_generate_key, /* generate_key */ |
917 | | NULL, |
918 | | NULL, /* encode private/public key */ |
919 | | NULL, /* finalize_card */ |
920 | | NULL, /* delete_object */ |
921 | | #ifdef ENABLE_OPENSSL |
922 | | cosm_emu_update_dir, |
923 | | cosm_emu_update_any_df, |
924 | | cosm_emu_update_tokeninfo, |
925 | | cosm_emu_write_info, |
926 | | NULL, |
927 | | NULL |
928 | | #else |
929 | | NULL, NULL, NULL, NULL, NULL, |
930 | | NULL |
931 | | #endif |
932 | | }; |
933 | | |
934 | | struct sc_pkcs15init_operations * |
935 | | sc_pkcs15init_get_oberthur_ops(void) |
936 | 0 | { |
937 | 0 | return &sc_pkcs15init_oberthur_operations; |
938 | 0 | } |