/src/opensc/src/pkcs15init/pkcs15-starcos.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Starcos SPK 2.3 specific operation for PKCS15 initialization |
3 | | * |
4 | | * Copyright (C) 2004 Nils Larsch <larsch@trustcenter.de> |
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 <sys/types.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <assert.h> |
27 | | #include <stdarg.h> |
28 | | |
29 | | #include "libopensc/log.h" |
30 | | #include "libopensc/opensc.h" |
31 | | #include "libopensc/cardctl.h" |
32 | | #include "pkcs15-init.h" |
33 | | #include "profile.h" |
34 | | |
35 | 251 | #define STARCOS_AC_NEVER 0x5f |
36 | 404 | #define STARCOS_AC_ALWAYS 0x9f |
37 | | |
38 | 469 | #define STARCOS_SOPIN_GID 0x01 |
39 | 55 | #define STARCOS_SOPIN_STATE 0x01 |
40 | 1 | #define STARCOS_SOPIN_GAC 0x01 |
41 | 55 | #define STARCOS_SOPIN_LID 0x81 |
42 | 1 | #define STARCOS_SOPIN_LAC 0x11; |
43 | | |
44 | | static int starcos_finalize_card(sc_card_t *card); |
45 | | |
46 | | static int starcos_erase_card(struct sc_profile *pro, sc_pkcs15_card_t *p15card) |
47 | 466 | { |
48 | 466 | return sc_card_ctl(p15card->card, SC_CARDCTL_ERASE_CARD, NULL); |
49 | 466 | } |
50 | | |
51 | | static u8 get_so_ac(const sc_file_t *file, unsigned int op, |
52 | | const sc_pkcs15_auth_info_t *auth, unsigned int def, |
53 | | unsigned int need_global) |
54 | 155 | { |
55 | 155 | int is_global = 1; |
56 | 155 | const sc_acl_entry_t *acl; |
57 | | |
58 | 155 | if (auth->attrs.pin.flags & SC_PKCS15_PIN_FLAG_LOCAL) |
59 | 136 | is_global = 0; |
60 | 155 | if (!is_global && need_global) |
61 | 12 | return def & 0xff; |
62 | 143 | acl = sc_file_get_acl_entry(file, op); |
63 | 143 | if (acl->method == SC_AC_NONE) |
64 | 119 | return STARCOS_AC_ALWAYS; |
65 | 24 | else if (acl->method == SC_AC_NEVER) |
66 | 1 | return STARCOS_AC_NEVER; |
67 | 23 | else if (acl->method == SC_AC_SYMBOLIC) { |
68 | 2 | if (is_global) |
69 | 1 | return STARCOS_SOPIN_GAC; |
70 | 1 | else |
71 | 1 | return STARCOS_SOPIN_LAC; |
72 | 0 | } else |
73 | 21 | return def; |
74 | 143 | } |
75 | | |
76 | | |
77 | | static int starcos_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card) |
78 | 132 | { |
79 | 132 | struct sc_card *card = p15card->card; |
80 | 132 | static const u8 key[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; |
81 | 132 | int ret; |
82 | 132 | sc_starcos_create_data mf_data, ipf_data; |
83 | 132 | sc_file_t *mf_file, *isf_file, *ipf_file; |
84 | 132 | sc_path_t tpath; |
85 | 132 | u8 *p = mf_data.data.mf.header, tmp = 0; |
86 | 132 | sc_pkcs15_auth_info_t sopin = {0}; |
87 | | |
88 | | /* test if we already have a MF */ |
89 | 132 | memset(&tpath, 0, sizeof(sc_path_t)); |
90 | 132 | tpath.value[0] = 0x3f; |
91 | 132 | tpath.value[1] = 0x00; |
92 | 132 | tpath.len = 2; |
93 | 132 | tpath.type = SC_PATH_TYPE_PATH; |
94 | 132 | ret = sc_select_file(card, &tpath, NULL); |
95 | 132 | if (ret == SC_SUCCESS) |
96 | | /* we already have a MF => return OK */ |
97 | 78 | return ret; |
98 | | |
99 | 54 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin); |
100 | | |
101 | | /* get mf profile */ |
102 | 54 | ret = sc_profile_get_file(profile, "MF", &mf_file); |
103 | 54 | if (ret < 0) |
104 | 0 | return ret; |
105 | | /* get size of the isf */ |
106 | 54 | ret = sc_profile_get_file(profile, "mf_isf", &isf_file); |
107 | 54 | if (ret < 0) { |
108 | 51 | sc_file_free(mf_file); |
109 | 51 | return ret; |
110 | 51 | } |
111 | 3 | mf_data.type = SC_STARCOS_MF_DATA; |
112 | 3 | memcpy(p, key, 8); |
113 | 3 | p += 8; |
114 | 3 | *p++ = (mf_file->size >> 8) & 0xff; |
115 | 3 | *p++ = mf_file->size & 0xff; |
116 | 3 | *p++ = (isf_file->size >> 8) & 0xff; |
117 | 3 | *p++ = isf_file->size & 0xff; |
118 | | /* AC CREATE EF */ |
119 | 3 | *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1); |
120 | | /* AC CREATE KEY */ |
121 | 3 | *p++ = get_so_ac(isf_file, SC_AC_OP_WRITE, &sopin, STARCOS_AC_NEVER, 1); |
122 | | /* AC CREATE DF */ |
123 | 3 | *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1); |
124 | | /* AC REGISTER DF */ |
125 | 3 | *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1); |
126 | 3 | *p++ = 0x00; /* SM CR: no */ |
127 | 3 | *p++ = 0x00; /* SM EF: no */ |
128 | 3 | *p = 0x00; /* SM ISF: no */ |
129 | 3 | sc_file_free(mf_file); |
130 | 3 | sc_file_free(isf_file); |
131 | | /* call CREATE MF */ |
132 | 3 | ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &mf_data); |
133 | 3 | if (ret != SC_SUCCESS) |
134 | 2 | return ret; |
135 | | /* create IPF */ |
136 | | /* get size of the ipf */ |
137 | 1 | ret = sc_profile_get_file(profile, "mf_ipf", &ipf_file); |
138 | 1 | if (ret < 0) |
139 | 1 | return ret; |
140 | 0 | ipf_data.type = SC_STARCOS_EF_DATA; |
141 | 0 | p = ipf_data.data.ef.header; |
142 | 0 | *p++ = (ipf_file->id >> 8) & 0xff; |
143 | 0 | *p++ = ipf_file->id & 0xff; |
144 | 0 | *p++ = STARCOS_AC_ALWAYS; /* AC READ: always */ |
145 | | /* AC WRITE IPF */ |
146 | 0 | *p++ = get_so_ac(ipf_file,SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1); |
147 | 0 | *p++ = STARCOS_AC_NEVER; /* AC ERASE */ |
148 | 0 | *p++ = STARCOS_AC_NEVER; /* AC LOCK */ |
149 | 0 | *p++ = STARCOS_AC_NEVER; /* AC UNLOCK */ |
150 | 0 | *p++ = STARCOS_AC_NEVER; /* AC INCREASE */ |
151 | 0 | *p++ = STARCOS_AC_NEVER; /* AC_DECREASE */ |
152 | 0 | *p++ = STARCOS_AC_NEVER; /* RFU */ |
153 | 0 | *p++ = STARCOS_AC_NEVER; /* RFU */ |
154 | 0 | *p++ = 0x00; /* SM */ |
155 | 0 | *p++ = 0x00; /* SID */ |
156 | 0 | *p++ = 0xA1; /* IPF */ |
157 | 0 | *p++ = (ipf_file->size >> 8) & 0xff; |
158 | 0 | *p = ipf_file->size & 0xff; |
159 | 0 | ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &ipf_data); |
160 | 0 | if (ret != SC_SUCCESS) { |
161 | 0 | sc_file_free(ipf_file); |
162 | 0 | return ret; |
163 | 0 | } |
164 | | /* init IPF */ |
165 | 0 | ret = sc_select_file(card, &ipf_file->path, NULL); |
166 | 0 | sc_file_free(ipf_file); |
167 | 0 | if (ret < 0) |
168 | 0 | return ret; |
169 | 0 | ret = sc_update_binary(card, 0, &tmp, 1, 0); |
170 | 0 | if (ret < 0) |
171 | 0 | return ret; |
172 | 0 | return SC_SUCCESS; |
173 | 0 | } |
174 | | |
175 | | static int starcos_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
176 | | sc_file_t *df) |
177 | 78 | { |
178 | 78 | struct sc_card *card = p15card->card; |
179 | 78 | int ret; |
180 | 78 | sc_starcos_create_data df_data, ipf_data; |
181 | 78 | sc_file_t *isf_file, *ipf_file; |
182 | 78 | u8 *p = df_data.data.df.header, tmp = 0; |
183 | 78 | sc_pkcs15_auth_info_t sopin = {0}; |
184 | | |
185 | 78 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin); |
186 | | |
187 | | /* get p15_isf profile */ |
188 | 78 | ret = sc_profile_get_file(profile, "p15_isf", &isf_file); |
189 | 78 | if (ret < 0) |
190 | 20 | return ret; |
191 | | |
192 | 58 | df_data.type = SC_STARCOS_DF_DATA; |
193 | 58 | memset(p, 0, 25); |
194 | 58 | *p++ = (df->id >> 8) & 0xff; |
195 | 58 | *p++ = df->id & 0xff; |
196 | 58 | *p++ = df->namelen & 0xff; |
197 | 58 | memcpy(p, df->name, (u8) df->namelen); |
198 | 58 | p += 16; |
199 | 58 | *p++ = (isf_file->size >> 8) & 0xff; |
200 | 58 | *p++ = isf_file->size & 0xff; |
201 | | /* AC CREATE EF */ |
202 | 58 | *p++ = get_so_ac(df, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 0); |
203 | | /* AC CREATE KEY */ |
204 | 58 | *p++ = get_so_ac(isf_file, SC_AC_OP_WRITE, &sopin, STARCOS_AC_NEVER, 0); |
205 | 58 | *p++ = 0x00; /* SM EF: no */ |
206 | 58 | *p = 0x00; /* SM ISF: no */ |
207 | 58 | df_data.data.df.size[0] = (df->size >> 8) & 0xff; |
208 | 58 | df_data.data.df.size[1] = df->size & 0xff; |
209 | 58 | sc_file_free(isf_file); |
210 | | /* call CREATE DF */ |
211 | 58 | ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &df_data); |
212 | 58 | if (ret != SC_SUCCESS) |
213 | 28 | return ret; |
214 | | /* create IPF */ |
215 | 30 | ret = sc_select_file(card, &df->path, NULL); |
216 | 30 | if (ret != SC_SUCCESS) |
217 | 1 | return ret; |
218 | 29 | ret = sc_profile_get_file(profile, "p15_ipf", &ipf_file); |
219 | 29 | if (ret < 0) |
220 | 2 | return ret; |
221 | 27 | ipf_data.type = SC_STARCOS_EF_DATA; |
222 | 27 | p = ipf_data.data.ef.header; |
223 | 27 | *p++ = (ipf_file->id >> 8) & 0xff; |
224 | 27 | *p++ = ipf_file->id & 0xff; |
225 | 27 | *p++ = STARCOS_AC_ALWAYS; /* AC READ */ |
226 | | /* AC WRITE IPF */ |
227 | 27 | *p++ = get_so_ac(ipf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 0); |
228 | 27 | *p++ = STARCOS_AC_NEVER; /* AC ERASE */ |
229 | 27 | *p++ = STARCOS_AC_NEVER; /* AC LOCK */ |
230 | 27 | *p++ = STARCOS_AC_NEVER; /* AC UNLOCK */ |
231 | 27 | *p++ = STARCOS_AC_NEVER; /* AC INCREASE */ |
232 | 27 | *p++ = STARCOS_AC_NEVER; /* AC_DECREASE */ |
233 | 27 | *p++ = STARCOS_AC_NEVER; /* RFU */ |
234 | 27 | *p++ = STARCOS_AC_NEVER; /* RFU */ |
235 | 27 | *p++ = 0x00; /* SM */ |
236 | 27 | *p++ = 0x00; /* SID */ |
237 | 27 | *p++ = 0xA1; /* IPF */ |
238 | 27 | *p++ = (ipf_file->size >> 8) & 0xff; |
239 | 27 | *p = ipf_file->size & 0xff; |
240 | 27 | ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &ipf_data); |
241 | 27 | if (ret != SC_SUCCESS) { |
242 | 4 | sc_file_free(ipf_file); |
243 | 4 | return ret; |
244 | 4 | } |
245 | | /* init IPF */ |
246 | 23 | ret = sc_select_file(card, &ipf_file->path, NULL); |
247 | 23 | sc_file_free(ipf_file); |
248 | 23 | if (ret < 0) |
249 | 2 | return ret; |
250 | 21 | ret = sc_update_binary(card, 0, &tmp, 1, 0); |
251 | 21 | if (ret < 0) |
252 | 2 | return ret; |
253 | 19 | return SC_SUCCESS; |
254 | 21 | } |
255 | | |
256 | | static int have_onepin(sc_profile_t *profile) |
257 | 503 | { |
258 | 503 | sc_pkcs15_auth_info_t sopin = {0}; |
259 | | |
260 | 503 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin); |
261 | | |
262 | 503 | if (!(sopin.attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)) |
263 | 371 | return 1; |
264 | 132 | else |
265 | 132 | return 0; |
266 | 503 | } |
267 | | |
268 | | /* range of possible key ids for pins (note: the key id of the puk |
269 | | * is the key id of the pin plus one) |
270 | | */ |
271 | 49 | #define STARCOS_MIN_LPIN_ID 0x83 |
272 | 34 | #define STARCOS_MAX_LPIN_ID 0x8f |
273 | 21 | #define STARCOS_MIN_GPIN_ID 0x03 |
274 | 19 | #define STARCOS_MAX_GPIN_ID 0x0f |
275 | | static int starcos_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
276 | | sc_pkcs15_auth_info_t *auth_info) |
277 | 490 | { |
278 | 490 | int tmp; |
279 | | |
280 | 490 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
281 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
282 | | |
283 | 490 | tmp = auth_info->attrs.pin.reference; |
284 | | |
285 | 490 | if (have_onepin(profile)) { |
286 | | /* we have the onepin profile */ |
287 | 359 | auth_info->attrs.pin.reference = STARCOS_SOPIN_GID; |
288 | 359 | return SC_SUCCESS; |
289 | 359 | } |
290 | | |
291 | 131 | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_LOCAL) { |
292 | | /* use local KID */ |
293 | | /* SO-pin */ |
294 | 89 | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
295 | 55 | tmp = STARCOS_SOPIN_LID; |
296 | 34 | else { |
297 | 34 | if (tmp < STARCOS_MIN_LPIN_ID) |
298 | 15 | tmp = STARCOS_MIN_LPIN_ID; |
299 | 34 | if (!(tmp & 0x01)) |
300 | | /* odd KIDs for PINs and even KIDs for PUKs */ |
301 | 12 | tmp++; |
302 | 34 | if (tmp > STARCOS_MAX_LPIN_ID) |
303 | 19 | return SC_ERROR_TOO_MANY_OBJECTS; |
304 | 34 | } |
305 | 89 | } else { |
306 | | /* use global KID */ |
307 | | /* SO-pin */ |
308 | 42 | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
309 | 23 | tmp = STARCOS_SOPIN_GID; |
310 | 19 | else { |
311 | 19 | if (tmp < STARCOS_MIN_GPIN_ID) |
312 | 2 | tmp = STARCOS_MIN_GPIN_ID; |
313 | 19 | if (!(tmp & 0x01)) |
314 | | /* odd KIDs for PINs and even KIDs for PUKs */ |
315 | 13 | tmp++; |
316 | 19 | if (tmp > STARCOS_MAX_GPIN_ID) |
317 | 15 | return SC_ERROR_TOO_MANY_OBJECTS; |
318 | 19 | } |
319 | 42 | } |
320 | 97 | auth_info->attrs.pin.reference = tmp; |
321 | | |
322 | 97 | return SC_SUCCESS; |
323 | 131 | } |
324 | | |
325 | | /* About STARCOS_PINID2STATE |
326 | | * Starcos SPK 2.3 uses a state machine to control the access |
327 | | * to files or keys. This means that the access to a certain |
328 | | * object is granted if the current state (of either the current |
329 | | * DF or the MF) is =, <, >= or != a specified state (see |
330 | | * Starcos S 2.1 manual). To map the pkcs15 access control model |
331 | | *(one object is protected by one pin etc.) to the Starcos S 2.1 |
332 | | * model the following approach is used: |
333 | | * the pin with the key id 3 (or 0x81) sets the global (or local) |
334 | | * state to 15 (note: 16 is the lowest initial state). |
335 | | * the pin with the key id 4 (or 0x82) is reserved for the PUK |
336 | | * the pin with the key id 5 (or 0x83) sets the global (or local) |
337 | | * state to 14. |
338 | | * ... |
339 | | * Note: the key id 1 and 2 (or local 0x81 and 0x82) is used for |
340 | | * the 'SO-pin' which sets the state to 0x01. |
341 | | * XXX: some card operations, like terminate card usage are only |
342 | | * possible in state 0x00 |
343 | | * |
344 | | * Nils |
345 | | */ |
346 | 87 | #define STARCOS_PINID2STATE(a) (((a) == STARCOS_SOPIN_GID) ? STARCOS_SOPIN_STATE : (0x0f - ((0x0f & (a)) >> 1))) |
347 | | |
348 | | static int starcos_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
349 | | sc_file_t *df, sc_pkcs15_object_t *pin_obj, |
350 | | const unsigned char *pin, size_t pin_len, |
351 | | const unsigned char *puk, size_t puk_len) |
352 | 338 | { |
353 | 338 | struct sc_card *card = p15card->card; |
354 | 338 | int r, is_local, pin_id, tmp, need_finalize = 0; |
355 | 338 | size_t akd; |
356 | 338 | sc_file_t *tfile; |
357 | 338 | const sc_acl_entry_t *acl_entry; |
358 | 338 | sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; |
359 | 338 | sc_starcos_wkey_data pin_d, puk_d; |
360 | 338 | u8 tpin[8]; |
361 | | |
362 | 338 | if (!pin || !pin_len || pin_len > 8) |
363 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
364 | | |
365 | 338 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
366 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
367 | | |
368 | 338 | is_local = 0x80 & auth_info->attrs.pin.reference; |
369 | 338 | if (is_local) |
370 | 18 | r = sc_select_file(card, &df->path, NULL); |
371 | 320 | else |
372 | 320 | r = sc_select_file(card, &profile->mf_info->file->path, NULL); |
373 | 338 | if (r < 0) |
374 | 267 | return r; |
375 | | /* get and verify sopin if necessary */ |
376 | 71 | r = sc_profile_get_file(profile, "p15_isf", &tfile); |
377 | 71 | if (r < 0) |
378 | 14 | return r; |
379 | 57 | acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE); |
380 | 57 | if (acl_entry->method != SC_AC_NONE) { |
381 | 13 | if ((auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) || have_onepin(profile)) |
382 | 12 | need_finalize = 1; |
383 | 1 | else |
384 | 1 | r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE); |
385 | 13 | } |
386 | 57 | sc_file_free(tfile); |
387 | 57 | if (r < 0) |
388 | 1 | return r; |
389 | | |
390 | | /* pad pin with 0 */ |
391 | 56 | memset(tpin, 0, 8); |
392 | 56 | memcpy(tpin, pin, pin_len); |
393 | | |
394 | | /* write PIN */ |
395 | 56 | tmp = auth_info->tries_left; |
396 | 56 | pin_id = auth_info->attrs.pin.reference; |
397 | | |
398 | 56 | pin_d.mode = 0; /* install */ |
399 | 56 | pin_d.kid = (u8) pin_id; |
400 | 56 | pin_d.key = tpin; |
401 | 56 | pin_d.key_len = 8; |
402 | 56 | pin_d.key_header[0] = pin_d.kid; |
403 | 56 | pin_d.key_header[1] = 0; |
404 | 56 | pin_d.key_header[2] = 8; |
405 | 56 | pin_d.key_header[3] = STARCOS_AC_ALWAYS; |
406 | 56 | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) |
407 | 3 | pin_d.key_header[4] = STARCOS_SOPIN_STATE; |
408 | 53 | else |
409 | 53 | pin_d.key_header[4] = STARCOS_PINID2STATE(pin_id); |
410 | 56 | pin_d.key_header[5] = STARCOS_AC_ALWAYS; |
411 | 56 | pin_d.key_header[6] = ((0x0f & tmp) << 4) | (0x0f & tmp); |
412 | 56 | pin_d.key_header[7] = 0x00; |
413 | 56 | pin_d.key_header[8] = 0x00; |
414 | 56 | akd = auth_info->attrs.pin.min_length; |
415 | 56 | if (akd < 4) |
416 | 36 | akd = 4; |
417 | 56 | if (akd > 8) |
418 | 1 | akd = 8; |
419 | 56 | akd--; |
420 | 56 | akd |= 0x08; |
421 | 56 | pin_d.key_header[9] = akd; /* AKD: standard + every char != 0 + |
422 | | * pin min length */ |
423 | 56 | pin_d.key_header[10] = 0x00; /* never allow WRITE KEY */ |
424 | 56 | pin_d.key_header[11] = 0x81; /* key attribute: akd + pin */ |
425 | | /* create/write PIN */ |
426 | 56 | r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &pin_d); |
427 | 56 | if (r != SC_SUCCESS) |
428 | 27 | return r; |
429 | | |
430 | 29 | if (puk && puk_len) { |
431 | 27 | sc_pkcs15_auth_info_t puk_info = {0}; |
432 | | |
433 | 27 | if (puk_len > 8) |
434 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
435 | 27 | memset(tpin, 0, 8); |
436 | 27 | memcpy(tpin, puk, puk_len); |
437 | | |
438 | 27 | sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &puk_info); |
439 | 27 | tmp = puk_info.tries_left; |
440 | | |
441 | 27 | puk_d.mode = 0; /* install */ |
442 | 27 | puk_d.kid = (u8) pin_id + 1; |
443 | 27 | puk_d.key = tpin; |
444 | 27 | puk_d.key_len = 8; |
445 | 27 | puk_d.key_header[0] = puk_d.kid; |
446 | 27 | puk_d.key_header[1] = 0; |
447 | 27 | puk_d.key_header[2] = 8; |
448 | 27 | puk_d.key_header[3] = STARCOS_AC_ALWAYS; |
449 | 27 | puk_d.key_header[4] = ((pin_id & 0x1f) << 3) | 0x05; |
450 | 27 | puk_d.key_header[5] = 0x01; |
451 | 27 | puk_d.key_header[6] = ((0x0f & tmp) << 4) | (0x0f & tmp); |
452 | 27 | puk_d.key_header[7] = 0x0; |
453 | 27 | puk_d.key_header[8] = 0x0; |
454 | 27 | puk_d.key_header[9] = 0x0; |
455 | 27 | puk_d.key_header[10] = 0x00; |
456 | 27 | puk_d.key_header[11] = 0x02; |
457 | | /* create/write PUK */ |
458 | 27 | r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &puk_d); |
459 | 27 | if (r != SC_SUCCESS) |
460 | 9 | return r; |
461 | 27 | } |
462 | | |
463 | | /* in case of a global pin: write dummy entry in df isf */ |
464 | 20 | if (!is_local) { |
465 | 18 | r = sc_select_file(card, &df->path, NULL); |
466 | 18 | if (r < 0) |
467 | 6 | return r; |
468 | 12 | pin_d.key = NULL; |
469 | 12 | pin_d.key_len = 0; |
470 | 12 | pin_d.key_header[1] = 0; |
471 | 12 | pin_d.key_header[2] = 0; |
472 | | /* create/write dummy PIN */ |
473 | 12 | r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &pin_d); |
474 | 12 | if (r != SC_SUCCESS) |
475 | 4 | return r; |
476 | 12 | } |
477 | | |
478 | | /* in case of a SOPIN: if AC WRITE KEY is protected by the |
479 | | * SOPIN, call starcos_finalize_card to activate the ACs */ |
480 | 10 | if (need_finalize) |
481 | 4 | r = starcos_finalize_card(card); |
482 | | |
483 | 10 | return r; |
484 | 20 | } |
485 | | |
486 | | /* range of possible key ids for private keys |
487 | | */ |
488 | 924 | #define STARCOS_MIN_LPKEY_ID 0x91 |
489 | 462 | #define STARCOS_MAX_LPKEY_ID 0x9f |
490 | | #define STARCOS_MIN_GPKEY_ID 0x11 |
491 | | #define STARCOS_MAX_GPKEY_ID 0x1f |
492 | | static int starcos_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
493 | | sc_pkcs15_prkey_info_t *prkey) |
494 | 462 | { |
495 | | /* use (local) KIDs 0x91-0x9f for private rsa keys */ |
496 | 462 | if (prkey->key_reference < STARCOS_MIN_LPKEY_ID) |
497 | 462 | prkey->key_reference = STARCOS_MIN_LPKEY_ID; |
498 | 462 | if (prkey->key_reference > STARCOS_MAX_LPKEY_ID) |
499 | 0 | return SC_ERROR_TOO_MANY_OBJECTS; |
500 | 462 | return SC_SUCCESS; |
501 | 462 | } |
502 | | |
503 | 118 | #define STARCOS_MAX_PR_KEYSIZE 370 |
504 | | |
505 | | static int starcos_encode_prkey(struct sc_pkcs15_prkey_rsa *rsa, u8 *buf) |
506 | 0 | { |
507 | 0 | size_t i = 0; |
508 | 0 | u8 *p = buf; |
509 | | |
510 | | /* clear key buffer */ |
511 | 0 | memset(buf, 0, STARCOS_MAX_PR_KEYSIZE); |
512 | |
|
513 | 0 | if (rsa->p.len && rsa->q.len && rsa->dmp1.len && |
514 | 0 | rsa->dmq1.len && rsa->iqmp.len) { |
515 | | /* CRT RSA key */ |
516 | | /* get number of 0x00 bytes */ |
517 | 0 | i = STARCOS_MAX_PR_KEYSIZE - rsa->p.len - rsa->q.len - |
518 | 0 | rsa->dmp1.len - rsa->dmq1.len - 45 - rsa->p.len; |
519 | | |
520 | | /* key format list */ |
521 | 0 | *p++ = 0x0c; |
522 | 0 | *p++ = 0x91; |
523 | 0 | *p++ = (u8) rsa->p.len; |
524 | 0 | *p++ = 0x92; |
525 | 0 | *p++ = (u8) rsa->q.len; |
526 | 0 | *p++ = 0x94; |
527 | 0 | *p++ = (u8) rsa->dmp1.len + 16; |
528 | 0 | *p++ = 0x95; |
529 | 0 | *p++ = (u8) rsa->dmq1.len + 16; |
530 | 0 | *p++ = 0x97; |
531 | 0 | *p++ = (u8) rsa->p.len; |
532 | 0 | *p++ = 0x00; |
533 | 0 | *p++ = (u8) i; |
534 | | /* copy key components */ |
535 | 0 | for (i = rsa->q.len; i != 0; i--) |
536 | 0 | *p++ = rsa->q.data[i - 1]; |
537 | 0 | for (i = rsa->p.len; i != 0; i--) |
538 | 0 | *p++ = rsa->p.data[i - 1]; |
539 | 0 | for (i = 16; i != 0; i--) |
540 | 0 | *p++ = 0x00; |
541 | 0 | for (i = rsa->dmp1.len; i != 0; i--) |
542 | 0 | *p++ = rsa->dmq1.data[i - 1]; |
543 | 0 | for (i = 16; i != 0; i--) |
544 | 0 | *p++ = 0x00; |
545 | 0 | for (i = rsa->dmq1.len; i != 0; i--) |
546 | 0 | *p++ = rsa->dmp1.data[i - 1]; |
547 | 0 | for (i = rsa->iqmp.len; i != 0; i--) |
548 | 0 | *p++ = rsa->iqmp.data[i - 1]; |
549 | 0 | for (i = rsa->p.len - rsa->iqmp.len; i != 0; i--) |
550 | 0 | *p++ = 0x00; |
551 | 0 | } else if (rsa->modulus.len && rsa->d.len) { |
552 | | /* normal RSA key */ |
553 | 0 | i = STARCOS_MAX_PR_KEYSIZE - 7 - rsa->modulus.len |
554 | 0 | - rsa->d.len - 16; |
555 | | /* key format list */ |
556 | 0 | *p++ = 6; |
557 | 0 | *p++ = 0x90; |
558 | 0 | *p++ = (u8) rsa->modulus.len; |
559 | 0 | *p++ = 0x93; |
560 | 0 | *p++ = (u8) rsa->d.len + 16; |
561 | 0 | *p++ = 0x00; |
562 | 0 | *p++ = (u8) i; |
563 | | /* copy key components */ |
564 | 0 | for (i = rsa->modulus.len; i != 0; i--) |
565 | 0 | *p++ = rsa->modulus.data[i - 1]; |
566 | 0 | for (i = 16; i != 0; i--) |
567 | 0 | *p++ = 0x00; |
568 | 0 | for (i = rsa->d.len; i != 0; i--) |
569 | 0 | *p++ = rsa->d.data[i - 1]; |
570 | 0 | } else |
571 | 0 | return SC_ERROR_INTERNAL; |
572 | | |
573 | 0 | return SC_SUCCESS; |
574 | 0 | } |
575 | | |
576 | | /* XXX the whole IPF stuff doesn't really work very well */ |
577 | | /** starcos_ipf_get_lastpos |
578 | | * returns the offset to the first byte after the last key |
579 | | */ |
580 | | static size_t starcos_ipf_get_lastpos(u8 *ipf, size_t ipf_len) |
581 | 0 | { |
582 | 0 | size_t num_keys, tmp; |
583 | 0 | u8 *p = ipf; |
584 | |
|
585 | 0 | if (!ipf || ipf_len < 13) |
586 | 0 | return 0; |
587 | 0 | num_keys = *p++; /* the first bytes contains the number of keys*/ |
588 | 0 | if (num_keys == 0xff) |
589 | 0 | num_keys = 0; |
590 | 0 | if (!num_keys) |
591 | 0 | return 1; |
592 | 0 | while (num_keys--) { |
593 | 0 | size_t offset = p - ipf; /* note: p > ipf */ |
594 | | /* get offset to the next key header */ |
595 | 0 | tmp = 12 + (p[1] << 8) + p[2]; |
596 | 0 | if (tmp + offset > ipf_len) |
597 | 0 | return 0; |
598 | 0 | p += tmp; |
599 | 0 | } |
600 | | |
601 | 0 | return p - ipf; |
602 | 0 | } |
603 | | |
604 | | static int starcos_encode_pukey(struct sc_pkcs15_prkey_rsa *rsa, u8 *buf, |
605 | | sc_pkcs15_prkey_info_t *kinfo) |
606 | 0 | { |
607 | 0 | size_t i = 0; |
608 | 0 | u8 *p = buf; |
609 | | |
610 | | /* if rsa == NULL return key header for key generation */ |
611 | 0 | if (!rsa) { |
612 | 0 | if (!buf) |
613 | | /* if buf == NULL return length of the encoded key */ |
614 | 0 | return 12 + (int)(kinfo->modulus_length >> 3); |
615 | 0 | *p++ = 0x06; /* length key header */ |
616 | 0 | *p++ = 0x01; /* CHA byte */ |
617 | 0 | *p++ = 0x01; |
618 | 0 | *p++ = 0x10; /* RSA: n */ |
619 | 0 | *p++ = (kinfo->modulus_length >> 3) & 0xff; |
620 | 0 | *p++ = 0x13; /* RSA: e */ |
621 | 0 | *p++ = 0x04; |
622 | 0 | *p = (u8) kinfo->key_reference; /* CHA byte */ |
623 | 0 | } else { |
624 | | /* encode normal public key */ |
625 | 0 | int mod_len = (int)rsa->modulus.len & 0xff, |
626 | 0 | exp_len = (int)rsa->exponent.len & 0xff; |
627 | |
|
628 | 0 | if (!buf) |
629 | 0 | return 8 + mod_len + exp_len + 1; |
630 | | |
631 | 0 | *p++ = 0x06; /* length key header */ |
632 | 0 | *p++ = 0x01; /* CHA byte */ |
633 | 0 | *p++ = 0x01; |
634 | 0 | *p++ = 0x10; /* RSA: n */ |
635 | 0 | *p++ = mod_len; |
636 | 0 | *p++ = 0x13; /* RSA: e */ |
637 | 0 | *p++ = exp_len + 1; |
638 | 0 | *p++ = (u8) kinfo->key_reference; /* CHA byte */ |
639 | | /* copy modulus */ |
640 | 0 | for (i = mod_len; i != 0; i--) |
641 | 0 | *p++ = rsa->modulus.data[i - 1]; |
642 | | /* copy exponent */ |
643 | 0 | for (i = exp_len; i != 0; i--) |
644 | 0 | *p++ = rsa->exponent.data[i - 1]; |
645 | 0 | *p = 0x00; |
646 | 0 | } |
647 | 0 | return SC_SUCCESS; |
648 | 0 | } |
649 | | |
650 | | static int starcos_write_pukey(sc_profile_t *profile, sc_card_t *card, |
651 | | struct sc_pkcs15_prkey_rsa *rsa, sc_pkcs15_prkey_info_t *kinfo) |
652 | 13 | { |
653 | 13 | int r; |
654 | 13 | size_t len, keylen, endpos; |
655 | 13 | u8 *buf, key[280], *p, num_keys; |
656 | 13 | sc_file_t *tfile = NULL; |
657 | 13 | sc_path_t tpath; |
658 | | |
659 | | /* get ipf profile */ |
660 | 13 | tpath = kinfo->path; |
661 | 13 | r = sc_profile_get_file_in(profile, &tpath, "p15_ipf", &tfile); |
662 | 13 | if (r < 0) |
663 | 11 | return r; |
664 | 2 | tpath = tfile->path; |
665 | 2 | sc_file_free(tfile); |
666 | 2 | tfile = NULL; |
667 | 2 | r = sc_select_file(card, &tpath, &tfile); |
668 | 2 | if (r != SC_SUCCESS) |
669 | | /* unable to select ipf */ |
670 | 1 | return r; |
671 | 1 | len = tfile->size; |
672 | 1 | sc_file_free(tfile); |
673 | 1 | if (len == 0) |
674 | 1 | return SC_ERROR_INTERNAL; |
675 | 0 | buf = malloc(len); |
676 | 0 | if (!buf) |
677 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
678 | | /* read the complete IPF */ |
679 | 0 | r = sc_read_binary(card, 0, buf, len, 0); |
680 | 0 | if (r < 0 || r != (int)len) { |
681 | 0 | free(buf); |
682 | 0 | return r; |
683 | 0 | } |
684 | | /* get/fix number of keys */ |
685 | 0 | num_keys = buf[0]; |
686 | 0 | if (num_keys == 0xff) |
687 | 0 | num_keys = 0; |
688 | | /* encode public key */ |
689 | 0 | keylen = starcos_encode_pukey(rsa, NULL, kinfo); |
690 | 0 | if (!keylen) { |
691 | 0 | free(buf); |
692 | 0 | return SC_ERROR_INTERNAL; |
693 | 0 | } |
694 | 0 | p = key; |
695 | 0 | *p++ = (u8) kinfo->key_reference; |
696 | 0 | *p++ = (keylen >> 8) & 0xff; |
697 | 0 | *p++ = keylen & 0xff; |
698 | 0 | *p++ = STARCOS_AC_ALWAYS; /* AC WRITE etc XXX */ |
699 | 0 | *p++ = 0x0f; |
700 | 0 | *p++ = 0; |
701 | 0 | *p++ = 0x09; /* ALGO XXX */ |
702 | 0 | *p++ = 0x4a; /* AKD XXX */ |
703 | 0 | *p++ = ((keylen >> 8) & 0xff) | 0x80; |
704 | 0 | *p++ = keylen & 0xff; |
705 | 0 | r = starcos_encode_pukey(rsa, p, kinfo); |
706 | 0 | if (r != SC_SUCCESS) { |
707 | 0 | free(buf); |
708 | 0 | return SC_ERROR_INTERNAL; |
709 | 0 | } |
710 | 0 | p += keylen; |
711 | 0 | *p++ = 0x04; /* CPI */ |
712 | 0 | *p = (u8) kinfo->key_reference; /* CHA */ |
713 | | /* updated IPF (XXX: currently append only) */ |
714 | 0 | num_keys++; |
715 | 0 | r = sc_update_binary(card, 0, &num_keys, 1, 0); |
716 | 0 | if (r < 0) { |
717 | 0 | free(buf); |
718 | 0 | return r; |
719 | 0 | } |
720 | 0 | endpos = starcos_ipf_get_lastpos(buf, len); |
721 | 0 | free(buf); |
722 | 0 | return sc_update_binary(card, (unsigned)endpos, key, keylen + 12, 0); |
723 | 0 | } |
724 | | |
725 | | static int starcos_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
726 | | sc_pkcs15_object_t *obj) |
727 | 462 | { |
728 | 462 | struct sc_card *card = p15card->card; |
729 | 462 | int r, pin_id; |
730 | 462 | u8 akd = 0, state; |
731 | | |
732 | 462 | sc_file_t *tfile; |
733 | 462 | const sc_acl_entry_t *acl_entry; |
734 | 462 | sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *)obj->data; |
735 | 462 | sc_starcos_wkey_data tkey; |
736 | | |
737 | | /* get and verify sopin if necessary */ |
738 | 462 | r = sc_profile_get_file(profile, "p15_isf", &tfile); |
739 | 462 | if (r < 0) |
740 | 283 | return r; |
741 | 179 | acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE); |
742 | 179 | if (acl_entry->method != SC_AC_NONE) { |
743 | 140 | r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE); |
744 | 140 | } |
745 | 39 | else { |
746 | 39 | r = sc_select_file(card, &tfile->path, NULL); |
747 | 39 | } |
748 | 179 | sc_file_free(tfile); |
749 | 179 | if (r < 0) |
750 | 120 | return r; |
751 | | |
752 | | /* create sc_starcos_wkey_data */ |
753 | 59 | tkey.mode = 0x00; /* install new key */ |
754 | 59 | tkey.kid = (u8) kinfo->key_reference; |
755 | 59 | tkey.key_header[0] = (u8) kinfo->key_reference; |
756 | 59 | tkey.key_header[1] = (STARCOS_MAX_PR_KEYSIZE >> 8) & 0xff; |
757 | 59 | tkey.key_header[2] = STARCOS_MAX_PR_KEYSIZE & 0xff; |
758 | | |
759 | 59 | pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC, |
760 | 59 | SC_PKCS15INIT_USER_PIN); |
761 | 59 | if (pin_id < 0) |
762 | 25 | state = STARCOS_AC_ALWAYS; |
763 | 34 | else { |
764 | 34 | state = STARCOS_PINID2STATE(pin_id); /* get the necessary state */ |
765 | 34 | state |= pin_id & 0x80 ? 0x10 : 0x00; /* local vs. global key id */ |
766 | 34 | } |
767 | 59 | tkey.key_header[3] = state; /* AC to access key */ |
768 | 59 | if (obj->user_consent) |
769 | 0 | tkey.key_header[4] = 0x0f; /* do state transition */ |
770 | 59 | else |
771 | 59 | tkey.key_header[4] = 0x8f; /* no state transition */ |
772 | 59 | tkey.key_header[5] = 0x11; /* require local state == 1 to update key */ |
773 | 59 | tkey.key_header[6] = 0x33; |
774 | 59 | tkey.key_header[7] = 0x00; |
775 | 59 | tkey.key_header[8] = 0x09; |
776 | 59 | if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) |
777 | 0 | akd |= 0x10; |
778 | 59 | if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_SIGN) |
779 | 59 | akd |= 0x31; /* allow DS, IA and PKCS11 */ |
780 | 59 | if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_SIGNRECOVER) |
781 | 0 | akd |= 0x31; /* allow DS, IA and PKCS11 */ |
782 | 59 | if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_DECRYPT || |
783 | 59 | kinfo->usage & SC_PKCS15_PRKEY_USAGE_UNWRAP) |
784 | 0 | akd |= 0x02; |
785 | 59 | tkey.key_header[9] = akd; |
786 | 59 | tkey.key_header[10] = 0x03; |
787 | 59 | tkey.key_header[11] = 0xa0; |
788 | 59 | tkey.key = NULL; |
789 | 59 | tkey.key_len = 0; |
790 | | |
791 | 59 | return sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &tkey); |
792 | 179 | } |
793 | | |
794 | | static int starcos_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
795 | | sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) |
796 | 0 | { |
797 | 0 | int r; |
798 | 0 | u8 key_buf[STARCOS_MAX_PR_KEYSIZE]; |
799 | |
|
800 | 0 | sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; |
801 | 0 | const sc_acl_entry_t *acl_entry; |
802 | 0 | sc_file_t *tfile; |
803 | 0 | struct sc_pkcs15_prkey_rsa *rsa = &key->u.rsa; |
804 | 0 | sc_starcos_wkey_data tkey; |
805 | |
|
806 | 0 | if (key->algorithm != SC_ALGORITHM_RSA) |
807 | | /* ignore non-RSA keys */ |
808 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
809 | | |
810 | | /* create sc_starcos_wkey_data */ |
811 | 0 | if (starcos_encode_prkey(rsa, key_buf)) |
812 | 0 | return SC_ERROR_INTERNAL; |
813 | | |
814 | | /* get and verify sopin if necessary */ |
815 | 0 | r = sc_profile_get_file(profile, "p15_isf", &tfile); |
816 | 0 | if (r < 0) |
817 | 0 | return r; |
818 | 0 | acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE); |
819 | 0 | if (acl_entry->method != SC_AC_NONE) { |
820 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE); |
821 | 0 | } |
822 | 0 | sc_file_free(tfile); |
823 | 0 | if (r < 0) |
824 | 0 | return r; |
825 | | |
826 | 0 | tkey.mode = 0x01; /* update key */ |
827 | 0 | tkey.kid = (u8) kinfo->key_reference; |
828 | 0 | tkey.key = key_buf; |
829 | 0 | tkey.key_len = STARCOS_MAX_PR_KEYSIZE; |
830 | |
|
831 | 0 | r = sc_card_ctl(p15card->card, SC_CARDCTL_STARCOS_WRITE_KEY, &tkey); |
832 | 0 | if (r != SC_SUCCESS) |
833 | 0 | return r; |
834 | | /* store public key in the IPF */ |
835 | 0 | return starcos_write_pukey(profile, p15card->card, rsa, kinfo); |
836 | 0 | } |
837 | | |
838 | | static int starcos_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
839 | | sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) |
840 | 15 | { |
841 | 15 | int r; |
842 | 15 | const sc_acl_entry_t *acl_entry; |
843 | 15 | sc_file_t *tfile; |
844 | 15 | sc_starcos_gen_key_data gendat; |
845 | 15 | sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; |
846 | | |
847 | 15 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) |
848 | 0 | return SC_ERROR_NOT_SUPPORTED; |
849 | | |
850 | | /* get and verify sopin if necessary */ |
851 | 15 | r = sc_profile_get_file(profile, "p15_isf", &tfile); |
852 | 15 | if (r < 0) |
853 | 0 | return r; |
854 | 15 | acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE); |
855 | 15 | if (acl_entry->method != SC_AC_NONE) { |
856 | 11 | r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE); |
857 | 11 | } |
858 | 15 | sc_file_free(tfile); |
859 | 15 | if (r < 0) |
860 | 2 | return r; |
861 | | |
862 | | /* XXX It would be better to write the public key header |
863 | | * in the IPF when the private key header is created, but |
864 | | * as we don't know the size of the exponent at this time |
865 | | * we would waste space. |
866 | | */ |
867 | | /* create (empty) public key entry */ |
868 | 13 | r = starcos_write_pukey(profile, p15card->card, NULL, kinfo); |
869 | 13 | if (r < 0) |
870 | 13 | return r; |
871 | | /* generate key pair */ |
872 | 0 | gendat.key_id = (u8) kinfo->key_reference; |
873 | 0 | gendat.key_length = (size_t) kinfo->modulus_length; |
874 | 0 | gendat.modulus = NULL; |
875 | 0 | r = sc_card_ctl(p15card->card, SC_CARDCTL_STARCOS_GENERATE_KEY, &gendat); |
876 | 0 | if (r != SC_SUCCESS) |
877 | 0 | return r; |
878 | | /* get the modulus via READ PUBLIC KEY */ |
879 | 0 | if (pubkey) { |
880 | 0 | u8 *buf; |
881 | 0 | struct sc_pkcs15_pubkey_rsa *rsa = &pubkey->u.rsa; |
882 | | /* set the modulus */ |
883 | 0 | rsa->modulus.data = gendat.modulus; |
884 | 0 | rsa->modulus.len = kinfo->modulus_length >> 3; |
885 | | /* set the exponent (always 0x10001) */ |
886 | 0 | buf = malloc(3); |
887 | 0 | if (!buf) |
888 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
889 | 0 | buf[0] = 0x01; |
890 | 0 | buf[1] = 0x00; |
891 | 0 | buf[2] = 0x01; |
892 | 0 | rsa->exponent.data = buf; |
893 | 0 | rsa->exponent.len = 3; |
894 | |
|
895 | 0 | pubkey->algorithm = SC_ALGORITHM_RSA; |
896 | 0 | } else |
897 | | /* free public key */ |
898 | 0 | free(gendat.modulus); |
899 | | |
900 | 0 | return SC_SUCCESS; |
901 | 0 | } |
902 | | |
903 | | static int starcos_finalize_card(sc_card_t *card) |
904 | 470 | { |
905 | 470 | int r; |
906 | 470 | sc_file_t tfile; |
907 | 470 | sc_path_t tpath; |
908 | | |
909 | | /* SELECT FILE MF */ |
910 | 470 | sc_format_path("3F00", &tpath); |
911 | 470 | r = sc_select_file(card, &tpath, NULL); |
912 | 470 | if (r < 0) |
913 | 410 | return r; |
914 | | |
915 | | /* call CREATE END for the MF (ignore errors) */ |
916 | 60 | tfile.type = SC_FILE_TYPE_DF; |
917 | 60 | tfile.id = 0x3f00; |
918 | 60 | r = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_END, &tfile); |
919 | 60 | if (r < 0) |
920 | 33 | sc_log(card->ctx, "failed to call CREATE END for the MF\n"); |
921 | | /* call CREATE END for the apps (pkcs15) DF */ |
922 | 60 | tfile.type = SC_FILE_TYPE_DF; |
923 | 60 | tfile.id = 0x5015; |
924 | 60 | r = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_END, &tfile); |
925 | 60 | if (r == SC_ERROR_NOT_ALLOWED) |
926 | | /* card is already finalized */ |
927 | 1 | return SC_SUCCESS; |
928 | 59 | return r; |
929 | 60 | } |
930 | | |
931 | | static struct sc_pkcs15init_operations sc_pkcs15init_starcos_operations = { |
932 | | starcos_erase_card, |
933 | | starcos_init_card, |
934 | | starcos_create_dir, |
935 | | NULL, /* create_domain */ |
936 | | starcos_pin_reference, |
937 | | starcos_create_pin, |
938 | | starcos_key_reference, |
939 | | starcos_create_key, |
940 | | starcos_store_key, |
941 | | starcos_generate_key, |
942 | | NULL, NULL, /* encode private/public key */ |
943 | | starcos_finalize_card, |
944 | | NULL, /* delete_object */ |
945 | | NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ |
946 | | NULL /* sanity_check */ |
947 | | }; |
948 | | |
949 | | struct sc_pkcs15init_operations *sc_pkcs15init_get_starcos_ops(void) |
950 | 1.19k | { |
951 | 1.19k | return &sc_pkcs15init_starcos_operations; |
952 | 1.19k | } |