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