1 /*
2 * pkcs15-westcos.c: pkcs15 support for westcos card
3 *
4 * Copyright (C) 2009 francois.leblanc@cev-sa.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26
27 #ifdef ENABLE_OPENSSL
28 #include <openssl/opensslv.h>
29 #include <openssl/bn.h>
30 #include <openssl/rsa.h>
31 #include <openssl/evp.h>
32 #include <openssl/pem.h>
33 #include <openssl/err.h>
34 #include <openssl/bio.h>
35 #endif
36
37 #include "libopensc/sc-ossl-compat.h"
38 #include "libopensc/opensc.h"
39 #include "libopensc/cardctl.h"
40 #include "pkcs15-init.h"
41 #include "profile.h"
42
westcos_pkcs15init_init_card(sc_profile_t * profile,sc_pkcs15_card_t * p15card)43 static int westcos_pkcs15init_init_card(sc_profile_t *profile,
44 sc_pkcs15_card_t *p15card)
45 {
46 int r;
47 struct sc_path path;
48
49 sc_format_path("3F00", &path);
50 r = sc_select_file(p15card->card, &path, NULL);
51 if(r) return (r);
52
53 return r;
54 }
55
westcos_pkcs15init_create_dir(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_file_t * df)56 static int westcos_pkcs15init_create_dir(sc_profile_t *profile,
57 sc_pkcs15_card_t *p15card,
58 sc_file_t *df)
59 {
60 int r;
61
62 /* Create the application DF */
63 r = sc_pkcs15init_create_file(profile, p15card, df);
64 if(r) return r;
65
66 r = sc_select_file(p15card->card, &df->path, NULL);
67 if(r) return r;
68
69 return 0;
70 }
71
72 /*
73 * Select the PIN reference
74 */
westcos_pkcs15_select_pin_reference(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_pkcs15_auth_info_t * auth_info)75 static int westcos_pkcs15_select_pin_reference(sc_profile_t *profile,
76 sc_pkcs15_card_t *p15card,
77 sc_pkcs15_auth_info_t *auth_info)
78 {
79
80 if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
81 return SC_ERROR_OBJECT_NOT_VALID;
82
83 if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
84 auth_info->attrs.pin.reference = 1;
85 } else {
86 auth_info->attrs.pin.reference = 0;
87 }
88
89 return 0;
90 }
91
92 /*
93 * Create a new PIN inside a DF
94 */
westcos_pkcs15_create_pin(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_file_t * df,sc_pkcs15_object_t * pin_obj,const u8 * pin,size_t pin_len,const u8 * puk,size_t puk_len)95 static int westcos_pkcs15_create_pin(sc_profile_t *profile,
96 sc_pkcs15_card_t *p15card,
97 sc_file_t *df,
98 sc_pkcs15_object_t *pin_obj,
99 const u8 *pin, size_t pin_len,
100 const u8 *puk, size_t puk_len)
101 {
102 int r;
103 sc_file_t *pinfile = NULL;
104
105 if(pin_len>9 || puk_len>9)
106 return SC_ERROR_INVALID_ARGUMENTS;
107
108 r = sc_profile_get_file(profile, "PINFILE", &pinfile);
109 if(r < 0) return r;
110
111 r = sc_create_file(p15card->card, pinfile);
112 if(r)
113 {
114 if(r != SC_ERROR_FILE_ALREADY_EXISTS)
115 return (r);
116
117 r = sc_select_file(p15card->card, &pinfile->path, NULL);
118 if(r) return (r);
119 }
120
121 sc_file_free(pinfile);
122
123 if(pin != NULL)
124 {
125 sc_changekey_t ck;
126 struct sc_pin_cmd_pin pin_cmd;
127 int ret;
128
129 memset(&pin_cmd, 0, sizeof(pin_cmd));
130 memset(&ck, 0, sizeof(ck));
131
132 memcpy(ck.key_template, "\x1e\x00\x00\x10", 4);
133
134 pin_cmd.encoding = SC_PIN_ENCODING_GLP;
135 pin_cmd.len = pin_len;
136 pin_cmd.data = pin;
137 pin_cmd.max_length = 8;
138
139 ret = sc_build_pin(ck.new_key.key_value,
140 sizeof(ck.new_key.key_value), &pin_cmd, 1);
141 if(ret < 0)
142 return SC_ERROR_CARD_CMD_FAILED;
143
144 ck.new_key.key_len = ret;
145 r = sc_card_ctl(p15card->card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
146 if(r) return r;
147 }
148
149 if(puk != NULL)
150 {
151 sc_changekey_t ck;
152 struct sc_pin_cmd_pin puk_cmd;
153 int ret;
154
155 memset(&puk_cmd, 0, sizeof(puk_cmd));
156 memset(&ck, 0, sizeof(ck));
157
158 memcpy(ck.key_template, "\x1e\x00\x00\x20", 4);
159
160 puk_cmd.encoding = SC_PIN_ENCODING_GLP;
161 puk_cmd.len = puk_len;
162 puk_cmd.data = puk;
163 puk_cmd.max_length = 8;
164
165 ret = sc_build_pin(ck.new_key.key_value,
166 sizeof(ck.new_key.key_value), &puk_cmd, 1);
167 if(ret < 0)
168 return SC_ERROR_CARD_CMD_FAILED;
169
170 ck.new_key.key_len = ret;
171 r = sc_card_ctl(p15card->card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
172 if(r) return r;
173 }
174
175 return 0;
176 }
177
178 /*
179 * Create a new key file
180 */
westcos_pkcs15init_create_key(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_pkcs15_object_t * obj)181 static int westcos_pkcs15init_create_key(sc_profile_t *profile,
182 sc_pkcs15_card_t *p15card,
183 sc_pkcs15_object_t *obj)
184 {
185
186 if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
187 return SC_ERROR_NOT_SUPPORTED;
188 }
189
190 return 0;
191 }
192
193
194 /*
195 * Store a private key
196 */
westcos_pkcs15init_store_key(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_pkcs15_object_t * obj,sc_pkcs15_prkey_t * key)197 static int westcos_pkcs15init_store_key(sc_profile_t *profile,
198 sc_pkcs15_card_t *p15card,
199 sc_pkcs15_object_t *obj,
200 sc_pkcs15_prkey_t *key)
201 {
202 return SC_ERROR_NOT_SUPPORTED;
203 }
204
205 /*
206 * Generate key
207 */
westcos_pkcs15init_generate_key(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_pkcs15_object_t * obj,sc_pkcs15_pubkey_t * pubkey)208 static int westcos_pkcs15init_generate_key(sc_profile_t *profile,
209 sc_pkcs15_card_t *p15card,
210 sc_pkcs15_object_t *obj,
211 sc_pkcs15_pubkey_t *pubkey)
212 {
213 #ifndef ENABLE_OPENSSL
214 return SC_ERROR_NOT_SUPPORTED;
215 #else
216 int r = SC_ERROR_UNKNOWN;
217 long lg;
218 u8 *p;
219 sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
220 RSA *rsa = NULL;
221 BIGNUM *bn = NULL;
222 BIO *mem = NULL;
223
224 sc_file_t *prkf = NULL;
225
226 if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
227 return SC_ERROR_NOT_SUPPORTED;
228 }
229
230 rsa = RSA_new();
231 bn = BN_new();
232 mem = BIO_new(BIO_s_mem());
233
234 if(rsa == NULL || bn == NULL || mem == NULL)
235 {
236 r = SC_ERROR_OUT_OF_MEMORY;
237 goto out;
238 }
239
240 if(!BN_set_word(bn, RSA_F4) ||
241 !RSA_generate_key_ex(rsa, key_info->modulus_length, bn, NULL))
242 {
243 r = SC_ERROR_UNKNOWN;
244 goto out;
245 }
246
247 RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
248
249 if(pubkey != NULL)
250 {
251 if(!i2d_RSAPublicKey_bio(mem, rsa))
252 {
253 r = SC_ERROR_UNKNOWN;
254 goto out;
255 }
256
257 lg = BIO_get_mem_data(mem, &p);
258
259 pubkey->algorithm = SC_ALGORITHM_RSA;
260
261 r = sc_pkcs15_decode_pubkey(p15card->card->ctx, pubkey, p, lg);
262 if (r < 0)
263 goto out;
264 }
265
266 (void) BIO_reset(mem);
267
268 if(!i2d_RSAPrivateKey_bio(mem, rsa))
269 {
270 r = SC_ERROR_UNKNOWN;
271 goto out;
272 }
273
274 lg = BIO_get_mem_data(mem, &p);
275
276 /* Get the private key file */
277 r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
278 if (r < 0)
279 {
280 char pbuf[SC_MAX_PATH_STRING_SIZE];
281
282 r = sc_path_print(pbuf, sizeof(pbuf), &key_info->path);
283 if (r != SC_SUCCESS)
284 pbuf[0] = '\0';
285
286 goto out;
287 }
288
289 prkf->size = lg;
290
291 r = sc_pkcs15init_create_file(profile, p15card, prkf);
292 if(r) goto out;
293
294 r = sc_pkcs15init_update_file(profile, p15card, prkf, p, lg);
295 if(r) goto out;
296
297 out:
298 if(mem)
299 BIO_free(mem);
300 if(bn)
301 BN_free(bn);
302 if(rsa)
303 RSA_free(rsa);
304 sc_file_free(prkf);
305
306 return r;
307 #endif
308 }
309
westcos_pkcs15init_finalize_card(sc_card_t * card)310 static int westcos_pkcs15init_finalize_card(sc_card_t *card)
311 {
312 int r;
313
314 /* be sure authenticate card */
315 r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL);
316 if(r) return (r);
317
318 return sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_USER);
319 }
320
321 static struct sc_pkcs15init_operations sc_pkcs15init_westcos_operations = {
322 NULL, /* erase_card */
323 westcos_pkcs15init_init_card, /* init_card */
324 westcos_pkcs15init_create_dir, /* create_dir */
325 NULL, /* create_domain */
326 westcos_pkcs15_select_pin_reference, /* select_pin_reference */
327 westcos_pkcs15_create_pin, /* create_pin */
328 NULL, /* select_key_reference */
329 westcos_pkcs15init_create_key, /* create_key */
330 westcos_pkcs15init_store_key, /* store_key */
331 westcos_pkcs15init_generate_key, /* generate_key */
332 NULL, NULL, /* encode private/public key */
333 westcos_pkcs15init_finalize_card, /* finalize_card */
334 NULL, /* delete_object */
335 NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */
336 NULL /* sanity_check */
337 };
338
sc_pkcs15init_get_westcos_ops(void)339 struct sc_pkcs15init_operations* sc_pkcs15init_get_westcos_ops(void)
340 {
341 return &sc_pkcs15init_westcos_operations;
342 }
343