/src/opensc/src/pkcs15init/pkcs15-cardos.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * CardOS specific operation for PKCS15 initialization |
3 | | * |
4 | | * Copyright (C) 2005 Nils Larsch <nils@larsch.net> |
5 | | * Copyright (C) 2002 Olaf Kirch <okir@suse.de> |
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 <assert.h> |
28 | | #include <stdarg.h> |
29 | | |
30 | | #include "libopensc/opensc.h" |
31 | | #include "libopensc/cardctl.h" |
32 | | #include "libopensc/log.h" |
33 | | #include "libopensc/cards.h" |
34 | | #include "libopensc/asn1.h" |
35 | | #include "pkcs15-init.h" |
36 | | #include "profile.h" |
37 | | |
38 | | #ifndef MIN |
39 | 0 | # define MIN(a, b) (((a) < (b))? (a) : (b)) |
40 | | #endif |
41 | | |
42 | | struct tlv { |
43 | | unsigned char * base; |
44 | | unsigned char * end; |
45 | | unsigned char * current; |
46 | | unsigned char * next; |
47 | | }; |
48 | | |
49 | | /* |
50 | | * Local functions |
51 | | */ |
52 | | static int cardos_store_pin(sc_profile_t *profile, sc_card_t *card, |
53 | | sc_pkcs15_auth_info_t *auth_info, int puk_id, |
54 | | const u8 *pin, size_t pin_len); |
55 | | static int cardos_create_sec_env(sc_profile_t *, sc_card_t *, |
56 | | unsigned int, unsigned int); |
57 | | static int cardos_put_key(struct sc_profile *, sc_pkcs15_card_t *, |
58 | | int, sc_pkcs15_prkey_info_t *, |
59 | | struct sc_pkcs15_prkey_rsa *); |
60 | | static int cardos_key_algorithm(unsigned int, size_t, int *); |
61 | | static int cardos_extract_pubkey(sc_card_t *, sc_pkcs15_pubkey_t *, |
62 | | sc_file_t *, int); |
63 | | static int do_cardos_extract_pubkey(sc_card_t *card, int nr, u8 tag, |
64 | | sc_pkcs15_bignum_t *bn); |
65 | | static int cardos_have_verifyrc_package(sc_card_t *card); |
66 | | |
67 | | /* Object IDs for PIN objects. |
68 | | * SO PIN = 0x01, SO PUK = 0x02 |
69 | | * each user pin is 2*N+1, each corresponding PUK is 2*N+2 |
70 | | */ |
71 | 0 | #define CARDOS_PIN_ID_MIN 1 |
72 | 0 | #define CARDOS_PIN_ID_MAX 15 |
73 | 0 | #define CARDOS_KEY_ID_MIN 16 |
74 | 0 | #define CARDOS_KEY_ID_MAX 31 |
75 | 0 | #define CARDOS_AC_NEVER 0xFF |
76 | | |
77 | | #define CARDOS_ALGO_RSA 0x08 |
78 | 0 | #define CARDOS_ALGO_RSA_PURE 0x0C |
79 | | #define CARDOS_ALGO_RSA_SIG 0x88 |
80 | 0 | #define CARDOS_ALGO_RSA_PURE_SIG 0x8C |
81 | | #define CARDOS_ALGO_RSA_SIG_SHA1 0xC8 |
82 | | #define CARDOS_ALGO_RSA_PURE_SIG_SHA1 0xCC |
83 | 0 | #define CARDOS_ALGO_EXT_RSA_PURE 0x0a |
84 | 0 | #define CARDOS_ALGO_EXT_RSA_SIG_PURE 0x8a |
85 | 0 | #define CARDOS_ALGO_PIN 0x87 |
86 | | |
87 | | static void tlv_init(struct tlv *tlv, u8 *base, size_t size) |
88 | 0 | { |
89 | 0 | tlv->base = base; |
90 | 0 | tlv->end = base + size; |
91 | 0 | tlv->current = tlv->next = base; |
92 | 0 | } |
93 | | |
94 | | static int tlv_next(struct tlv *tlv, u8 tag) |
95 | 0 | { |
96 | 0 | if (tlv->next + 2 >= tlv->end) |
97 | 0 | return SC_ERROR_INTERNAL; |
98 | 0 | tlv->current = tlv->next; |
99 | 0 | *(tlv->next++) = tag; |
100 | 0 | *(tlv->next++) = 0; |
101 | 0 | return SC_SUCCESS; |
102 | 0 | } |
103 | | |
104 | | static int tlv_add(struct tlv *tlv, u8 val) |
105 | 0 | { |
106 | 0 | if (tlv->next + 1 >= tlv->end) |
107 | 0 | return SC_ERROR_INTERNAL; |
108 | 0 | *(tlv->next++) = val; |
109 | 0 | tlv->current[1]++; |
110 | 0 | return SC_SUCCESS; |
111 | 0 | } |
112 | | |
113 | | static size_t |
114 | | tlv_len(struct tlv *tlv) |
115 | 0 | { |
116 | 0 | return tlv->next - tlv->base; |
117 | 0 | } |
118 | | |
119 | | /* |
120 | | * Try to delete pkcs15 structure |
121 | | * This is not quite the same as erasing the whole token, but |
122 | | * it's close enough to be useful. |
123 | | */ |
124 | | static int |
125 | | cardos_erase(struct sc_profile *profile, sc_pkcs15_card_t *p15card) |
126 | 0 | { |
127 | 0 | return sc_pkcs15init_erase_card_recursively(p15card, profile); |
128 | 0 | } |
129 | | |
130 | | /* |
131 | | * Create the Application DF |
132 | | */ |
133 | | static int |
134 | | cardos_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) |
135 | 0 | { |
136 | 0 | int r; |
137 | | |
138 | | /* Create the application DF */ |
139 | 0 | if ((r = sc_pkcs15init_create_file(profile, p15card, df)) < 0) |
140 | 0 | return r; |
141 | | |
142 | 0 | if ((r = sc_select_file(p15card->card, &df->path, NULL)) < 0) |
143 | 0 | return r; |
144 | | |
145 | | /* Create a default security environment for this DF. |
146 | | * This SE automatically becomes the current SE when the |
147 | | * DF is selected. */ |
148 | 0 | if ((r = cardos_create_sec_env(profile, p15card->card, 0x01, 0x00)) < 0) |
149 | 0 | return r; |
150 | | |
151 | 0 | return 0; |
152 | 0 | } |
153 | | |
154 | | /* |
155 | | * Caller passes in a suggested PIN reference. |
156 | | * See if it's good, and if it isn't, propose something better |
157 | | */ |
158 | | static int |
159 | | cardos_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
160 | | sc_pkcs15_auth_info_t *auth_info) |
161 | 0 | { |
162 | 0 | int preferred, current; |
163 | |
|
164 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
165 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
166 | | |
167 | 0 | if ((current = auth_info->attrs.pin.reference) < 0) |
168 | 0 | current = CARDOS_PIN_ID_MIN; |
169 | |
|
170 | 0 | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
171 | 0 | preferred = 1; |
172 | 0 | if (current > preferred) |
173 | 0 | return SC_ERROR_TOO_MANY_OBJECTS; |
174 | 0 | } else { |
175 | 0 | preferred = current; |
176 | | /* PINs are even numbered, PUKs are odd */ |
177 | 0 | if (!(preferred & 1)) |
178 | 0 | preferred++; |
179 | 0 | } |
180 | | |
181 | 0 | if (preferred > CARDOS_PIN_ID_MAX) |
182 | 0 | return SC_ERROR_TOO_MANY_OBJECTS; |
183 | 0 | auth_info->attrs.pin.reference = preferred; |
184 | |
|
185 | 0 | return SC_SUCCESS; |
186 | 0 | } |
187 | | |
188 | | /* |
189 | | * Store a PIN |
190 | | */ |
191 | | static int |
192 | | cardos_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df, |
193 | | sc_pkcs15_object_t *pin_obj, |
194 | | const u8 *pin, size_t pin_len, |
195 | | const u8 *puk, size_t puk_len) |
196 | 0 | { |
197 | 0 | sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; |
198 | 0 | struct sc_card *card = p15card->card; |
199 | 0 | unsigned int puk_id = CARDOS_AC_NEVER; |
200 | 0 | int r; |
201 | |
|
202 | 0 | if (!pin || !pin_len) |
203 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
204 | | |
205 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
206 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
207 | | |
208 | 0 | r = sc_select_file(card, auth_info->attrs.pin.reference & 0x80 ? &df->path : sc_get_mf_path(), NULL); |
209 | 0 | if (r < 0) |
210 | 0 | return r; |
211 | | |
212 | 0 | if (puk && puk_len) { |
213 | 0 | struct sc_pkcs15_auth_info puk_ainfo = {0}; |
214 | |
|
215 | 0 | sc_profile_get_pin_info(profile, |
216 | 0 | SC_PKCS15INIT_USER_PUK, &puk_ainfo); |
217 | 0 | puk_ainfo.attrs.pin.reference = puk_id = auth_info->attrs.pin.reference + 1; |
218 | 0 | r = cardos_store_pin(profile, card, |
219 | 0 | &puk_ainfo, CARDOS_AC_NEVER, |
220 | 0 | puk, puk_len); |
221 | 0 | } |
222 | |
|
223 | 0 | if (r >= 0) { |
224 | 0 | r = cardos_store_pin(profile, card, |
225 | 0 | auth_info, puk_id, pin, pin_len); |
226 | 0 | } |
227 | |
|
228 | 0 | return r; |
229 | 0 | } |
230 | | |
231 | | /* |
232 | | * Select a key reference |
233 | | */ |
234 | | static int |
235 | | cardos_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
236 | | sc_pkcs15_prkey_info_t *key_info) |
237 | 0 | { |
238 | 0 | if (key_info->key_reference < CARDOS_KEY_ID_MIN) |
239 | 0 | key_info->key_reference = CARDOS_KEY_ID_MIN; |
240 | 0 | if (key_info->key_reference > CARDOS_KEY_ID_MAX) |
241 | 0 | return SC_ERROR_TOO_MANY_OBJECTS; |
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | /* |
246 | | * Create a private key object. |
247 | | * This is a no-op. |
248 | | */ |
249 | | static int |
250 | | cardos_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
251 | | sc_pkcs15_object_t *obj) |
252 | 0 | { |
253 | 0 | return 0; |
254 | 0 | } |
255 | | |
256 | | /* |
257 | | * Store a private key object. |
258 | | */ |
259 | | static int |
260 | | cardos_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
261 | | sc_pkcs15_object_t *obj, |
262 | | sc_pkcs15_prkey_t *key) |
263 | 0 | { |
264 | 0 | struct sc_context *ctx = p15card->card->ctx; |
265 | 0 | sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; |
266 | 0 | struct sc_file *file = NULL; |
267 | 0 | int algorithm = 0, r; |
268 | |
|
269 | 0 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { |
270 | 0 | sc_log(ctx, "CardOS supports RSA keys only."); |
271 | 0 | return SC_ERROR_NOT_SUPPORTED; |
272 | 0 | } |
273 | | |
274 | 0 | if (cardos_key_algorithm(key_info->usage, key_info->modulus_length, &algorithm) < 0) { |
275 | 0 | sc_log(ctx, "CardOS does not support keys " |
276 | 0 | "that can both sign _and_ decrypt."); |
277 | 0 | return SC_ERROR_NOT_SUPPORTED; |
278 | 0 | } |
279 | | |
280 | 0 | r = sc_select_file(p15card->card, &key_info->path, &file); |
281 | 0 | if (r) { |
282 | 0 | sc_log(ctx, "Failed to store key: cannot select parent DF"); |
283 | 0 | return r; |
284 | 0 | } |
285 | | |
286 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
287 | 0 | sc_file_free(file); |
288 | 0 | if (r) { |
289 | 0 | sc_log(ctx, "Failed to store key: 'UPDATE' authentication failed"); |
290 | 0 | return r; |
291 | 0 | } |
292 | | |
293 | 0 | r = cardos_put_key(profile, p15card, algorithm, key_info, &key->u.rsa); |
294 | |
|
295 | 0 | return r; |
296 | 0 | } |
297 | | |
298 | | static void init_key_object(struct sc_pkcs15_prkey_rsa *key, |
299 | | u8 *data, size_t len) |
300 | 0 | { |
301 | | /* Create a key object, initializing components to 0xff */ |
302 | 0 | memset(key, 0x00, sizeof(*key)); |
303 | 0 | memset(data, 0xff, len); |
304 | 0 | key->modulus.data = data; |
305 | 0 | key->modulus.len = len; |
306 | 0 | key->d.data = data; |
307 | 0 | key->d.len = len; |
308 | 0 | key->p.len = len >> 1; |
309 | 0 | key->p.data = data; |
310 | 0 | key->q.len = len >> 1; |
311 | 0 | key->q.data = data; |
312 | 0 | key->iqmp.len = len >> 1; |
313 | 0 | key->iqmp.data = data; |
314 | 0 | key->dmp1.len = len >> 1; |
315 | 0 | key->dmp1.data = data; |
316 | 0 | key->dmq1.len = len >> 1; |
317 | 0 | key->dmq1.data = data; |
318 | 0 | } |
319 | | |
320 | | /* |
321 | | * Key generation |
322 | | */ |
323 | | static int |
324 | | cardos_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
325 | | sc_pkcs15_object_t *obj, |
326 | | sc_pkcs15_pubkey_t *pubkey) |
327 | 0 | { |
328 | 0 | struct sc_context *ctx = p15card->card->ctx; |
329 | 0 | struct sc_pkcs15_prkey_info *key_info = (sc_pkcs15_prkey_info_t *) obj->data; |
330 | 0 | struct sc_pkcs15_prkey_rsa key_obj; |
331 | 0 | struct sc_cardctl_cardos_genkey_info args; |
332 | 0 | struct sc_file *temp; |
333 | 0 | u8 abignum[256]; |
334 | 0 | int algorithm = 0, r, delete_it = 0, use_ext_rsa = 0; |
335 | 0 | size_t keybits, rsa_max_size; |
336 | 0 | int pin_id = -1; |
337 | |
|
338 | 0 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) |
339 | 0 | return SC_ERROR_NOT_SUPPORTED; |
340 | | |
341 | 0 | rsa_max_size = (sc_card_find_rsa_alg(p15card->card, 2048) != NULL) ? 2048 : 1024; |
342 | 0 | keybits = key_info->modulus_length & ~7UL; |
343 | 0 | if (keybits > rsa_max_size) { |
344 | 0 | sc_log(ctx, "Unable to generate key, max size is %lu", |
345 | 0 | (unsigned long) rsa_max_size); |
346 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
347 | 0 | } |
348 | | |
349 | 0 | if (keybits > 1024) |
350 | 0 | use_ext_rsa = 1; |
351 | |
|
352 | 0 | if (cardos_key_algorithm(key_info->usage, keybits, &algorithm) < 0) { |
353 | 0 | sc_log(ctx, "CardOS does not support keys " |
354 | 0 | "that can both sign _and_ decrypt."); |
355 | 0 | return SC_ERROR_NOT_SUPPORTED; |
356 | 0 | } |
357 | | |
358 | 0 | if (sc_profile_get_file(profile, "tempfile", &temp) < 0) { |
359 | 0 | sc_log(ctx, "Profile doesn't define temporary file " |
360 | 0 | "for key generation."); |
361 | 0 | return SC_ERROR_NOT_SUPPORTED; |
362 | 0 | } |
363 | | |
364 | 0 | pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, |
365 | 0 | SC_AC_SYMBOLIC, SC_PKCS15INIT_USER_PIN); |
366 | 0 | if (pin_id >= 0) { |
367 | 0 | r = sc_pkcs15init_verify_secret(profile, p15card, NULL, SC_AC_CHV, pin_id); |
368 | 0 | if (r < 0) |
369 | 0 | return r; |
370 | 0 | } |
371 | 0 | if (use_ext_rsa == 0) |
372 | 0 | temp->ef_structure = SC_FILE_EF_LINEAR_VARIABLE_TLV; |
373 | 0 | else |
374 | 0 | temp->ef_structure = SC_FILE_EF_TRANSPARENT; |
375 | |
|
376 | 0 | if ((r = sc_pkcs15init_create_file(profile, p15card, temp)) < 0) |
377 | 0 | goto out; |
378 | 0 | delete_it = 1; |
379 | |
|
380 | 0 | init_key_object(&key_obj, abignum, keybits >> 3); |
381 | |
|
382 | 0 | r = cardos_put_key(profile, p15card, algorithm, key_info, &key_obj); |
383 | 0 | if (r < 0) |
384 | 0 | goto out; |
385 | | |
386 | 0 | memset(&args, 0, sizeof(args)); |
387 | 0 | args.key_id = key_info->key_reference; |
388 | 0 | args.key_bits = keybits; |
389 | 0 | args.fid = temp->id; |
390 | 0 | r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_GENERATE_KEY, &args); |
391 | 0 | if (r < 0) |
392 | 0 | goto out; |
393 | | |
394 | 0 | r = cardos_extract_pubkey(p15card->card, pubkey, temp, use_ext_rsa); |
395 | 0 | out: |
396 | 0 | if (delete_it != 0) |
397 | 0 | sc_pkcs15init_rmdir(p15card, profile, temp); |
398 | 0 | sc_file_free(temp); |
399 | |
|
400 | 0 | if (r < 0) { |
401 | 0 | if (pubkey->u.rsa.modulus.data) |
402 | 0 | free (pubkey->u.rsa.modulus.data); |
403 | 0 | if (pubkey->u.rsa.exponent.data) |
404 | 0 | free (pubkey->u.rsa.exponent.data); |
405 | 0 | } |
406 | 0 | return r; |
407 | 0 | } |
408 | | |
409 | | /* |
410 | | * Object deletion. |
411 | | */ |
412 | | static int |
413 | | cardos_delete_object(sc_profile_t *profile, struct sc_pkcs15_card *p15card, |
414 | | struct sc_pkcs15_object *obj, const struct sc_path *path) |
415 | 0 | { |
416 | 0 | int r = SC_SUCCESS, stored_in_ef = 0, algorithm = 0; |
417 | 0 | size_t keybits; |
418 | 0 | sc_file_t *file = NULL; |
419 | 0 | struct sc_pkcs15_prkey_info *key_info; |
420 | 0 | struct sc_pkcs15_prkey_rsa key_obj; |
421 | 0 | struct sc_context *ctx = p15card->card->ctx; |
422 | 0 | uint8_t abignum[256]; |
423 | |
|
424 | 0 | LOG_FUNC_CALLED(ctx); |
425 | | /* |
426 | | * If we are deleting a private key, overwrite it so it can't be used. |
427 | | */ |
428 | 0 | if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) { |
429 | 0 | key_info = obj->data; |
430 | 0 | keybits = key_info->modulus_length & ~7UL; |
431 | 0 | init_key_object(&key_obj, abignum, keybits >> 3); |
432 | 0 | r = cardos_key_algorithm(key_info->usage, keybits, &algorithm); |
433 | 0 | LOG_TEST_RET(ctx, r, "cardos_key_algorithm failed"); |
434 | | |
435 | 0 | r = sc_select_file(p15card->card, &key_info->path, &file); |
436 | 0 | LOG_TEST_RET(ctx, r, "Failed to store key: cannot select parent DF"); |
437 | | |
438 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
439 | 0 | sc_file_free(file); |
440 | 0 | LOG_TEST_RET(ctx, r, "Failed to store key: UPDATE authentication failed"); |
441 | | |
442 | 0 | r = cardos_put_key(profile, p15card, algorithm, key_info, &key_obj); |
443 | 0 | LOG_TEST_RET(ctx, r, "cardos_put_key failed"); |
444 | 0 | } |
445 | | |
446 | | /* Delete object from the PKCS15 file system. */ |
447 | 0 | if (path->len || path->aid.len) { |
448 | 0 | r = sc_select_file(p15card->card, path, &file); |
449 | 0 | if (r != SC_ERROR_FILE_NOT_FOUND) |
450 | 0 | LOG_TEST_RET(ctx, r, "select object path failed"); |
451 | | |
452 | 0 | stored_in_ef = (file->type != SC_FILE_TYPE_DF); |
453 | 0 | sc_file_free(file); |
454 | 0 | } |
455 | | |
456 | | /* If the object is stored in a normal EF, try to delete the EF. */ |
457 | 0 | if (r == SC_SUCCESS && stored_in_ef) { |
458 | 0 | r = sc_pkcs15init_delete_by_path(profile, p15card, path); |
459 | 0 | LOG_TEST_RET(ctx, r, "Failed to delete object by path"); |
460 | 0 | } |
461 | | |
462 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
463 | 0 | } |
464 | | |
465 | | /* |
466 | | * Store a PIN or PUK |
467 | | */ |
468 | | static int |
469 | | cardos_store_pin(sc_profile_t *profile, sc_card_t *card, |
470 | | sc_pkcs15_auth_info_t *auth_info, int puk_id, |
471 | | const u8 *pin, size_t pin_len) |
472 | 0 | { |
473 | 0 | struct sc_cardctl_cardos_obj_info args; |
474 | 0 | unsigned char buffer[256]; |
475 | 0 | unsigned char pinpadded[256]; |
476 | 0 | struct tlv tlv; |
477 | 0 | unsigned int attempts, maxlen; |
478 | 0 | u8 minlen; |
479 | 0 | int r, hasverifyrc; |
480 | |
|
481 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
482 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
483 | | |
484 | | /* We need to do padding because pkcs15-lib.c does it. |
485 | | * Would be nice to have a flag in the profile that says |
486 | | * "no padding required". */ |
487 | 0 | maxlen = MIN(profile->pin_maxlen, sizeof(pinpadded)); |
488 | 0 | if (pin_len > maxlen) { |
489 | 0 | sc_log(card->ctx, |
490 | 0 | "invalid pin length: %"SC_FORMAT_LEN_SIZE_T"u (max %u)\n", |
491 | 0 | pin_len, maxlen); |
492 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
493 | 0 | } |
494 | 0 | memcpy(pinpadded, pin, pin_len); |
495 | 0 | while (pin_len < maxlen) |
496 | 0 | pinpadded[pin_len++] = profile->pin_pad_char; |
497 | 0 | pin = pinpadded; |
498 | |
|
499 | 0 | attempts = auth_info->tries_left; |
500 | 0 | minlen = (u8)auth_info->attrs.pin.min_length; |
501 | |
|
502 | 0 | tlv_init(&tlv, buffer, sizeof(buffer)); |
503 | | |
504 | | /* object address: class, id */ |
505 | 0 | if (tlv_next(&tlv, 0x83) != SC_SUCCESS |
506 | 0 | || tlv_add(&tlv, 0x00) != SC_SUCCESS /* class byte: usage TEST, k=0 */ |
507 | 0 | || tlv_add(&tlv, auth_info->attrs.pin.reference & 0x7f) != SC_SUCCESS) |
508 | 0 | return SC_ERROR_INTERNAL; |
509 | | |
510 | | /* parameters */ |
511 | 0 | if (tlv_next(&tlv, 0x85) |
512 | 0 | || tlv_add(&tlv, 0x02) /* options byte */) |
513 | 0 | return SC_ERROR_INTERNAL; |
514 | | |
515 | 0 | hasverifyrc = cardos_have_verifyrc_package(card); |
516 | 0 | if (hasverifyrc == 1) |
517 | | /* Use 9 byte OCI parameters to be able to set VerifyRC bit */ |
518 | 0 | if (tlv_add(&tlv, 0x04) != SC_SUCCESS /* options_2 byte with bit 2 set to return CurrentErrorCounter */) |
519 | 0 | return SC_ERROR_INTERNAL; |
520 | | |
521 | 0 | if (tlv_add(&tlv, attempts & 0xf) != SC_SUCCESS /* flags byte */ |
522 | 0 | || tlv_add(&tlv, CARDOS_ALGO_PIN) != SC_SUCCESS /* algorithm = pin-test */ |
523 | 0 | || tlv_add(&tlv, attempts & 0xf) != SC_SUCCESS /* errcount = attempts */) |
524 | 0 | return SC_ERROR_INTERNAL; |
525 | | |
526 | | /* usecount: not documented, but seems to work like this: |
527 | | * - value of 0xff means pin can be presented any number |
528 | | * of times |
529 | | * - anything less: max # of times before BS object is blocked. |
530 | | */ |
531 | 0 | if (tlv_add(&tlv, 0xff) != SC_SUCCESS) |
532 | 0 | return SC_ERROR_INTERNAL; |
533 | | |
534 | | /* DEK: not documented, no idea what it means */ |
535 | 0 | if (tlv_add(&tlv, 0xff) != SC_SUCCESS) |
536 | 0 | return SC_ERROR_INTERNAL; |
537 | | |
538 | | /* ARA counter: number of times the test object can be used before |
539 | | * another verification is required (~ user consent) |
540 | | * (0x00 unlimited usage) |
541 | | */ |
542 | 0 | if (tlv_add(&tlv, 0x00) != SC_SUCCESS |
543 | 0 | || tlv_add(&tlv, minlen) != SC_SUCCESS /* minlen */) |
544 | 0 | return SC_ERROR_INTERNAL; |
545 | | |
546 | | /* AC conditions */ |
547 | 0 | if (tlv_next(&tlv, 0x86) != SC_SUCCESS |
548 | 0 | || tlv_add(&tlv, 0x00) != SC_SUCCESS /* use: always */ |
549 | 0 | || tlv_add(&tlv, auth_info->attrs.pin.reference) != SC_SUCCESS /* change: PIN */ |
550 | 0 | || tlv_add(&tlv, puk_id) != SC_SUCCESS /* unblock: PUK */) |
551 | 0 | return SC_ERROR_INTERNAL; |
552 | | |
553 | | /* data: PIN */ |
554 | 0 | if (tlv_next(&tlv, 0x8f) != SC_SUCCESS) |
555 | 0 | return SC_ERROR_INTERNAL; |
556 | 0 | while (pin_len--) |
557 | 0 | if (tlv_add(&tlv, *pin++) != SC_SUCCESS) |
558 | 0 | return SC_ERROR_INTERNAL; |
559 | | |
560 | 0 | args.data = buffer; |
561 | 0 | args.len = tlv_len(&tlv); |
562 | | |
563 | | /* ensure we are in the correct lifecycle */ |
564 | 0 | r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); |
565 | 0 | if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) |
566 | 0 | return r; |
567 | | |
568 | 0 | return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args); |
569 | 0 | } |
570 | | |
571 | | /* |
572 | | * Create an empty security environment |
573 | | */ |
574 | | static int |
575 | | cardos_create_sec_env(struct sc_profile *profile, sc_card_t *card, |
576 | | unsigned int se_id, unsigned int key_id) |
577 | 0 | { |
578 | 0 | struct sc_cardctl_cardos_obj_info args; |
579 | 0 | struct tlv tlv; |
580 | 0 | unsigned char buffer[64]; |
581 | 0 | int r; |
582 | |
|
583 | 0 | tlv_init(&tlv, buffer, sizeof(buffer)); |
584 | 0 | if (tlv_next(&tlv, 0x83) != SC_SUCCESS |
585 | 0 | || tlv_add(&tlv, se_id) != SC_SUCCESS |
586 | 0 | || tlv_next(&tlv, 0x86) != SC_SUCCESS |
587 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS |
588 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS |
589 | 0 | || tlv_next(&tlv, 0x8f) != SC_SUCCESS |
590 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS |
591 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS |
592 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS |
593 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS |
594 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS |
595 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS) |
596 | 0 | return SC_ERROR_INTERNAL; |
597 | | |
598 | 0 | args.data = buffer; |
599 | 0 | args.len = tlv_len(&tlv); |
600 | | |
601 | | /* ensure we are in the correct lifecycle */ |
602 | 0 | r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); |
603 | 0 | if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) |
604 | 0 | return r; |
605 | | |
606 | 0 | return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_SECI, &args); |
607 | 0 | } |
608 | | |
609 | | /* |
610 | | * Determine the key algorithm based on the intended usage |
611 | | * Note that CardOS/M4 does not support keys that can be used |
612 | | * for signing _and_ decipherment |
613 | | */ |
614 | 0 | #define USAGE_ANY_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN|\ |
615 | 0 | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) |
616 | 0 | #define USAGE_ANY_DECIPHER (SC_PKCS15_PRKEY_USAGE_DECRYPT|\ |
617 | 0 | SC_PKCS15_PRKEY_USAGE_UNWRAP) |
618 | | |
619 | | static int cardos_key_algorithm(unsigned int usage, size_t keylen, int *algop) |
620 | 0 | { |
621 | | /* if it is sign and decipher, we use decipher and emulate sign */ |
622 | 0 | if (usage & USAGE_ANY_DECIPHER) { |
623 | 0 | if (keylen <= 1024) |
624 | 0 | *algop = CARDOS_ALGO_RSA_PURE; |
625 | 0 | else |
626 | 0 | *algop = CARDOS_ALGO_EXT_RSA_PURE; |
627 | 0 | return 0; |
628 | 0 | } |
629 | 0 | if (usage & USAGE_ANY_SIGN) { |
630 | 0 | if (keylen <= 1024) |
631 | 0 | *algop = CARDOS_ALGO_RSA_PURE_SIG; |
632 | 0 | else |
633 | 0 | *algop = CARDOS_ALGO_EXT_RSA_SIG_PURE; |
634 | 0 | return 0; |
635 | 0 | } |
636 | 0 | return -1; |
637 | 0 | } |
638 | | |
639 | | /* |
640 | | * Create a private key object |
641 | | */ |
642 | 0 | #define CARDOS_KEY_OPTIONS 0x02 |
643 | 0 | #define CARDOS_KEY_FLAGS 0x00 |
644 | | static int |
645 | | cardos_store_key_component(sc_card_t *card, |
646 | | int algorithm, |
647 | | unsigned int key_id, unsigned int pin_id, |
648 | | unsigned int num, |
649 | | const u8 *data, size_t len, |
650 | | int last, int use_prefix) |
651 | 0 | { |
652 | 0 | struct sc_cardctl_cardos_obj_info args; |
653 | 0 | struct tlv tlv; |
654 | 0 | unsigned char buffer[256]; |
655 | | #ifdef SET_SM_BYTES |
656 | | unsigned int n; |
657 | | #endif |
658 | 0 | int r; |
659 | | |
660 | | /* Initialize the TLV encoder */ |
661 | 0 | tlv_init(&tlv, buffer, sizeof(buffer)); |
662 | | |
663 | | /* Object address */ |
664 | 0 | if (tlv_next(&tlv, 0x83) != SC_SUCCESS |
665 | 0 | || tlv_add(&tlv, 0x20|num) != SC_SUCCESS /* PSO, n-th component */ |
666 | 0 | || tlv_add(&tlv, key_id) != SC_SUCCESS) |
667 | 0 | return SC_ERROR_INTERNAL; |
668 | | |
669 | | /* Object parameters */ |
670 | 0 | if (tlv_next(&tlv, 0x85) != SC_SUCCESS |
671 | 0 | || tlv_add(&tlv, CARDOS_KEY_OPTIONS|(last? 0x00 : 0x20)) != SC_SUCCESS |
672 | 0 | || tlv_add(&tlv, CARDOS_KEY_FLAGS) != SC_SUCCESS |
673 | 0 | || tlv_add(&tlv, algorithm) != SC_SUCCESS |
674 | 0 | || tlv_add(&tlv, 0x00) != SC_SUCCESS |
675 | 0 | || tlv_add(&tlv, 0xFF) != SC_SUCCESS /* use count */ |
676 | 0 | || tlv_add(&tlv, 0xFF) != SC_SUCCESS /* DEK (whatever this is) */ |
677 | 0 | || tlv_add(&tlv, 0x00) != SC_SUCCESS |
678 | 0 | || tlv_add(&tlv, 0x00) != SC_SUCCESS) |
679 | 0 | return SC_ERROR_INTERNAL; |
680 | | |
681 | | /* AC bytes */ |
682 | 0 | if (tlv_next(&tlv, 0x86) != SC_SUCCESS |
683 | 0 | || tlv_add(&tlv, pin_id) != SC_SUCCESS /* AC USE */ |
684 | 0 | || tlv_add(&tlv, pin_id) != SC_SUCCESS /* AC CHANGE */ |
685 | 0 | || tlv_add(&tlv, pin_id) != SC_SUCCESS /* UNKNOWN */ |
686 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS /* rfu */ |
687 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS /* rfu */ |
688 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS /* rfu */ |
689 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS) |
690 | 0 | return SC_ERROR_INTERNAL; |
691 | | |
692 | | #ifdef SET_SM_BYTES |
693 | | /* it shouldn't be necessary to set the default value */ |
694 | | /* SM bytes */ |
695 | | if (tlv_next(&tlv, 0x8B) != SC_SUCCESS) |
696 | | return SC_ERROR_INTERNAL; |
697 | | for (n = 0; n < 16; n++) |
698 | | if (tlv_add(&tlv, 0xFF) != SC_SUCCESS) |
699 | | return SC_ERROR_INTERNAL; |
700 | | #endif |
701 | | |
702 | | /* key component */ |
703 | 0 | if (tlv_next(&tlv, 0x8f) != SC_SUCCESS) |
704 | 0 | return SC_ERROR_INTERNAL; |
705 | 0 | if (use_prefix != 0) { |
706 | 0 | if (tlv_add(&tlv, len+1) != SC_SUCCESS |
707 | 0 | || tlv_add(&tlv, 0) != SC_SUCCESS) |
708 | 0 | return SC_ERROR_INTERNAL; |
709 | 0 | } |
710 | 0 | while (len--) |
711 | 0 | if (tlv_add(&tlv, *data++) != SC_SUCCESS) |
712 | 0 | return SC_ERROR_INTERNAL; |
713 | | |
714 | 0 | args.data = buffer; |
715 | 0 | args.len = tlv_len(&tlv); |
716 | | |
717 | | /* ensure we are in the correct lifecycle */ |
718 | 0 | r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); |
719 | 0 | if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) |
720 | 0 | return r; |
721 | | |
722 | 0 | return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args); |
723 | 0 | } |
724 | | |
725 | | |
726 | | static int |
727 | | cardos_put_key(sc_profile_t *profile, struct sc_pkcs15_card *p15card, |
728 | | int algorithm, sc_pkcs15_prkey_info_t *key_info, |
729 | | struct sc_pkcs15_prkey_rsa *key) |
730 | 0 | { |
731 | 0 | struct sc_card *card = p15card->card; |
732 | 0 | int r, key_id, pin_id; |
733 | |
|
734 | 0 | pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC, |
735 | 0 | SC_PKCS15INIT_USER_PIN); |
736 | 0 | if (pin_id < 0) |
737 | 0 | pin_id = 0; |
738 | |
|
739 | 0 | key_id = key_info->key_reference; |
740 | 0 | if (key_info->modulus_length > 1024 && (card->type == SC_CARD_TYPE_CARDOS_M4_2 || |
741 | 0 | card->type == SC_CARD_TYPE_CARDOS_M4_3 ||card->type == SC_CARD_TYPE_CARDOS_M4_2B || |
742 | 0 | card->type == SC_CARD_TYPE_CARDOS_M4_2C ||card->type == SC_CARD_TYPE_CARDOS_M4_4)) { |
743 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 0, |
744 | 0 | key->p.data, key->p.len, 0, 0); |
745 | 0 | if (r != SC_SUCCESS) |
746 | 0 | return r; |
747 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 1, |
748 | 0 | key->q.data, key->q.len, 0, 0); |
749 | 0 | if (r != SC_SUCCESS) |
750 | 0 | return r; |
751 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 2, |
752 | 0 | key->dmp1.data, key->dmp1.len, 0, 0); |
753 | 0 | if (r != SC_SUCCESS) |
754 | 0 | return r; |
755 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 3, |
756 | 0 | key->dmq1.data, key->dmq1.len, 0, 0); |
757 | 0 | if (r != SC_SUCCESS) |
758 | 0 | return r; |
759 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 4, |
760 | 0 | key->iqmp.data, key->iqmp.len, 1, 0); |
761 | 0 | } else { |
762 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 0, |
763 | 0 | key->modulus.data, key->modulus.len, 0, 1); |
764 | 0 | if (r != SC_SUCCESS) |
765 | 0 | return r; |
766 | 0 | r = cardos_store_key_component(card, algorithm, key_id, pin_id, 1, |
767 | 0 | key->d.data, key->d.len, 1, 1); |
768 | 0 | } |
769 | | |
770 | 0 | return r; |
771 | 0 | } |
772 | | |
773 | | /* |
774 | | * Extract a key component from the public key file populated by |
775 | | * GENERATE KEY PAIR |
776 | | */ |
777 | | static int parse_ext_pubkey_file(sc_card_t *card, const u8 *data, size_t len, |
778 | | sc_pkcs15_pubkey_t *pubkey) |
779 | 0 | { |
780 | 0 | const u8 *p; |
781 | 0 | size_t ilen = 0, tlen = 0; |
782 | |
|
783 | 0 | if (data == NULL || len < 32) |
784 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
785 | 0 | data = sc_asn1_find_tag(card->ctx, data, len, 0x7f49, &ilen); |
786 | 0 | if (data == NULL) { |
787 | 0 | sc_log(card->ctx, "invalid public key data: missing tag"); |
788 | 0 | return SC_ERROR_INTERNAL; |
789 | 0 | } |
790 | | |
791 | 0 | p = sc_asn1_find_tag(card->ctx, data, ilen, 0x81, &tlen); |
792 | 0 | if (p == NULL) { |
793 | 0 | sc_log(card->ctx, "invalid public key data: missing modulus"); |
794 | 0 | return SC_ERROR_INTERNAL; |
795 | 0 | } |
796 | 0 | pubkey->u.rsa.modulus.len = tlen; |
797 | 0 | pubkey->u.rsa.modulus.data = malloc(tlen); |
798 | 0 | if (pubkey->u.rsa.modulus.data == NULL) |
799 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
800 | 0 | memcpy(pubkey->u.rsa.modulus.data, p, tlen); |
801 | |
|
802 | 0 | p = sc_asn1_find_tag(card->ctx, data, ilen, 0x82, &tlen); |
803 | 0 | if (p == NULL) { |
804 | 0 | sc_log(card->ctx, "invalid public key data: missing exponent"); |
805 | 0 | return SC_ERROR_INTERNAL; |
806 | 0 | } |
807 | 0 | pubkey->u.rsa.exponent.len = tlen; |
808 | 0 | pubkey->u.rsa.exponent.data = malloc(tlen); |
809 | 0 | if (pubkey->u.rsa.exponent.data == NULL) |
810 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
811 | 0 | memcpy(pubkey->u.rsa.exponent.data, p, tlen); |
812 | |
|
813 | 0 | return SC_SUCCESS; |
814 | 0 | } |
815 | | |
816 | | static int |
817 | | do_cardos_extract_pubkey(sc_card_t *card, int nr, u8 tag, |
818 | | sc_pkcs15_bignum_t *bn) |
819 | 0 | { |
820 | 0 | u8 buf[256]; |
821 | 0 | int r, count; |
822 | |
|
823 | 0 | r = sc_read_record(card, nr, 0, buf, sizeof(buf), SC_RECORD_BY_REC_NR); |
824 | 0 | if (r < 0) |
825 | 0 | return r; |
826 | 0 | count = r - 4; |
827 | 0 | if (count <= 0 || buf[0] != tag || buf[1] != count + 2 |
828 | 0 | || buf[2] != count + 1 || buf[3] != 0) |
829 | 0 | return SC_ERROR_INTERNAL; |
830 | 0 | bn->len = count; |
831 | 0 | bn->data = malloc(count); |
832 | 0 | if (bn->data == NULL) |
833 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
834 | 0 | memcpy(bn->data, buf + 4, count); |
835 | 0 | return SC_SUCCESS; |
836 | 0 | } |
837 | | |
838 | | static int cardos_extract_pubkey(sc_card_t *card, sc_pkcs15_pubkey_t *pubkey, |
839 | | sc_file_t *tfile, int use_ext_rsa) |
840 | 0 | { |
841 | 0 | int r; |
842 | |
|
843 | 0 | memset(pubkey, 0, sizeof(*pubkey)); |
844 | |
|
845 | 0 | r = sc_select_file(card, &tfile->path, NULL); |
846 | 0 | if (r != SC_SUCCESS) |
847 | 0 | return r; |
848 | | |
849 | 0 | if (use_ext_rsa == 0) { |
850 | 0 | r = do_cardos_extract_pubkey(card, 1, 0x10, &pubkey->u.rsa.modulus); |
851 | 0 | if (r != SC_SUCCESS) |
852 | 0 | return r; |
853 | 0 | r = do_cardos_extract_pubkey(card, 2, 0x11, &pubkey->u.rsa.exponent); |
854 | 0 | } else { |
855 | 0 | u8 *buf; |
856 | |
|
857 | 0 | buf = malloc(tfile->size); |
858 | 0 | if (buf == NULL) |
859 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
860 | 0 | r = sc_read_binary(card, 0, buf, tfile->size, 0); |
861 | 0 | if (r > 0) |
862 | 0 | r = parse_ext_pubkey_file(card, buf, (size_t)r, pubkey); |
863 | 0 | free(buf); |
864 | 0 | } |
865 | | |
866 | 0 | pubkey->algorithm = SC_ALGORITHM_RSA; |
867 | |
|
868 | 0 | return r; |
869 | 0 | } |
870 | | |
871 | | static int cardos_have_verifyrc_package(sc_card_t *card) |
872 | 0 | { |
873 | 0 | sc_apdu_t apdu; |
874 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; |
875 | 0 | int r; |
876 | 0 | const u8 *p = rbuf, *q, *pp; |
877 | 0 | size_t len, tlen = 0, ilen = 0; |
878 | |
|
879 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x88); |
880 | 0 | apdu.resp = rbuf; |
881 | 0 | apdu.resplen = sizeof(rbuf); |
882 | 0 | apdu.lc = 0; |
883 | 0 | apdu.le = 256; |
884 | 0 | r = sc_transmit_apdu(card, &apdu); |
885 | 0 | LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); |
886 | | |
887 | 0 | if ((len = apdu.resplen) == 0) |
888 | | /* looks like no package has been installed */ |
889 | 0 | return 0; |
890 | | |
891 | 0 | while (len != 0) { |
892 | 0 | pp = sc_asn1_find_tag(card->ctx, p, len, 0xe1, &tlen); |
893 | 0 | if (pp == NULL) |
894 | 0 | return 0; |
895 | 0 | if (card->type == SC_CARD_TYPE_CARDOS_M4_3) { |
896 | | /* the verifyRC package on CardOS 4.3B use Manufacturer ID 0x01 */ |
897 | | /* and Package Number 0x07 */ |
898 | 0 | q = sc_asn1_find_tag(card->ctx, pp, tlen, 0x01, &ilen); |
899 | 0 | if (q == NULL || ilen != 4) |
900 | 0 | return 0; |
901 | 0 | if (q[0] == 0x07) |
902 | 0 | return 1; |
903 | 0 | } else if (card->type == SC_CARD_TYPE_CARDOS_M4_4) { |
904 | | /* the verifyRC package on CardOS 4.4 use Manufacturer ID 0x03 */ |
905 | | /* and Package Number 0x02 */ |
906 | 0 | q = sc_asn1_find_tag(card->ctx, pp, tlen, 0x03, &ilen); |
907 | 0 | if (q == NULL || ilen != 4) |
908 | 0 | return 0; |
909 | 0 | if (q[0] == 0x02) |
910 | 0 | return 1; |
911 | 0 | } else { |
912 | 0 | return 0; |
913 | 0 | } |
914 | 0 | p += tlen; |
915 | 0 | len -= tlen + 2; |
916 | 0 | } |
917 | | |
918 | 0 | return 0; |
919 | 0 | } |
920 | | |
921 | | static struct sc_pkcs15init_operations sc_pkcs15init_cardos_operations = { |
922 | | cardos_erase, |
923 | | NULL, /* init_card */ |
924 | | cardos_create_dir, |
925 | | NULL, /* create_domain */ |
926 | | cardos_select_pin_reference, |
927 | | cardos_create_pin, |
928 | | cardos_select_key_reference, |
929 | | cardos_create_key, |
930 | | cardos_store_key, |
931 | | cardos_generate_key, |
932 | | NULL, NULL, /* encode private/public key */ |
933 | | NULL, /* finalize_card */ |
934 | | cardos_delete_object, |
935 | | NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ |
936 | | NULL /* sanity_check */ |
937 | | }; |
938 | | |
939 | | struct sc_pkcs15init_operations * |
940 | | sc_pkcs15init_get_cardos_ops(void) |
941 | 0 | { |
942 | 0 | return &sc_pkcs15init_cardos_operations; |
943 | 0 | } |