/src/opensc/src/pkcs15init/pkcs15-myeid.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * MyEID specific operations for PKCS15 initialization |
3 | | * |
4 | | * Copyright (C) 2008-2009 Aventra Ltd. |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include "config.h" |
22 | | |
23 | | #include <assert.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <sys/types.h> |
27 | | |
28 | | #include "libopensc/opensc.h" |
29 | | #include "libopensc/cardctl.h" |
30 | | #include "libopensc/internal.h" |
31 | | #include "libopensc/log.h" |
32 | | #include "pkcs15-init.h" |
33 | | #include "profile.h" |
34 | | #include "libopensc/asn1.h" |
35 | | #include "pkcs11/pkcs11.h" |
36 | | |
37 | | #undef KEEP_AC_NONE_FOR_INIT_APPLET |
38 | | |
39 | 1.64k | #define MYEID_MAX_PINS 14 |
40 | | #define MYEID_MAX_RSA_KEY_LEN 4096 |
41 | | |
42 | | unsigned char MYEID_DEFAULT_PUBKEY[] = {0x01, 0x00, 0x01}; |
43 | 204 | #define MYEID_DEFAULT_PUBKEY_LEN sizeof(MYEID_DEFAULT_PUBKEY) |
44 | | |
45 | 591 | #define MYEID_PROP_INFO_2_EXCTRACTABLE 0x08; |
46 | | #define MYEID_PROP_INFO_1_TRUSTED 0x04; |
47 | | #define MYEID_PROP_INFO_1_WRAP_WITH_TRUSTED 0x08; |
48 | 0 | #define MYEID_PROP_INFO_2_SESSION_OBJECT 0x01; |
49 | | |
50 | | static const struct sc_object_id id_aes128_ecb = { { 2, 16, 840, 1, 101, 3, 4, 1, 1, -1 } }; |
51 | | static const struct sc_object_id id_aes128_cbc = { { 2, 16, 840, 1, 101, 3, 4, 1, 2, -1 } }; |
52 | | static const struct sc_object_id id_aes256_ecb = { { 2, 16, 840, 1, 101, 3, 4, 1, 41, -1 } }; |
53 | | static const struct sc_object_id id_aes256_cbc = { { 2, 16, 840, 1, 101, 3, 4, 1, 42, -1 } }; |
54 | | |
55 | | static void |
56 | | _add_supported_algo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, |
57 | | unsigned operations, unsigned mechanism, const struct sc_object_id *oid); |
58 | | |
59 | | /* For Myeid, all objects are files that can be deleted in any order */ |
60 | | static int |
61 | | myeid_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
62 | 0 | struct sc_pkcs15_object *object, const struct sc_path *path) { |
63 | 0 | LOG_FUNC_CALLED(p15card->card->ctx); |
64 | 0 | return sc_pkcs15init_delete_by_path(profile, p15card, path); |
65 | 0 | } |
66 | | |
67 | | /* |
68 | | * Get 'Initialize Applet' data |
69 | | * using the ACLs defined in card profile. |
70 | | */ |
71 | | static int |
72 | | myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
73 | 1.06k | unsigned char *data, size_t data_len) { |
74 | 1.06k | struct sc_context *ctx = p15card->card->ctx; |
75 | 1.06k | struct sc_file *tmp_file = NULL; |
76 | 1.06k | const struct sc_acl_entry *entry = NULL; |
77 | 1.06k | int r; |
78 | | |
79 | 1.06k | LOG_FUNC_CALLED(ctx); |
80 | | |
81 | 1.06k | if (data_len < 8) |
82 | 1.06k | LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Cannot get init applet data"); |
83 | | |
84 | 1.06k | *(data + 0) = 0xFF; |
85 | 1.06k | *(data + 1) = 0xFF; |
86 | | |
87 | | /* MF acls */ |
88 | 1.06k | sc_file_dup(&tmp_file, profile->mf_info->file); |
89 | 1.06k | if (tmp_file == NULL) |
90 | 1.06k | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate MF file"); |
91 | | |
92 | 1.06k | r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file); |
93 | 1.06k | if (r < 0) |
94 | 19 | sc_file_free(tmp_file); |
95 | 1.06k | LOG_TEST_RET(ctx, r, "MF fixup failed"); |
96 | | |
97 | | /* AC 'Create DF' and 'Create EF' */ |
98 | 1.04k | *(data + 2) = 0x00; /* 'NONE' */ |
99 | 1.04k | entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE); |
100 | 1.04k | if (entry->method == SC_AC_CHV) |
101 | 110 | *(data + 2) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx'. */ |
102 | 935 | else if (entry->method == SC_AC_NEVER) |
103 | 1 | *(data + 2) = 0xFF; /* 'NEVER'. */ |
104 | | |
105 | | /* AC 'INITIALISE APPLET'. */ |
106 | 1.04k | *(data + 3) = 0x0F; /* 'NONE' */ |
107 | 1.04k | #ifndef KEEP_AC_NONE_FOR_INIT_APPLET |
108 | 1.04k | entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE); |
109 | 1.04k | if (entry->method == SC_AC_CHV) |
110 | 171 | *(data + 3) = (entry->key_ref << 4) | 0xF; |
111 | 874 | else if (entry->method == SC_AC_NEVER) |
112 | 1 | *(data + 3) = 0xFF; |
113 | 1.04k | #endif |
114 | 1.04k | *(data + 4) = 0xFF; |
115 | | |
116 | 1.04k | sc_file_free(tmp_file); |
117 | 1.04k | tmp_file = NULL; |
118 | | |
119 | | /* Application DF (5015) acls */ |
120 | 1.04k | sc_file_dup(&tmp_file, profile->df_info->file); |
121 | 1.04k | if (tmp_file == NULL) |
122 | 1.04k | LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate Application DF file"); |
123 | 1.04k | r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file); |
124 | 1.04k | if (r < 0) |
125 | 2 | sc_file_free(tmp_file); |
126 | 1.04k | LOG_TEST_RET(ctx, r, "Application DF fixup failed"); |
127 | | |
128 | | /* AC 'Create DF' and 'Create EF' */ |
129 | 1.04k | *(data + 5) = 0x00; /* 'NONE' */ |
130 | 1.04k | entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE); |
131 | 1.04k | if (entry->method == SC_AC_CHV) |
132 | 103 | *(data + 5) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx' */ |
133 | 940 | else if (entry->method == SC_AC_NEVER) |
134 | 29 | *(data + 5) = 0xFF; /* 'NEVER'. */ |
135 | | |
136 | | /* AC 'Self delete' */ |
137 | 1.04k | *(data + 6) = 0x0F; /* 'NONE' */ |
138 | 1.04k | entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE); |
139 | 1.04k | if (entry->method == SC_AC_CHV) |
140 | 123 | *(data + 6) = (entry->key_ref << 4) | 0xF; /* 'CHVx' */ |
141 | 920 | else if (entry->method == SC_AC_NEVER) |
142 | 4 | *(data + 6) = 0xFF; /* 'NEVER'. */ |
143 | 1.04k | *(data + 7) = 0xFF; |
144 | | |
145 | 1.04k | sc_file_free(tmp_file); |
146 | 1.04k | LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS); |
147 | 1.04k | } |
148 | | |
149 | | /* |
150 | | * Erase the card. |
151 | | */ |
152 | | static int |
153 | 1.06k | myeid_erase_card(struct sc_profile *profile, struct sc_pkcs15_card *p15card) { |
154 | 1.06k | struct sc_context *ctx = p15card->card->ctx; |
155 | 1.06k | struct sc_cardctl_myeid_data_obj data_obj; |
156 | 1.06k | struct sc_file *mf = NULL; |
157 | 1.06k | unsigned char data[8]; |
158 | 1.06k | int r; |
159 | | |
160 | 1.06k | LOG_FUNC_CALLED(ctx); |
161 | | |
162 | 1.06k | r = myeid_get_init_applet_data(profile, p15card, data, sizeof (data)); |
163 | 1.06k | LOG_TEST_RET(ctx, r, "Get init applet date error"); |
164 | | |
165 | | /* Select parent DF and verify PINs/key as necessary */ |
166 | 1.04k | r = sc_select_file(p15card->card, sc_get_mf_path(), &mf); |
167 | 1.04k | LOG_TEST_RET(ctx, r, "Cannot select MF"); |
168 | | |
169 | | /* ACLs are not actives if file is not in the operational state */ |
170 | 30 | if (mf->status == SC_FILE_STATUS_ACTIVATED) |
171 | 16 | r = sc_pkcs15init_authenticate(profile, p15card, mf, SC_AC_OP_DELETE); |
172 | 30 | if (r < 0) |
173 | 2 | sc_file_free(mf); |
174 | 30 | LOG_TEST_RET(ctx, r, "'DELETE' authentication failed on MF"); |
175 | | |
176 | 28 | data_obj.P1 = 0x01; |
177 | 28 | data_obj.P2 = 0xE0; |
178 | 28 | data_obj.Data = data; |
179 | 28 | data_obj.DataLen = sizeof (data); |
180 | | |
181 | 28 | r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj); |
182 | 28 | sc_file_free(mf); |
183 | | |
184 | 28 | LOG_FUNC_RETURN(p15card->card->ctx, r); |
185 | 28 | } |
186 | | |
187 | | |
188 | | |
189 | | static int |
190 | | myeid_init_card(sc_profile_t *profile, |
191 | 509 | sc_pkcs15_card_t *p15card) { |
192 | 509 | struct sc_path path; |
193 | 509 | struct sc_file *file = NULL; |
194 | 509 | u8 rbuf[256]; |
195 | 509 | int r; |
196 | | |
197 | 509 | LOG_FUNC_CALLED(p15card->card->ctx); |
198 | | |
199 | 509 | p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT; |
200 | | |
201 | 509 | _add_supported_algo(profile, p15card, NULL, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_ECB, &id_aes128_ecb); |
202 | 509 | _add_supported_algo(profile, p15card, NULL, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_CBC, &id_aes128_cbc); |
203 | 509 | _add_supported_algo(profile, p15card, NULL, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_ECB, &id_aes256_ecb); |
204 | 509 | _add_supported_algo(profile, p15card, NULL, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_CBC, &id_aes256_cbc); |
205 | | |
206 | 509 | r = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &rbuf); |
207 | 509 | LOG_TEST_RET(p15card->card->ctx, r, "Get applet info failed"); |
208 | | |
209 | 332 | sc_format_path("3F00", &path); |
210 | 332 | r = sc_select_file(p15card->card, &path, &file); |
211 | | |
212 | 332 | sc_file_free(file); |
213 | | |
214 | 332 | LOG_FUNC_RETURN(p15card->card->ctx, r); |
215 | 332 | } |
216 | | |
217 | | /* |
218 | | * Create a DF |
219 | | */ |
220 | | static int |
221 | 329 | myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { |
222 | 329 | struct sc_context *ctx = NULL; |
223 | 329 | struct sc_file *file = NULL; |
224 | 329 | int r = 0, ii; |
225 | 329 | static const char *create_dfs[] = { |
226 | 329 | "PKCS15-PrKDF", |
227 | 329 | "PKCS15-PuKDF", |
228 | 329 | "PKCS15-SKDF", |
229 | 329 | "PKCS15-CDF", |
230 | 329 | "PKCS15-CDF-TRUSTED", |
231 | 329 | "PKCS15-DODF", |
232 | 329 | NULL |
233 | 329 | }; |
234 | | |
235 | 329 | static const int create_dfs_val[] = { |
236 | 329 | SC_PKCS15_PRKDF, |
237 | 329 | SC_PKCS15_PUKDF, |
238 | 329 | SC_PKCS15_SKDF, |
239 | 329 | SC_PKCS15_CDF, |
240 | 329 | SC_PKCS15_CDF_TRUSTED, |
241 | 329 | SC_PKCS15_DODF |
242 | 329 | }; |
243 | | |
244 | 329 | if (!profile || !p15card || !p15card->card || !df) |
245 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
246 | | |
247 | 329 | ctx = p15card->card->ctx; |
248 | 329 | LOG_FUNC_CALLED(ctx); |
249 | 329 | sc_log(ctx, "id (%x)", df->id); |
250 | | |
251 | 329 | if (df->id == 0x5015) { |
252 | 299 | sc_log(ctx, "Select (%x)", df->id); |
253 | 299 | r = sc_select_file(p15card->card, &df->path, NULL); |
254 | | |
255 | 1.32k | for (ii = 0; create_dfs[ii]; ii++) { |
256 | 1.18k | sc_log(ctx, "Create '%s'", create_dfs[ii]); |
257 | | |
258 | 1.18k | file = NULL; |
259 | 1.18k | r = sc_profile_get_file(profile, create_dfs[ii], &file); |
260 | 1.18k | sc_file_free(file); |
261 | 1.18k | if (r) { |
262 | 12 | sc_log(ctx, "Inconsistent profile: cannot find %s", create_dfs[ii]); |
263 | 12 | LOG_FUNC_RETURN(ctx, SC_ERROR_INCONSISTENT_PROFILE); |
264 | 12 | } |
265 | | |
266 | 1.17k | r = sc_pkcs15init_add_object(p15card, profile, create_dfs_val[ii], NULL); |
267 | | |
268 | 1.17k | if (r != SC_ERROR_FILE_ALREADY_EXISTS) |
269 | 1.17k | LOG_TEST_RET(ctx, r, "Failed to create MyEID xDF file"); |
270 | 1.17k | } |
271 | 299 | } |
272 | | |
273 | 176 | LOG_FUNC_RETURN(p15card->card->ctx, r); |
274 | 176 | } |
275 | | |
276 | | /* |
277 | | * Select the PIN reference |
278 | | */ |
279 | | static int |
280 | | myeid_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
281 | 1.46k | sc_pkcs15_auth_info_t *auth_info) { |
282 | 1.46k | SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); |
283 | | |
284 | 1.46k | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
285 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
286 | | |
287 | 1.46k | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
288 | 297 | sc_log(p15card->card->ctx, |
289 | 297 | "PIN_FLAG_SO_PIN, ref (%d), tries_left (%d)", |
290 | 297 | auth_info->attrs.pin.reference, auth_info->tries_left); |
291 | 1.16k | } else { |
292 | 1.16k | sc_log(p15card->card->ctx, |
293 | 1.16k | "PIN_FLAG_PIN, ref (%d), tries_left (%d)", |
294 | 1.16k | auth_info->attrs.pin.reference, auth_info->tries_left); |
295 | | |
296 | 1.16k | } |
297 | | |
298 | 1.46k | if (auth_info->attrs.pin.reference <= 0 || auth_info->attrs.pin.reference > MYEID_MAX_PINS) |
299 | 1.14k | auth_info->attrs.pin.reference = 1; |
300 | | |
301 | 1.46k | LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS); |
302 | 1.46k | } |
303 | | |
304 | | /* |
305 | | * Create a new PIN |
306 | | */ |
307 | | static int |
308 | | myeid_create_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
309 | | struct sc_file *df, struct sc_pkcs15_object *pin_obj, |
310 | | const unsigned char *pin, size_t pin_len, |
311 | 958 | const unsigned char *puk, size_t puk_len) { |
312 | 958 | struct sc_context *ctx = p15card->card->ctx; |
313 | 958 | unsigned char data[20]; |
314 | 958 | struct sc_cardctl_myeid_data_obj data_obj; |
315 | 958 | struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data; |
316 | 958 | struct sc_pkcs15_auth_info puk_ainfo = {0}; |
317 | 958 | int r; |
318 | | |
319 | 958 | LOG_FUNC_CALLED(ctx); |
320 | 958 | sc_log(ctx, |
321 | 958 | "PIN('%s',ref:%i,flags:0x%X,pin_len:%"SC_FORMAT_LEN_SIZE_T"u,puk_len:%"SC_FORMAT_LEN_SIZE_T"u)\n", |
322 | 958 | pin_obj->label, auth_info->attrs.pin.reference, |
323 | 958 | auth_info->attrs.pin.flags, pin_len, puk_len); |
324 | | |
325 | 958 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
326 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
327 | 958 | if (auth_info->attrs.pin.reference >= MYEID_MAX_PINS) |
328 | 1 | return SC_ERROR_INVALID_ARGUMENTS; |
329 | 957 | if (pin == NULL || puk == NULL || pin_len < 4 || puk_len < 4) |
330 | 1 | return SC_ERROR_INVALID_PIN_LENGTH; |
331 | | |
332 | 956 | sc_profile_get_pin_info(profile, (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
333 | 956 | ? SC_PKCS15INIT_SO_PUK : SC_PKCS15INIT_USER_PUK, |
334 | 956 | &puk_ainfo); |
335 | | |
336 | 956 | memset(data, 0, sizeof (data)); |
337 | | /* Make command to add a pin-record */ |
338 | 956 | data_obj.P1 = 0x01; |
339 | 956 | data_obj.P2 = auth_info->attrs.pin.reference; /* myeid pin number */ |
340 | | |
341 | 956 | memset(data, auth_info->attrs.pin.pad_char, 8); |
342 | 956 | memcpy(&data[0], (u8 *) pin, pin_len); /* copy pin */ |
343 | | |
344 | 956 | memset(&data[8], puk_ainfo.attrs.pin.pad_char, 8); |
345 | 956 | memcpy(&data[8], (u8 *) puk, puk_len); /* copy puk */ |
346 | | |
347 | 956 | if (auth_info->tries_left > 0 && auth_info->tries_left < 15) |
348 | 913 | data[16] = auth_info->tries_left; |
349 | 43 | else |
350 | 43 | data[16] = 5; /* default value */ |
351 | | |
352 | 956 | if (puk_ainfo.tries_left > 0 && puk_ainfo.tries_left < 15) |
353 | 947 | data[17] = puk_ainfo.tries_left; |
354 | 9 | else |
355 | 9 | data[17] = 5; /* default value */ |
356 | | |
357 | 956 | data[18] = 0x00; |
358 | | |
359 | 956 | data_obj.Data = data; |
360 | 956 | data_obj.DataLen = 19; |
361 | | |
362 | 956 | r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj); |
363 | 956 | LOG_TEST_RET(ctx, r, "Initialize PIN failed"); |
364 | | |
365 | 379 | LOG_FUNC_RETURN(ctx, r); |
366 | 379 | } |
367 | | |
368 | | /* |
369 | | * Setup file struct & path: get correct template from the profile, construct full path |
370 | | * num = number of objects of this type already on the card |
371 | | */ |
372 | | static int |
373 | | myeid_new_file(sc_profile_t *profile, sc_card_t *card, |
374 | | unsigned int type, unsigned int num, |
375 | 4.21k | sc_file_t **out) { |
376 | 4.21k | sc_file_t *file; |
377 | 4.21k | sc_path_t *p; |
378 | 4.21k | char name[64]; |
379 | 4.21k | const char *tag = NULL; |
380 | 4.21k | int r; |
381 | | |
382 | 4.21k | LOG_FUNC_CALLED(card->ctx); |
383 | 4.21k | switch (type) { |
384 | 590 | case SC_PKCS15_TYPE_PRKEY_RSA: |
385 | 1.14k | case SC_PKCS15_TYPE_PRKEY_EC: |
386 | 1.14k | tag = "private-key"; |
387 | 1.14k | break; |
388 | 0 | case SC_PKCS15_TYPE_PUBKEY_RSA: |
389 | 0 | case SC_PKCS15_TYPE_PUBKEY_EC: |
390 | 0 | tag = "public-key"; |
391 | 0 | break; |
392 | 1.02k | case SC_PKCS15_TYPE_SKEY_GENERIC: |
393 | 2.05k | case SC_PKCS15_TYPE_SKEY_DES: |
394 | 3.07k | case SC_PKCS15_TYPE_SKEY_3DES: |
395 | 3.07k | tag = "secret-key"; |
396 | 3.07k | break; |
397 | 0 | default: |
398 | 0 | if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT) |
399 | 0 | tag = "certificate"; |
400 | 0 | else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_DATA_OBJECT) |
401 | 0 | tag = "data"; |
402 | 0 | break; |
403 | 4.21k | } |
404 | | |
405 | 4.21k | if (!tag) { |
406 | 0 | sc_log(card->ctx, "Unsupported file type"); |
407 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
408 | 0 | } |
409 | | |
410 | | /* Get template from profile */ |
411 | 4.21k | snprintf(name, sizeof (name), "template-%s", tag); |
412 | 4.21k | if (sc_profile_get_file(profile, name, &file) < 0) { |
413 | 3.05k | sc_log(card->ctx, "Profile doesn't define %s", name); |
414 | 3.05k | return SC_ERROR_NOT_SUPPORTED; |
415 | 3.05k | } |
416 | | |
417 | | /* Auto-increment FID for next object */ |
418 | 1.16k | file->id += num; |
419 | 1.16k | p = &file->path; |
420 | 1.16k | *p = profile->df_info->file->path; |
421 | 1.16k | if (p->len >= SC_MAX_PATH_SIZE - 2) { |
422 | 12 | sc_log(card->ctx, "Wrong path length"); |
423 | 12 | sc_file_free(file); |
424 | 12 | return SC_ERROR_INTERNAL; |
425 | 12 | } |
426 | 1.14k | p->value[p->len++] = (u8) (file->id / 256); |
427 | 1.14k | p->value[p->len++] = (u8) (file->id % 256); |
428 | | |
429 | | /* Increment FID until there's no file with such path */ |
430 | 1.14k | r = sc_select_file(card, p, NULL); |
431 | 3.12k | while (r == 0) { |
432 | 1.97k | file->id++; |
433 | 1.97k | p->value[p->len - 2] = (u8) (file->id / 256); |
434 | 1.97k | p->value[p->len - 1] = (u8) (file->id % 256); |
435 | 1.97k | r = sc_select_file(card, p, NULL); |
436 | 1.97k | } |
437 | | |
438 | 1.14k | *out = file; |
439 | 1.14k | LOG_FUNC_RETURN(card->ctx, 0); |
440 | 1.14k | } |
441 | | |
442 | | static int |
443 | | myeid_encode_private_key(sc_profile_t *profile, sc_card_t *card, |
444 | | struct sc_pkcs15_prkey_rsa *rsa, u8 *key, |
445 | 0 | size_t *keysize, int key_ref) { |
446 | 0 | LOG_FUNC_CALLED(card->ctx); |
447 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
448 | 0 | } |
449 | | |
450 | | static int |
451 | | myeid_encode_public_key(sc_profile_t *profile, sc_card_t *card, |
452 | | struct sc_pkcs15_prkey_rsa *rsa, u8 *key, |
453 | 0 | size_t *keysize, int key_ref) { |
454 | 0 | LOG_FUNC_CALLED(card->ctx); |
455 | 0 | LOG_FUNC_RETURN(card->ctx, 0); |
456 | 0 | } |
457 | | |
458 | | /* |
459 | | * Add AlgorithmInfo of a supported algorithm to supportedAlgorithms field in tokenInfo. If object != NULL, |
460 | | * add reference to the algorithmInfo to the passed object. |
461 | | */ |
462 | | static void |
463 | | _add_supported_algo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, |
464 | | unsigned operations, unsigned mechanism, const struct sc_object_id *oid) |
465 | 4.09k | { |
466 | 4.09k | struct sc_supported_algo_info *algo; |
467 | 4.09k | struct sc_context *ctx = p15card->card->ctx; |
468 | 4.09k | if (oid == NULL) { |
469 | 0 | sc_log(ctx, "Failed to add algorithms refs - invalid arguments."); |
470 | 0 | return; |
471 | 0 | } |
472 | 4.09k | algo = sc_pkcs15_get_specific_supported_algo(p15card, operations, mechanism, oid); |
473 | 4.09k | int rv; |
474 | | |
475 | 4.09k | LOG_FUNC_CALLED(ctx); |
476 | 4.09k | if (!algo) { |
477 | 4.02k | unsigned ref = 1, ii; |
478 | | |
479 | 8.43k | for (ii=0;ii<SC_MAX_SUPPORTED_ALGORITHMS && p15card->tokeninfo->supported_algos[ii].reference; ii++) |
480 | 4.41k | if (p15card->tokeninfo->supported_algos[ii].reference >= ref) |
481 | 4.33k | ref = p15card->tokeninfo->supported_algos[ii].reference + 1; |
482 | 4.02k | if (ii < SC_MAX_SUPPORTED_ALGORITHMS) { |
483 | 4.02k | algo = &p15card->tokeninfo->supported_algos[ii]; |
484 | 4.02k | algo->reference = ref; |
485 | 4.02k | algo->mechanism = mechanism; |
486 | 4.02k | algo->operations = operations; |
487 | 4.02k | algo->algo_id = *oid; |
488 | 4.02k | profile->dirty = 1; |
489 | 4.02k | profile->pkcs15.do_last_update = 1; |
490 | 4.02k | } |
491 | | |
492 | 4.02k | } |
493 | 4.09k | if (object != NULL) |
494 | 2.05k | rv = sc_pkcs15_add_supported_algo_ref(object, algo); |
495 | 2.03k | else |
496 | 2.03k | rv = SC_SUCCESS; |
497 | | |
498 | 4.09k | if (rv != SC_SUCCESS) { |
499 | 0 | sc_log(ctx, "Failed to add algorithms refs"); |
500 | 0 | } |
501 | 4.09k | } |
502 | | |
503 | | static void |
504 | | myeid_fixup_supported_algos(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object) |
505 | 4.21k | { |
506 | 4.21k | struct sc_context *ctx = p15card->card->ctx; |
507 | 4.21k | struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data; |
508 | | |
509 | 4.21k | LOG_FUNC_CALLED(ctx); |
510 | 4.21k | switch (object->type) { |
511 | 1.02k | case SC_PKCS15_TYPE_SKEY_GENERIC: |
512 | 1.02k | switch (skey_info->key_type | (skey_info->value_len << 16)) { |
513 | 1.02k | case CKK_AES | (128 << 16): |
514 | 1.02k | _add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_ECB, &id_aes128_ecb); |
515 | 1.02k | _add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_CBC, &id_aes128_cbc); |
516 | 1.02k | break; |
517 | 0 | case CKK_AES | (256 << 16): |
518 | 0 | _add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_ECB, &id_aes256_ecb); |
519 | 0 | _add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_CBC, &id_aes256_cbc); |
520 | 0 | break; |
521 | 1.02k | } |
522 | 1.02k | break; |
523 | 4.21k | } |
524 | 4.21k | } |
525 | | |
526 | | |
527 | | /* |
528 | | * Create a private key file |
529 | | */ |
530 | | static int |
531 | | myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
532 | 4.21k | struct sc_pkcs15_object *object) { |
533 | 4.21k | struct sc_context *ctx = p15card->card->ctx; |
534 | 4.21k | struct sc_card *card = p15card->card; |
535 | 4.21k | struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) object->data; |
536 | 4.21k | struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data; |
537 | 4.21k | struct sc_pkcs15_id *id; |
538 | 4.21k | struct sc_path *path; |
539 | 4.21k | int *key_reference; |
540 | 4.21k | struct sc_file *file = NULL; |
541 | 4.21k | struct sc_pkcs15_object *pin_object = NULL; |
542 | 4.21k | struct sc_pkcs15_auth_info *pkcs15_auth_info = NULL; |
543 | 4.21k | unsigned char sec_attrs[] = {0xFF, 0xFF, 0xFF}; |
544 | 4.21k | int r, ef_structure = 0, pin_reference = -1; |
545 | 4.21k | size_t keybits = 0; |
546 | 4.21k | unsigned char prop_info[] = {0x00, 0x00}; |
547 | 4.21k | int extractable = FALSE; |
548 | | |
549 | 4.21k | LOG_FUNC_CALLED(card->ctx); |
550 | | |
551 | 4.21k | switch (object->type) { |
552 | 590 | case SC_PKCS15_TYPE_PRKEY_RSA: |
553 | 590 | ef_structure = SC_CARDCTL_MYEID_KEY_RSA; |
554 | 590 | keybits = prkey_info->modulus_length; |
555 | 590 | break; |
556 | 551 | case SC_PKCS15_TYPE_PRKEY_EC: |
557 | 551 | ef_structure = SC_CARDCTL_MYEID_KEY_EC; |
558 | 551 | keybits = prkey_info->field_length; |
559 | 551 | break; |
560 | 1.02k | case SC_PKCS15_TYPE_SKEY_DES: |
561 | 2.05k | case SC_PKCS15_TYPE_SKEY_3DES: |
562 | 2.05k | ef_structure = SC_CARDCTL_MYEID_KEY_DES; |
563 | 2.05k | keybits = skey_info->value_len; |
564 | 2.05k | if ((skey_info->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE) == SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE) |
565 | 2.05k | extractable = TRUE; |
566 | 2.05k | break; |
567 | 1.02k | case SC_PKCS15_TYPE_SKEY_GENERIC: |
568 | 1.02k | keybits = skey_info->value_len; |
569 | 1.02k | if ((skey_info->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE) == SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE) |
570 | 1.02k | extractable = TRUE; |
571 | 1.02k | switch (skey_info->key_type) { |
572 | 1.02k | case CKK_AES: |
573 | 1.02k | ef_structure = SC_CARDCTL_MYEID_KEY_AES; |
574 | 1.02k | break; |
575 | 0 | case CKK_DES: |
576 | 0 | ef_structure = SC_CARDCTL_MYEID_KEY_DES; |
577 | 0 | break; |
578 | 0 | default: |
579 | 0 | if (object->type == SC_PKCS15_TYPE_SKEY_GENERIC) |
580 | 0 | ef_structure = SC_CARDCTL_MYEID_KEY_GENERIC_SECRET; |
581 | 0 | break; |
582 | 1.02k | } |
583 | 1.02k | break; |
584 | 4.21k | } |
585 | 4.21k | if (!ef_structure) { |
586 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, |
587 | 0 | "Unsupported key type"); |
588 | 0 | } |
589 | | |
590 | 4.21k | myeid_fixup_supported_algos(profile, p15card, object); |
591 | | |
592 | 4.21k | if ((object->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) { |
593 | 1.14k | id = &prkey_info->id; |
594 | 1.14k | path = &prkey_info->path; |
595 | 1.14k | key_reference = &prkey_info->key_reference; |
596 | 3.07k | } else { |
597 | 3.07k | id = &skey_info->id; |
598 | 3.07k | path = &skey_info->path; |
599 | 3.07k | key_reference = &skey_info->key_reference; |
600 | 3.07k | } |
601 | | |
602 | 4.21k | sc_log(ctx, "create MyEID key ID:%s", sc_pkcs15_print_id(id)); |
603 | | |
604 | | /* Get the private key file */ |
605 | 4.21k | r = myeid_new_file(profile, card, object->type, *key_reference, &file); |
606 | 4.21k | LOG_TEST_RET(ctx, r, "Cannot get new MyEID key file"); |
607 | | |
608 | 1.14k | if (!file || !file->path.len || file->path.len > SC_MAX_PATH_SIZE) { |
609 | 0 | sc_file_free(file); |
610 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot determine key file"); |
611 | 0 | } |
612 | | |
613 | 1.14k | sc_log(ctx, "Key file size %zu", keybits); |
614 | 1.14k | file->size = keybits; |
615 | 1.14k | file->ef_structure = ef_structure; |
616 | | |
617 | 1.14k | memcpy(path->value, &file->path.value, file->path.len); |
618 | 1.14k | *key_reference = file->path.value[file->path.len - 1] & 0xFF; |
619 | | |
620 | 1.14k | sc_log(ctx, "Path of MyEID key file to create %s", |
621 | 1.14k | sc_print_path(&file->path)); |
622 | | |
623 | 1.14k | if (object->auth_id.len >= 1) { |
624 | 1.14k | r = sc_pkcs15_find_pin_by_auth_id(p15card, &object->auth_id, &pin_object); |
625 | | |
626 | 1.14k | if (r != SC_SUCCESS) |
627 | 265 | sc_file_free(file); |
628 | 1.14k | LOG_TEST_RET(ctx, r, "Failed to get pin object by auth_id"); |
629 | | |
630 | 883 | if (pin_object->type != SC_PKCS15_TYPE_AUTH_PIN) { |
631 | 0 | sc_file_free(file); |
632 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, "Invalid object returned when locating pin object."); |
633 | 0 | } |
634 | | |
635 | 883 | pkcs15_auth_info = (struct sc_pkcs15_auth_info*) pin_object->data; |
636 | | |
637 | 883 | if (pkcs15_auth_info == NULL || pkcs15_auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) { |
638 | 0 | sc_file_free(file); |
639 | 0 | LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, "NULL or invalid sc_pkcs15_auth_info in pin object"); |
640 | 0 | } |
641 | | |
642 | 883 | pin_reference = pkcs15_auth_info->attrs.pin.reference; |
643 | | |
644 | 883 | if (pin_reference >= 1 && pin_reference < MYEID_MAX_PINS) { |
645 | 295 | sec_attrs[0] = (pin_reference << 4 | (pin_reference & 0x0F)); |
646 | 295 | sec_attrs[1] = (pin_reference << 4 | (pin_reference & 0x0F)); |
647 | 295 | sc_file_set_sec_attr(file, sec_attrs, sizeof(sec_attrs)); |
648 | 295 | } |
649 | 883 | } |
650 | 0 | else { |
651 | 0 | sc_file_free(file); |
652 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid AuthID value for a private key."); |
653 | 0 | } |
654 | | |
655 | | /* TODO: fill all proprietary attributes here based on the object */ |
656 | | |
657 | 883 | if (object->user_consent != 0 && pin_reference >= 1) |
658 | 0 | prop_info[0] |= (pin_reference << 4); |
659 | | |
660 | 883 | if (extractable) |
661 | 591 | prop_info[1] |= MYEID_PROP_INFO_2_EXCTRACTABLE; |
662 | | |
663 | 883 | if (object->session_object != 0) /* Object will be removed during next reset. */ |
664 | 0 | prop_info[1] |= MYEID_PROP_INFO_2_SESSION_OBJECT; |
665 | | |
666 | | /* TODO: add other flags, like CKA_TRUSTED and CKA_WRAP_WITH_TRUSTED */ |
667 | | |
668 | 883 | r = sc_file_set_prop_attr(file, prop_info, 2); |
669 | 883 | LOG_TEST_RET(ctx, r, "Cannot create MyEID key file"); |
670 | | |
671 | | /* Now create the key file */ |
672 | 883 | r = sc_pkcs15init_create_file(profile, p15card, file); |
673 | 883 | sc_file_free(file); |
674 | 883 | LOG_TEST_RET(ctx, r, "Cannot create MyEID key file"); |
675 | | |
676 | 328 | LOG_FUNC_RETURN(ctx, r); |
677 | 328 | } |
678 | | |
679 | | /* |
680 | | * Store a private key |
681 | | */ |
682 | | static int |
683 | | myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
684 | | struct sc_pkcs15_object *object, |
685 | 177 | struct sc_pkcs15_prkey *prkey) { |
686 | 177 | struct sc_context *ctx = p15card->card->ctx; |
687 | 177 | struct sc_card *card = p15card->card; |
688 | 177 | struct sc_cardctl_myeid_gen_store_key_info args; |
689 | 177 | struct sc_file *file = NULL; |
690 | 177 | struct sc_pkcs15_id *id; |
691 | 177 | struct sc_path *path; |
692 | 177 | int r; |
693 | | |
694 | 177 | LOG_FUNC_CALLED(ctx); |
695 | | |
696 | 177 | if ((object->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) { |
697 | 0 | struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) object->data; |
698 | 0 | id = &prkey_info->id; |
699 | 0 | path = &prkey_info->path; |
700 | 177 | } else { |
701 | 177 | struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data; |
702 | 177 | id = &skey_info->id; |
703 | 177 | path = &skey_info->path; |
704 | 177 | } |
705 | | |
706 | 177 | sc_log(ctx, "store MyEID key with ID:%s and path:%s", |
707 | 177 | sc_pkcs15_print_id(id), sc_print_path(path)); |
708 | | |
709 | 177 | r = sc_select_file(card, path, &file); |
710 | 177 | LOG_TEST_RET(ctx, r, "Cannot store MyEID key: select key file failed"); |
711 | | |
712 | 111 | r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); |
713 | 111 | sc_file_free(file); |
714 | 111 | LOG_TEST_RET(ctx, r, "No authorisation to store MyEID private key"); |
715 | | |
716 | | /* Fill in data structure */ |
717 | 95 | memset(&args, 0, sizeof (args)); |
718 | | |
719 | 95 | args.op_type = OP_TYPE_STORE; |
720 | | |
721 | 95 | switch (object->type) { |
722 | 0 | case SC_PKCS15_TYPE_PRKEY_RSA: |
723 | 0 | args.key_type = SC_CARDCTL_MYEID_KEY_RSA; |
724 | 0 | args.pubexp_len = prkey->u.rsa.exponent.len; |
725 | 0 | args.pubexp = prkey->u.rsa.exponent.data; |
726 | 0 | args.primep_len = prkey->u.rsa.p.len; |
727 | 0 | args.primep = prkey->u.rsa.p.data; |
728 | 0 | args.primeq_len = prkey->u.rsa.q.len; |
729 | 0 | args.primeq = prkey->u.rsa.q.data; |
730 | |
|
731 | 0 | args.dp1_len = prkey->u.rsa.dmp1.len; |
732 | 0 | args.dp1 = prkey->u.rsa.dmp1.data; |
733 | 0 | args.dq1_len = prkey->u.rsa.dmq1.len; |
734 | 0 | args.dq1 = prkey->u.rsa.dmq1.data; |
735 | 0 | args.invq_len = prkey->u.rsa.iqmp.len; |
736 | 0 | args.invq = prkey->u.rsa.iqmp.data; |
737 | | |
738 | | //args.key_len_bits = keybits; |
739 | 0 | args.key_len_bits = prkey->u.rsa.modulus.len; |
740 | 0 | args.mod = prkey->u.rsa.modulus.data; |
741 | 0 | break; |
742 | 0 | case SC_PKCS15_TYPE_PRKEY_EC: |
743 | 0 | args.key_type = SC_CARDCTL_MYEID_KEY_EC; |
744 | 0 | args.d = prkey->u.ec.privateD.data; |
745 | 0 | args.d_len = prkey->u.ec.privateD.len; |
746 | 0 | args.ecpublic_point = prkey->u.ec.ecpointQ.value; |
747 | 0 | args.ecpublic_point_len = prkey->u.ec.ecpointQ.len; |
748 | 0 | args.key_len_bits = prkey->u.ec.params.field_length; |
749 | 0 | break; |
750 | 38 | case SC_PKCS15_TYPE_SKEY_GENERIC: |
751 | 76 | case SC_PKCS15_TYPE_SKEY_DES: |
752 | 76 | case SC_PKCS15_TYPE_SKEY_2DES: |
753 | 95 | case SC_PKCS15_TYPE_SKEY_3DES: |
754 | 95 | switch (prkey->algorithm) { |
755 | 38 | case SC_ALGORITHM_AES: |
756 | 38 | args.key_type = SC_CARDCTL_MYEID_KEY_AES; |
757 | 38 | break; |
758 | 38 | case SC_ALGORITHM_DES: |
759 | 38 | args.key_type = SC_CARDCTL_MYEID_KEY_DES; |
760 | 38 | break; |
761 | 95 | } |
762 | 95 | args.d = prkey->u.secret.data; |
763 | 95 | args.d_len = prkey->u.secret.data_len; |
764 | 95 | break; |
765 | 95 | } |
766 | | /* Store RSA key */ |
767 | 95 | r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args); |
768 | 95 | LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed"); |
769 | | |
770 | 81 | LOG_FUNC_RETURN(ctx, r); |
771 | 81 | } |
772 | | |
773 | | static int |
774 | | myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, |
775 | | struct sc_pkcs15_object *object, |
776 | 151 | struct sc_pkcs15_pubkey *pubkey) { |
777 | 151 | struct sc_context *ctx = p15card->card->ctx; |
778 | 151 | struct sc_card *card = p15card->card; |
779 | 151 | struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data; |
780 | 151 | struct sc_cardctl_myeid_gen_store_key_info args; |
781 | 151 | struct sc_file *file = NULL; |
782 | 151 | int r; |
783 | 151 | unsigned int cla,tag; |
784 | 151 | size_t taglen; |
785 | 151 | unsigned int keybits = (unsigned int)key_info->modulus_length; |
786 | 151 | u8 raw_pubkey[MYEID_MAX_RSA_KEY_LEN / 8]; |
787 | 151 | u8* dataptr; |
788 | | |
789 | 151 | LOG_FUNC_CALLED(ctx); |
790 | 151 | if (object->type != SC_PKCS15_TYPE_PRKEY_RSA && object->type != SC_PKCS15_TYPE_PRKEY_EC) |
791 | 151 | LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: only RSA and EC supported"); |
792 | | |
793 | | /* Check that the card supports the requested modulus length */ |
794 | 151 | switch (object->type) { |
795 | 80 | case SC_PKCS15_TYPE_PRKEY_RSA: |
796 | 80 | if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL) |
797 | 80 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size"); |
798 | 80 | break; |
799 | 80 | case SC_PKCS15_TYPE_PRKEY_EC: |
800 | | /* EC is supported in MyEID v > 3.5. TODO: set correct return value if older MyEID version. */ |
801 | | /* Here the information about curve is not available, that's why supported algorithm is checked |
802 | | without curve OID. */ |
803 | | |
804 | 71 | if(key_info->field_length != 0) |
805 | 71 | keybits = (unsigned int)key_info->field_length; |
806 | 0 | else |
807 | 0 | key_info->field_length = keybits; |
808 | | |
809 | 71 | if (sc_card_find_ec_alg(p15card->card, keybits, NULL) == NULL) |
810 | 71 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); |
811 | | |
812 | 71 | break; |
813 | 71 | default: |
814 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type"); |
815 | 151 | } |
816 | | |
817 | 151 | sc_log(ctx, "Generate key with ID:%s and path:%s", |
818 | 151 | sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path)); |
819 | | |
820 | 151 | r = sc_select_file(card, &key_info->path, &file); |
821 | 151 | LOG_TEST_RET(ctx, r, "Cannot generate key: failed to select key file"); |
822 | | |
823 | 116 | r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_GENERATE); |
824 | 116 | if (r < 0) |
825 | 5 | sc_file_free(file); |
826 | 116 | LOG_TEST_RET(ctx, r, "No authorisation to generate private key"); |
827 | | |
828 | | /* Fill in data structure */ |
829 | 111 | memset(&args, 0, sizeof (args)); |
830 | 111 | args.key_len_bits = keybits; |
831 | 111 | args.op_type = OP_TYPE_GENERATE; |
832 | 111 | if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) { |
833 | 57 | args.key_type = SC_CARDCTL_MYEID_KEY_RSA; |
834 | 57 | args.pubexp_len = MYEID_DEFAULT_PUBKEY_LEN; |
835 | 57 | args.pubexp = MYEID_DEFAULT_PUBKEY; |
836 | 57 | } else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { |
837 | 54 | args.key_type = SC_CARDCTL_MYEID_KEY_EC; |
838 | 54 | } |
839 | | |
840 | | /* Generate the key */ |
841 | 111 | r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args); |
842 | 111 | if (r < 0) |
843 | 11 | sc_file_free(file); |
844 | 111 | LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed"); |
845 | | |
846 | | /* Key pair generation -> collect public key info */ |
847 | 100 | if (pubkey != NULL) { |
848 | 100 | struct sc_cardctl_myeid_data_obj data_obj; |
849 | | |
850 | 100 | if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) { |
851 | 49 | pubkey->algorithm = SC_ALGORITHM_RSA; |
852 | 49 | pubkey->u.rsa.modulus.len = BYTES4BITS(keybits); |
853 | 49 | pubkey->u.rsa.modulus.data = malloc(pubkey->u.rsa.modulus.len); |
854 | 49 | pubkey->u.rsa.exponent.len = MYEID_DEFAULT_PUBKEY_LEN; |
855 | 49 | pubkey->u.rsa.exponent.data = malloc(MYEID_DEFAULT_PUBKEY_LEN); |
856 | 49 | memcpy(pubkey->u.rsa.exponent.data, MYEID_DEFAULT_PUBKEY, MYEID_DEFAULT_PUBKEY_LEN); |
857 | | |
858 | | /* Get public key modulus */ |
859 | 49 | r = sc_select_file(card, &file->path, NULL); |
860 | 49 | sc_file_free(file); |
861 | 49 | file = NULL; |
862 | 49 | LOG_TEST_RET(ctx, r, "Cannot get key modulus: select key file failed"); |
863 | | |
864 | 44 | data_obj.P1 = 0x01; |
865 | 44 | data_obj.P2 = 0x01; |
866 | 44 | data_obj.Data = raw_pubkey; |
867 | 44 | data_obj.DataLen = sizeof (raw_pubkey); |
868 | | |
869 | 44 | r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); |
870 | 44 | LOG_TEST_RET(ctx, r, "Cannot get RSA key modulus: 'MYEID_GETDATA' failed"); |
871 | | |
872 | 36 | if ((data_obj.DataLen * 8) != key_info->modulus_length) |
873 | 36 | LOG_TEST_RET(ctx, SC_ERROR_PKCS15INIT, "Cannot get RSA key modulus: invalid key-size"); |
874 | | |
875 | 13 | memcpy(pubkey->u.rsa.modulus.data, raw_pubkey, pubkey->u.rsa.modulus.len); |
876 | 13 | } |
877 | 51 | else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { |
878 | 51 | struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)key_info->params.data; |
879 | | |
880 | 51 | sc_log(ctx, |
881 | 51 | "curve '%s', len %"SC_FORMAT_LEN_SIZE_T"u, oid '%s'", |
882 | 51 | ecparams->named_curve, ecparams->field_length, |
883 | 51 | sc_dump_oid(&(ecparams->id))); |
884 | 51 | pubkey->algorithm = SC_ALGORITHM_EC; |
885 | | |
886 | 51 | r = sc_select_file(card, &file->path, NULL); |
887 | 51 | sc_file_free(file); |
888 | 51 | file = NULL; |
889 | 51 | LOG_TEST_RET(ctx, r, "Cannot get public key: select key file failed"); |
890 | | |
891 | 49 | data_obj.P1 = 0x01; |
892 | 49 | data_obj.P2 = 0x86; /* Get public EC key (Q) */ |
893 | 49 | data_obj.Data = raw_pubkey; |
894 | 49 | data_obj.DataLen = sizeof (raw_pubkey); |
895 | | |
896 | 49 | r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); |
897 | 49 | LOG_TEST_RET(ctx, r, "Cannot get EC public key: 'MYEID_GETDATA' failed"); |
898 | | |
899 | 42 | dataptr = data_obj.Data; |
900 | 42 | r = sc_asn1_read_tag((const u8 **)&dataptr, data_obj.DataLen, &cla, &tag, &taglen); |
901 | 42 | if (dataptr == NULL) |
902 | 11 | r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; |
903 | 42 | LOG_TEST_RET(ctx, r, "Invalid EC public key data. Cannot parse DER structure."); |
904 | | |
905 | 31 | if (taglen == 0) |
906 | 31 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
907 | | |
908 | 30 | if (pubkey->u.ec.ecpointQ.value) |
909 | 0 | free(pubkey->u.ec.ecpointQ.value); |
910 | | |
911 | 30 | pubkey->u.ec.ecpointQ.value = malloc(taglen); |
912 | | |
913 | 30 | if (pubkey->u.ec.ecpointQ.value == NULL) |
914 | 30 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
915 | | |
916 | 30 | memcpy(pubkey->u.ec.ecpointQ.value, dataptr, taglen); |
917 | 30 | pubkey->u.ec.ecpointQ.len = taglen; |
918 | | |
919 | 30 | if (pubkey->u.ec.params.named_curve) |
920 | 30 | free(pubkey->u.ec.params.named_curve); |
921 | 30 | pubkey->u.ec.params.named_curve = NULL; |
922 | 30 | if (pubkey->u.ec.params.der.value) |
923 | 30 | free(pubkey->u.ec.params.der.value); |
924 | 30 | pubkey->u.ec.params.der.value = NULL; |
925 | 30 | pubkey->u.ec.params.der.len = 0; |
926 | | |
927 | 30 | pubkey->u.ec.params.named_curve = strdup(ecparams->named_curve); |
928 | 30 | if (!pubkey->u.ec.params.named_curve) { |
929 | 0 | free(pubkey->u.ec.ecpointQ.value); |
930 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
931 | 0 | } |
932 | | |
933 | 30 | r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params); |
934 | 30 | if (r < 0) |
935 | 0 | free(pubkey->u.ec.ecpointQ.value); |
936 | 30 | LOG_TEST_RET(ctx, r, "Cannot fix EC parameters"); |
937 | 30 | } |
938 | 100 | } |
939 | | |
940 | 43 | sc_file_free(file); |
941 | | |
942 | 43 | LOG_FUNC_RETURN(ctx, r); |
943 | 43 | } |
944 | | |
945 | | /* Finish initialization. After this ACL is in affect */ |
946 | 1.06k | static int myeid_finalize_card(sc_card_t *card) { |
947 | 1.06k | LOG_FUNC_CALLED(card->ctx); |
948 | 1.06k | LOG_FUNC_RETURN(card->ctx, sc_card_ctl(card, SC_CARDCTL_MYEID_ACTIVATE_CARD, NULL)); |
949 | 1.06k | } |
950 | | |
951 | | |
952 | | /* |
953 | | * Create a new PIN |
954 | | */ |
955 | | static struct sc_pkcs15init_operations sc_pkcs15init_myeid_operations = { |
956 | | myeid_erase_card, |
957 | | myeid_init_card, /* init_card */ |
958 | | myeid_create_dir, /* create_dir */ |
959 | | NULL, /* create_domain */ |
960 | | myeid_select_pin_reference, |
961 | | myeid_create_pin, |
962 | | NULL, /* select_key_reference */ |
963 | | myeid_create_key, |
964 | | myeid_store_key, |
965 | | myeid_generate_key, |
966 | | myeid_encode_private_key, |
967 | | myeid_encode_public_key, |
968 | | myeid_finalize_card, |
969 | | myeid_delete_object, /* delete_object */ |
970 | | NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ |
971 | | NULL /* sanity_check */ |
972 | | }; |
973 | | |
974 | 1.45k | struct sc_pkcs15init_operations *sc_pkcs15init_get_myeid_ops(void) { |
975 | 1.45k | return &sc_pkcs15init_myeid_operations; |
976 | 1.45k | } |