/src/opensc/src/pkcs15init/pkcs15-muscle.c
Line | Count | Source |
1 | | /* |
2 | | * pkcs15-muscle.c: Support for MuscleCard Applet from musclecard.com |
3 | | * |
4 | | * Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com> |
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 | | #ifdef HAVE_UNISTD_H |
29 | | #include <unistd.h> |
30 | | #endif |
31 | | |
32 | | #include "libopensc/pkcs15.h" |
33 | | #include "libopensc/opensc.h" |
34 | | #include "libopensc/cardctl.h" |
35 | | #include "libopensc/cards.h" |
36 | | #include "libopensc/log.h" |
37 | | #include "pkcs15-init.h" |
38 | | #include "profile.h" |
39 | | |
40 | 0 | #define MUSCLE_KEY_ID_MIN 0x00 |
41 | 0 | #define MUSCLE_KEY_ID_MAX 0x0F |
42 | | |
43 | | static int muscle_erase_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card) |
44 | 0 | { |
45 | 0 | int r; |
46 | 0 | struct sc_file *file; |
47 | 0 | struct sc_path path; |
48 | 0 | memset(&file, 0, sizeof(file)); |
49 | 0 | sc_format_path("3F00", &path); |
50 | 0 | if ((r = sc_select_file(p15card->card, &path, &file)) < 0) |
51 | 0 | return r; |
52 | 0 | if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_ERASE)) < 0) { |
53 | 0 | sc_file_free(file); |
54 | 0 | return r; |
55 | 0 | } |
56 | 0 | sc_file_free(file); |
57 | 0 | if ((r = sc_delete_file(p15card->card, &path)) < 0) |
58 | 0 | return r; |
59 | 0 | return 0; |
60 | 0 | } |
61 | | |
62 | | |
63 | | static int muscle_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card) |
64 | 0 | { |
65 | 0 | return 0; |
66 | 0 | } |
67 | | |
68 | | static int |
69 | | muscle_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) |
70 | 0 | { |
71 | 0 | int r; |
72 | 0 | struct sc_file *file; |
73 | 0 | struct sc_path path; |
74 | 0 | memset(&file, 0, sizeof(file)); |
75 | 0 | sc_format_path("3F00", &path); |
76 | 0 | if ((r = sc_select_file(p15card->card, &path, &file)) < 0) |
77 | 0 | return r; |
78 | 0 | if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE)) < 0) { |
79 | 0 | sc_file_free(file); |
80 | 0 | return r; |
81 | 0 | } |
82 | 0 | sc_file_free(file); |
83 | | |
84 | | /* Create the application DF */ |
85 | 0 | if ((r = sc_pkcs15init_create_file(profile, p15card, df)) < 0) |
86 | 0 | return r; |
87 | | |
88 | 0 | if ((r = sc_select_file(p15card->card, &df->path, NULL)) < 0) |
89 | 0 | return r; |
90 | | |
91 | | |
92 | 0 | return 0; |
93 | 0 | } |
94 | | |
95 | | static int |
96 | | muscle_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
97 | | sc_file_t *df, sc_pkcs15_object_t *pin_obj, |
98 | | const unsigned char *pin, size_t pin_len, |
99 | | const unsigned char *puk, size_t puk_len) |
100 | 0 | { |
101 | 0 | sc_file_t *file; |
102 | 0 | sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; |
103 | 0 | int r; |
104 | |
|
105 | 0 | if ((r = sc_select_file(p15card->card, &df->path, &file)) < 0) |
106 | 0 | return r; |
107 | 0 | if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_WRITE)) < 0) { |
108 | 0 | sc_file_free(file); |
109 | 0 | return r; |
110 | 0 | } |
111 | | |
112 | 0 | auth_info->attrs.pin.flags &= ~SC_PKCS15_PIN_FLAG_LOCAL; |
113 | 0 | sc_file_free(file); |
114 | 0 | return 0; |
115 | 0 | } |
116 | | |
117 | | static int |
118 | | muscle_select_pin_reference(sc_profile_t *profike, sc_pkcs15_card_t *p15card, |
119 | | sc_pkcs15_auth_info_t *auth_info) |
120 | 0 | { |
121 | 0 | int preferred; |
122 | |
|
123 | 0 | if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) |
124 | 0 | return SC_ERROR_OBJECT_NOT_VALID; |
125 | | |
126 | 0 | if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { |
127 | 0 | preferred = 0; |
128 | 0 | } else { |
129 | 0 | preferred = 1; |
130 | 0 | } |
131 | 0 | if (auth_info->attrs.pin.reference <= preferred) { |
132 | 0 | auth_info->attrs.pin.reference = preferred; |
133 | 0 | return 0; |
134 | 0 | } |
135 | | |
136 | 0 | if (auth_info->attrs.pin.reference > 2) |
137 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
138 | | |
139 | | /* Caller, please select a different PIN reference */ |
140 | 0 | return SC_ERROR_INVALID_PIN_REFERENCE; |
141 | 0 | } |
142 | | |
143 | | /* |
144 | | * Select a key reference |
145 | | */ |
146 | | static int |
147 | | muscle_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
148 | | sc_pkcs15_prkey_info_t *key_info) |
149 | 0 | { |
150 | 0 | if (key_info->key_reference < MUSCLE_KEY_ID_MIN) |
151 | 0 | key_info->key_reference = MUSCLE_KEY_ID_MIN; |
152 | 0 | if (key_info->key_reference > MUSCLE_KEY_ID_MAX) |
153 | 0 | return SC_ERROR_TOO_MANY_OBJECTS; |
154 | 0 | return 0; |
155 | 0 | } |
156 | | |
157 | | /* |
158 | | * Create a private key object. |
159 | | * This is a no-op. |
160 | | */ |
161 | | static int |
162 | | muscle_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
163 | | sc_pkcs15_object_t *obj) |
164 | 0 | { |
165 | 0 | return 0; |
166 | 0 | } |
167 | | |
168 | | /* |
169 | | * Store a private key object. |
170 | | */ |
171 | | static int |
172 | | muscle_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
173 | | sc_pkcs15_object_t *obj, |
174 | | sc_pkcs15_prkey_t *key) |
175 | 0 | { |
176 | 0 | struct sc_context *ctx = p15card->card->ctx; |
177 | 0 | sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; |
178 | 0 | sc_file_t* prkf; |
179 | 0 | struct sc_pkcs15_prkey_rsa *rsa; |
180 | 0 | sc_cardctl_muscle_key_info_t info; |
181 | 0 | int r; |
182 | |
|
183 | 0 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { |
184 | 0 | sc_log(ctx, "Muscle supports RSA keys only."); |
185 | 0 | return SC_ERROR_NOT_SUPPORTED; |
186 | 0 | } |
187 | | /* Verification stuff */ |
188 | | /* Used for verification AND for obtaining private key acls */ |
189 | 0 | r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); |
190 | 0 | if (r < 0 || !prkf) |
191 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); |
192 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO); |
193 | 0 | if (r < 0) { |
194 | 0 | sc_file_free(prkf); |
195 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); |
196 | 0 | } |
197 | 0 | sc_file_free(prkf); |
198 | 0 | r = muscle_select_key_reference(profile, p15card, key_info); |
199 | 0 | if (r < 0) { |
200 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,r); |
201 | 0 | } |
202 | 0 | rsa = &key->u.rsa; |
203 | |
|
204 | 0 | info.keySize = rsa->modulus.len << 3; |
205 | 0 | info.keyType = 0x03; /* CRT type */ |
206 | 0 | info.keyLocation = key_info->key_reference * 2; /* Mult by 2 to preserve even/odd keynumber structure */ |
207 | |
|
208 | 0 | info.pLength = rsa->p.len; |
209 | 0 | info.pValue = rsa->p.data; |
210 | 0 | info.qLength = rsa->q.len; |
211 | 0 | info.qValue = rsa->q.data; |
212 | |
|
213 | 0 | info.pqLength = rsa->iqmp.len; |
214 | 0 | info.pqValue = rsa->iqmp.data; |
215 | |
|
216 | 0 | info.dp1Length = rsa->dmp1.len; |
217 | 0 | info.dp1Value = rsa->dmp1.data; |
218 | 0 | info.dq1Length = rsa->dmq1.len; |
219 | 0 | info.dq1Value = rsa->dmq1.data; |
220 | |
|
221 | 0 | r = sc_card_ctl(p15card->card, SC_CARDCTL_MUSCLE_IMPORT_KEY, &info); |
222 | 0 | if (r < 0) { |
223 | 0 | sc_log(ctx, "Unable to import key"); |
224 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,r); |
225 | 0 | } |
226 | 0 | return r; |
227 | 0 | } |
228 | | |
229 | | static int |
230 | | muscle_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, |
231 | | sc_pkcs15_object_t *obj, |
232 | | sc_pkcs15_pubkey_t *pubkey) |
233 | 0 | { |
234 | 0 | sc_cardctl_muscle_gen_key_info_t args; |
235 | 0 | sc_cardctl_muscle_key_info_t extArgs; |
236 | 0 | sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; |
237 | 0 | sc_card_t *card = p15card->card; |
238 | 0 | sc_file_t* prkf; |
239 | 0 | size_t keybits; |
240 | 0 | int r; |
241 | |
|
242 | 0 | if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { |
243 | 0 | sc_log(card->ctx, "Muscle supports only RSA keys (for now)."); |
244 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); |
245 | 0 | } |
246 | 0 | keybits = key_info->modulus_length & ~7UL; |
247 | 0 | if (keybits > 2048) { |
248 | 0 | sc_log(card->ctx, "Unable to generate key, max size is %d", |
249 | 0 | 2048); |
250 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); |
251 | 0 | } |
252 | | /* Verification stuff */ |
253 | | /* Used for verification AND for obtaining private key acls */ |
254 | 0 | r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); |
255 | 0 | if(r < 0 || !prkf) |
256 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); |
257 | 0 | r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO); |
258 | 0 | if (r < 0) { |
259 | 0 | sc_file_free(prkf); |
260 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); |
261 | 0 | } |
262 | 0 | sc_file_free(prkf); |
263 | | |
264 | | /* END VERIFICATION STUFF */ |
265 | | |
266 | | /* Public key acls... get_file_by_path as well? */ |
267 | |
|
268 | 0 | memset(&args, 0, sizeof(args)); |
269 | 0 | args.keyType = 0x01; /* RSA forced */ |
270 | 0 | args.privateKeyLocation = key_info->key_reference * 2; |
271 | 0 | args.publicKeyLocation = key_info->key_reference * 2 + 1; |
272 | |
|
273 | 0 | args.keySize = keybits; |
274 | |
|
275 | 0 | r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_GENERATE_KEY, &args); |
276 | 0 | if (r < 0) { |
277 | 0 | sc_log(card->ctx, "Unable to generate key"); |
278 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r); |
279 | 0 | } |
280 | | |
281 | 0 | memset(&extArgs, 0, sizeof(extArgs)); |
282 | 0 | memset(pubkey, 0, sizeof(*pubkey)); |
283 | |
|
284 | 0 | extArgs.keyType = 0x01; |
285 | 0 | extArgs.keyLocation = args.publicKeyLocation; |
286 | 0 | r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_EXTRACT_KEY, &extArgs); |
287 | 0 | if (r < 0) { |
288 | 0 | sc_log(card->ctx, "Unable to extract the public key"); |
289 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r); |
290 | 0 | } |
291 | | |
292 | 0 | pubkey->algorithm = SC_ALGORITHM_RSA; |
293 | 0 | pubkey->u.rsa.modulus.len = extArgs.modLength; |
294 | 0 | pubkey->u.rsa.modulus.data = extArgs.modValue; |
295 | 0 | pubkey->u.rsa.exponent.len = extArgs.expLength; |
296 | 0 | pubkey->u.rsa.exponent.data = extArgs.expValue; |
297 | |
|
298 | 0 | return r; |
299 | 0 | } |
300 | | |
301 | | |
302 | | static struct sc_pkcs15init_operations sc_pkcs15init_muscle_operations = { |
303 | | muscle_erase_card, /* erase card */ |
304 | | muscle_init_card, /* init_card */ |
305 | | muscle_create_dir, /* create_dir */ |
306 | | NULL, /* create_domain */ |
307 | | muscle_select_pin_reference, /* select pin reference */ |
308 | | muscle_create_pin, /* Create PIN */ |
309 | | muscle_select_key_reference, /* select_key_reference */ |
310 | | muscle_create_key, /* create_key */ |
311 | | muscle_store_key, /* store_key */ |
312 | | muscle_generate_key, /* generate_key */ |
313 | | NULL, NULL, /* encode private/public key */ |
314 | | NULL, /* finalize_card */ |
315 | | NULL, /* delete_object */ |
316 | | NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */ |
317 | | NULL /* sanity_check */ |
318 | | }; |
319 | | |
320 | | struct sc_pkcs15init_operations * |
321 | | sc_pkcs15init_get_muscle_ops(void) |
322 | 0 | { |
323 | 0 | return &sc_pkcs15init_muscle_operations; |
324 | 0 | } |