/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 | 596 | #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 | 91 | #define SC_DEVICE_SPECIFIC_TYPE 0x1000 |
41 | | |
42 | 91 | #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 | 338 | { |
123 | 338 | struct sc_context *ctx = p15card->card->ctx; |
124 | 338 | struct sc_path path; |
125 | 338 | struct sc_file *parent; |
126 | 338 | int rv = 0; |
127 | | |
128 | 338 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
129 | 338 | sc_log(ctx, "id %04X", df->id); |
130 | 338 | if (df->type==SC_FILE_TYPE_DF) { |
131 | 287 | rv = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_DELETE); |
132 | 287 | LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE"); |
133 | 287 | } |
134 | | |
135 | | /* Select the parent DF */ |
136 | 66 | path = df->path; |
137 | 66 | if (path.len < 2) { |
138 | 2 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
139 | 2 | } |
140 | 64 | path.len -= 2; |
141 | | |
142 | 64 | rv = sc_select_file(p15card->card, &path, &parent); |
143 | 64 | LOG_TEST_RET(ctx, rv, "Cannot select parent"); |
144 | | |
145 | 49 | rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE); |
146 | 49 | sc_file_free(parent); |
147 | 49 | LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE"); |
148 | | |
149 | 49 | memset(&path, 0, sizeof(path)); |
150 | 49 | path.type = SC_PATH_TYPE_FILE_ID; |
151 | 49 | path.value[0] = df->id >> 8; |
152 | 49 | path.value[1] = df->id & 0xFF; |
153 | 49 | path.len = 2; |
154 | | |
155 | 49 | rv = sc_delete_file(p15card->card, &path); |
156 | | |
157 | 49 | LOG_FUNC_RETURN(ctx, rv); |
158 | 49 | } |
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 | 290 | { |
167 | 290 | struct sc_context *ctx = p15card->card->ctx; |
168 | 290 | struct sc_file *df = profile->df_info->file, *dir; |
169 | 290 | int rv; |
170 | | |
171 | 290 | 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 | 290 | if (sc_profile_get_file(profile, "DIR", &dir) >= 0) { |
179 | 6 | sc_log(ctx, "erase file dir %04X",dir->id); |
180 | 6 | rv = cosm_delete_file(p15card, profile, dir); |
181 | 6 | sc_file_free(dir); |
182 | 6 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
183 | 2 | goto done; |
184 | 6 | } |
185 | | |
186 | 288 | sc_log(ctx, "erase file ddf %04X",df->id); |
187 | 288 | rv = cosm_delete_file(p15card, profile, df); |
188 | 288 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
189 | 287 | goto done; |
190 | | |
191 | 1 | if (sc_profile_get_file(profile, "private-DF", &dir) >= 0) { |
192 | 1 | sc_log(ctx, "erase file dir %04X",dir->id); |
193 | 1 | rv = cosm_delete_file(p15card, profile, dir); |
194 | 1 | sc_file_free(dir); |
195 | 1 | if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND) |
196 | 1 | goto done; |
197 | 1 | } |
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 | 290 | done: |
216 | 290 | if (rv == SC_ERROR_FILE_NOT_FOUND) |
217 | 0 | rv = 0; |
218 | | |
219 | 290 | LOG_FUNC_RETURN(ctx, rv); |
220 | 290 | } |
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 | 299 | { |
380 | 299 | struct sc_context *ctx = p15card->card->ctx; |
381 | 299 | struct sc_pkcs15_pin_attributes *pin_attrs; |
382 | 299 | struct sc_file *pinfile; |
383 | | |
384 | 299 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
385 | 299 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
386 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
387 | | |
388 | 299 | pin_attrs = &auth_info->attrs.pin; |
389 | | |
390 | 299 | sc_log(ctx, "ref %i; flags %X", pin_attrs->reference, pin_attrs->flags); |
391 | 299 | if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) { |
392 | 296 | sc_log(ctx, "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF"); |
393 | 296 | return SC_ERROR_INCONSISTENT_PROFILE; |
394 | 296 | } |
395 | | |
396 | 3 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
397 | 0 | auth_info->path = pinfile->path; |
398 | | |
399 | 3 | sc_file_free(pinfile); |
400 | | |
401 | 3 | if (pin_attrs->reference <= 0) { |
402 | 2 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
403 | 0 | pin_attrs->reference = 4; |
404 | 2 | else if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) |
405 | 1 | pin_attrs->reference = 4; |
406 | 1 | else |
407 | 1 | pin_attrs->reference = 1; |
408 | | |
409 | 2 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
410 | 0 | pin_attrs->reference |= 0x80; |
411 | 2 | } |
412 | | |
413 | 3 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
414 | 3 | } |
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 | 1 | { |
426 | 1 | struct sc_context *ctx = p15card->card->ctx; |
427 | 1 | struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data; |
428 | 1 | struct sc_pkcs15_pin_attributes *pin_attrs; |
429 | 1 | struct sc_file *pin_file; |
430 | 1 | int rv = 0; |
431 | | |
432 | 1 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
433 | 1 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
434 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
435 | | |
436 | 1 | pin_attrs = &auth_info->attrs.pin; |
437 | | |
438 | 1 | 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 | 1 | if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pin_file) < 0) |
440 | 1 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "\""COSM_TITLE"-AppDF\" not defined"); |
441 | | |
442 | 1 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL) |
443 | 0 | auth_info->path = pin_file->path; |
444 | | |
445 | 1 | sc_file_free(pin_file); |
446 | | |
447 | 1 | 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 | 1 | else { |
457 | 1 | if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { |
458 | 1 | if (pin_attrs->reference != 0x84) |
459 | 1 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PUK reference"); |
460 | 1 | } |
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 | 1 | } |
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 | 91 | { |
483 | 91 | struct sc_file *file; |
484 | 91 | const char *_template = NULL, *desc = NULL; |
485 | 91 | unsigned int structure = 0xFFFFFFFF; |
486 | | |
487 | 91 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
488 | 91 | sc_log(card->ctx, "cosm_new_file() type %X; num %i",type, num); |
489 | 91 | while (1) { |
490 | 91 | switch (type) { |
491 | 91 | case SC_PKCS15_TYPE_PRKEY_RSA: |
492 | 91 | case COSM_TYPE_PRKEY_RSA: |
493 | 91 | desc = "RSA private key"; |
494 | 91 | _template = "template-private-key"; |
495 | 91 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
496 | 91 | 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 | 91 | } |
512 | 91 | if (_template) |
513 | 91 | 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 | 91 | sc_log(card->ctx, "cosm_new_file() template %s; num %i",_template, num); |
527 | 91 | if (sc_profile_get_file(profile, _template, &file) < 0) { |
528 | 37 | sc_log(card->ctx, "Profile doesn't define %s template '%s'", |
529 | 37 | desc, _template); |
530 | 37 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
531 | 37 | } |
532 | | |
533 | 54 | file->id |= (num & 0xFF); |
534 | 54 | if (file->path.len) { |
535 | 54 | file->path.value[file->path.len - 1] |= (num & 0xFF); |
536 | 54 | } |
537 | 54 | if (file->type == SC_FILE_TYPE_INTERNAL_EF) { |
538 | 1 | file->ef_structure = structure; |
539 | 1 | } |
540 | | |
541 | 54 | sc_log(card->ctx, |
542 | 54 | "cosm_new_file() file size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X", |
543 | 54 | file->size, file->type, file->ef_structure, file->id); |
544 | 54 | *out = file; |
545 | | |
546 | 54 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
547 | 54 | } |
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 | 5 | { |
554 | 5 | struct sc_context *ctx = card->ctx; |
555 | 5 | const struct sc_acl_entry *entry = NULL; |
556 | 5 | struct sc_file *file = NULL; |
557 | 5 | int rv; |
558 | | |
559 | 5 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
560 | 5 | if (!pubkey_file || !prvkey_file) |
561 | 5 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
562 | | |
563 | 5 | file = sc_file_new(); |
564 | 5 | if (!file) |
565 | 5 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); |
566 | | |
567 | 5 | file->status = SC_FILE_STATUS_ACTIVATED; |
568 | 5 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
569 | 5 | file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC; |
570 | 5 | file->id = 0x1012; |
571 | 5 | memcpy(&file->path, &prvkey_file->path, sizeof(file->path)); |
572 | 5 | file->path.value[file->path.len - 2] = 0x10; |
573 | 5 | file->path.value[file->path.len - 1] = 0x12; |
574 | 5 | file->size = prvkey_file->size; |
575 | | |
576 | 5 | entry = sc_file_get_acl_entry(prvkey_file, SC_AC_OP_UPDATE); |
577 | 5 | if (!entry) { |
578 | 1 | sc_file_free(file); |
579 | 1 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Failed to find ACL entry"); |
580 | 1 | } |
581 | 4 | rv = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, entry->method, entry->key_ref); |
582 | 4 | if (!rv) |
583 | 4 | rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_ENCRYPT, SC_AC_NONE, 0); |
584 | 4 | if (!rv) |
585 | 4 | rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_VERIFY_SIGNATURE, SC_AC_NONE, 0); |
586 | 4 | if (!rv) |
587 | 4 | rv = sc_file_add_acl_entry(file, SC_AC_OP_EXTERNAL_AUTHENTICATE, SC_AC_NONE, 0); |
588 | 4 | if (rv < 0) |
589 | 0 | sc_file_free(file); |
590 | 4 | LOG_TEST_RET(ctx, rv, "Failed to add ACL entry to the temporary public key file"); |
591 | | |
592 | 4 | *pubkey_file = file; |
593 | | |
594 | 4 | LOG_FUNC_RETURN(card->ctx, rv); |
595 | 4 | } |
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 | 10 | { |
603 | 10 | struct sc_context *ctx = p15card->card->ctx; |
604 | 10 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
605 | 10 | struct sc_cardctl_oberthur_genkey_info args; |
606 | 10 | struct sc_file *prkf = NULL, *tmpf = NULL; |
607 | 10 | struct sc_path path; |
608 | 10 | int rv = 0; |
609 | | |
610 | 10 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
611 | | |
612 | 10 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA) |
613 | 10 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: RSA only supported"); |
614 | | |
615 | 10 | if (key_info->path.len < 4) { |
616 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, |
617 | 0 | "The path needs to be at least four bytes long"); |
618 | 0 | } |
619 | | |
620 | 10 | path = key_info->path; |
621 | 10 | path.len -= 2; |
622 | | |
623 | 10 | rv = sc_select_file(p15card->card, &path, &tmpf); |
624 | 10 | LOG_TEST_RET(ctx, rv, "Cannot generate key: failed to select private object DF"); |
625 | | |
626 | 9 | rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CRYPTO); |
627 | 9 | if (rv != SC_SUCCESS) { |
628 | 1 | sc_file_free(tmpf); |
629 | 1 | LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CRYPTO' authentication failed"); |
630 | 1 | } |
631 | | |
632 | 8 | rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CREATE); |
633 | 8 | sc_file_free(tmpf); |
634 | 8 | tmpf = NULL; |
635 | 8 | LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CREATE' authentication failed"); |
636 | | |
637 | 7 | rv = sc_select_file(p15card->card, &key_info->path, &prkf); |
638 | 7 | LOG_TEST_RET(ctx, rv, "Failed to generate key: cannot select private key file"); |
639 | | |
640 | | /* In the private key DF create the temporary public RSA file. */ |
641 | 5 | rv = cosm_get_temporary_public_key_file(p15card->card, prkf, &tmpf); |
642 | 5 | if (rv != SC_SUCCESS) { |
643 | 1 | sc_file_free(prkf); |
644 | 1 | LOG_TEST_RET(ctx, rv, "Error while getting temporary public key file"); |
645 | 1 | } |
646 | | |
647 | 4 | rv = sc_pkcs15init_create_file(profile, p15card, tmpf); |
648 | 4 | if (rv != SC_SUCCESS) { |
649 | 0 | sc_file_free(prkf); |
650 | 0 | sc_file_free(tmpf); |
651 | 0 | LOG_TEST_RET(ctx, rv, "cosm_generate_key() failed to create temporary public key EF"); |
652 | 0 | } |
653 | | |
654 | 4 | memset(&args, 0, sizeof(args)); |
655 | 4 | args.id_prv = prkf->id; |
656 | 4 | args.id_pub = tmpf->id; |
657 | 4 | args.exponent = 0x10001; |
658 | 4 | args.key_bits = key_info->modulus_length; |
659 | 4 | args.pubkey_len = key_info->modulus_length / 8; |
660 | 4 | args.pubkey = malloc(key_info->modulus_length / 8); |
661 | 4 | if (!args.pubkey) { |
662 | 0 | sc_file_free(prkf); |
663 | 0 | sc_file_free(tmpf); |
664 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate pubkey"); |
665 | 0 | } |
666 | | |
667 | 4 | rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_GENERATE_KEY, &args); |
668 | 4 | if (rv != SC_SUCCESS) { |
669 | 3 | sc_file_free(prkf); |
670 | 3 | sc_file_free(tmpf); |
671 | 3 | free(args.pubkey); |
672 | 3 | } |
673 | 4 | LOG_TEST_RET(ctx, rv, "cosm_generate_key() CARDCTL_OBERTHUR_GENERATE_KEY failed"); |
674 | | |
675 | | /* extract public key */ |
676 | 1 | pubkey->algorithm = SC_ALGORITHM_RSA; |
677 | 1 | pubkey->u.rsa.modulus.len = key_info->modulus_length / 8; |
678 | 1 | pubkey->u.rsa.modulus.data = malloc(key_info->modulus_length / 8); |
679 | 1 | if (!pubkey->u.rsa.modulus.data) { |
680 | 0 | sc_file_free(prkf); |
681 | 0 | sc_file_free(tmpf); |
682 | 0 | free(args.pubkey); |
683 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate modulus buf"); |
684 | 0 | } |
685 | | |
686 | | /* FIXME and if the exponent length is not 3? */ |
687 | 1 | pubkey->u.rsa.exponent.len = 3; |
688 | 1 | pubkey->u.rsa.exponent.data = malloc(3); |
689 | 1 | if (!pubkey->u.rsa.exponent.data) { |
690 | 0 | sc_file_free(prkf); |
691 | 0 | sc_file_free(tmpf); |
692 | 0 | free(args.pubkey); |
693 | 0 | free(pubkey->u.rsa.modulus.data); |
694 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate exponent buf"); |
695 | 0 | } |
696 | 1 | memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3); |
697 | 1 | memcpy(pubkey->u.rsa.modulus.data, args.pubkey, args.pubkey_len); |
698 | 1 | pubkey->u.rsa.modulus.len = args.pubkey_len; |
699 | | |
700 | 1 | key_info->key_reference = prkf->path.value[prkf->path.len - 1] & 0xFF; |
701 | 1 | key_info->path = prkf->path; |
702 | | |
703 | 1 | sc_log(ctx, "cosm_generate_key() now delete temporary public key"); |
704 | 1 | rv = cosm_delete_file(p15card, profile, tmpf); |
705 | | |
706 | 1 | sc_file_free(tmpf); |
707 | 1 | sc_file_free(prkf); |
708 | 1 | free(args.pubkey); |
709 | | |
710 | 1 | LOG_FUNC_RETURN(ctx, rv); |
711 | 1 | } |
712 | | |
713 | | |
714 | | /* |
715 | | * Create private key file |
716 | | */ |
717 | | static int |
718 | | cosm_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
719 | | struct sc_pkcs15_object *object) |
720 | 1.15k | { |
721 | 1.15k | struct sc_context *ctx = p15card->card->ctx; |
722 | 1.15k | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
723 | 1.15k | struct sc_file *file = NULL; |
724 | 1.15k | int rv = 0; |
725 | | |
726 | 1.15k | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
727 | 1.15k | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA) |
728 | 1.15k | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Create key failed: RSA only supported"); |
729 | | |
730 | 288 | if (key_info->path.len < 2) { |
731 | 197 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, |
732 | 197 | "The path needs to be at least two bytes long"); |
733 | 197 | } |
734 | | |
735 | 91 | sc_log(ctx, "create private key ID:%s", sc_pkcs15_print_id(&key_info->id)); |
736 | | /* Here, the path of private key file should be defined. |
737 | | * Nevertheless, we need to instantiate private key to get the ACLs. */ |
738 | 91 | rv = cosm_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file); |
739 | 91 | LOG_TEST_RET(ctx, rv, "Cannot create key: failed to allocate new key object"); |
740 | | |
741 | 54 | file->size = key_info->modulus_length; |
742 | 54 | memcpy(&file->path, &key_info->path, sizeof(file->path)); |
743 | 54 | file->id = file->path.value[file->path.len - 2] * 0x100 |
744 | 54 | + file->path.value[file->path.len - 1]; |
745 | | |
746 | 54 | sc_log(ctx, "Path of private key file to create %s", sc_print_path(&file->path)); |
747 | | |
748 | 54 | rv = sc_select_file(p15card->card, &file->path, NULL); |
749 | 54 | if (rv == 0) { |
750 | 42 | rv = cosm_delete_file(p15card, profile, file); |
751 | 42 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to delete private key file"); |
752 | 42 | } |
753 | 12 | else if (rv != SC_ERROR_FILE_NOT_FOUND) { |
754 | 1 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Select private key file error"); |
755 | 1 | } |
756 | | |
757 | 12 | rv = sc_pkcs15init_create_file(profile, p15card, file); |
758 | 12 | SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to create private key file"); |
759 | | |
760 | 10 | key_info->key_reference = file->path.value[file->path.len - 1]; |
761 | | |
762 | 54 | err: |
763 | 54 | sc_file_free(file); |
764 | | |
765 | 54 | LOG_FUNC_RETURN(ctx, rv); |
766 | 54 | } |
767 | | |
768 | | |
769 | | /* |
770 | | * Store a private key |
771 | | */ |
772 | | static int |
773 | | cosm_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
774 | | struct sc_pkcs15_object *object, |
775 | | struct sc_pkcs15_prkey *prkey) |
776 | 0 | { |
777 | 0 | struct sc_context *ctx = p15card->card->ctx; |
778 | 0 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data; |
779 | 0 | struct sc_file *file = NULL; |
780 | 0 | struct sc_cardctl_oberthur_updatekey_info update_info; |
781 | 0 | int rv = 0; |
782 | |
|
783 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
784 | 0 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA || prkey->algorithm != SC_ALGORITHM_RSA) |
785 | 0 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Store key failed: RSA only supported"); |
786 | | |
787 | 0 | sc_log(ctx, "store key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), |
788 | 0 | sc_print_path(&key_info->path)); |
789 | |
|
790 | 0 | rv = sc_select_file(p15card->card, &key_info->path, &file); |
791 | 0 | LOG_TEST_RET(ctx, rv, "Cannot store key: select key file failed"); |
792 | | |
793 | 0 | rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
794 | 0 | LOG_TEST_RET(ctx, rv, "No authorisation to store private key"); |
795 | | |
796 | 0 | if (key_info->id.len > sizeof(update_info.id)) |
797 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
798 | | |
799 | 0 | memset(&update_info, 0, sizeof(update_info)); |
800 | 0 | update_info.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
801 | 0 | update_info.data = (void *)&prkey->u.rsa; |
802 | 0 | update_info.data_len = sizeof(void *); |
803 | 0 | update_info.id_len = key_info->id.len; |
804 | 0 | memcpy(update_info.id, key_info->id.value, update_info.id_len); |
805 | |
|
806 | 0 | rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_UPDATE_KEY, &update_info); |
807 | 0 | LOG_TEST_RET(ctx, rv, "Cannot update private key"); |
808 | | |
809 | 0 | sc_file_free(file); |
810 | |
|
811 | 0 | LOG_FUNC_RETURN(ctx, rv); |
812 | 0 | } |
813 | | |
814 | | |
815 | | #ifdef ENABLE_OPENSSL |
816 | | static int |
817 | | cosm_emu_update_dir (struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
818 | | struct sc_app_info *info) |
819 | 0 | { |
820 | 0 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
821 | | /* No DIR file in the native Oberthur card */ |
822 | 0 | SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); |
823 | 0 | } |
824 | | |
825 | | |
826 | | static int |
827 | | cosm_emu_update_any_df(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
828 | | unsigned op, struct sc_pkcs15_object *object) |
829 | 0 | { |
830 | 0 | struct sc_context *ctx = p15card->card->ctx; |
831 | 0 | int rv = SC_ERROR_NOT_SUPPORTED; |
832 | |
|
833 | 0 | SC_FUNC_CALLED(ctx, 1); |
834 | 0 | switch(op) { |
835 | 0 | case SC_AC_OP_ERASE: |
836 | 0 | sc_log(ctx, "Update DF; erase object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type); |
837 | 0 | rv = awp_update_df_delete(p15card, profile, object); |
838 | 0 | break; |
839 | 0 | case SC_AC_OP_CREATE: |
840 | 0 | sc_log(ctx, "Update DF; create object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type); |
841 | 0 | rv = awp_update_df_create(p15card, profile, object); |
842 | 0 | break; |
843 | 0 | } |
844 | 0 | SC_FUNC_RETURN(ctx, 1, rv); |
845 | 0 | } |
846 | | |
847 | | |
848 | | static int |
849 | | cosm_emu_update_tokeninfo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
850 | | struct sc_pkcs15_tokeninfo *tinfo) |
851 | 0 | { |
852 | 0 | struct sc_context *ctx = p15card->card->ctx; |
853 | 0 | struct sc_file *file = NULL; |
854 | 0 | int rv, flags = 0; |
855 | 0 | size_t label_len; |
856 | 0 | unsigned char *buf = NULL; |
857 | |
|
858 | 0 | SC_FUNC_CALLED(ctx, 1); |
859 | |
|
860 | 0 | if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) |
861 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "cannot find "COSM_TITLE"-token-info"); |
862 | | |
863 | 0 | buf = calloc(1, file->size); |
864 | 0 | if (!buf) { |
865 | 0 | sc_file_free(file); |
866 | 0 | SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); |
867 | 0 | } |
868 | | |
869 | 0 | label_len = strlen(tinfo->label) > (file->size - 4) ? (file->size - 4) : strlen(tinfo->label); |
870 | 0 | memcpy(buf, tinfo->label, label_len); |
871 | 0 | memset(buf + label_len, ' ', file->size - 4 - label_len); |
872 | | |
873 | | /* current PKCS#11 flags should be read from the token, |
874 | | * but for simplicity assume that user-pin is already initialised -- Andre 2010-10-05 |
875 | | */ |
876 | 0 | flags = COSM_TOKEN_FLAG_TOKEN_INITIALIZED |
877 | 0 | | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED |
878 | 0 | | COSM_TOKEN_FLAG_LOGIN_REQUIRED |
879 | 0 | | COSM_TOKEN_FLAG_PRN_GENERATION; |
880 | |
|
881 | 0 | memset(buf + file->size - 4, 0, 4); |
882 | 0 | *(buf + file->size - 1) = flags % 0x100; |
883 | 0 | *(buf + file->size - 2) = (flags % 0x10000) / 0x100; |
884 | |
|
885 | 0 | sc_log(ctx, "Update token info (label:'%s',flags:%X,p15card->flags:%X)", buf, flags, p15card->flags); |
886 | 0 | rv = sc_pkcs15init_update_file(profile, p15card, file, buf, file->size); |
887 | 0 | free(buf); |
888 | 0 | sc_file_free(file); |
889 | |
|
890 | 0 | if (rv > 0) |
891 | 0 | rv = 0; |
892 | |
|
893 | 0 | SC_FUNC_RETURN(ctx, 1, rv); |
894 | 0 | } |
895 | | |
896 | | |
897 | | static int |
898 | | cosm_emu_write_info(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
899 | | struct sc_pkcs15_object *pin_obj) |
900 | 0 | { |
901 | 0 | SC_FUNC_CALLED(p15card->card->ctx, 1); |
902 | | /* No OpenSC Info file in the native Oberthur card */ |
903 | 0 | SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); |
904 | 0 | } |
905 | | #endif |
906 | | |
907 | | |
908 | | static struct sc_pkcs15init_operations |
909 | | sc_pkcs15init_oberthur_operations = { |
910 | | cosm_erase_card, |
911 | | NULL, /* init_card */ |
912 | | cosm_create_dir, /* create_dir */ |
913 | | NULL, /* create_domain */ |
914 | | cosm_select_pin_reference, |
915 | | cosm_create_pin, |
916 | | NULL, /* select_key_reference */ |
917 | | cosm_create_key, /* create_key */ |
918 | | cosm_store_key, /* store_key */ |
919 | | cosm_generate_key, /* generate_key */ |
920 | | NULL, |
921 | | NULL, /* encode private/public key */ |
922 | | NULL, /* finalize_card */ |
923 | | NULL, /* delete_object */ |
924 | | #ifdef ENABLE_OPENSSL |
925 | | cosm_emu_update_dir, |
926 | | cosm_emu_update_any_df, |
927 | | cosm_emu_update_tokeninfo, |
928 | | cosm_emu_write_info, |
929 | | NULL, |
930 | | NULL |
931 | | #else |
932 | | NULL, NULL, NULL, NULL, NULL, |
933 | | NULL |
934 | | #endif |
935 | | }; |
936 | | |
937 | | struct sc_pkcs15init_operations * |
938 | | sc_pkcs15init_get_oberthur_ops(void) |
939 | 449 | { |
940 | 449 | return &sc_pkcs15init_oberthur_operations; |
941 | 449 | } |