/src/opensc/src/libopensc/pkcs15-coolkey.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * partial PKCS15 emulation for Coolkey cards |
3 | | * |
4 | | * Copyright (C) 2005,2006,2007,2008,2009,2010 |
5 | | * Douglas E. Engert <deengert@anl.gov> |
6 | | * 2004, Nils Larsch <larsch@trustcenter.de> |
7 | | * Copyright (C) 2006, Identity Alliance, |
8 | | * Thomas Harning <thomas.harning@identityalliance.com> |
9 | | * Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com> |
10 | | * Copyright (C) 2016, Red Hat, Inc. |
11 | | * |
12 | | * Coolkey driver author: Robert Relyea <rrelyea@redhat.com> |
13 | | * |
14 | | * This library is free software; you can redistribute it and/or |
15 | | * modify it under the terms of the GNU Lesser General Public |
16 | | * License as published by the Free Software Foundation; either |
17 | | * version 2.1 of the License, or (at your option) any later version. |
18 | | * |
19 | | * This library is distributed in the hope that it will be useful, |
20 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 | | * Lesser General Public License for more details. |
23 | | * |
24 | | * You should have received a copy of the GNU Lesser General Public |
25 | | * License along with this library; if not, write to the Free Software |
26 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
27 | | */ |
28 | | |
29 | | #ifdef HAVE_CONFIG_H |
30 | | #include "config.h" |
31 | | #endif |
32 | | |
33 | | #include <stdlib.h> |
34 | | #include <string.h> |
35 | | #include <stdio.h> |
36 | | #include <ctype.h> |
37 | | |
38 | | #include "internal.h" |
39 | | #include "cardctl.h" |
40 | | #include "asn1.h" |
41 | | #include "pkcs15.h" |
42 | | #include "../pkcs11/pkcs11.h" |
43 | | |
44 | | typedef struct pdata_st { |
45 | | const char *id; |
46 | | const char *label; |
47 | | const char *path; |
48 | | int ref; |
49 | | int type; |
50 | | unsigned int maxlen; |
51 | | unsigned int minlen; |
52 | | unsigned int storedlen; |
53 | | int flags; |
54 | | int tries_left; |
55 | | const unsigned char pad_char; |
56 | | int obj_flags; |
57 | | } pindata; |
58 | | |
59 | | static int coolkey_detect_card(sc_pkcs15_card_t *p15card) |
60 | 0 | { |
61 | 0 | sc_card_t *card = p15card->card; |
62 | |
|
63 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
64 | 0 | if (card->type < SC_CARD_TYPE_COOLKEY_GENERIC |
65 | 0 | || card->type >= SC_CARD_TYPE_COOLKEY_GENERIC+1000) |
66 | 0 | return SC_ERROR_INVALID_CARD; |
67 | 0 | return SC_SUCCESS; |
68 | 0 | } |
69 | | |
70 | | static int |
71 | 0 | coolkey_get_object(sc_card_t *card, unsigned long object_id, sc_cardctl_coolkey_object_t **obj) { |
72 | 0 | sc_cardctl_coolkey_find_object_t fobj; |
73 | 0 | int r; |
74 | |
|
75 | 0 | fobj.type = SC_CARDCTL_COOLKEY_FIND_BY_ID; |
76 | 0 | fobj.find_id = object_id; |
77 | 0 | fobj.obj = NULL; |
78 | 0 | r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_FIND_OBJECT, &fobj); |
79 | 0 | if (r < 0) { |
80 | 0 | return r; |
81 | 0 | } |
82 | 0 | *obj = fobj.obj; |
83 | 0 | return SC_SUCCESS; |
84 | 0 | } |
85 | | |
86 | | |
87 | | /* |
88 | | * fetch attributes from an object |
89 | | */ |
90 | | static int |
91 | 0 | coolkey_get_attribute(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, const u8 **val, size_t *val_len, u8 *data_type) { |
92 | 0 | sc_cardctl_coolkey_attribute_t attribute; |
93 | 0 | int r; |
94 | |
|
95 | 0 | attribute.object = obj; |
96 | 0 | attribute.attribute_type = type; |
97 | |
|
98 | 0 | r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_GET_ATTRIBUTE, &attribute); |
99 | 0 | if (r < 0) { |
100 | 0 | return r; |
101 | 0 | } |
102 | 0 | *val = attribute.attribute_value; |
103 | 0 | *val_len = attribute.attribute_length; |
104 | 0 | if (data_type) { |
105 | 0 | *data_type = attribute.attribute_data_type; |
106 | 0 | } |
107 | 0 | return SC_SUCCESS; |
108 | 0 | } |
109 | | |
110 | | static int |
111 | 0 | coolkey_find_matching_cert(sc_card_t *card, sc_cardctl_coolkey_object_t *in_obj, sc_cardctl_coolkey_object_t **cert_obj) { |
112 | 0 | sc_cardctl_coolkey_find_object_t fobj; |
113 | 0 | sc_cardctl_coolkey_attribute_t template[2]; |
114 | 0 | u8 obj_class[4]; |
115 | 0 | int r; |
116 | | |
117 | | /* we are searching for certs .. */ |
118 | 0 | template[0].attribute_type = CKA_CLASS; |
119 | 0 | template[0].attribute_data_type = SC_CARDCTL_COOLKEY_ATTR_TYPE_ULONG; |
120 | 0 | template[0].attribute_length = sizeof(obj_class); |
121 | 0 | template[0].attribute_value = obj_class; |
122 | 0 | ulong2bebytes(obj_class, CKO_CERTIFICATE); |
123 | | |
124 | | /* fetch the current object's CKA_ID */ |
125 | 0 | template[1].attribute_type = CKA_ID; |
126 | 0 | template[1].object = in_obj; |
127 | 0 | r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_GET_ATTRIBUTE, &template[1]); |
128 | 0 | if (r < 0) { |
129 | 0 | return r; |
130 | 0 | } |
131 | 0 | template[0].object = NULL; /*paranoia */ |
132 | 0 | template[1].object = NULL; /*paranoia */ |
133 | | |
134 | | /* now find the cert that has the ID */ |
135 | 0 | fobj.type = SC_CARDCTL_COOLKEY_FIND_BY_TEMPLATE; |
136 | 0 | fobj.obj = NULL; |
137 | 0 | fobj.coolkey_template = &template[0]; |
138 | 0 | fobj.template_count=2; |
139 | 0 | r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_FIND_OBJECT, &fobj); |
140 | 0 | if (r < 0) { |
141 | 0 | return r; |
142 | 0 | } |
143 | 0 | *cert_obj = fobj.obj; |
144 | 0 | return SC_SUCCESS; |
145 | 0 | } |
146 | | |
147 | | static int |
148 | | coolkey_get_attribute_ulong(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, CK_ULONG *value) |
149 | 0 | { |
150 | 0 | const u8 *val = NULL; |
151 | 0 | size_t val_len = 0; |
152 | 0 | u8 data_type = 0; |
153 | 0 | int r; |
154 | |
|
155 | 0 | r = coolkey_get_attribute(card, obj, type, &val, &val_len, &data_type); |
156 | 0 | if (r < 0) { |
157 | 0 | return r; |
158 | 0 | } |
159 | 0 | if ((data_type != SC_CARDCTL_COOLKEY_ATTR_TYPE_ULONG) && |
160 | 0 | (val_len != sizeof(CK_ULONG))) { |
161 | 0 | return SC_ERROR_CORRUPTED_DATA; |
162 | 0 | } |
163 | 0 | *value = bebytes2ulong(val); |
164 | 0 | return SC_SUCCESS; |
165 | 0 | } |
166 | | |
167 | | static int |
168 | | coolkey_get_attribute_boolean(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE attr_type) |
169 | 0 | { |
170 | 0 | int r; |
171 | 0 | const u8 *val = NULL; |
172 | 0 | size_t val_len = 0; |
173 | |
|
174 | 0 | r = coolkey_get_attribute(card, obj, attr_type, &val, &val_len, NULL); |
175 | 0 | if (r < 0) { |
176 | | /* attribute not valid for this object, set boolean to false */ |
177 | 0 | return 0; |
178 | 0 | } |
179 | 0 | if ((val_len == 1) && (*val == 1)) { |
180 | 0 | return 1; |
181 | 0 | } |
182 | 0 | return 0; |
183 | 0 | } |
184 | | |
185 | | static int |
186 | | coolkey_get_attribute_bytes(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, u8 *data, size_t *data_len, size_t max_data_len) |
187 | 0 | { |
188 | 0 | const u8 *val; |
189 | 0 | size_t val_len = 0; |
190 | 0 | int r; |
191 | |
|
192 | 0 | r = coolkey_get_attribute(card, obj, type, &val, &val_len, NULL); |
193 | 0 | if (r < 0) { |
194 | 0 | return r; |
195 | 0 | } |
196 | 0 | if (val_len > max_data_len) { |
197 | 0 | val_len = max_data_len; |
198 | 0 | } |
199 | 0 | memcpy(data, val, val_len); |
200 | 0 | *data_len = val_len; |
201 | 0 | return SC_SUCCESS; |
202 | 0 | } |
203 | | |
204 | | static int |
205 | | coolkey_get_attribute_bytes_alloc(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, u8 **data, size_t *data_len) |
206 | 0 | { |
207 | 0 | const u8 *val; |
208 | 0 | size_t val_len; |
209 | 0 | int r; |
210 | |
|
211 | 0 | r = coolkey_get_attribute(card, obj, type, &val, &val_len, NULL); |
212 | 0 | if (r < 0) { |
213 | 0 | return r; |
214 | 0 | } |
215 | 0 | *data = malloc(val_len); |
216 | 0 | if (*data == NULL) { |
217 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
218 | 0 | } |
219 | 0 | memcpy(*data, val, val_len); |
220 | 0 | *data_len = val_len; |
221 | 0 | return SC_SUCCESS; |
222 | 0 | } |
223 | | |
224 | | static int |
225 | | coolkey_get_id(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, struct sc_pkcs15_id *id) |
226 | 0 | { |
227 | 0 | return coolkey_get_attribute_bytes(card, obj, CKA_ID, id->value , &id->len, sizeof(id->value)); |
228 | 0 | } |
229 | | |
230 | | /* |
231 | | * A number of opensc structure have the same layout, use a common function to fill them |
232 | | * int: |
233 | | * structure name first parameter second parameter |
234 | | * sc_lv_data unsigned char * value size_t len |
235 | | * sc_pkcs15_data u8 *data size_t data_len |
236 | | * sc_pkcs15_bignum u8 *data size_t len |
237 | | * sc_pkcs15_der u8 *value size_t len |
238 | | * sc_pkcs15_u8 u8 *value size_t len |
239 | | * |
240 | | * The following can properly assign all of them |
241 | | */ |
242 | | int |
243 | | coolkey_get_attribute_lv(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, void *ptr) |
244 | 0 | { |
245 | 0 | struct sc_pkcs15_data *item = (struct sc_pkcs15_data *)ptr; |
246 | 0 | return coolkey_get_attribute_bytes_alloc(card, obj, type, &item->data, &item->data_len); |
247 | 0 | } |
248 | | |
249 | 0 | #define COOLKEY_ID_CERT ((unsigned long)'c') |
250 | | #define COOLKEY_ID_KEY ((unsigned long)'k') |
251 | 0 | #define COOLKEY_ID_CERT_DATA ((unsigned long)'C') |
252 | | |
253 | | static unsigned long |
254 | 0 | coolkey_get_object_type(unsigned long object_id) { return ((object_id >> 24 ) & 0xff); } |
255 | | |
256 | | static unsigned long |
257 | | coolkey_make_new_id(unsigned long object_id, unsigned long id_type) |
258 | 0 | { return ((object_id & 0x00ffffffUL)|(id_type << 24)); } |
259 | | |
260 | | |
261 | | /* |
262 | | * We need cert data to fill in some of our keys. Also, some older tokens store the cert data in a separate |
263 | | * object from the rest of the cert attributes. This function handles both of these complications |
264 | | */ |
265 | | static int |
266 | | coolkey_get_certificate(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, struct sc_pkcs15_der *cert) |
267 | 0 | { |
268 | 0 | sc_cardctl_coolkey_object_t *cert_obj; |
269 | 0 | unsigned long object_id; |
270 | 0 | int r; |
271 | |
|
272 | 0 | cert_obj = obj; |
273 | 0 | if (coolkey_get_object_type(obj->id) != COOLKEY_ID_CERT) { |
274 | 0 | r = coolkey_find_matching_cert(card, obj, &cert_obj); |
275 | 0 | if (r < 0) { |
276 | 0 | return r; |
277 | 0 | } |
278 | 0 | } |
279 | 0 | r = coolkey_get_attribute_lv(card, cert_obj, CKA_VALUE, cert); |
280 | 0 | if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) { |
281 | 0 | object_id = coolkey_make_new_id(cert_obj->id, COOLKEY_ID_CERT_DATA); |
282 | 0 | r = coolkey_get_object(card, object_id, &cert_obj); |
283 | 0 | if (r < 0) { |
284 | 0 | return r; |
285 | 0 | } |
286 | | /* fill in cert data */ |
287 | 0 | cert->value = malloc(cert_obj->length); |
288 | 0 | if (cert->value == NULL) { |
289 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
290 | 0 | } |
291 | 0 | memcpy(cert->value, cert_obj->data, cert_obj->length); |
292 | 0 | cert->len = cert_obj->length; |
293 | 0 | return SC_SUCCESS; |
294 | 0 | } |
295 | 0 | return r; |
296 | 0 | } |
297 | | |
298 | | |
299 | | |
300 | | struct coolkey_attr_flags { |
301 | | CK_ATTRIBUTE_TYPE attribute_type; |
302 | | unsigned int pkcs15_flags; |
303 | | }; |
304 | | |
305 | | static struct coolkey_attr_flags usage_table[] = { |
306 | | { CKA_ENCRYPT, SC_PKCS15_PRKEY_USAGE_ENCRYPT }, |
307 | | { CKA_DECRYPT, SC_PKCS15_PRKEY_USAGE_DECRYPT }, |
308 | | { CKA_SIGN, SC_PKCS15_PRKEY_USAGE_SIGN }, |
309 | | { CKA_SIGN_RECOVER, SC_PKCS15_PRKEY_USAGE_SIGNRECOVER }, |
310 | | { CKA_WRAP, SC_PKCS15_PRKEY_USAGE_WRAP }, |
311 | | { CKA_UNWRAP, SC_PKCS15_PRKEY_USAGE_UNWRAP }, |
312 | | { CKA_VERIFY, SC_PKCS15_PRKEY_USAGE_VERIFY }, |
313 | | { CKA_VERIFY_RECOVER, SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER }, |
314 | | { CKA_DERIVE, SC_PKCS15_PRKEY_USAGE_DERIVE } |
315 | | }; |
316 | | |
317 | | static struct coolkey_attr_flags access_table[] = { |
318 | | { CKA_SENSITIVE, SC_PKCS15_PRKEY_ACCESS_SENSITIVE }, |
319 | | { CKA_EXTRACTABLE, SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE }, |
320 | | { CKA_ALWAYS_SENSITIVE, SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE }, |
321 | | { CKA_NEVER_EXTRACTABLE,SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE}, |
322 | | { CKA_LOCAL, SC_PKCS15_PRKEY_ACCESS_LOCAL } |
323 | | }; |
324 | | |
325 | | static struct coolkey_attr_flags flag_table[] = { |
326 | | { CKA_PRIVATE, SC_PKCS15_CO_FLAG_PRIVATE }, |
327 | | { CKA_MODIFIABLE, SC_PKCS15_CO_FLAG_MODIFIABLE } |
328 | | }; |
329 | | |
330 | | static int usage_table_size = sizeof(usage_table)/sizeof(usage_table[0]); |
331 | | static int access_table_size = sizeof(access_table)/sizeof(access_table[0]); |
332 | | static int flag_table_size = sizeof(flag_table)/sizeof(flag_table[0]); |
333 | | |
334 | | static int |
335 | | coolkey_set_bool_flags(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, unsigned int *flags_ptr, struct coolkey_attr_flags *table, int table_size) |
336 | 0 | { |
337 | 0 | unsigned int flags = 0; |
338 | 0 | int i; |
339 | |
|
340 | 0 | for (i=0; i< table_size; i++) { |
341 | 0 | if (coolkey_get_attribute_boolean(card, obj, table[i].attribute_type)) { |
342 | 0 | flags |= table[i].pkcs15_flags; |
343 | 0 | } |
344 | 0 | } |
345 | 0 | *flags_ptr = flags; |
346 | 0 | return SC_SUCCESS; |
347 | 0 | } |
348 | | |
349 | | /* map a cert usage and algorithm to public and private key usages */ |
350 | | static int |
351 | | coolkey_get_usage(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, unsigned int *usage_ptr) |
352 | 0 | { |
353 | 0 | return coolkey_set_bool_flags(card, obj, usage_ptr, usage_table, usage_table_size); |
354 | 0 | } |
355 | | |
356 | | /* map a cert usage and algorithm to public and private key usages */ |
357 | | static int |
358 | | coolkey_get_flags(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, unsigned int *flag_ptr) |
359 | 0 | { |
360 | 0 | return coolkey_set_bool_flags(card, obj, flag_ptr, flag_table, flag_table_size); |
361 | 0 | } |
362 | | |
363 | | static int |
364 | | coolkey_get_access(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, unsigned int *access_ptr) |
365 | 0 | { |
366 | 0 | return coolkey_set_bool_flags(card, obj, access_ptr, access_table, access_table_size); |
367 | 0 | } |
368 | | |
369 | | |
370 | | /* |
371 | | * turn a coolkey object into a pkcss 15 pubkey. object should already be type |
372 | | * CKO_PUBLIC_KEY */ |
373 | | static sc_pkcs15_pubkey_t * |
374 | | coolkey_make_public_key(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_KEY_TYPE key_type) |
375 | 0 | { |
376 | 0 | sc_pkcs15_pubkey_t *key; |
377 | 0 | int r; |
378 | |
|
379 | 0 | key = calloc(1, sizeof(struct sc_pkcs15_pubkey)); |
380 | 0 | if (!key) |
381 | 0 | return NULL; |
382 | 0 | switch (key_type) { |
383 | 0 | case CKK_RSA: |
384 | 0 | key->algorithm = SC_ALGORITHM_RSA; |
385 | 0 | r = coolkey_get_attribute_lv(card, obj, CKA_MODULUS, &key->u.rsa.modulus); |
386 | 0 | if (r != SC_SUCCESS) { |
387 | 0 | goto fail; |
388 | 0 | } |
389 | 0 | r = coolkey_get_attribute_lv(card, obj, CKA_PUBLIC_EXPONENT, &key->u.rsa.exponent); |
390 | 0 | if (r != SC_SUCCESS) { |
391 | 0 | goto fail; |
392 | 0 | } |
393 | 0 | break; |
394 | 0 | case CKK_EC: |
395 | 0 | key->algorithm = SC_ALGORITHM_EC; |
396 | 0 | r = coolkey_get_attribute_bytes_alloc(card, obj, CKA_EC_POINT, &key->u.ec.ecpointQ.value, &key->u.ec.ecpointQ.len); |
397 | 0 | if(r < 0) { |
398 | 0 | goto fail; |
399 | 0 | } |
400 | 0 | r = coolkey_get_attribute_bytes_alloc(card, obj, CKA_EC_PARAMS, |
401 | 0 | &key->u.ec.params.der.value, &key->u.ec.params.der.len); |
402 | 0 | if (r < 0) { |
403 | 0 | goto fail; |
404 | 0 | } |
405 | 0 | r = sc_pkcs15_fix_ec_parameters(card->ctx, &key->u.ec.params); |
406 | 0 | if (r < 0) { |
407 | 0 | goto fail; |
408 | 0 | } |
409 | 0 | break; |
410 | 0 | } |
411 | 0 | return key; |
412 | 0 | fail: |
413 | 0 | sc_pkcs15_free_pubkey(key); |
414 | | |
415 | | /* now parse the DER cert */ |
416 | 0 | return NULL; |
417 | 0 | } |
418 | | |
419 | | |
420 | | static sc_pkcs15_pubkey_t * |
421 | | coolkey_get_public_key_from_certificate(sc_pkcs15_card_t *p15card, sc_cardctl_coolkey_object_t *obj) |
422 | 0 | { |
423 | 0 | sc_pkcs15_cert_info_t cert_info; |
424 | 0 | sc_pkcs15_cert_t *cert_out = NULL; |
425 | 0 | sc_pkcs15_pubkey_t *key = NULL; |
426 | 0 | int r, private_obj; |
427 | 0 | unsigned int flags; |
428 | |
|
429 | 0 | memset(&cert_info, 0, sizeof(cert_info)); |
430 | |
|
431 | 0 | r = coolkey_get_certificate(p15card->card, obj, &cert_info.value); |
432 | 0 | if (r < 0) { |
433 | 0 | goto fail; |
434 | 0 | } |
435 | | |
436 | 0 | coolkey_get_flags(p15card->card, obj, &flags); |
437 | 0 | private_obj = flags & SC_PKCS15_CO_FLAG_PRIVATE; |
438 | 0 | r = sc_pkcs15_read_certificate(p15card, &cert_info, private_obj, &cert_out); |
439 | 0 | if (r < 0) { |
440 | 0 | goto fail; |
441 | 0 | } |
442 | 0 | key = cert_out->key; |
443 | 0 | cert_out->key = NULL; /* adopt the key from the cert */ |
444 | 0 | fail: |
445 | 0 | if (cert_out) { |
446 | 0 | sc_pkcs15_free_certificate(cert_out); |
447 | 0 | } |
448 | 0 | if (cert_info.value.value) { |
449 | 0 | free(cert_info.value.value); |
450 | 0 | } |
451 | 0 | return key; |
452 | 0 | } |
453 | | |
454 | | static sc_pkcs15_pubkey_t * |
455 | | coolkey_get_public_key(sc_pkcs15_card_t *p15card, sc_cardctl_coolkey_object_t *obj, CK_KEY_TYPE key_type) |
456 | 0 | { |
457 | 0 | sc_pkcs15_pubkey_t *key; |
458 | |
|
459 | 0 | key = coolkey_make_public_key(p15card->card, obj, key_type); |
460 | 0 | if (key) { |
461 | 0 | return key; |
462 | 0 | } |
463 | 0 | return coolkey_get_public_key_from_certificate(p15card, obj); |
464 | 0 | } |
465 | | |
466 | | static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card) |
467 | 0 | { |
468 | 0 | int use_pin_cache_backup = p15card->opts.use_pin_cache; |
469 | 0 | static const pindata pins[] = { |
470 | 0 | { "1", NULL, "", 0x00, |
471 | 0 | SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, |
472 | 0 | 32, 4, 32, |
473 | 0 | SC_PKCS15_PIN_FLAG_INITIALIZED, |
474 | 0 | -1, 0xFF, |
475 | 0 | SC_PKCS15_CO_FLAG_PRIVATE }, |
476 | 0 | { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0} |
477 | 0 | }; |
478 | | |
479 | | /* |
480 | | * The size of the key or the algid is not really known |
481 | | * but can be derived from the certificates. |
482 | | * the cert, pubkey and privkey are a set. |
483 | | * Key usages bits taken from certificate key usage extension. |
484 | | */ |
485 | |
|
486 | 0 | int r, i; |
487 | 0 | sc_card_t *card = p15card->card; |
488 | 0 | sc_serial_number_t serial; |
489 | 0 | int count; |
490 | 0 | struct sc_pkcs15_object *obj; |
491 | |
|
492 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
493 | |
|
494 | 0 | memset(&serial, 0, sizeof(serial)); |
495 | | |
496 | | /* coolkey caches a nonce once it logs in, don't keep the pin around. The card will |
497 | | * stay logged in until it's been pulled from the reader, in which case you want to reauthenticate |
498 | | * anyway */ |
499 | 0 | p15card->opts.use_pin_cache = 0; |
500 | | |
501 | | /* get the token info from the card */ |
502 | 0 | r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_GET_TOKEN_INFO, p15card->tokeninfo); |
503 | 0 | if (r < 0) { |
504 | | /* put some defaults in if we didn't succeed */ |
505 | 0 | set_string(&p15card->tokeninfo->label, "Coolkey"); |
506 | 0 | set_string(&p15card->tokeninfo->manufacturer_id, "Unknown"); |
507 | 0 | set_string(&p15card->tokeninfo->serial_number, "00000000"); |
508 | 0 | } |
509 | | |
510 | | /* set pins */ |
511 | 0 | sc_log(card->ctx, "Coolkey adding pins..."); |
512 | 0 | for (i = 0; pins[i].id; i++) { |
513 | 0 | struct sc_pkcs15_auth_info pin_info; |
514 | 0 | struct sc_pkcs15_object pin_obj; |
515 | 0 | const char * label; |
516 | |
|
517 | 0 | memset(&pin_info, 0, sizeof(pin_info)); |
518 | 0 | memset(&pin_obj, 0, sizeof(pin_obj)); |
519 | |
|
520 | 0 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
521 | 0 | sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id); |
522 | 0 | pin_info.attrs.pin.reference = pins[i].ref; |
523 | 0 | pin_info.attrs.pin.flags = pins[i].flags; |
524 | 0 | pin_info.attrs.pin.type = pins[i].type; |
525 | 0 | pin_info.attrs.pin.min_length = pins[i].minlen; |
526 | 0 | pin_info.attrs.pin.stored_length = pins[i].storedlen; |
527 | 0 | pin_info.attrs.pin.max_length = pins[i].maxlen; |
528 | 0 | pin_info.attrs.pin.pad_char = pins[i].pad_char; |
529 | 0 | sc_format_path(pins[i].path, &pin_info.path); |
530 | 0 | pin_info.tries_left = -1; |
531 | |
|
532 | 0 | label = pins[i].label? pins[i].label : p15card->tokeninfo->label; |
533 | 0 | sc_log(card->ctx, "Coolkey Adding pin %d label=%s",i, label); |
534 | 0 | strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1); |
535 | 0 | pin_obj.flags = pins[i].obj_flags; |
536 | |
|
537 | 0 | r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
538 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add pin object."); |
539 | 0 | } |
540 | | |
541 | | /* set other objects */ |
542 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_INIT_GET_OBJECTS, &count); |
543 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate objects."); |
544 | | |
545 | 0 | sc_log(card->ctx, "Iterating over %d objects", count); |
546 | 0 | for (i = 0; i < count; i++) { |
547 | 0 | struct sc_cardctl_coolkey_object coolkey_obj; |
548 | 0 | struct sc_pkcs15_object obj_obj; |
549 | 0 | struct sc_pkcs15_cert_info cert_info = {0}; |
550 | 0 | struct sc_pkcs15_pubkey_info pubkey_info; |
551 | 0 | struct sc_pkcs15_prkey_info prkey_info; |
552 | 0 | sc_pkcs15_pubkey_t *key = NULL; |
553 | 0 | void *obj_info = NULL; |
554 | 0 | int obj_type = 0; |
555 | 0 | CK_KEY_TYPE key_type; |
556 | 0 | CK_OBJECT_CLASS obj_class; |
557 | 0 | size_t len; |
558 | |
|
559 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_GET_NEXT_OBJECT, &coolkey_obj); |
560 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get next object from card."); |
561 | 0 | sc_log(card->ctx, "Loading object %d", i); |
562 | 0 | memset(&obj_obj, 0, sizeof(obj_obj)); |
563 | | /* coolkey applets have label only on the certificates, |
564 | | * but we should copy it also to the keys matching the same ID */ |
565 | 0 | coolkey_get_attribute_bytes(card, &coolkey_obj, CKA_LABEL, (u8 *)obj_obj.label, &len, sizeof(obj_obj.label)); |
566 | 0 | coolkey_get_flags(card, &coolkey_obj, &obj_obj.flags); |
567 | 0 | if (obj_obj.flags & SC_PKCS15_CO_FLAG_PRIVATE) { |
568 | 0 | sc_pkcs15_format_id(pins[0].id, &obj_obj.auth_id); |
569 | 0 | } |
570 | |
|
571 | 0 | r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_CLASS, &obj_class); |
572 | 0 | if (r < 0) { |
573 | 0 | goto fail; |
574 | 0 | } |
575 | 0 | switch (obj_class) { |
576 | 0 | case CKO_PRIVATE_KEY: |
577 | 0 | sc_log(card->ctx, "Processing private key object %d", i); |
578 | 0 | r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_KEY_TYPE, &key_type); |
579 | | /* default to CKK_RSA */ |
580 | 0 | if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) { |
581 | 0 | key_type = CKK_RSA; |
582 | 0 | r = SC_SUCCESS; |
583 | 0 | } |
584 | 0 | if (r < 0) { |
585 | 0 | goto fail; |
586 | 0 | } |
587 | | /* set the info values */ |
588 | 0 | obj_info = &prkey_info; |
589 | 0 | memset(&prkey_info, 0, sizeof(prkey_info)); |
590 | 0 | coolkey_get_id(card, &coolkey_obj, &prkey_info.id); |
591 | 0 | prkey_info.path = coolkey_obj.path; |
592 | 0 | prkey_info.key_reference = (int)coolkey_obj.id; |
593 | 0 | prkey_info.native = 1; |
594 | 0 | coolkey_get_usage(card, &coolkey_obj, &prkey_info.usage); |
595 | 0 | coolkey_get_access(card, &coolkey_obj, &prkey_info.access_flags); |
596 | 0 | key = coolkey_get_public_key(p15card, &coolkey_obj, key_type); |
597 | 0 | if (key_type == CKK_RSA) { |
598 | 0 | obj_type = SC_PKCS15_TYPE_PRKEY_RSA; |
599 | 0 | if (key) { |
600 | 0 | prkey_info.modulus_length = key->u.rsa.modulus.len*8; |
601 | 0 | } |
602 | 0 | } else if (key_type == CKK_EC) { |
603 | 0 | obj_type = SC_PKCS15_TYPE_PRKEY_EC; |
604 | 0 | if (key) { |
605 | 0 | prkey_info.field_length = key->u.ec.params.field_length; |
606 | 0 | } |
607 | 0 | } else { |
608 | 0 | goto fail; |
609 | 0 | } |
610 | 0 | break; |
611 | | |
612 | 0 | case CKO_PUBLIC_KEY: |
613 | 0 | sc_log(card->ctx, "Processing public key object %d", i); |
614 | 0 | r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_KEY_TYPE, &key_type); |
615 | | /* default to CKK_RSA */ |
616 | 0 | if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) { |
617 | 0 | key_type = CKK_RSA; |
618 | 0 | r = SC_SUCCESS; |
619 | 0 | } |
620 | 0 | if (r < 0) { |
621 | 0 | goto fail; |
622 | 0 | } |
623 | 0 | key = coolkey_get_public_key(p15card, &coolkey_obj, key_type); |
624 | 0 | if (key == NULL) { |
625 | 0 | goto fail; |
626 | 0 | } |
627 | | /* set the info values */ |
628 | 0 | obj_info = &pubkey_info; |
629 | 0 | memset(&pubkey_info, 0, sizeof(pubkey_info)); |
630 | 0 | r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, key, &pubkey_info.direct.spki.value, |
631 | 0 | &pubkey_info.direct.spki.len); |
632 | 0 | if (r < 0) |
633 | 0 | goto fail; |
634 | 0 | coolkey_get_id(card, &coolkey_obj, &pubkey_info.id); |
635 | 0 | pubkey_info.path = coolkey_obj.path; |
636 | 0 | pubkey_info.native = 1; |
637 | 0 | pubkey_info.key_reference = (int)coolkey_obj.id; |
638 | 0 | coolkey_get_usage(card, &coolkey_obj, &pubkey_info.usage); |
639 | 0 | coolkey_get_access(card, &coolkey_obj, &pubkey_info.access_flags); |
640 | 0 | if (key_type == CKK_RSA) { |
641 | 0 | obj_type = SC_PKCS15_TYPE_PUBKEY_RSA; |
642 | 0 | pubkey_info.modulus_length = key->u.rsa.modulus.len*8; |
643 | 0 | } else if (key_type == CKK_EC) { |
644 | 0 | obj_type = SC_PKCS15_TYPE_PUBKEY_EC; |
645 | 0 | pubkey_info.field_length = key->u.ec.params.field_length; |
646 | 0 | } else { |
647 | 0 | free(pubkey_info.direct.spki.value); |
648 | 0 | goto fail; |
649 | 0 | } |
650 | | /* set the obj values */ |
651 | 0 | obj_obj.emulated = key; |
652 | 0 | key = NULL; |
653 | 0 | break; |
654 | | |
655 | 0 | case CKO_CERTIFICATE: |
656 | 0 | sc_log(card->ctx, "Processing certificate object %d", i); |
657 | 0 | obj_info = &cert_info; |
658 | 0 | memset(&cert_info, 0, sizeof(cert_info)); |
659 | 0 | coolkey_get_id(card, &coolkey_obj, &cert_info.id); |
660 | 0 | cert_info.path = coolkey_obj.path; |
661 | 0 | obj_type = SC_PKCS15_TYPE_CERT_X509; |
662 | | |
663 | | /* following will find the cached cert in cert_info */ |
664 | 0 | r = coolkey_get_certificate(card, &coolkey_obj, &cert_info.value); |
665 | 0 | if (r < 0) { |
666 | 0 | goto fail; |
667 | 0 | } |
668 | 0 | break; |
669 | | |
670 | | |
671 | 0 | default: |
672 | | /* no other recognized types which are stored 'on card' */ |
673 | 0 | sc_log(card->ctx, "Unknown object type %lu, skipping", obj_class); |
674 | 0 | continue; |
675 | 0 | } |
676 | | |
677 | 0 | r = sc_pkcs15emu_object_add(p15card, obj_type, &obj_obj, obj_info); |
678 | 0 | if (r != SC_SUCCESS) |
679 | 0 | sc_log(card->ctx, "sc_pkcs15emu_object_add() returned %d", r); |
680 | 0 | fail: |
681 | 0 | if (key) { |
682 | 0 | sc_pkcs15_free_pubkey(key); |
683 | 0 | } |
684 | 0 | if (r != SC_SUCCESS) { |
685 | 0 | free(cert_info.value.value); |
686 | 0 | } |
687 | 0 | } |
688 | 0 | r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_FINAL_GET_OBJECTS, &count); |
689 | 0 | LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize objects."); |
690 | | |
691 | | /* Iterate over all the created objects and fill missing labels */ |
692 | 0 | for (obj = p15card->obj_list; obj != NULL; obj = obj->next) { |
693 | 0 | struct sc_pkcs15_id *id = NULL; |
694 | 0 | struct sc_pkcs15_object *cert_object; |
695 | | |
696 | | /* label non-empty -- do not overwrite */ |
697 | 0 | if (obj->label[0] != '\0') |
698 | 0 | continue; |
699 | | |
700 | 0 | switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) { |
701 | 0 | case SC_PKCS15_TYPE_PUBKEY: |
702 | 0 | id = &((struct sc_pkcs15_pubkey_info *)obj->data)->id; |
703 | 0 | break; |
704 | 0 | case SC_PKCS15_TYPE_PRKEY: |
705 | 0 | id = &((struct sc_pkcs15_prkey_info *)obj->data)->id; |
706 | 0 | break; |
707 | 0 | default: |
708 | | /* We do not care about other objects */ |
709 | 0 | continue; |
710 | 0 | } |
711 | 0 | r = sc_pkcs15_find_cert_by_id(p15card, id, &cert_object); |
712 | 0 | if (r != 0) |
713 | 0 | continue; |
714 | | |
715 | 0 | sc_log(card->ctx, "Copy label \"%s\" from cert to key object", |
716 | 0 | cert_object->label); |
717 | 0 | memcpy(obj->label, cert_object->label, SC_PKCS15_MAX_LABEL_SIZE); |
718 | 0 | } |
719 | | |
720 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
721 | | |
722 | 0 | err: |
723 | 0 | sc_pkcs15_card_clear(p15card); |
724 | 0 | p15card->opts.use_pin_cache = use_pin_cache_backup; |
725 | |
|
726 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
727 | 0 | } |
728 | | |
729 | | int |
730 | | sc_pkcs15emu_coolkey_init_ex(sc_pkcs15_card_t *p15card, |
731 | | struct sc_aid *aid) |
732 | 0 | { |
733 | 0 | sc_card_t *card = p15card->card; |
734 | 0 | sc_context_t *ctx = card->ctx; |
735 | 0 | int rv; |
736 | |
|
737 | 0 | LOG_FUNC_CALLED(ctx); |
738 | |
|
739 | 0 | rv = coolkey_detect_card(p15card); |
740 | 0 | if (rv) |
741 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD); |
742 | 0 | rv = sc_pkcs15emu_coolkey_init(p15card); |
743 | |
|
744 | 0 | LOG_FUNC_RETURN(ctx, rv); |
745 | 0 | } |