/src/opensc/src/pkcs15init/pkcs15-epass2003.c
Line | Count | Source |
1 | | /* |
2 | | * Support for ePass2003 smart cards |
3 | | * |
4 | | * Copyright (C) 2008, Weitao Sun <weitao@ftsafe.com> |
5 | | * Copyright (C) 2011, Xiaoshuo Wu <xiaoshuo@ftsafe.com> |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "config.h" |
23 | | |
24 | | #include <sys/types.h> |
25 | | #include <stdlib.h> |
26 | | #include <string.h> |
27 | | #include <stdarg.h> |
28 | | |
29 | | #include "libopensc/log.h" |
30 | | #include "libopensc/opensc.h" |
31 | | #include "libopensc/cardctl.h" |
32 | | #include "libopensc/cards.h" |
33 | | #include "pkcs15-init.h" |
34 | | #include "profile.h" |
35 | | static int epass2003_pkcs15_erase_card(struct sc_profile *profile, |
36 | | struct sc_pkcs15_card *p15card) |
37 | 0 | { |
38 | 0 | SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); |
39 | |
|
40 | 0 | if (sc_select_file(p15card->card, sc_get_mf_path(), NULL) < 0) |
41 | 0 | return SC_SUCCESS; |
42 | | |
43 | 0 | return sc_card_ctl(p15card->card, SC_CARDCTL_ERASE_CARD, 0); |
44 | 0 | } |
45 | | |
46 | | static int epass2003_pkcs15_init_card(struct sc_profile *profile, |
47 | | struct sc_pkcs15_card *p15card) |
48 | 0 | { |
49 | 0 | struct sc_card *card = p15card->card; |
50 | 0 | int ret; |
51 | |
|
52 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
53 | 0 | sc_do_log(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,NULL,0,NULL, |
54 | 0 | "ePass2003 doesn't support SO-PIN and SO-PUK. You can unblock key with PUK. \n"); |
55 | 0 | { /* MF */ |
56 | 0 | struct sc_file *mf_file; |
57 | 0 | struct sc_file *skey_file; |
58 | |
|
59 | 0 | ret = sc_profile_get_file(profile, "MF", &mf_file); |
60 | 0 | LOG_TEST_RET(card->ctx, ret, |
61 | 0 | "Get MF info failed"); |
62 | 0 | ret = sc_create_file(card, mf_file); |
63 | 0 | sc_file_free(mf_file); |
64 | 0 | LOG_TEST_RET(card->ctx, ret, |
65 | 0 | "Create MF failed"); |
66 | | |
67 | 0 | ret = sc_profile_get_file(profile, "SKey-MF", &skey_file); |
68 | 0 | LOG_TEST_RET(card->ctx, ret, |
69 | 0 | "Get SKey info failed"); |
70 | 0 | ret = sc_create_file(card, skey_file); |
71 | 0 | sc_file_free(skey_file); |
72 | 0 | LOG_TEST_RET(card->ctx, ret, |
73 | 0 | "Create SKey failed"); |
74 | |
|
75 | 0 | } |
76 | | |
77 | 0 | { /* EF(DIR) */ |
78 | 0 | struct sc_file *dir_file; |
79 | | |
80 | | /* get dir profile */ |
81 | 0 | ret = sc_profile_get_file(profile, "DIR", &dir_file); |
82 | 0 | LOG_TEST_RET(card->ctx, ret, |
83 | 0 | "Get EF(DIR) info failed"); |
84 | 0 | ret = sc_create_file(card, dir_file); |
85 | 0 | sc_file_free(dir_file); |
86 | 0 | LOG_TEST_RET(card->ctx, ret, |
87 | 0 | "Create EF(DIR) failed"); |
88 | | |
89 | 0 | sc_free_apps(card); |
90 | 0 | } |
91 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
92 | 0 | } |
93 | | |
94 | | static int epass2003_pkcs15_create_dir(struct sc_profile *profile, |
95 | | struct sc_pkcs15_card *p15card, |
96 | | struct sc_file *df) |
97 | 0 | { |
98 | 0 | struct sc_card *card = p15card->card; |
99 | 0 | int ret; |
100 | |
|
101 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
102 | |
|
103 | 0 | { /* p15 DF */ |
104 | 0 | struct sc_file *df_file; |
105 | 0 | struct sc_file *skey_file; |
106 | 0 | struct sc_file *ef_file; |
107 | 0 | u8 max_counter[2] = { 0 }; |
108 | 0 | int id; |
109 | 0 | u8 user_maxtries = 0; |
110 | 0 | u8 so_maxtries = 0; |
111 | |
|
112 | 0 | ret = sc_profile_get_file(profile, "PKCS15-AppDF", &df_file); |
113 | 0 | LOG_TEST_RET(card->ctx, ret, |
114 | 0 | "Get PKCS15-AppDF info failed"); |
115 | 0 | ret = sc_create_file(card, df_file); |
116 | 0 | sc_file_free(df_file); |
117 | 0 | LOG_TEST_RET(card->ctx, ret, |
118 | 0 | "Create PKCS15-AppDF failed"); |
119 | | |
120 | 0 | ret = sc_profile_get_file(profile, "SKey-AppDF", &skey_file); |
121 | 0 | LOG_TEST_RET(card->ctx, ret, |
122 | 0 | "Get SKey info failed"); |
123 | 0 | ret = sc_create_file(card, skey_file); |
124 | 0 | sc_file_free(skey_file); |
125 | 0 | LOG_TEST_RET(card->ctx, ret, |
126 | 0 | "Create SKey info failed"); |
127 | | |
128 | 0 | ret = sc_profile_get_file(profile, "MAXPIN", &ef_file); |
129 | 0 | LOG_TEST_RET(card->ctx, ret, |
130 | 0 | "Get MAXPIN info failed"); |
131 | 0 | ret = sc_create_file(card, ef_file); |
132 | 0 | LOG_TEST_RET(card->ctx, ret, |
133 | 0 | "Create MAXPIN failed"); |
134 | 0 | ret = sc_select_file(card, &(ef_file->path), &ef_file); |
135 | 0 | LOG_TEST_RET(card->ctx, ret, |
136 | 0 | "Select MAXPIN failed"); |
137 | | |
138 | 0 | ret = sc_profile_get_pin_id(profile, 2, &id); |
139 | 0 | LOG_TEST_RET(card->ctx, ret, |
140 | 0 | "Get User PIN id error!"); |
141 | 0 | user_maxtries = (u8) sc_profile_get_pin_retries(profile, id); |
142 | |
|
143 | 0 | ret = sc_profile_get_pin_id(profile, 1, &id); |
144 | 0 | LOG_TEST_RET(card->ctx, ret, |
145 | 0 | "Get User PIN id error!"); |
146 | 0 | so_maxtries = (u8) sc_profile_get_pin_retries(profile, id); |
147 | |
|
148 | 0 | max_counter[0] = user_maxtries; |
149 | 0 | max_counter[1] = so_maxtries; |
150 | |
|
151 | 0 | ret = sc_update_binary(card, 0, max_counter, 2, 0); |
152 | |
|
153 | 0 | LOG_TEST_RET(card->ctx, ret, |
154 | 0 | "Update MAXPIN failed"); |
155 | 0 | sc_file_free(ef_file); |
156 | 0 | } |
157 | | |
158 | 0 | { /* p15 efs */ |
159 | 0 | char *create_efs[] = { |
160 | 0 | "PKCS15-ODF", |
161 | 0 | "PKCS15-TokenInfo", |
162 | 0 | "PKCS15-UnusedSpace", |
163 | 0 | "PKCS15-AODF", |
164 | 0 | "PKCS15-PrKDF", |
165 | 0 | "PKCS15-PuKDF", |
166 | 0 | "PKCS15-CDF", |
167 | 0 | "PKCS15-DODF", |
168 | 0 | NULL, |
169 | 0 | }; |
170 | 0 | int i; |
171 | 0 | struct sc_file *file = 0; |
172 | |
|
173 | 0 | for (i = 0; create_efs[i]; ++i) { |
174 | 0 | if (sc_profile_get_file(profile, create_efs[i], &file)) { |
175 | 0 | sc_log(card->ctx, |
176 | 0 | "Inconsistent profile: cannot find %s", |
177 | 0 | create_efs[i]); |
178 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, |
179 | 0 | SC_ERROR_INCONSISTENT_PROFILE); |
180 | 0 | } |
181 | 0 | ret = sc_create_file(card, file); |
182 | 0 | sc_file_free(file); |
183 | 0 | LOG_TEST_RET(card->ctx, ret, |
184 | 0 | "Create pkcs15 file failed"); |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret); |
189 | 0 | } |
190 | | |
191 | | static int epass2003_pkcs15_pin_reference(struct sc_profile *profile, |
192 | | struct sc_pkcs15_card *p15card, |
193 | | struct sc_pkcs15_auth_info *auth_info) |
194 | 0 | { |
195 | 0 | SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); |
196 | |
|
197 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
198 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
199 | | |
200 | 0 | if (auth_info->attrs.pin.reference < ENTERSAFE_USER_PIN_ID |
201 | 0 | || auth_info->attrs.pin.reference > ENTERSAFE_SO_PIN_ID) |
202 | 0 | return SC_ERROR_INVALID_PIN_REFERENCE; |
203 | | |
204 | 0 | SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
205 | 0 | } |
206 | | |
207 | | static int epass2003_pkcs15_create_pin(struct sc_profile *profile, |
208 | | struct sc_pkcs15_card *p15card, |
209 | | struct sc_file *df, |
210 | | struct sc_pkcs15_object *pin_obj, |
211 | | const unsigned char *pin, size_t pin_len, |
212 | | const unsigned char *puk, size_t puk_len) |
213 | 0 | { |
214 | 0 | struct sc_card *card = p15card->card; |
215 | 0 | int r; |
216 | 0 | struct sc_pkcs15_auth_info *auth_info; |
217 | |
|
218 | 0 | if (NULL == pin_obj) |
219 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
220 | | |
221 | 0 | auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; |
222 | |
|
223 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
224 | |
|
225 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
226 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
227 | | |
228 | 0 | { /*pin */ |
229 | 0 | sc_epass2003_wkey_data data; |
230 | 0 | int id; |
231 | |
|
232 | 0 | if (!pin || !pin_len || pin_len > 16) |
233 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
234 | | |
235 | 0 | data.type = SC_EPASS2003_SECRET_PIN; |
236 | 0 | data.key_data.es_secret.kid = auth_info->attrs.pin.reference; |
237 | 0 | data.key_data.es_secret.ac[0] = |
238 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE; |
239 | 0 | data.key_data.es_secret.ac[1] = |
240 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_USER; |
241 | |
|
242 | 0 | r = sc_profile_get_pin_id(profile, 2, &id); |
243 | 0 | LOG_TEST_RET(card->ctx, r, |
244 | 0 | "Get User PIN id error!"); |
245 | 0 | data.key_data.es_secret.EC = |
246 | 0 | sc_profile_get_pin_retries(profile, id); |
247 | | |
248 | | /* pad pin with 0 */ |
249 | 0 | memset(data.key_data.es_secret.key_val, 0, |
250 | 0 | sizeof(data.key_data.es_secret.key_val)); |
251 | 0 | memcpy(data.key_data.es_secret.key_val, pin, pin_len); |
252 | 0 | data.key_data.es_secret.key_len = pin_len; |
253 | |
|
254 | 0 | r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); |
255 | 0 | if (r < 0) |
256 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
257 | 0 | if (pin_obj) { |
258 | | /* Cache new PIN value. */ |
259 | 0 | sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | 0 | { /*puk */ |
264 | 0 | sc_epass2003_wkey_data data; |
265 | 0 | int id; |
266 | |
|
267 | 0 | if (!puk || !puk_len || puk_len > 16) |
268 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
269 | | |
270 | 0 | data.type = SC_EPASS2003_SECRET_PIN; |
271 | 0 | data.key_data.es_secret.kid = |
272 | 0 | auth_info->attrs.pin.reference + 1; |
273 | 0 | data.key_data.es_secret.ac[0] = |
274 | 0 | EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE; |
275 | 0 | data.key_data.es_secret.ac[1] = |
276 | 0 | EPASS2003_AC_MAC_EQUAL | EPASS2003_AC_SO; |
277 | |
|
278 | 0 | r = sc_profile_get_pin_id(profile, 1, &id); |
279 | 0 | LOG_TEST_RET(card->ctx, r, |
280 | 0 | "Get User PIN id error!"); |
281 | 0 | data.key_data.es_secret.EC = |
282 | 0 | sc_profile_get_pin_retries(profile, id); |
283 | | |
284 | | /* pad pin with 0 */ |
285 | 0 | memset(data.key_data.es_secret.key_val, 0, |
286 | 0 | sizeof(data.key_data.es_secret.key_val)); |
287 | 0 | memcpy(data.key_data.es_secret.key_val, puk, puk_len); |
288 | 0 | data.key_data.es_secret.key_len = puk_len; |
289 | |
|
290 | 0 | r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); |
291 | 0 | } |
292 | | |
293 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
294 | 0 | } |
295 | | |
296 | | static int epass2003_pkcs15_key_reference(struct sc_profile *profile, |
297 | | struct sc_pkcs15_card *p15card, |
298 | | struct sc_pkcs15_prkey_info *prkey) |
299 | 0 | { |
300 | 0 | SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); |
301 | 0 | if (prkey->path.len == 0) |
302 | 0 | SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); |
303 | 0 | prkey->key_reference = prkey->path.value[prkey->path.len - 1]; |
304 | 0 | SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
305 | 0 | } |
306 | | |
307 | | /* from pkcs15-oberthur.c, modified */ |
308 | | static int |
309 | | cosm_new_file(struct sc_profile *profile, struct sc_card *card, |
310 | | unsigned int type, unsigned int num, struct sc_file **out) |
311 | 0 | { |
312 | 0 | struct sc_file *file = NULL; |
313 | 0 | const char *_template = NULL, *desc = NULL; |
314 | 0 | unsigned int structure = 0xFFFFFFFF; |
315 | |
|
316 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
317 | 0 | sc_log(card->ctx, "type %X; num %i\n", type, |
318 | 0 | num); |
319 | 0 | while (1) { |
320 | 0 | switch (type) { |
321 | 0 | case SC_PKCS15_TYPE_PRKEY_EC: |
322 | 0 | desc = "EC private key"; |
323 | 0 | _template = "private-key"; |
324 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_EC_CRT; |
325 | 0 | break; |
326 | 0 | case SC_PKCS15_TYPE_PUBKEY_EC: |
327 | 0 | desc = "EC public key"; |
328 | 0 | _template = "public-key"; |
329 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC; |
330 | 0 | break; |
331 | 0 | case SC_PKCS15_TYPE_PRKEY_RSA: |
332 | 0 | desc = "RSA private key"; |
333 | 0 | _template = "private-key"; |
334 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT; |
335 | 0 | break; |
336 | 0 | case SC_PKCS15_TYPE_PUBKEY_RSA: |
337 | 0 | desc = "RSA public key"; |
338 | 0 | _template = "public-key"; |
339 | 0 | structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC; |
340 | 0 | break; |
341 | 0 | case SC_PKCS15_TYPE_PRKEY: |
342 | 0 | desc = "extractable private key"; |
343 | 0 | _template = "extractable-key"; |
344 | 0 | break; |
345 | 0 | case SC_PKCS15_TYPE_CERT: |
346 | 0 | desc = "certificate"; |
347 | 0 | _template = "certificate"; |
348 | 0 | break; |
349 | 0 | case SC_PKCS15_TYPE_DATA_OBJECT: |
350 | 0 | desc = "data object"; |
351 | 0 | _template = "data"; |
352 | 0 | break; |
353 | 0 | } |
354 | 0 | if (_template) |
355 | 0 | break; |
356 | | /* If this is a specific type such as |
357 | | * SC_PKCS15_TYPE_CERT_FOOBAR, fall back to |
358 | | * the generic class (SC_PKCS15_TYPE_CERT) |
359 | | */ |
360 | 0 | if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) { |
361 | 0 | sc_log(card->ctx, |
362 | 0 | "File type %X not supported by card driver", |
363 | 0 | type); |
364 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
365 | 0 | } |
366 | 0 | type &= SC_PKCS15_TYPE_CLASS_MASK; |
367 | 0 | } |
368 | | |
369 | 0 | sc_log(card->ctx, "template %s; num %i\n", |
370 | 0 | _template, num); |
371 | 0 | if (sc_profile_get_file(profile, _template, &file) < 0) { |
372 | 0 | sc_log(card->ctx, |
373 | 0 | "Profile doesn't define %s template '%s'\n", desc, |
374 | 0 | _template); |
375 | 0 | return SC_ERROR_NOT_SUPPORTED; |
376 | 0 | } |
377 | | |
378 | 0 | if (file->path.len < 1) { |
379 | 0 | sc_file_free(file); |
380 | 0 | return SC_ERROR_INTERNAL; |
381 | 0 | } |
382 | | |
383 | 0 | file->id &= 0xFF00; |
384 | 0 | file->id |= (num & 0x00FF); |
385 | |
|
386 | 0 | file->path.value[file->path.len - 1] = (num & 0xFF); |
387 | 0 | file->type = SC_FILE_TYPE_INTERNAL_EF; |
388 | 0 | file->ef_structure = structure; |
389 | |
|
390 | 0 | sc_log(card->ctx, |
391 | 0 | "file size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X, path_len %"SC_FORMAT_LEN_SIZE_T"u\n", |
392 | 0 | file->size, file->type, file->ef_structure, file->id, |
393 | 0 | file->path.len); |
394 | 0 | sc_log(card->ctx, "file path: %s", |
395 | 0 | sc_print_path(&(file->path))); |
396 | 0 | *out = file; |
397 | |
|
398 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
399 | 0 | } |
400 | | |
401 | | static int epass2003_pkcs15_create_key(struct sc_profile *profile, |
402 | | struct sc_pkcs15_card *p15card, |
403 | | struct sc_pkcs15_object *obj) |
404 | 0 | { |
405 | 0 | struct sc_card *card = p15card->card; |
406 | |
|
407 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
408 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); |
409 | 0 | } |
410 | | |
411 | | static int epass2003_pkcs15_store_key(struct sc_profile *profile, |
412 | | struct sc_pkcs15_card *p15card, |
413 | | struct sc_pkcs15_object *obj, |
414 | | struct sc_pkcs15_prkey *key) |
415 | 0 | { |
416 | 0 | struct sc_card *card = p15card->card; |
417 | 0 | struct sc_pkcs15_prkey_info *key_info = |
418 | 0 | (struct sc_pkcs15_prkey_info *)obj->data; |
419 | 0 | size_t idx = key_info->key_reference; |
420 | 0 | size_t keybits = key_info->modulus_length; |
421 | 0 | struct sc_path path; |
422 | 0 | struct sc_file *tfile = NULL; |
423 | 0 | struct sc_file *file = NULL; |
424 | 0 | sc_epass2003_wkey_data data; |
425 | 0 | int r; |
426 | 0 | int fidl = 0; |
427 | |
|
428 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
429 | |
|
430 | 0 | sc_log(card->ctx, |
431 | 0 | "index %"SC_FORMAT_LEN_SIZE_T"u; id %s\n", idx, |
432 | 0 | sc_pkcs15_print_id(&key_info->id)); |
433 | 0 | if (key->algorithm != SC_ALGORITHM_RSA |
434 | 0 | || key->algorithm != SC_ALGORITHM_RSA) |
435 | 0 | LOG_TEST_RET(card->ctx, |
436 | 0 | SC_ERROR_NOT_SUPPORTED, |
437 | 0 | "store key: only support RSA"); |
438 | | |
439 | 0 | sc_log(card->ctx, |
440 | 0 | "store key: with ID:%s and path:%s", |
441 | 0 | sc_pkcs15_print_id(&key_info->id), |
442 | 0 | sc_print_path(&key_info->path)); |
443 | | |
444 | | /* allocate key object */ |
445 | 0 | r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, |
446 | 0 | key_info->key_reference, &file); |
447 | 0 | LOG_TEST_RET(card->ctx, r, |
448 | 0 | "create key: failed to allocate new key object"); |
449 | 0 | file->size = keybits; |
450 | 0 | sc_log(card->ctx, "private key path: %s", |
451 | 0 | sc_print_path(&(file->path))); |
452 | 0 | sc_log(card->ctx, "private key_info path: %s", |
453 | 0 | sc_print_path(&(key_info->path))); |
454 | 0 | sc_delete_file(p15card->card, &file->path); |
455 | | /* create */ |
456 | 0 | r = sc_pkcs15init_create_file(profile, p15card, file); |
457 | 0 | LOG_TEST_RET(card->ctx, r, |
458 | 0 | "create key: failed to create key file"); |
459 | | |
460 | 0 | sc_log(card->ctx, |
461 | 0 | "index %"SC_FORMAT_LEN_SIZE_T"u; keybits %"SC_FORMAT_LEN_SIZE_T"u\n", |
462 | 0 | idx, keybits); |
463 | 0 | if (keybits < 1024 || keybits > 2048 || (keybits % 0x20)) { |
464 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, |
465 | 0 | "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", |
466 | 0 | keybits); |
467 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
468 | 0 | } |
469 | | |
470 | 0 | path = key_info->path; |
471 | 0 | path.len -= 2; |
472 | |
|
473 | 0 | r = sc_select_file(card, &path, &tfile); |
474 | 0 | LOG_TEST_RET(card->ctx, r, |
475 | 0 | "generate key: no private object DF"); |
476 | | |
477 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
478 | 0 | LOG_TEST_RET(card->ctx, r, |
479 | 0 | "No authorisation to store private key"); |
480 | | |
481 | 0 | sc_file_free(tfile); |
482 | |
|
483 | 0 | fidl = (file->id & 0xff) * FID_STEP; |
484 | 0 | file->id = (file->id & 0xff00) + fidl; |
485 | 0 | data.type = SC_EPASS2003_KEY_RSA; |
486 | 0 | data.key_data.es_key.fid = file->id; |
487 | 0 | data.key_data.es_key.rsa = (void *)&key->u.rsa; |
488 | |
|
489 | 0 | r = sc_card_ctl(p15card->card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); |
490 | 0 | LOG_TEST_RET(card->ctx, r, |
491 | 0 | "store key: cannot update private key"); |
492 | | |
493 | 0 | sc_file_free(file); |
494 | |
|
495 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
496 | 0 | } |
497 | | |
498 | | static int epass2003_pkcs15_generate_key(struct sc_profile *profile, |
499 | | struct sc_pkcs15_card *p15card, |
500 | | struct sc_pkcs15_object *obj, |
501 | | struct sc_pkcs15_pubkey *pubkey) |
502 | 0 | { |
503 | 0 | struct sc_card *card = p15card->card; |
504 | 0 | int r; |
505 | 0 | sc_epass2003_gen_key_data gendat; |
506 | 0 | struct sc_pkcs15_prkey_info *key_info = |
507 | 0 | (struct sc_pkcs15_prkey_info *)obj->data; |
508 | 0 | int idx = key_info->key_reference; |
509 | 0 | size_t keybits = key_info->modulus_length; |
510 | 0 | struct sc_file *tfile = NULL, *pukf = NULL; |
511 | 0 | struct sc_path path; |
512 | 0 | struct sc_file *file = NULL; |
513 | 0 | int fidl = 0; |
514 | |
|
515 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
516 | |
|
517 | 0 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA && obj->type != SC_PKCS15_TYPE_PRKEY_EC) |
518 | 0 | return SC_ERROR_NOT_SUPPORTED; |
519 | | |
520 | 0 | if(obj->type == SC_PKCS15_TYPE_PRKEY_EC && keybits == 0) |
521 | 0 | keybits = 256; //EC key length is 256 ... |
522 | | |
523 | | /* allocate key object */ |
524 | 0 | r = cosm_new_file(profile, card, obj->type, idx, &file); //replace SC_PKCS15_TYPE_PRKEY_RSA with obj->type |
525 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
526 | 0 | "create key: failed to allocate new key object"); |
527 | 0 | file->size = keybits; |
528 | 0 | sc_log(card->ctx, "private key path: %s", |
529 | 0 | sc_print_path(&file->path)); |
530 | 0 | sc_log(card->ctx, "private key_info path: %s", |
531 | 0 | sc_print_path(&(key_info->path))); |
532 | |
|
533 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, file, |
534 | 0 | SC_AC_OP_DELETE); |
535 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
536 | 0 | "generate key: pkcs15init_authenticate(SC_AC_OP_DELETE) failed"); |
537 | | |
538 | 0 | sc_delete_file(p15card->card, &file->path); |
539 | | /* create */ |
540 | 0 | r = sc_pkcs15init_create_file(profile, p15card, file); |
541 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
542 | 0 | "create key: failed to create key file"); |
543 | | |
544 | 0 | sc_log(card->ctx, |
545 | 0 | "index %u; keybits %"SC_FORMAT_LEN_SIZE_T"u\n", |
546 | 0 | idx, keybits); |
547 | 0 | if (keybits < 1024 || keybits > 2048 || (keybits % 0x20)) { |
548 | 0 | if(obj->type == SC_PKCS15_TYPE_PRKEY_EC && keybits == 256) |
549 | 0 | { |
550 | 0 | sc_log(card->ctx, "current Alg is EC,Only support 256 ..\n"); |
551 | 0 | } |
552 | 0 | else |
553 | 0 | { |
554 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, |
555 | 0 | "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", |
556 | 0 | keybits); |
557 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
558 | 0 | goto err; |
559 | 0 | } |
560 | 0 | } |
561 | | |
562 | 0 | path = key_info->path; |
563 | 0 | path.len -= 2; |
564 | |
|
565 | 0 | r = sc_select_file(card, &path, &tfile); |
566 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
567 | 0 | "generate key: no private object DF"); |
568 | | |
569 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, tfile, |
570 | 0 | SC_AC_OP_CRYPTO); |
571 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
572 | 0 | "generate key: pkcs15init_authenticate(SC_AC_OP_CRYPTO) failed"); |
573 | | |
574 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, tfile, |
575 | 0 | SC_AC_OP_CREATE); |
576 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
577 | 0 | "generate key: pkcs15init_authenticate(SC_AC_OP_CREATE) failed"); |
578 | | |
579 | 0 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA ) |
580 | 0 | { |
581 | 0 | r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_EC, idx, &pukf); |
582 | 0 | } |
583 | 0 | else |
584 | 0 | { |
585 | 0 | r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_RSA, idx, &pukf); |
586 | 0 | } |
587 | |
|
588 | 0 | if (r < 0) { |
589 | 0 | sc_log(card->ctx, |
590 | 0 | "generate key: create temporary pukf failed\n"); |
591 | 0 | goto err; |
592 | 0 | } |
593 | | |
594 | 0 | pukf->size = keybits; |
595 | 0 | pukf->id = pukf->path.value[pukf->path.len - 2] * 0x100 |
596 | 0 | + pukf->path.value[pukf->path.len - 1]; |
597 | |
|
598 | 0 | sc_log(card->ctx, |
599 | 0 | "public key size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X; path: %s", |
600 | 0 | pukf->size, pukf->type, pukf->ef_structure, pukf->id, |
601 | 0 | sc_print_path(&pukf->path)); |
602 | |
|
603 | 0 | r = sc_select_file(p15card->card, &pukf->path, NULL); |
604 | | /* if exist, delete */ |
605 | 0 | if (r == SC_SUCCESS) { |
606 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, pukf, |
607 | 0 | SC_AC_OP_DELETE); |
608 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
609 | 0 | "generate key - pubkey: pkcs15init_authenticate(SC_AC_OP_DELETE) failed"); |
610 | | |
611 | 0 | r = sc_pkcs15init_delete_by_path(profile, p15card, &pukf->path); |
612 | 0 | if (r != SC_SUCCESS) { |
613 | 0 | sc_log(card->ctx, |
614 | 0 | "generate key: failed to delete existing key file\n"); |
615 | 0 | goto err; |
616 | 0 | } |
617 | 0 | } |
618 | | /* create */ |
619 | 0 | r = sc_pkcs15init_create_file(profile, p15card, pukf); |
620 | 0 | if (r != SC_SUCCESS) { |
621 | 0 | sc_log(card->ctx, |
622 | 0 | "generate key: pukf create file failed\n"); |
623 | 0 | goto err; |
624 | 0 | } |
625 | | |
626 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, pukf, |
627 | 0 | SC_AC_OP_UPDATE); |
628 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
629 | 0 | "generate key - pubkey: pkcs15init_authenticate(SC_AC_OP_UPDATE) failed"); |
630 | | |
631 | | /* generate key pair */ |
632 | 0 | fidl = (file->id & 0xff) * FID_STEP; |
633 | 0 | file->id = (file->id & 0xff00) + fidl; |
634 | 0 | pukf->id = (pukf->id & 0xff00) + fidl; |
635 | 0 | gendat.prkey_id = file->id; |
636 | 0 | gendat.pukey_id = pukf->id; |
637 | 0 | gendat.key_length = keybits; |
638 | 0 | gendat.modulus = NULL; |
639 | 0 | gendat.modulus_len = 0; |
640 | 0 | r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_GENERATE_KEY, &gendat); |
641 | 0 | SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_VERBOSE, r, |
642 | 0 | "generate RSA key pair failed"); |
643 | | |
644 | 0 | if (!gendat.modulus) { |
645 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
646 | 0 | goto err; |
647 | 0 | } |
648 | | |
649 | | /* get the modulus */ |
650 | 0 | if (pubkey && (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)) { |
651 | 0 | u8 *buf; |
652 | 0 | struct sc_pkcs15_pubkey_rsa *rsa = &pubkey->u.rsa; |
653 | | /* set the modulus */ |
654 | 0 | rsa->modulus.data = gendat.modulus; |
655 | 0 | rsa->modulus.len = keybits >> 3; |
656 | | /* set the exponent (always 0x10001) */ |
657 | 0 | buf = (u8 *) malloc(3); |
658 | 0 | if (!buf) { |
659 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
660 | 0 | goto err; |
661 | 0 | } |
662 | 0 | buf[0] = 0x01; |
663 | 0 | buf[1] = 0x00; |
664 | 0 | buf[2] = 0x01; |
665 | 0 | rsa->exponent.data = buf; |
666 | 0 | rsa->exponent.len = 3; |
667 | |
|
668 | 0 | pubkey->algorithm = SC_ALGORITHM_RSA; |
669 | 0 | } |
670 | 0 | else if(pubkey && (obj->type == SC_PKCS15_TYPE_PRKEY_EC)){ |
671 | 0 | struct sc_ec_parameters *ecparams = (struct |
672 | 0 | sc_ec_parameters *)key_info->params.data; |
673 | 0 | pubkey->algorithm = SC_ALGORITHM_EC; |
674 | 0 | pubkey->u.ec.ecpointQ.value = (u8 *)malloc(gendat.modulus_len + 1); |
675 | 0 | if (!pubkey->u.ec.ecpointQ.value) { |
676 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
677 | 0 | goto err; |
678 | 0 | } |
679 | | |
680 | 0 | pubkey->u.ec.ecpointQ.value[0] = 0x04; |
681 | 0 | memcpy(&pubkey->u.ec.ecpointQ.value[1], gendat.modulus, gendat.modulus_len); |
682 | 0 | pubkey->u.ec.ecpointQ.len = gendat.modulus_len + 1; |
683 | 0 | free(gendat.modulus); |
684 | |
|
685 | 0 | free(pubkey->u.ec.params.named_curve); |
686 | 0 | pubkey->u.ec.params.named_curve = NULL; |
687 | |
|
688 | 0 | free(pubkey->u.ec.params.der.value); |
689 | 0 | pubkey->u.ec.params.der.value = NULL; |
690 | 0 | pubkey->u.ec.params.der.len = 0; |
691 | 0 | pubkey->u.ec.params.named_curve = strdup(ecparams->named_curve); |
692 | |
|
693 | 0 | if (!pubkey->u.ec.params.named_curve){ |
694 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
695 | 0 | goto err; |
696 | 0 | } |
697 | | |
698 | 0 | r = sc_pkcs15_fix_ec_parameters(card->ctx, &pubkey->u.ec.params); |
699 | 0 | } |
700 | 0 | else |
701 | | /* free public key */ |
702 | 0 | free(gendat.modulus); |
703 | | |
704 | 0 | err: |
705 | 0 | sc_file_free(pukf); |
706 | 0 | sc_file_free(file); |
707 | 0 | sc_file_free(tfile); |
708 | |
|
709 | 0 | if(r < 0 && pubkey->u.ec.ecpointQ.value) |
710 | 0 | { |
711 | 0 | free(pubkey->u.ec.ecpointQ.value); |
712 | 0 | pubkey->u.ec.ecpointQ.value = NULL; |
713 | 0 | pubkey->u.ec.ecpointQ.len = 0; |
714 | 0 | } |
715 | |
|
716 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
717 | 0 | } |
718 | | |
719 | | static int epass2003_pkcs15_delete_object(struct sc_profile *profile, |
720 | | struct sc_pkcs15_card *p15card, |
721 | | struct sc_pkcs15_object *object, |
722 | | const struct sc_path *path) |
723 | 0 | { |
724 | 0 | SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); |
725 | 0 | return sc_pkcs15init_delete_by_path(profile, p15card, path); |
726 | 0 | } |
727 | | |
728 | | static int epass2003_pkcs15_sanity_check(sc_profile_t * profile, |
729 | | sc_pkcs15_card_t * p15card) |
730 | 0 | { |
731 | 0 | struct sc_context *ctx = p15card->card->ctx; |
732 | 0 | struct sc_pkcs15_auth_info profile_auth = {0}; |
733 | 0 | struct sc_pkcs15_object *objs[32]; |
734 | 0 | int rv, nn, ii, update_df = 0; |
735 | |
|
736 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
737 | |
|
738 | 0 | sc_log(ctx, |
739 | 0 | "Check and if needed update PinFlags"); |
740 | 0 | rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 32); |
741 | 0 | LOG_TEST_RET(ctx, rv, "Failed to get PINs"); |
742 | 0 | nn = rv; |
743 | |
|
744 | 0 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &profile_auth); |
745 | 0 | LOG_TEST_RET(ctx, rv, "Failed to get PIN info"); |
746 | | |
747 | 0 | for (ii = 0; ii < nn; ii++) { |
748 | 0 | struct sc_pkcs15_auth_info *ainfo = |
749 | 0 | (struct sc_pkcs15_auth_info *)objs[ii]->data; |
750 | 0 | struct sc_pkcs15_pin_attributes *pin_attrs = &ainfo->attrs.pin; |
751 | |
|
752 | 0 | if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
753 | 0 | continue; |
754 | | |
755 | 0 | if (pin_attrs->reference == profile_auth.attrs.pin.reference |
756 | 0 | && pin_attrs->flags != profile_auth.attrs.pin.flags) { |
757 | 0 | sc_log(ctx, |
758 | 0 | "Set flags of '%s'(flags:%X,ref:%i,id:%s) to %X", |
759 | 0 | objs[ii]->label, pin_attrs->flags, |
760 | 0 | pin_attrs->reference, |
761 | 0 | sc_pkcs15_print_id(&ainfo->auth_id), |
762 | 0 | profile_auth.attrs.pin.flags); |
763 | 0 | pin_attrs->flags = profile_auth.attrs.pin.flags; |
764 | 0 | update_df = 1; |
765 | 0 | } |
766 | 0 | } |
767 | 0 | if (update_df) { |
768 | 0 | struct sc_pkcs15_df *df = p15card->df_list; |
769 | |
|
770 | 0 | while (df != NULL && df->type != SC_PKCS15_AODF) |
771 | 0 | df = df->next; |
772 | 0 | if (!df) |
773 | 0 | LOG_TEST_RET(ctx, |
774 | 0 | SC_ERROR_OBJECT_NOT_FOUND, |
775 | 0 | "Cannot find AODF"); |
776 | 0 | rv = sc_pkcs15init_update_any_df(p15card, profile, df, 0); |
777 | 0 | LOG_TEST_RET(ctx, rv, "Update AODF error"); |
778 | 0 | } |
779 | | |
780 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, rv); |
781 | 0 | } |
782 | | |
783 | | static struct sc_pkcs15init_operations sc_pkcs15init_epass2003_operations = { |
784 | | epass2003_pkcs15_erase_card, |
785 | | epass2003_pkcs15_init_card, |
786 | | epass2003_pkcs15_create_dir, |
787 | | NULL, /* create_domain */ |
788 | | epass2003_pkcs15_pin_reference, |
789 | | epass2003_pkcs15_create_pin, |
790 | | epass2003_pkcs15_key_reference, |
791 | | epass2003_pkcs15_create_key, |
792 | | epass2003_pkcs15_store_key, |
793 | | epass2003_pkcs15_generate_key, |
794 | | NULL, NULL, /* encode private/public key */ |
795 | | NULL, /* finalize */ |
796 | | epass2003_pkcs15_delete_object, |
797 | | NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ |
798 | | epass2003_pkcs15_sanity_check, |
799 | | }; |
800 | | |
801 | | struct sc_pkcs15init_operations *sc_pkcs15init_get_epass2003_ops(void) |
802 | 5 | { |
803 | 5 | return &sc_pkcs15init_epass2003_operations; |
804 | 5 | } |