1 /*
2  * Rutoken S specific operation for PKCS15 initialization
3  *
4  * Copyright (C) 2007  Pavel Mironchik <rutoken@rutoken.ru>
5  * Copyright (C) 2007  Eugene Hermann <rutoken@rutoken.ru>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #include "config.h"
23 
24 #include <sys/types.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "libopensc/opensc.h"
30 #include "libopensc/cardctl.h"
31 #include "libopensc/log.h"
32 #include "libopensc/pkcs15.h"
33 #include "pkcs15-init.h"
34 #include "profile.h"
35 
36 static const sc_SecAttrV2_t wn_sec_attr = {
37 	0x43, 1, 1, 0, 0, 0, 0, -1,
38 	2, 0, 0, 0,
39 	2
40 };
41 static const sc_SecAttrV2_t p2_sec_attr = {
42 	0x43, 1, 1, 0, 0, 0, 0, -1,
43 	1, 0, 0, 0,
44 	2
45 };
46 static const sc_SecAttrV2_t p1_sec_attr = {
47 	0x43, -1, 1, 0, 0, 0, 0, -1,
48 	0, 0, 0, 0,
49 	1
50 };
51 
52 static const struct
53 {
54 	u8                     id, options, flags, try, pass[8];
55 	sc_SecAttrV2_t const*  p_sattr;
56 } do_pins[] =
57 		{
58 			{ SC_RUTOKEN_DEF_ID_GCHV_USER, SC_RUTOKEN_OPTIONS_GACCESS_USER,
59 			  SC_RUTOKEN_FLAGS_COMPACT_DO, 0xFF,
60 			  { '1', '2', '3', '4', '5', '6', '7', '8' }, &p2_sec_attr
61 			},
62 			{ SC_RUTOKEN_DEF_ID_GCHV_ADMIN, SC_RUTOKEN_OPTIONS_GACCESS_ADMIN,
63 			  SC_RUTOKEN_FLAGS_COMPACT_DO, 0xFF,
64 			  { '8', '7', '6', '5', '4', '3', '2', '1' }, &p1_sec_attr
65 			}
66 		};
67 
68 /*
69  * Create a DF
70  */
71 static int
rutoken_create_dir(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_file_t * df)72 rutoken_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
73 		sc_file_t *df)
74 {
75 	if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df)
76 		return SC_ERROR_INVALID_ARGUMENTS;
77 	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
78 	return sc_pkcs15init_create_file(profile, p15card, df);
79 }
80 
81 /*
82  * Select a PIN reference
83  */
84 static int
rutoken_select_pin_reference(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_pkcs15_auth_info_t * auth_info)85 rutoken_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
86 			sc_pkcs15_auth_info_t *auth_info)
87 {
88 	int pin_ref;
89 	unsigned int so_pin_flag;
90 
91 	if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !auth_info)
92 		return SC_ERROR_INVALID_ARGUMENTS;
93 
94 	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
95 
96 	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
97 		return SC_ERROR_OBJECT_NOT_VALID;
98 
99 	pin_ref = auth_info->attrs.pin.reference;
100 	so_pin_flag = auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN;
101 
102 	sc_log(p15card->card->ctx,  "PIN reference %i%s\n",
103 			pin_ref, so_pin_flag ? " SO PIN flag" : "");
104 
105 	if ((pin_ref == SC_RUTOKEN_DEF_ID_GCHV_ADMIN && so_pin_flag)
106 			|| (pin_ref == SC_RUTOKEN_DEF_ID_GCHV_USER && !so_pin_flag)
107 	)
108 		return SC_SUCCESS;
109 	else
110 		return SC_ERROR_NOT_SUPPORTED;
111 }
112 
113 /*
114  * Create a PIN object within the given DF
115  */
116 static int
rutoken_create_pin(sc_profile_t * profile,sc_pkcs15_card_t * p15card,sc_file_t * df,sc_pkcs15_object_t * pin_obj,const unsigned char * pin,size_t pin_len,const unsigned char * puk,size_t puk_len)117 rutoken_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
118 			sc_file_t *df, sc_pkcs15_object_t *pin_obj,
119 			const unsigned char *pin, size_t pin_len,
120 			const unsigned char *puk, size_t puk_len)
121 {
122 	sc_context_t *ctx;
123 	sc_pkcs15_auth_info_t *auth_info;
124 	size_t i;
125 
126 	(void)puk; /* no warning */
127 	if (!profile || !p15card || !p15card->card || !p15card->card->ctx
128 			|| !df || !pin_obj || !pin_obj->data || !pin || !pin_len)
129 		return SC_ERROR_INVALID_ARGUMENTS;
130 
131 	ctx = p15card->card->ctx;
132 	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
133 
134 	if (puk_len != 0)
135 	{
136 		sc_log(ctx,
137 				"Do not enter User unblocking PIN (PUK): %s\n",
138 				sc_strerror(SC_ERROR_NOT_SUPPORTED));
139 		return SC_ERROR_NOT_SUPPORTED;
140 	}
141 
142 	auth_info = (sc_pkcs15_auth_info_t *)pin_obj->data;
143 	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
144                 return SC_ERROR_OBJECT_NOT_VALID;
145 
146 	for (i = 0; i < sizeof(do_pins)/sizeof(do_pins[0]); ++i)
147 		if (auth_info->attrs.pin.reference == do_pins[i].id)
148 		{
149 			if (pin_len == sizeof(do_pins[i].pass)
150 					&&  memcmp(do_pins[i].pass, pin, pin_len) == 0
151 			)
152 				return SC_SUCCESS;
153 			else
154 			{
155 				sc_log(ctx,  "Incorrect PIN\n");
156 				break;
157 			}
158 		}
159 	sc_log(ctx,
160 			"PIN reference %i not found in standard (Rutoken) PINs\n",
161 			auth_info->attrs.pin.reference);
162 	return SC_ERROR_NOT_SUPPORTED;
163 }
164 
165 /*
166  * Initialization routine
167  */
168 
create_pins(sc_card_t * card)169 static int create_pins(sc_card_t *card)
170 {
171 	sc_DO_V2_t param_do;
172 	size_t i;
173 	int r = SC_SUCCESS;
174 
175 	for (i = 0; i < sizeof(do_pins)/sizeof(do_pins[0]); ++i)
176 	{
177 		memset(&param_do, 0, sizeof(param_do));
178 		param_do.HDR.OTID.byObjectType  = SC_RUTOKEN_TYPE_CHV;
179 		param_do.HDR.OTID.byObjectID    = do_pins[i].id;
180 		param_do.HDR.OP.byObjectOptions = do_pins[i].options;
181 		param_do.HDR.OP.byObjectFlags   = do_pins[i].flags;
182 		param_do.HDR.OP.byObjectTry     = do_pins[i].try;
183 		param_do.HDR.wDOBodyLen = sizeof(do_pins[i].pass);
184 		/* assert(do_pins[i].p_sattr != NULL); */
185 		/* assert(sizeof(*param_do.HDR.SA_V2)) */
186 		/* assert(sizeof(param_do.HDR.SA_V2) == sizeof(*do_pins[i].p_sattr)); */
187 		memcpy(param_do.HDR.SA_V2, *do_pins[i].p_sattr,
188 				sizeof(*do_pins[i].p_sattr));
189 		/* assert(do_pins[i].pass); */
190 		/* assert(sizeof(*param_do.abyDOBody)) */
191 		/* assert(sizeof(param_do.abyDOBody) >= sizeof(do_pins[i].pass)); */
192 		memcpy(param_do.abyDOBody, do_pins[i].pass, sizeof(do_pins[i].pass));
193 
194 		r = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_CREATE_DO, &param_do);
195 		if (r != SC_SUCCESS) break;
196 	}
197 	return r;
198 }
199 
create_typical_fs(sc_card_t * card)200 static int create_typical_fs(sc_card_t *card)
201 {
202 	sc_file_t *df;
203 	int r;
204 
205 	df = sc_file_new();
206 	if (!df)
207 		return SC_ERROR_OUT_OF_MEMORY;
208 	df->type = SC_FILE_TYPE_DF;
209 	do
210 	{
211 		r = sc_file_set_sec_attr(df, wn_sec_attr, sizeof(wn_sec_attr));
212 		if (r != SC_SUCCESS) break;
213 
214 		/* Create MF  3F00 */
215 		df->id = 0x3F00;
216 		sc_format_path("3F00", &df->path);
217 		r = sc_create_file(card, df);
218 		if (r != SC_SUCCESS) break;
219 
220 		/* Create     3F00/0000 */
221 		df->id = 0x0000;
222 		sc_append_file_id(&df->path, df->id);
223 		r = sc_create_file(card, df);
224 		if (r != SC_SUCCESS) break;
225 
226 		/* Create     3F00/0000/0000 */
227 		df->id = 0x0000;
228 		sc_append_file_id(&df->path, df->id);
229 		r = sc_create_file(card, df);
230 		if (r != SC_SUCCESS) break;
231 
232 		/* Create USER PIN and SO PIN*/
233 		r = create_pins(card);
234 		if (r != SC_SUCCESS) break;
235 
236 		/* VERIFY USER PIN */
237 		r = sc_verify(card, SC_AC_CHV, do_pins[0].id,
238 				do_pins[0].pass, sizeof(do_pins[0].pass), NULL);
239 		if (r != SC_SUCCESS) break;
240 
241 		/* Create     3F00/0000/0000/0001 */
242 		df->id = 0x0001;
243 		sc_append_file_id(&df->path, df->id);
244 		r = sc_create_file(card, df);
245 		if (r != SC_SUCCESS) break;
246 
247 		sc_format_path("3F0000000000", &df->path);
248 		r = sc_select_file(card, &df->path, NULL);
249 		if (r != SC_SUCCESS) break;
250 
251 		/* Create     3F00/0000/0000/0002 */
252 		df->id = 0x0002;
253 		sc_append_file_id(&df->path, df->id);
254 		r = sc_create_file(card, df);
255 		if (r != SC_SUCCESS) break;
256 
257 		sc_format_path("3F000000", &df->path);
258 		r = sc_select_file(card, &df->path, NULL);
259 		if (r != SC_SUCCESS) break;
260 
261 		/* Create     3F00/0000/0001 */
262 		df->id = 0x0001;
263 		sc_append_file_id(&df->path, df->id);
264 		r = sc_create_file(card, df);
265 		if (r != SC_SUCCESS) break;
266 
267 		/* RESET ACCESS RIGHTS */
268 		r = sc_logout(card);
269 	} while(0);
270 	sc_file_free(df);
271 	return r;
272 }
273 
274 /*
275  * Erase everything that's on the card
276  */
277 static int
rutoken_erase(struct sc_profile * profile,sc_pkcs15_card_t * p15card)278 rutoken_erase(struct sc_profile *profile, sc_pkcs15_card_t *p15card)
279 {
280 	sc_card_t *card;
281 	int ret, ret_end;
282 
283 	if (!profile || !p15card || !p15card->card || !p15card->card->ctx)
284 		return SC_ERROR_INVALID_ARGUMENTS;
285 
286 	card = p15card->card;
287 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
288 
289 	/* ret = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); */
290 	ret = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_FORMAT_INIT, NULL);
291 	if (ret == SC_SUCCESS)
292 	{
293 		ret = create_typical_fs(card);
294 		if (ret != SC_SUCCESS)
295 			sc_log(card->ctx,
296 					"Failed to create typical fs: %s\n",
297 					sc_strerror(ret));
298 		ret_end = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_FORMAT_END, NULL);
299 		if (ret_end != SC_SUCCESS)
300 			ret = ret_end;
301 	}
302 	if (ret != SC_SUCCESS)
303 		sc_log(card->ctx,
304 				"Failed to erase: %s\n", sc_strerror(ret));
305 	else
306 		sc_free_apps(card);
307 	return ret;
308 }
309 
310 static struct sc_pkcs15init_operations sc_pkcs15init_rutoken_operations = {
311 	rutoken_erase,                  /* erase_card */
312 	NULL,                           /* init_card */
313 	rutoken_create_dir,             /* create_dir */
314 	NULL,                           /* create_domain */
315 	rutoken_select_pin_reference,   /* select_pin_reference */
316 	rutoken_create_pin,             /* create_pin */
317 	NULL,                           /* select_key_reference */
318 	NULL,                           /* create_key */
319 	NULL,                           /* store_key */
320 	NULL,                           /* generate_key */
321 	NULL,                           /* encode_private_key */
322 	NULL,                           /* encode_public_key */
323 	NULL,                           /* finalize_card */
324 	NULL,                           /* delete_object */
325 	NULL, NULL, NULL, NULL, NULL,   /* pkcs15init emulation */
326 	NULL                            /* sanity_check */
327 };
328 
sc_pkcs15init_get_rutoken_ops(void)329 struct sc_pkcs15init_operations* sc_pkcs15init_get_rutoken_ops(void)
330 {
331 	return &sc_pkcs15init_rutoken_operations;
332 }
333 
334