/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, |
284 | 0 | "pin lens %"SC_FORMAT_LEN_SIZE_T"u/%"SC_FORMAT_LEN_SIZE_T"u", |
285 | 0 | pin_len, puk_len); |
286 | 0 | if (!pin || pin_len>0x40) |
287 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
288 | 0 | if (puk && !puk_len) |
289 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
290 | 0 | if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
291 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
292 | | |
293 | 0 | rv = sc_select_file(card, &ainfo->path, NULL); |
294 | 0 | LOG_TEST_RET(ctx, rv, "Cannot select file"); |
295 | | |
296 | 0 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &profile_auth_pin); |
297 | 0 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &profile_auth_puk); |
298 | |
|
299 | 0 | memset(&args, 0, sizeof(args)); |
300 | 0 | args.type = SC_AC_CHV; |
301 | 0 | args.ref = ainfo->attrs.pin.reference; |
302 | 0 | args.pin = pin; |
303 | 0 | args.pin_len = pin_len; |
304 | |
|
305 | 0 | if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)) { |
306 | 0 | args.pin_tries = profile_auth_pin.tries_left; |
307 | 0 | if (profile_auth_puk.tries_left > 0) { |
308 | 0 | args.puk = oberthur_puk; |
309 | 0 | args.puk_len = sizeof(oberthur_puk); |
310 | 0 | args.puk_tries = 5; |
311 | 0 | } |
312 | 0 | } |
313 | 0 | else { |
314 | 0 | args.pin_tries = profile_auth_puk.tries_left; |
315 | 0 | } |
316 | |
|
317 | 0 | rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_CREATE_PIN, &args); |
318 | 0 | LOG_TEST_RET(ctx, rv, "'CREATE_PIN' card specific command failed"); |
319 | | |
320 | 0 | if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) |
321 | 0 | && (profile_auth_puk.tries_left > 0)) { |
322 | 0 | struct sc_file *file = NULL; |
323 | |
|
324 | 0 | if (sc_profile_get_file(profile, COSM_TITLE"-puk-file", &file)) |
325 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Cannot find PUKFILE"); |
326 | | |
327 | 0 | rv = sc_pkcs15init_update_file(profile, p15card, file, oberthur_puk, sizeof(oberthur_puk)); |
328 | 0 | LOG_TEST_RET(ctx, rv, "Failed to update pukfile"); |
329 | | |
330 | 0 | sc_file_free(file); |
331 | 0 | } |
332 | | |
333 | 0 | LOG_FUNC_RETURN(ctx, rv); |
334 | 0 | } |
335 | | |
336 | | |
337 | | /* |
338 | | * Update PIN |
339 | | */ |
340 | | static int |
341 | | cosm_update_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
342 | | struct sc_pkcs15_auth_info *ainfo, const unsigned char *pin, size_t pin_len, |
343 | | const unsigned char *puk, size_t puk_len ) |
344 | 0 | { |
345 | 0 | struct sc_context *ctx = p15card->card->ctx; |
346 | 0 | int rv; |
347 | |
|
348 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
349 | 0 | if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
350 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
351 | | |
352 | 0 | sc_log(ctx, "ref %i; flags 0x%X", ainfo->attrs.pin.reference, ainfo->attrs.pin.flags); |
353 | |
|
354 | 0 | if (ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
355 | 0 | if (ainfo->attrs.pin.reference != 4) |
356 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "cosm_update_pin() invalid SOPIN reference"); |
357 | 0 | sc_log(ctx, "Update SOPIN ignored"); |
358 | 0 | rv = SC_SUCCESS; |
359 | 0 | } |
360 | 0 | else { |
361 | 0 | rv = cosm_create_reference_data(profile, p15card, ainfo, pin, pin_len, puk, puk_len); |
362 | 0 | LOG_TEST_RET(ctx, rv, "cosm_update_pin() failed to change PIN"); |
363 | | |
364 | 0 | rv = cosm_write_tokeninfo(p15card, profile, NULL, |
365 | 0 | COSM_TOKEN_FLAG_TOKEN_INITIALIZED |
366 | 0 | | COSM_TOKEN_FLAG_PRN_GENERATION |
367 | 0 | | COSM_TOKEN_FLAG_LOGIN_REQUIRED |
368 | 0 | | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED); |
369 | 0 | LOG_TEST_RET(ctx, rv, "cosm_update_pin() failed to update tokeninfo"); |
370 | 0 | } |
371 | | |
372 | 0 | LOG_FUNC_RETURN(ctx, rv); |
373 | 0 | } |
374 | | |
375 | | |
376 | | static int |
377 | | cosm_select_pin_reference(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
378 | | struct sc_pkcs15_auth_info *auth_info) |
379 | 0 | { |
380 | 0 | struct sc_context *ctx = p15card->card->ctx; |
381 | 0 | struct sc_pkcs15_pin_attributes *pin_attrs; |
382 | 0 | struct sc_file *pinfile; |
383 | |
|
384 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
385 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
386 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
387 | | |
388 | 0 | pin_attrs = &auth_info->attrs.pin; |
389 | |
|
390 | 0 | sc_log(ctx, "ref %i; flags %X", pin_attrs->reference, pin_attrs->flags); |
391 | 0 | if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) { |
392 | 0 | sc_log(ctx, "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF"); |
393 | 0 | return SC_ERROR_INCONSISTENT_PROFILE; |
394 | 0 | } |
395 | | |
396 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
397 | 0 | auth_info->path = pinfile->path; |
398 | |
|
399 | 0 | sc_file_free(pinfile); |
400 | |
|
401 | 0 | if (pin_attrs->reference <= 0) { |
402 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
403 | 0 | pin_attrs->reference = 4; |
404 | 0 | else if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) |
405 | 0 | pin_attrs->reference = 4; |
406 | 0 | else |
407 | 0 | pin_attrs->reference = 1; |
408 | |
|
409 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
410 | 0 | pin_attrs->reference |= 0x80; |
411 | 0 | } |
412 | |
|
413 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
414 | 0 | } |
415 | | |
416 | | |
417 | | /* |
418 | | * Store a PIN |
419 | | */ |
420 | | static int |
421 | | cosm_create_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
422 | | struct sc_file *df, struct sc_pkcs15_object *pin_obj, |
423 | | const unsigned char *pin, size_t pin_len, |
424 | | const unsigned char *puk, size_t puk_len) |
425 | 0 | { |
426 | 0 | struct sc_context *ctx = p15card->card->ctx; |
427 | 0 | struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data; |
428 | 0 | struct sc_pkcs15_pin_attributes *pin_attrs; |
429 | 0 | struct sc_file *pin_file; |
430 | 0 | int rv = 0; |
431 | |
|
432 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
433 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
434 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
435 | | |
436 | 0 | pin_attrs = &auth_info->attrs.pin; |
437 | |
|
438 | 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); |
439 | 0 | if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pin_file) < 0) |
440 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "\""COSM_TITLE"-AppDF\" not defined"); |
441 | | |
442 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
443 | 0 | auth_info->path = pin_file->path; |
444 | |
|
445 | 0 | sc_file_free(pin_file); |
446 | |
|
447 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
448 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { |
449 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "SOPIN unblocking is not supported"); |
450 | 0 | } |
451 | 0 | else { |
452 | 0 | if (pin_attrs->reference != 4) |
453 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid SOPIN reference"); |
454 | 0 | } |
455 | 0 | } |
456 | 0 | else { |
457 | 0 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { |
458 | 0 | if (pin_attrs->reference != 0x84) |
459 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PUK reference"); |
460 | 0 | } |
461 | 0 | else { |
462 | 0 | if (pin_attrs->reference != 0x81) |
463 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PIN reference"); |
464 | 0 | } |
465 | 0 | } |
466 | | |
467 | 0 | if (pin && pin_len) { |
468 | 0 | rv = cosm_update_pin(profile, p15card, auth_info, pin, pin_len, puk, puk_len); |
469 | 0 | LOG_TEST_RET(ctx, rv, "Update PIN failed"); |
470 | 0 | } |
471 | | |
472 | 0 | LOG_FUNC_RETURN(ctx, rv); |
473 | 0 | } |
474 | | |
475 | | |
476 | | /* |
477 | | * Allocate a file |
478 | | */ |
479 | | static int |
480 | | cosm_new_file(struct sc_profile *profile, struct sc_card *card, |
481 | | unsigned int type, unsigned int num, struct sc_file **out) |
482 | 0 | { |
483 | 0 | struct sc_file *file; |
484 | 0 | const char *_template = NULL, *desc = NULL; |
485 | 0 | unsigned int structure = 0xFFFFFFFF; |
486 | |
|
487 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
488 | 0 | sc_log(card->ctx, "cosm_new_file() type %X; num %i",type, num); |
489 | 0 | while (1) { |
490 | 0 | switch (type) { |
491 | 0 | case SC_PKCS15_TYPE_PRKEY_RSA: |
492 | 0 | case COSM_TYPE_PRKEY_RSA: |
493 | 0 | desc = "RSA private key"; |
494 | 0 | _template = "template-private-key"; |
495 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
496 | 0 | break; |
497 | 0 | case SC_PKCS15_TYPE_PUBKEY_RSA: |
498 | 0 | case COSM_TYPE_PUBKEY_RSA: |
499 | 0 | desc = "RSA public key"; |
500 | 0 | _template = "template-public-key"; |
501 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC; |
502 | 0 | break; |
503 | 0 | case SC_PKCS15_TYPE_CERT: |
504 | 0 | desc = "certificate"; |
505 | 0 | _template = "template-certificate"; |
506 | 0 | break; |
507 | 0 | case SC_PKCS15_TYPE_DATA_OBJECT: |
508 | 0 | desc = "data object"; |
509 | 0 | _template = "template-public-data"; |
510 | 0 | break; |
511 | 0 | } |
512 | 0 | if (_template) |
513 | 0 | break; |
514 | | /* If this is a specific type such as |
515 | | * SC_PKCS15_TYPE_CERT_FOOBAR, fall back to |
516 | | * the generic class (SC_PKCS15_TYPE_CERT) |
517 | | */ |
518 | 0 | if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) { |
519 | 0 | sc_log(card->ctx, "File type %X not supported by card driver", |
520 | 0 | type); |
521 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
522 | 0 | } |
523 | 0 | type &= SC_PKCS15_TYPE_CLASS_MASK; |
524 | 0 | } |
525 | | |
526 | 0 | sc_log(card->ctx, "cosm_new_file() template %s; num %i",_template, num); |
527 | 0 | if (sc_profile_get_file(profile, _template, &file) < 0) { |
528 | 0 | sc_log(card->ctx, "Profile doesn't define %s template '%s'", |
529 | 0 | desc, _template); |
530 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
531 | 0 | } |
532 | | |
533 | 0 | file->id |= (num & 0xFF); |
534 | 0 | if (file->path.len) { |
535 | 0 | file->path.value[file->path.len - 1] |= (num & 0xFF); |
536 | 0 | } |
537 | 0 | if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
538 | 0 | file->ef_structure = structure; |
539 | 0 | } |
540 | |
|
541 | 0 | sc_log(card->ctx, |
542 | 0 | "cosm_new_file() file size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X", |
543 | 0 | file->size, file->type, file->ef_structure, file->id); |
544 | 0 | *out = file; |
545 | |
|
546 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
547 | 0 | } |
548 | | |
549 | | |
550 | | static int |
551 | | cosm_get_temporary_public_key_file(struct sc_card *card, |
552 | | struct sc_file *prvkey_file, struct sc_file **pubkey_file) |
553 | 0 | { |
554 | 0 | struct sc_context *ctx = card->ctx; |
555 | 0 | const struct sc_acl_entry *entry = NULL; |
556 | 0 | struct sc_file *file = NULL; |
557 | 0 | int rv; |
558 | |
|
559 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
560 | 0 | if (!pubkey_file || !prvkey_file) |
561 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
562 | | |
563 | 0 | file = sc_file_new(); |
564 | 0 | if (!file) |
565 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
566 | | |
567 | 0 | file->status = SC_FILE_STATUS_ACTIVATED; |
568 | 0 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
569 | 0 | file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC; |
570 | 0 | file->id = 0x1012; |
571 | 0 | memcpy(&file->path, &prvkey_file->path, sizeof(file->path)); |
572 | 0 | file->path.value[file->path.len - 2] = 0x10; |
573 | 0 | file->path.value[file->path.len - 1] = 0x12; |
574 | 0 | file->size = prvkey_file->size; |
575 | |
|
576 | 0 | entry = sc_file_get_acl_entry(prvkey_file, SC_AC_OP_UPDATE); |
577 | 0 | if (!entry) { |
578 | 0 | sc_file_free(file); |
579 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Failed to find ACL entry"); |
580 | 0 | } |
581 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, entry->method, entry->key_ref); |
582 | 0 | if (!rv) |
583 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_ENCRYPT, SC_AC_NONE, 0); |
584 | 0 | if (!rv) |
585 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_VERIFY_SIGNATURE, SC_AC_NONE, 0); |
586 | 0 | if (!rv) |
587 | 0 | rv = sc_file_add_acl_entry(file, SC_AC_OP_EXTERNAL_AUTHENTICATE, SC_AC_NONE, 0); |
588 | 0 | if (rv < 0) |
589 | 0 | sc_file_free(file); |
590 | 0 | LOG_TEST_RET(ctx, rv, "Failed to add ACL entry to the temporary public key file"); |
591 | | |
592 | 0 | *pubkey_file = file; |
593 | |
|
594 | 0 | LOG_FUNC_RETURN(card->ctx, rv); |
595 | 0 | } |
596 | | |
597 | | |
598 | | static int |
599 | | cosm_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
600 | | struct sc_pkcs15_object *object, |
601 | | struct sc_pkcs15_pubkey *pubkey) |
602 | 0 | { |
603 | 0 | struct sc_context *ctx = p15card->card->ctx; |
604 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
605 | 0 | struct sc_cardctl_oberthur_genkey_info args; |
606 | 0 | struct sc_file *prkf = NULL, *tmpf = NULL; |
607 | 0 | struct sc_path path; |
608 | 0 | int rv = 0; |
609 | |
|
610 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
611 | |
|
612 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA) |
613 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: RSA only supported"); |
614 | | |
615 | 0 | path = key_info->path; |
616 | 0 | path.len -= 2; |
617 | |
|
618 | 0 | rv = sc_select_file(p15card->card, &path, &tmpf); |
619 | 0 | LOG_TEST_RET(ctx, rv, "Cannot generate key: failed to select private object DF"); |
620 | | |
621 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CRYPTO); |
622 | 0 | if (rv != SC_SUCCESS) { |
623 | 0 | sc_file_free(tmpf); |
624 | 0 | LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CRYPTO' authentication failed"); |
625 | 0 | } |
626 | | |
627 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CREATE); |
628 | 0 | sc_file_free(tmpf); |
629 | 0 | tmpf = NULL; |
630 | 0 | LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CREATE' authentication failed"); |
631 | | |
632 | 0 | rv = sc_select_file(p15card->card, &key_info->path, &prkf); |
633 | 0 | LOG_TEST_RET(ctx, rv, "Failed to generate key: cannot select private key file"); |
634 | | |
635 | | /* In the private key DF create the temporary public RSA file. */ |
636 | 0 | rv = cosm_get_temporary_public_key_file(p15card->card, prkf, &tmpf); |
637 | 0 | if (rv != SC_SUCCESS) { |
638 | 0 | sc_file_free(prkf); |
639 | 0 | LOG_TEST_RET(ctx, rv, "Error while getting temporary public key file"); |
640 | 0 | } |
641 | | |
642 | 0 | rv = sc_pkcs15init_create_file(profile, p15card, tmpf); |
643 | 0 | if (rv != SC_SUCCESS) { |
644 | 0 | sc_file_free(prkf); |
645 | 0 | sc_file_free(tmpf); |
646 | 0 | LOG_TEST_RET(ctx, rv, "cosm_generate_key() failed to create temporary public key EF"); |
647 | 0 | } |
648 | | |
649 | 0 | memset(&args, 0, sizeof(args)); |
650 | 0 | args.id_prv = prkf->id; |
651 | 0 | args.id_pub = tmpf->id; |
652 | 0 | args.exponent = 0x10001; |
653 | 0 | args.key_bits = key_info->modulus_length; |
654 | 0 | args.pubkey_len = key_info->modulus_length / 8; |
655 | 0 | args.pubkey = malloc(key_info->modulus_length / 8); |
656 | 0 | if (!args.pubkey) { |
657 | 0 | sc_file_free(prkf); |
658 | 0 | sc_file_free(tmpf); |
659 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate pubkey"); |
660 | 0 | } |
661 | | |
662 | 0 | rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_GENERATE_KEY, &args); |
663 | 0 | if (rv != SC_SUCCESS) { |
664 | 0 | sc_file_free(prkf); |
665 | 0 | sc_file_free(tmpf); |
666 | 0 | free(args.pubkey); |
667 | 0 | } |
668 | 0 | LOG_TEST_RET(ctx, rv, "cosm_generate_key() CARDCTL_OBERTHUR_GENERATE_KEY failed"); |
669 | | |
670 | | /* extract public key */ |
671 | 0 | pubkey->algorithm = SC_ALGORITHM_RSA; |
672 | 0 | pubkey->u.rsa.modulus.len = key_info->modulus_length / 8; |
673 | 0 | pubkey->u.rsa.modulus.data = malloc(key_info->modulus_length / 8); |
674 | 0 | if (!pubkey->u.rsa.modulus.data) { |
675 | 0 | sc_file_free(prkf); |
676 | 0 | sc_file_free(tmpf); |
677 | 0 | free(args.pubkey); |
678 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate modulus buf"); |
679 | 0 | } |
680 | | |
681 | | /* FIXME and if the exponent length is not 3? */ |
682 | 0 | pubkey->u.rsa.exponent.len = 3; |
683 | 0 | pubkey->u.rsa.exponent.data = malloc(3); |
684 | 0 | if (!pubkey->u.rsa.exponent.data) { |
685 | 0 | sc_file_free(prkf); |
686 | 0 | sc_file_free(tmpf); |
687 | 0 | free(args.pubkey); |
688 | 0 | free(pubkey->u.rsa.modulus.data); |
689 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate exponent buf"); |
690 | 0 | } |
691 | 0 | memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3); |
692 | 0 | memcpy(pubkey->u.rsa.modulus.data, args.pubkey, args.pubkey_len); |
693 | |
|
694 | 0 | key_info->key_reference = prkf->path.value[prkf->path.len - 1] & 0xFF; |
695 | 0 | key_info->path = prkf->path; |
696 | |
|
697 | 0 | sc_log(ctx, "cosm_generate_key() now delete temporary public key"); |
698 | 0 | rv = cosm_delete_file(p15card, profile, tmpf); |
699 | |
|
700 | 0 | sc_file_free(tmpf); |
701 | 0 | sc_file_free(prkf); |
702 | 0 | free(args.pubkey); |
703 | |
|
704 | 0 | LOG_FUNC_RETURN(ctx, rv); |
705 | 0 | } |
706 | | |
707 | | |
708 | | /* |
709 | | * Create private key file |
710 | | */ |
711 | | static int |
712 | | cosm_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
713 | | struct sc_pkcs15_object *object) |
714 | 0 | { |
715 | 0 | struct sc_context *ctx = p15card->card->ctx; |
716 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
717 | 0 | struct sc_file *file = NULL; |
718 | 0 | int rv = 0; |
719 | |
|
720 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
721 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA) |
722 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Create key failed: RSA only supported"); |
723 | | |
724 | 0 | if (key_info->path.len < 2) |
725 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, "The path needs to be at least to bytes long"); |
726 | | |
727 | 0 | sc_log(ctx, "create private key ID:%s", sc_pkcs15_print_id(&key_info->id)); |
728 | | /* Here, the path of private key file should be defined. |
729 | | * Nevertheless, we need to instantiate private key to get the ACLs. */ |
730 | 0 | rv = cosm_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file); |
731 | 0 | LOG_TEST_RET(ctx, rv, "Cannot create key: failed to allocate new key object"); |
732 | | |
733 | 0 | file->size = key_info->modulus_length; |
734 | 0 | memcpy(&file->path, &key_info->path, sizeof(file->path)); |
735 | 0 | file->id = file->path.value[file->path.len - 2] * 0x100 |
736 | 0 | + file->path.value[file->path.len - 1]; |
737 | |
|
738 | 0 | sc_log(ctx, "Path of private key file to create %s", sc_print_path(&file->path)); |
739 | |
|
740 | 0 | rv = sc_select_file(p15card->card, &file->path, NULL); |
741 | 0 | if (rv == 0) { |
742 | 0 | rv = cosm_delete_file(p15card, profile, file); |
743 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to delete private key file"); |
744 | 0 | } |
745 | 0 | else if (rv != SC_ERROR_FILE_NOT_FOUND) { |
746 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Select private key file error"); |
747 | 0 | } |
748 | | |
749 | 0 | rv = sc_pkcs15init_create_file(profile, p15card, file); |
750 | 0 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to create private key file"); |
751 | | |
752 | 0 | key_info->key_reference = file->path.value[file->path.len - 1]; |
753 | |
|
754 | 0 | err: |
755 | 0 | sc_file_free(file); |
756 | |
|
757 | 0 | LOG_FUNC_RETURN(ctx, rv); |
758 | 0 | } |
759 | | |
760 | | |
761 | | /* |
762 | | * Store a private key |
763 | | */ |
764 | | static int |
765 | | cosm_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
766 | | struct sc_pkcs15_object *object, |
767 | | struct sc_pkcs15_prkey *prkey) |
768 | 0 | { |
769 | 0 | struct sc_context *ctx = p15card->card->ctx; |
770 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
771 | 0 | struct sc_file *file = NULL; |
772 | 0 | struct sc_cardctl_oberthur_updatekey_info update_info; |
773 | 0 | int rv = 0; |
774 | |
|
775 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
776 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA || prkey->algorithm != SC_ALGORITHM_RSA) |
777 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Store key failed: RSA only supported"); |
778 | | |
779 | 0 | sc_log(ctx, "store key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), |
780 | 0 | sc_print_path(&key_info->path)); |
781 | |
|
782 | 0 | rv = sc_select_file(p15card->card, &key_info->path, &file); |
783 | 0 | LOG_TEST_RET(ctx, rv, "Cannot store key: select key file failed"); |
784 | | |
785 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
786 | 0 | LOG_TEST_RET(ctx, rv, "No authorisation to store private key"); |
787 | | |
788 | 0 | if (key_info->id.len > sizeof(update_info.id)) |
789 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
790 | | |
791 | 0 | memset(&update_info, 0, sizeof(update_info)); |
792 | 0 | update_info.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
793 | 0 | update_info.data = (void *)&prkey->u.rsa; |
794 | 0 | update_info.data_len = sizeof(void *); |
795 | 0 | update_info.id_len = key_info->id.len; |
796 | 0 | memcpy(update_info.id, key_info->id.value, update_info.id_len); |
797 | |
|
798 | 0 | rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_UPDATE_KEY, &update_info); |
799 | 0 | LOG_TEST_RET(ctx, rv, "Cannot update private key"); |
800 | | |
801 | 0 | sc_file_free(file); |
802 | |
|
803 | 0 | LOG_FUNC_RETURN(ctx, rv); |
804 | 0 | } |
805 | | |
806 | | |
807 | | #ifdef ENABLE_OPENSSL |
808 | | static int |
809 | | cosm_emu_update_dir (struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
810 | | struct sc_app_info *info) |
811 | 0 | { |
812 | 0 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
813 | | /* No DIR file in the native Oberthur card */ |
814 | 0 | SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); |
815 | 0 | } |
816 | | |
817 | | |
818 | | static int |
819 | | cosm_emu_update_any_df(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
820 | | unsigned op, struct sc_pkcs15_object *object) |
821 | 0 | { |
822 | 0 | struct sc_context *ctx = p15card->card->ctx; |
823 | 0 | int rv = SC_ERROR_NOT_SUPPORTED; |
824 | |
|
825 | 0 | SC_FUNC_CALLED(ctx, 1); |
826 | 0 | switch(op) { |
827 | 0 | case SC_AC_OP_ERASE: |
828 | 0 | sc_log(ctx, "Update DF; erase object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type); |
829 | 0 | rv = awp_update_df_delete(p15card, profile, object); |
830 | 0 | break; |
831 | 0 | case SC_AC_OP_CREATE: |
832 | 0 | sc_log(ctx, "Update DF; create object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type); |
833 | 0 | rv = awp_update_df_create(p15card, profile, object); |
834 | 0 | break; |
835 | 0 | } |
836 | 0 | SC_FUNC_RETURN(ctx, 1, rv); |
837 | 0 | } |
838 | | |
839 | | |
840 | | static int |
841 | | cosm_emu_update_tokeninfo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
842 | | struct sc_pkcs15_tokeninfo *tinfo) |
843 | 0 | { |
844 | 0 | struct sc_context *ctx = p15card->card->ctx; |
845 | 0 | struct sc_file *file = NULL; |
846 | 0 | int rv, flags = 0; |
847 | 0 | size_t label_len; |
848 | 0 | unsigned char *buf = NULL; |
849 | |
|
850 | 0 | SC_FUNC_CALLED(ctx, 1); |
851 | |
|
852 | 0 | if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) |
853 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "cannot find "COSM_TITLE"-token-info"); |
854 | | |
855 | 0 | buf = calloc(1, file->size); |
856 | 0 | if (!buf) { |
857 | 0 | sc_file_free(file); |
858 | 0 | SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); |
859 | 0 | } |
860 | | |
861 | 0 | label_len = strlen(tinfo->label) > (file->size - 4) ? (file->size - 4) : strlen(tinfo->label); |
862 | 0 | memcpy(buf, tinfo->label, label_len); |
863 | 0 | memset(buf + label_len, ' ', file->size - 4 - label_len); |
864 | | |
865 | | /* current PKCS#11 flags should be read from the token, |
866 | | * but for simplicity assume that user-pin is already initialised -- Andre 2010-10-05 |
867 | | */ |
868 | 0 | flags = COSM_TOKEN_FLAG_TOKEN_INITIALIZED |
869 | 0 | | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED |
870 | 0 | | COSM_TOKEN_FLAG_LOGIN_REQUIRED |
871 | 0 | | COSM_TOKEN_FLAG_PRN_GENERATION; |
872 | |
|
873 | 0 | memset(buf + file->size - 4, 0, 4); |
874 | 0 | *(buf + file->size - 1) = flags % 0x100; |
875 | 0 | *(buf + file->size - 2) = (flags % 0x10000) / 0x100; |
876 | |
|
877 | 0 | sc_log(ctx, "Update token info (label:'%s',flags:%X,p15card->flags:%X)", buf, flags, p15card->flags); |
878 | 0 | rv = sc_pkcs15init_update_file(profile, p15card, file, buf, file->size); |
879 | 0 | free(buf); |
880 | 0 | sc_file_free(file); |
881 | |
|
882 | 0 | if (rv > 0) |
883 | 0 | rv = 0; |
884 | |
|
885 | 0 | SC_FUNC_RETURN(ctx, 1, rv); |
886 | 0 | } |
887 | | |
888 | | |
889 | | static int |
890 | | cosm_emu_write_info(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
891 | | struct sc_pkcs15_object *pin_obj) |
892 | 0 | { |
893 | 0 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
894 | | /* No OpenSC Info file in the native Oberthur card */ |
895 | 0 | SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); |
896 | 0 | } |
897 | | #endif |
898 | | |
899 | | |
900 | | static struct sc_pkcs15init_operations |
901 | | sc_pkcs15init_oberthur_operations = { |
902 | | cosm_erase_card, |
903 | | NULL, /* init_card */ |
904 | | cosm_create_dir, /* create_dir */ |
905 | | NULL, /* create_domain */ |
906 | | cosm_select_pin_reference, |
907 | | cosm_create_pin, |
908 | | NULL, /* select_key_reference */ |
909 | | cosm_create_key, /* create_key */ |
910 | | cosm_store_key, /* store_key */ |
911 | | cosm_generate_key, /* generate_key */ |
912 | | NULL, |
913 | | NULL, /* encode private/public key */ |
914 | | NULL, /* finalize_card */ |
915 | | NULL, /* delete_object */ |
916 | | #ifdef ENABLE_OPENSSL |
917 | | cosm_emu_update_dir, |
918 | | cosm_emu_update_any_df, |
919 | | cosm_emu_update_tokeninfo, |
920 | | cosm_emu_write_info, |
921 | | NULL, |
922 | | NULL |
923 | | #else |
924 | | NULL, NULL, NULL, NULL, NULL, |
925 | | NULL |
926 | | #endif |
927 | | }; |
928 | | |
929 | | struct sc_pkcs15init_operations * |
930 | | sc_pkcs15init_get_oberthur_ops(void) |
931 | 1 | { |
932 | 1 | return &sc_pkcs15init_oberthur_operations; |
933 | 1 | } |