1 /*
2  * iasecc-sdo.c: library to manipulate the Security Data Objects (SDO)
3  *		used by IAS/ECC card support.
4  *
5  * Copyright (C) 2010  Viktor Tarasov <vtarasov@opentrust.com>
6  *			OpenTrust <www.opentrust.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #ifdef ENABLE_OPENSSL   /* empty file without openssl */
28 
29 #include <string.h>
30 #include <stdlib.h>
31 
32 #include "internal.h"
33 #include "asn1.h"
34 #include "cardctl.h"
35 
36 #include "iasecc.h"
37 #include "iasecc-sdo.h"
38 
39 static int iasecc_parse_size(unsigned char *data, size_t *out);
40 
41 
42 static int
iasecc_parse_acls(struct sc_card * card,struct iasecc_sdo_docp * docp,int flags)43 iasecc_parse_acls(struct sc_card *card, struct iasecc_sdo_docp *docp, int flags)
44 {
45 	struct sc_context *ctx = card->ctx;
46 	struct iasecc_extended_tlv *acls = &docp->acls_contact;
47 	int ii, offs;
48 	unsigned char mask = 0x40;
49 
50 	if (flags)
51 		acls = &docp->acls_contactless;
52 
53 	if (!acls->size)
54 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
55 
56 	docp->amb = *(acls->value + 0);
57 	memset(docp->scbs, 0xFF, sizeof(docp->scbs));
58 	for (ii=0, offs = 1; ii<7; ii++, mask >>= 1)
59 		if (mask & docp->amb)
60 			docp->scbs[ii] = *(acls->value + offs++);
61 
62 	sc_log(ctx, "iasecc_parse_docp() SCBs %02X:%02X:%02X:%02X:%02X:%02X:%02X",
63 			docp->scbs[0],docp->scbs[1],docp->scbs[2],docp->scbs[3],
64 			docp->scbs[4],docp->scbs[5],docp->scbs[6]);
65 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
66 }
67 
68 
69 int
iasecc_sdo_convert_acl(struct sc_card * card,struct iasecc_sdo * sdo,unsigned char op,unsigned * out_method,unsigned * out_ref)70 iasecc_sdo_convert_acl(struct sc_card *card, struct iasecc_sdo *sdo,
71 		unsigned char op, unsigned *out_method, unsigned *out_ref)
72 {
73 	struct sc_context *ctx = card->ctx;
74 	struct acl_op {
75 		unsigned char op;
76 		unsigned char mask;
77 	} ops[] = {
78 		{SC_AC_OP_PSO_COMPUTE_SIGNATURE,IASECC_ACL_PSO_SIGNATURE},
79 		{SC_AC_OP_INTERNAL_AUTHENTICATE,IASECC_ACL_INTERNAL_AUTHENTICATE},
80 		{SC_AC_OP_PSO_DECRYPT,	IASECC_ACL_PSO_DECIPHER},
81 		{SC_AC_OP_GENERATE,	IASECC_ACL_GENERATE_KEY},
82 		{SC_AC_OP_UPDATE,	IASECC_ACL_PUT_DATA},
83 		{SC_AC_OP_READ,		IASECC_ACL_GET_DATA},
84 		{0x00, 0x00}
85 	};
86 	unsigned char mask = 0x80, op_mask = 0;
87 	int ii;
88 
89 	LOG_FUNC_CALLED(ctx);
90 
91 	for (ii=0; ops[ii].mask; ii++)   {
92 		if (op == ops[ii].op)   {
93 			op_mask = ops[ii].mask;
94 			break;
95 		}
96 	}
97 	if (op_mask == 0)
98 		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
99 
100 	sc_log(ctx, "OP:%i, mask:0x%X", op, op_mask);
101 	sc_log(ctx, "AMB:%X, scbs:%s", sdo->docp.amb, sc_dump_hex(sdo->docp.scbs, IASECC_MAX_SCBS));
102 	sc_log(ctx, "docp.acls_contact:%s", sc_dump_hex(sdo->docp.acls_contact.value, sdo->docp.acls_contact.size));
103 
104 	if (!sdo->docp.amb && sdo->docp.acls_contact.size)   {
105 		int rv = iasecc_parse_acls(card, &sdo->docp, 0);
106 		LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP");
107 	}
108 
109 	*out_method = SC_AC_NEVER;
110 	*out_ref = SC_AC_NEVER;
111 
112 	for (ii=0; ii<7; ii++)   {
113 		mask >>= 1;
114 		if (sdo->docp.amb & mask)   {
115 			if (op_mask == mask)   {
116 				unsigned char scb = sdo->docp.scbs[ii];
117 				sc_log(ctx, "ii:%i, scb:0x%X", ii, scb);
118 
119 				*out_ref = scb & 0x0F;
120 				if (scb == 0)
121 					*out_method = SC_AC_NONE;
122 				else if (scb == 0xFF)
123 					*out_method = SC_AC_NEVER;
124 				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_USER_AUTH)
125 					*out_method = SC_AC_SEN;
126 				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_EXT_AUTH)
127 					*out_method = SC_AC_AUT;
128 				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_SM)
129 					*out_method = SC_AC_PRO;
130 				else
131 					*out_method = SC_AC_SCB, *out_ref = scb;
132 
133 				break;
134 			}
135 		}
136 	}
137 
138 	sc_log(ctx, "returns method %X; ref %X", *out_method, *out_ref);
139 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
140 }
141 
142 
143 void
iasecc_sdo_free_fields(struct sc_card * card,struct iasecc_sdo * sdo)144 iasecc_sdo_free_fields(struct sc_card *card, struct iasecc_sdo *sdo)
145 {
146 	if (sdo->docp.tries_remaining.value)
147 		free(sdo->docp.tries_remaining.value);
148 	if (sdo->docp.usage_remaining.value)
149 		free(sdo->docp.usage_remaining.value);
150 	if (sdo->docp.non_repudiation.value)
151 		free(sdo->docp.non_repudiation.value);
152 	if (sdo->docp.acls_contact.value)
153 		free(sdo->docp.acls_contact.value);
154 	if (sdo->docp.size.value)
155 		free(sdo->docp.size.value);
156 	if (sdo->docp.name.value)
157 		free(sdo->docp.name.value);
158 	if (sdo->docp.issuer_data.value)
159 		free(sdo->docp.issuer_data.value);
160 
161 	if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PUBLIC)   {
162 		if (sdo->data.pub_key.n.value)
163 			free(sdo->data.pub_key.n.value);
164 		if (sdo->data.pub_key.e.value)
165 			free(sdo->data.pub_key.e.value);
166 		if (sdo->data.pub_key.compulsory.value)
167 			free(sdo->data.pub_key.compulsory.value);
168 		if (sdo->data.pub_key.chr.value)
169 			free(sdo->data.pub_key.chr.value);
170 		if (sdo->data.pub_key.cha.value)
171 			free(sdo->data.pub_key.cha.value);
172 	}
173 	else if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PRIVATE)   {
174 		if (sdo->data.prv_key.p.value)
175 			free(sdo->data.prv_key.p.value);
176 		if (sdo->data.prv_key.q.value)
177 			free(sdo->data.prv_key.q.value);
178 		if (sdo->data.prv_key.iqmp.value)
179 			free(sdo->data.prv_key.iqmp.value);
180 		if (sdo->data.prv_key.dmp1.value)
181 			free(sdo->data.prv_key.dmp1.value);
182 		if (sdo->data.prv_key.dmq1.value)
183 			free(sdo->data.prv_key.dmq1.value);
184 		if (sdo->data.prv_key.compulsory.value)
185 			free(sdo->data.prv_key.compulsory.value);
186 	}
187 	else if (sdo->sdo_class == IASECC_SDO_CLASS_CHV)   {
188 		if (sdo->data.chv.size_max.value)
189 			free(sdo->data.chv.size_max.value);
190 		if (sdo->data.chv.size_min.value)
191 			free(sdo->data.chv.size_min.value);
192 		if (sdo->data.chv.value.value)
193 			free(sdo->data.chv.value.value);
194 	}
195 }
196 
197 
198 void
iasecc_sdo_free(struct sc_card * card,struct iasecc_sdo * sdo)199 iasecc_sdo_free(struct sc_card *card, struct iasecc_sdo *sdo)
200 {
201 	iasecc_sdo_free_fields(card, sdo);
202 	free(sdo);
203 }
204 
205 
206 static int
iasecc_crt_parse(struct sc_card * card,unsigned char * data,struct iasecc_se_info * se)207 iasecc_crt_parse(struct sc_card *card, unsigned char *data, struct iasecc_se_info *se)
208 {
209 	struct sc_context *ctx = card->ctx;
210 	struct sc_crt crt;
211 	int ii, offs, len, parsed_len = -1;
212 
213 	sc_log(ctx, "iasecc_crt_parse(0x%X) called", *data);
214 
215 	memset(&crt, 0, sizeof(crt));
216 	crt.tag = *(data + 0);
217 	len = *(data + 1);
218 
219 	for(offs = 2; offs < len + 2; offs += 3)   {
220 		sc_log(ctx, "iasecc_crt_parse(0x%X) CRT %X -> %X", *data, *(data + offs), *(data + offs + 2));
221 		if (*(data + offs) == IASECC_CRT_TAG_USAGE)   {
222 			crt.usage = *(data + offs + 2);
223 		}
224 		else if (*(data + offs) == IASECC_CRT_TAG_REFERENCE)   {
225 			int nn_refs = sizeof(crt.refs) / sizeof(crt.refs[0]);
226 
227 			for (ii=0; ii<nn_refs && crt.refs[ii]; ii++)
228 				;
229 			if (ii == nn_refs)
230 				LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
231 
232 			crt.refs[ii] = *(data + offs + 2);
233 		}
234 		else if (*(data + offs) == IASECC_CRT_TAG_ALGO)   {
235 			crt.algo = *(data + offs + 2);
236 		}
237 		else   {
238 			LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
239 		}
240 	}
241 
242 	for (ii=0; ii<SC_MAX_CRTS_IN_SE; ii++)
243 		if (!se->crts[ii].tag)
244 			break;
245 
246 	if (ii==SC_MAX_CRTS_IN_SE)
247 		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_crt_parse() error: too much CRTs in SE");
248 
249 	memcpy(&se->crts[ii], &crt, sizeof(crt));
250 	parsed_len = len + 2;
251 	LOG_FUNC_RETURN(ctx, parsed_len);
252 }
253 
254 
255 int
iasecc_se_get_crt(struct sc_card * card,struct iasecc_se_info * se,struct sc_crt * crt)256 iasecc_se_get_crt(struct sc_card *card, struct iasecc_se_info *se, struct sc_crt *crt)
257 {
258 	struct sc_context *ctx = card->ctx;
259 	int ii;
260 
261 	LOG_FUNC_CALLED(ctx);
262 	if (!se || !crt)
263 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
264 	sc_log(ctx, "CRT search template: %X:%X:%X, refs %X:%X:...",
265 			crt->tag, crt->algo, crt->usage, crt->refs[0], crt->refs[1]);
266 
267 	for (ii=0; ii<SC_MAX_CRTS_IN_SE && se->crts[ii].tag; ii++)   {
268 		if (crt->tag != se->crts[ii].tag)
269 			continue;
270 		if (crt->algo && crt->algo != se->crts[ii].algo)
271 			continue;
272 		if (crt->usage && crt->usage != se->crts[ii].usage)
273 			continue;
274 		if (crt->refs[0] && crt->refs[0] != se->crts[ii].refs[0])
275 			continue;
276 
277 		memcpy(crt, &se->crts[ii], sizeof(*crt));
278 
279 		sc_log(ctx, "iasecc_se_get_crt() found CRT with refs %X:%X:...",
280 				se->crts[ii].refs[0], se->crts[ii].refs[1]);
281 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
282 	}
283 
284 	sc_log(ctx, "iasecc_se_get_crt() CRT is not found");
285 	return SC_ERROR_DATA_OBJECT_NOT_FOUND;
286 }
287 
288 
289 int
iasecc_se_get_crt_by_usage(struct sc_card * card,struct iasecc_se_info * se,unsigned char tag,unsigned char usage,struct sc_crt * crt)290 iasecc_se_get_crt_by_usage(struct sc_card *card, struct iasecc_se_info *se, unsigned char tag,
291 		unsigned char usage, struct sc_crt *crt)
292 {
293 	struct sc_context *ctx = card->ctx;
294 	int ii;
295 
296 	LOG_FUNC_CALLED(ctx);
297 	if (!se || !crt || !tag || !usage)
298 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
299 	sc_log(ctx, "CRT search template with TAG:0x%X and UQB:0x%X", tag, usage);
300 
301 	for (ii=0; ii<SC_MAX_CRTS_IN_SE && se->crts[ii].tag; ii++)   {
302 		if (tag != se->crts[ii].tag)
303 			continue;
304 		if (usage != se->crts[ii].usage)
305 			continue;
306 
307 		memcpy(crt, &se->crts[ii], sizeof(*crt));
308 
309 		sc_log(ctx, "iasecc_se_get_crt() found CRT with refs %X:%X:...", crt->refs[0], crt->refs[1]);
310 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
311 	}
312 
313 	sc_log(ctx, "iasecc_se_get_crt() CRT is not found");
314 	LOG_FUNC_RETURN(ctx, SC_ERROR_DATA_OBJECT_NOT_FOUND);
315 }
316 
317 
318 int
iasecc_se_parse(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_se_info * se)319 iasecc_se_parse(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_se_info *se)
320 {
321 	struct sc_context *ctx = card->ctx;
322 	size_t size, offs, size_size;
323 	int rv;
324 
325 	LOG_FUNC_CALLED(ctx);
326 
327 	if (*data == IASECC_SDO_TEMPLATE_TAG)   {
328 		size_size = iasecc_parse_size(data + 1, &size);
329 		LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE");
330 
331 		data += size_size + 1;
332 		data_len = size;
333 		sc_log(ctx,
334 		       "IASECC_SDO_TEMPLATE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %"SC_FORMAT_LEN_SIZE_T"u",
335 		       size, size_size);
336 
337 		if (*data != IASECC_SDO_TAG_HEADER)
338 			LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
339 
340 		if ((*(data + 1) & 0x7F) != IASECC_SDO_CLASS_SE)
341 			 LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
342 
343 		size_size = iasecc_parse_size(data + 3, &size);
344 		LOG_TEST_RET(ctx, size_size, "parse error: invalid SDO SE data size");
345 
346 		if (data_len != size + size_size + 3)
347 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO SE data size");
348 
349 		data += 3 + size_size;
350 		data_len = size;
351 		sc_log(ctx,
352 		       "IASECC_SDO_TEMPLATE SE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %"SC_FORMAT_LEN_SIZE_T"u",
353 		       size, size_size);
354 	}
355 
356 	if (*data != IASECC_SDO_CLASS_SE)   {
357 		sc_log(ctx,
358 		       "Invalid SE tag 0x%X; data length %"SC_FORMAT_LEN_SIZE_T"u",
359 		       *data, data_len);
360 		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
361 	}
362 
363 	size_size = iasecc_parse_size(data + 1, &size);
364 	LOG_TEST_RET(ctx, size_size, "parse error: invalid size data");
365 
366 	if (data_len != size + size_size + 1)
367 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SE data size");
368 
369 	offs = 1 + size_size;
370 	for (; offs < data_len;)   {
371 		rv = iasecc_crt_parse(card, data + offs, se);
372 		LOG_TEST_RET(ctx, rv, "parse error: invalid SE data");
373 
374 		offs += rv;
375 	}
376 
377 	if (offs != data_len)
378 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed");
379 
380 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
381 }
382 
383 
384 static int
iasecc_parse_size(unsigned char * data,size_t * out)385 iasecc_parse_size(unsigned char *data, size_t *out)
386 {
387 	if (*data < 0x80)   {
388 		*out = *data;
389 		return 1;
390 	}
391 	else if (*data == 0x81)   {
392 		*out = *(data + 1);
393 		return 2;
394 	}
395 	else if (*data == 0x82)   {
396 		*out = *(data + 1) * 0x100 + *(data + 2);
397 		return 3;
398 	}
399 
400 	return SC_ERROR_INVALID_DATA;
401 }
402 
403 
404 static int
iasecc_parse_get_tlv(struct sc_card * card,unsigned char * data,struct iasecc_extended_tlv * tlv)405 iasecc_parse_get_tlv(struct sc_card *card, unsigned char *data, struct iasecc_extended_tlv *tlv)
406 {
407 	struct sc_context *ctx = card->ctx;
408 	size_t size_len, tag_len;
409 
410 	memset(tlv, 0, sizeof(*tlv));
411 	sc_log(ctx, "iasecc_parse_get_tlv() called for tag 0x%X", *data);
412 	if ((*data == 0x7F) || (*data == 0x5F))   {
413 		tlv->tag = *data * 0x100 + *(data + 1);
414 		tag_len = 2;
415 	}
416 	else   {
417 		tlv->tag = *data;
418 		tag_len = 1;
419 	}
420 
421 	sc_log(ctx, "iasecc_parse_get_tlv() tlv->tag 0x%X", tlv->tag);
422 	size_len = iasecc_parse_size(data + tag_len, &tlv->size);
423 	LOG_TEST_RET(ctx, size_len, "parse error: invalid size data");
424 
425 	tlv->value = calloc(1, tlv->size);
426 	if (!tlv->value)
427 		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
428 	memcpy(tlv->value, data + size_len + tag_len, tlv->size);
429 
430 	tlv->on_card = 1;
431 
432 	sc_log(ctx,
433 	       "iasecc_parse_get_tlv() parsed %"SC_FORMAT_LEN_SIZE_T"u bytes",
434 	       tag_len + size_len + tlv->size);
435 	return tag_len + size_len + tlv->size;
436 }
437 
438 
439 static int
iasecc_parse_chv(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo_chv * chv)440 iasecc_parse_chv(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_chv *chv)
441 {
442 	struct sc_context *ctx = card->ctx;
443 	size_t offs = 0;
444 	int rv;
445 
446 	LOG_FUNC_CALLED(ctx);
447 	while(offs < data_len)   {
448 		struct iasecc_extended_tlv tlv;
449 
450 		rv = iasecc_parse_get_tlv(card, data + offs, &tlv);
451 		LOG_TEST_RET(ctx, rv, "iasecc_parse_chv() get and parse TLV error");
452 
453 		sc_log(ctx,
454 		       "iasecc_parse_chv() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
455 		       rv, tlv.tag, tlv.size);
456 
457 		if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MAX)
458 			chv->size_max = tlv;
459 		else if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MIN)
460 			chv->size_min = tlv;
461 		else if (tlv.tag == IASECC_SDO_CHV_TAG_VALUE)
462 			chv->value = tlv;
463 		else
464 			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non CHV SDO tag");
465 
466 		offs += rv;
467 	}
468 
469 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
470 }
471 
472 
473 static int
iasecc_parse_prvkey(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo_prvkey * prvkey)474 iasecc_parse_prvkey(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_prvkey *prvkey)
475 {
476 	struct sc_context *ctx = card->ctx;
477 	size_t offs = 0;
478 	int rv;
479 
480 	LOG_FUNC_CALLED(ctx);
481 	while(offs < data_len)   {
482 		struct iasecc_extended_tlv tlv;
483 
484 		rv = iasecc_parse_get_tlv(card, data + offs, &tlv);
485 		LOG_TEST_RET(ctx, rv, "iasecc_parse_prvkey() get and parse TLV error");
486 
487 		sc_log(ctx,
488 		       "iasecc_parse_prvkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
489 		       rv, tlv.tag, tlv.size);
490 
491 		if (tlv.tag == IASECC_SDO_PRVKEY_TAG_COMPULSORY)
492 			prvkey->compulsory = tlv;
493 		else
494 			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non PrvKey SDO tag");
495 
496 		offs += rv;
497 	}
498 
499 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
500 }
501 
502 
503 static int
iasecc_parse_pubkey(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo_pubkey * pubkey)504 iasecc_parse_pubkey(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_pubkey *pubkey)
505 {
506 	struct sc_context *ctx = card->ctx;
507 	size_t offs = 0;
508 	int rv;
509 
510 	LOG_FUNC_CALLED(ctx);
511 	while(offs < data_len)   {
512 		struct iasecc_extended_tlv tlv;
513 
514 		rv = iasecc_parse_get_tlv(card, data + offs, &tlv);
515 		LOG_TEST_RET(ctx, rv, "iasecc_parse_pubkey() get and parse TLV error");
516 
517 		sc_log(ctx,
518 		       "iasecc_parse_pubkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
519 		       rv, tlv.tag, tlv.size);
520 
521 		if (tlv.tag == IASECC_SDO_PUBKEY_TAG_N)
522 			pubkey->n = tlv;
523 		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_E)
524 			pubkey->e = tlv;
525 		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHR)
526 			pubkey->chr = tlv;
527 		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHA)
528 			pubkey->cha = tlv;
529 		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_COMPULSORY)
530 			pubkey->compulsory = tlv;
531 		else
532 			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non PubKey SDO tag");
533 
534 		offs += rv;
535 	}
536 
537 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
538 }
539 
540 
541 static int
iasecc_parse_keyset(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo_keyset * keyset)542 iasecc_parse_keyset(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_keyset *keyset)
543 {
544 	struct sc_context *ctx = card->ctx;
545 	size_t offs = 0;
546 	int rv;
547 
548 	LOG_FUNC_CALLED(ctx);
549 	while(offs < data_len)   {
550 		struct iasecc_extended_tlv tlv;
551 
552 		rv = iasecc_parse_get_tlv(card, data + offs, &tlv);
553 		LOG_TEST_RET(ctx, rv, "iasecc_parse_keyset() get and parse TLV error");
554 
555 		sc_log(ctx,
556 		       "iasecc_parse_prvkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
557 		       rv, tlv.tag, tlv.size);
558 
559 		if (tlv.tag == IASECC_SDO_KEYSET_TAG_COMPULSORY)
560 			keyset->compulsory = tlv;
561 		else {
562 			free(tlv.value);
563 			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non KeySet SDO tag");
564 		}
565 
566 		offs += rv;
567 	}
568 
569 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
570 }
571 
572 
573 static int
iasecc_parse_docp(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo * sdo)574 iasecc_parse_docp(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo)
575 {
576 	struct sc_context *ctx = card->ctx;
577 	size_t offs = 0;
578 	int rv;
579 
580 	LOG_FUNC_CALLED(ctx);
581 	while(offs < data_len)   {
582 		struct iasecc_extended_tlv tlv;
583 
584 		rv = iasecc_parse_get_tlv(card, data + offs, &tlv);
585 		LOG_TEST_RET(ctx, rv, "iasecc_parse_get_tlv() get and parse TLV error");
586 
587 		sc_log(ctx,
588 		       "iasecc_parse_docp() parse_get_tlv returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
589 		       rv, tlv.tag, tlv.size);
590 
591 		if (tlv.tag == IASECC_DOCP_TAG_ACLS)   {
592 			int _rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo);
593 			free(tlv.value);
594 			LOG_TEST_RET(ctx, _rv, "parse error: cannot parse DOCP");
595 		}
596 		else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACT)   {
597 			sdo->docp.acls_contact = tlv;
598 		}
599 		else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACTLESS)   {
600 			sdo->docp.acls_contactless = tlv;
601 		}
602 		else if (tlv.tag == IASECC_DOCP_TAG_SIZE)   {
603 			sdo->docp.size = tlv;
604 		}
605 		else if (tlv.tag == IASECC_DOCP_TAG_NAME)   {
606 			sdo->docp.name = tlv;
607 		}
608 		else if (tlv.tag == IASECC_DOCP_TAG_ISSUER_DATA)   {
609 			sdo->docp.issuer_data = tlv;
610 		}
611 		else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION)   {
612 			sdo->docp.non_repudiation = tlv;
613 		}
614 		else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING)   {
615 			sdo->docp.usage_remaining = tlv;
616 		}
617 		else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM)   {
618 			sdo->docp.tries_maximum = tlv;
619 		}
620 		else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING)   {
621 			sdo->docp.tries_remaining = tlv;
622 		}
623 		else   {
624 			free(tlv.value);
625 			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_parse_get_tlv() parse error: non DOCP tag");
626 		}
627 
628 		offs += rv;
629 	}
630 
631 	rv = iasecc_parse_acls(card, &sdo->docp, 0);
632 	LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP");
633 
634 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
635 }
636 
637 
638 static int
iasecc_sdo_parse_data(struct sc_card * card,unsigned char * data,struct iasecc_sdo * sdo)639 iasecc_sdo_parse_data(struct sc_card *card, unsigned char *data, struct iasecc_sdo *sdo)
640 {
641 	struct sc_context *ctx = card->ctx;
642 	struct iasecc_extended_tlv tlv;
643 	int tlv_size, rv;
644 
645 	LOG_FUNC_CALLED(ctx);
646 	sc_log(ctx, "iasecc_sdo_parse_data() class %X; ref %X", sdo->sdo_class, sdo->sdo_ref);
647 
648 	tlv_size = iasecc_parse_get_tlv(card, data, &tlv);
649 	LOG_TEST_RET(ctx, tlv_size, "parse error: get TLV");
650 
651 	sc_log(ctx, "iasecc_sdo_parse_data() tlv.tag 0x%X", tlv.tag);
652 	if (tlv.tag == IASECC_DOCP_TAG)   {
653 		sc_log(ctx,
654 		       "iasecc_sdo_parse_data() parse IASECC_DOCP_TAG: 0x%X; size %"SC_FORMAT_LEN_SIZE_T"u",
655 		       tlv.tag, tlv.size);
656 		rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo);
657 		sc_log(ctx, "iasecc_sdo_parse_data() parsed IASECC_DOCP_TAG rv %i", rv);
658 		free(tlv.value);
659 		LOG_TEST_RET(ctx, rv, "parse error: cannot parse DOCP");
660 	}
661 	else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION)   {
662 		sdo->docp.non_repudiation = tlv;
663 	}
664 	else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING)   {
665 		sdo->docp.usage_remaining = tlv;
666 	}
667 	else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM)   {
668 		sdo->docp.tries_maximum = tlv;
669 	}
670 	else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING)   {
671 		sdo->docp.tries_remaining = tlv;
672 	}
673 	else if (tlv.tag == IASECC_SDO_CHV_TAG)   {
674 		if (sdo->sdo_class != IASECC_SDO_CLASS_CHV) {
675 			free(tlv.value);
676 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: IASECC_SDO_CHV_TAG tag in non User CHV SDO");
677 		}
678 
679 		rv = iasecc_parse_chv(card, tlv.value, tlv.size, &sdo->data.chv);
680 		free(tlv.value);
681 		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO CHV data");
682 	}
683 	else if (tlv.tag == IASECC_SDO_PUBKEY_TAG)   {
684 		if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PUBLIC) {
685 			free(tlv.value);
686 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PUBLIC_KEY tag in non PUBLIC_KEY SDO");
687 		}
688 
689 		rv = iasecc_parse_pubkey(card, tlv.value, tlv.size, &sdo->data.pub_key);
690 		free(tlv.value);
691 		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PUBLIC KEY data");
692 	}
693 	else if (tlv.tag == IASECC_SDO_PRVKEY_TAG)   {
694 		if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PRIVATE) {
695 			free(tlv.value);
696 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PRIVATE_KEY tag in non PRIVATE_KEY SDO");
697 		}
698 
699 		rv = iasecc_parse_prvkey(card, tlv.value, tlv.size, &sdo->data.prv_key);
700 		free(tlv.value);
701 		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PRIVATE KEY data");
702 	}
703 	else if (tlv.tag == IASECC_SDO_KEYSET_TAG)   {
704 		if (sdo->sdo_class != IASECC_SDO_CLASS_KEYSET) {
705 			free(tlv.value);
706 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_KEYSET tag in non KEYSET SDO");
707 		}
708 
709 		rv = iasecc_parse_keyset(card, tlv.value, tlv.size, &sdo->data.keyset);
710 		free(tlv.value);
711 		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO KEYSET data");
712 	}
713 	else   {
714 		sc_log(ctx, "iasecc_sdo_parse_data() non supported tag 0x%X", tlv.tag);
715 		free(tlv.value);
716 		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
717 	}
718 
719 	return tlv_size;
720 }
721 
722 
723 int
iasecc_sdo_parse(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo * sdo)724 iasecc_sdo_parse(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo)
725 {
726 	struct sc_context *ctx = card->ctx;
727 	size_t size, offs, size_size;
728 	int rv;
729 
730 	LOG_FUNC_CALLED(ctx);
731 
732 	if (*data == IASECC_SDO_TEMPLATE_TAG)   {
733 		size_size = iasecc_parse_size(data + 1, &size);
734 		LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE");
735 
736 		data += size_size + 1;
737 		data_len = size;
738 		sc_log(ctx,
739 		       "IASECC_SDO_TEMPLATE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %"SC_FORMAT_LEN_SIZE_T"u",
740 		       size, size_size);
741 	}
742 
743 	if (*data != IASECC_SDO_TAG_HEADER)
744 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
745 
746 	if (sdo->sdo_class != (*(data + 1) & 0x7F))
747 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
748 
749 	if (sdo->sdo_ref != (*(data + 2) & 0x3F))
750 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
751 
752 	size_size = iasecc_parse_size(data + 3, &size);
753 	LOG_TEST_RET(ctx, size_size, "parse error: invalid size data");
754 
755 	if (data_len != size + size_size + 3)
756 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size");
757 
758 	sc_log(ctx,
759 	       "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %"SC_FORMAT_LEN_SIZE_T"u",
760 	       size, size_size);
761 
762 	offs = 3 + size_size;
763 	for (; offs < data_len;)   {
764 		rv = iasecc_sdo_parse_data(card, data + offs, sdo);
765 		LOG_TEST_RET(ctx, rv, "parse error: invalid SDO data");
766 
767 		offs += rv;
768 	}
769 
770 	if (offs != data_len)
771 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed");
772 
773 	sc_log(ctx,
774 	       "docp.acls_contact.size %"SC_FORMAT_LEN_SIZE_T"u, docp.size.size %"SC_FORMAT_LEN_SIZE_T"u",
775 	       sdo->docp.acls_contact.size, sdo->docp.size.size);
776 
777 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
778 }
779 
780 
781 int
iasecc_sdo_allocate_and_parse(struct sc_card * card,unsigned char * data,size_t data_len,struct iasecc_sdo ** out)782 iasecc_sdo_allocate_and_parse(struct sc_card *card, unsigned char *data, size_t data_len,
783 		struct iasecc_sdo **out)
784 {
785 	struct sc_context *ctx = card->ctx;
786 	struct iasecc_sdo *sdo = NULL;
787 	size_t size, offs, size_size;
788 	int rv;
789 
790 	LOG_FUNC_CALLED(ctx);
791 
792 	if (*data != IASECC_SDO_TAG_HEADER)
793 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
794 
795 	if (data_len < 3)
796 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
797 
798 	sdo = calloc(1, sizeof(struct iasecc_sdo));
799 	if (!sdo)
800 		return SC_ERROR_OUT_OF_MEMORY;
801 	*out = sdo;
802 
803 	sdo->sdo_class = *(data + 1) & 0x7F;
804 	sdo->sdo_ref = *(data + 2) & 0x3F;
805 
806 	sc_log(ctx, "sdo_class 0x%X, sdo_ref 0x%X", sdo->sdo_class, sdo->sdo_ref);
807 	if (data_len == 3)
808 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
809 
810 	size_size = iasecc_parse_size(data + 3, &size);
811 	LOG_TEST_RET(ctx, size_size, "parse error: invalid size data");
812 
813 	if (data_len != size + size_size + 3)
814 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size");
815 
816 	sc_log(ctx,
817 	       "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %"SC_FORMAT_LEN_SIZE_T"u",
818 	       size, size_size);
819 
820 	offs = 3 + size_size;
821 	for (; offs < data_len;)   {
822 		rv = iasecc_sdo_parse_data(card, data + offs, sdo);
823 		LOG_TEST_RET(ctx, rv, "parse error: invalid SDO data");
824 
825 		offs += rv;
826 	}
827 
828 	if (offs != data_len)
829 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed");
830 
831 	sc_log(ctx,
832 	       "docp.acls_contact.size %"SC_FORMAT_LEN_SIZE_T"u; docp.size.size %"SC_FORMAT_LEN_SIZE_T"u",
833 	       sdo->docp.acls_contact.size, sdo->docp.size.size);
834 
835 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
836 }
837 
838 
839 static int
iasecc_update_blob(struct sc_context * ctx,struct iasecc_extended_tlv * tlv,unsigned char ** blob,size_t * blob_size)840 iasecc_update_blob(struct sc_context *ctx, struct iasecc_extended_tlv *tlv,
841 		unsigned char **blob, size_t *blob_size)
842 {
843 	unsigned char *pp = NULL;
844 	int offs = 0, sz;
845 
846 	if (tlv->size == 0)
847 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
848 
849 	sz = tlv->size + 2;
850 
851 	if (tlv->tag > 0xFF)
852 		sz += 1;
853 
854 	if (tlv->size > 0x7F && tlv->size < 0x100)
855 		sz += 1;
856 	else if (tlv->size >= 0x100)
857 		sz += 2;
858 
859 	pp = realloc(*blob, *blob_size + sz);
860 	if (!pp)
861 		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
862 
863 	if (tlv->tag > 0xFF)
864 		*(pp + *blob_size + offs++) = (tlv->tag >> 8) & 0xFF;
865 	*(pp + *blob_size + offs++) = tlv->tag & 0xFF;
866 
867 	if (tlv->size >= 0x100) {
868 		*(pp + *blob_size + offs++) = 0x82;
869 		*(pp + *blob_size + offs++) = (tlv->size >> 8) & 0xFF;
870 	}
871 	else if (tlv->size > 0x7F)   {
872 		*(pp + *blob_size + offs++) = 0x81;
873 	}
874 	*(pp + *blob_size + offs++) = tlv->size & 0xFF;
875 
876 	memcpy(pp + *blob_size + offs, tlv->value, tlv->size);
877 
878 	*blob_size += sz;
879 	*blob = pp;
880 
881 	return 0;
882 }
883 
884 
885 static int
iasecc_encode_docp(struct sc_context * ctx,struct iasecc_sdo_docp * docp,unsigned char ** out,size_t * out_len)886 iasecc_encode_docp(struct sc_context *ctx, struct iasecc_sdo_docp *docp, unsigned char **out, size_t *out_len)
887 {
888 	struct iasecc_extended_tlv tlv, tlv_st;
889 	unsigned char *st_blob = NULL, *tmp_blob = NULL, *docp_blob = NULL;
890 	size_t blob_size;
891 	int rv;
892 
893 	LOG_FUNC_CALLED(ctx);
894 	if (!docp->acls_contact.size || (docp->size.size != 2))
895 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
896 
897 	memset(&tlv, 0, sizeof(tlv));
898 	memset(&tlv_st, 0, sizeof(tlv_st));
899 
900 	blob_size = 0;
901 	rv = iasecc_update_blob(ctx, &docp->acls_contact, &st_blob, &blob_size);
902 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add contact ACLs to blob");
903 
904 	rv = iasecc_update_blob(ctx, &docp->acls_contactless, &st_blob, &blob_size);
905 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add contactless ACLs to blob");
906 
907 	tlv.tag = IASECC_DOCP_TAG_ACLS;
908 	tlv.size = blob_size;
909 	tlv.value = st_blob;
910 
911 	blob_size = 0;
912 	rv = iasecc_update_blob(ctx, &tlv, &tmp_blob, &blob_size);
913 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add ACLs template to blob");
914 
915 	rv = iasecc_update_blob(ctx, &docp->name, &tmp_blob, &blob_size);
916 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add NAME to blob");
917 
918 	rv = iasecc_update_blob(ctx, &docp->tries_maximum, &tmp_blob, &blob_size);
919 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add TRIES MAXIMUM to blob");
920 
921 	rv = iasecc_update_blob(ctx, &docp->tries_remaining, &tmp_blob, &blob_size);
922 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add TRIES REMAINING to blob");
923 
924 	rv = iasecc_update_blob(ctx, &docp->usage_maximum, &tmp_blob, &blob_size);
925 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add USAGE MAXIMUM to blob");
926 
927 	rv = iasecc_update_blob(ctx, &docp->usage_remaining, &tmp_blob, &blob_size);
928 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add USAGE REMAINING to blob");
929 
930 	rv = iasecc_update_blob(ctx, &docp->non_repudiation, &tmp_blob, &blob_size);
931 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add NON REPUDIATION to blob");
932 
933 	rv = iasecc_update_blob(ctx, &docp->size, &tmp_blob, &blob_size);
934 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add SIZE to blob");
935 
936 	rv = iasecc_update_blob(ctx, &docp->issuer_data, &tmp_blob, &blob_size);
937 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add IDATA to blob");
938 
939 	tlv.tag = IASECC_DOCP_TAG;
940 	tlv.size = blob_size;
941 	tlv.value = tmp_blob;
942 
943 	blob_size = 0;
944 	rv = iasecc_update_blob(ctx, &tlv, &docp_blob, &blob_size);
945 	LOG_TEST_GOTO_ERR(ctx, rv, "ECC: cannot add ACLs to blob");
946 
947 	if (out && out_len)   {
948 		*out = docp_blob;
949 		*out_len = blob_size;
950 		docp_blob = NULL;
951 	}
952 
953 err:
954 	free(docp_blob);
955 	free(tmp_blob);
956 	free(st_blob);
957 
958 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
959 }
960 
961 
962 static unsigned
iasecc_sdo_encode_asn1_tag(unsigned in_tag)963 iasecc_sdo_encode_asn1_tag(unsigned in_tag)
964 {
965 	unsigned short_tag;
966 	unsigned out_tag;
967 
968 	for (short_tag = in_tag; short_tag > 0xFF; short_tag >>= 8)
969 		;
970 	out_tag = in_tag;
971 	switch (short_tag & SC_ASN1_TAG_CLASS)   {
972 	case SC_ASN1_TAG_APPLICATION:
973 		out_tag |= SC_ASN1_APP;
974 		break;
975 	case SC_ASN1_TAG_CONTEXT:
976 		out_tag |= SC_ASN1_CTX;
977 		break;
978 	case SC_ASN1_TAG_PRIVATE:
979 		out_tag |= SC_ASN1_PRV;
980 		break;
981 	}
982 	return out_tag;
983 }
984 
985 
986 int
iasecc_sdo_encode_create(struct sc_context * ctx,struct iasecc_sdo * sdo,unsigned char ** out)987 iasecc_sdo_encode_create(struct sc_context *ctx, struct iasecc_sdo *sdo, unsigned char **out)
988 {
989 	struct sc_asn1_entry c_asn1_docp_data[2] = {
990 		{ "docpData", SC_ASN1_OCTET_STRING, 0, SC_ASN1_ALLOC, NULL, NULL },
991 		{ NULL, 0, 0, 0, NULL, NULL }
992 	};
993 	struct sc_asn1_entry c_asn1_create_data[2] = {
994 		{ "createData", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_APP | SC_ASN1_CONS, 0, NULL, NULL },
995 		{ NULL, 0, 0, 0, NULL, NULL }
996 	};
997 	struct sc_asn1_entry asn1_docp_data[2], asn1_create_data[2];
998 	unsigned char *blob = NULL;
999 	size_t len, out_len;
1000 	unsigned sdo_full_ref;
1001 	int rv;
1002 
1003 	LOG_FUNC_CALLED(ctx);
1004 	sc_log(ctx, "ecc_sdo_encode_create() sdo->sdo_class %X", sdo->sdo_class);
1005 	sc_log(ctx, "id %02X%02X%02X", IASECC_SDO_TAG_HEADER, sdo->sdo_class | 0x80, sdo->sdo_ref);
1006 
1007 	if (out)
1008 		*out = NULL;
1009 
1010 	rv = iasecc_encode_docp(ctx, &sdo->docp, &blob, &len);
1011 	LOG_TEST_RET(ctx, rv, "ECC encode DOCP error");
1012 
1013 	sdo_full_ref = (sdo->sdo_ref&0x3F)  + 0x100*(sdo->sdo_class | IASECC_OBJECT_REF_LOCAL) + 0x10000*IASECC_SDO_TAG_HEADER;
1014 	c_asn1_docp_data[0].tag = iasecc_sdo_encode_asn1_tag(sdo_full_ref) | SC_ASN1_CONS;
1015 
1016 	sc_copy_asn1_entry(c_asn1_docp_data, asn1_docp_data);
1017 	sc_copy_asn1_entry(c_asn1_create_data, asn1_create_data);
1018 
1019 	sc_format_asn1_entry(asn1_docp_data + 0, blob, &len, 1);
1020 	sc_format_asn1_entry(asn1_create_data + 0, asn1_docp_data, NULL, 1);
1021 
1022 	rv = sc_asn1_encode(ctx, asn1_create_data, out, &out_len);
1023 	LOG_TEST_RET(ctx, rv, "Encode create data error");
1024 	if (out)
1025 		sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Create data: %s", sc_dump_hex(*out, out_len));
1026 
1027 	LOG_FUNC_RETURN(ctx, out_len);
1028 }
1029 
1030 
1031 int
iasecc_sdo_encode_update_field(struct sc_context * ctx,unsigned char sdo_class,unsigned char sdo_ref,struct iasecc_extended_tlv * tlv,unsigned char ** out)1032 iasecc_sdo_encode_update_field(struct sc_context *ctx, unsigned char sdo_class, unsigned char sdo_ref,
1033 		struct iasecc_extended_tlv *tlv, unsigned char **out)
1034 {
1035 	unsigned sdo_full_ref;
1036 	size_t out_len;
1037 	int rv;
1038 
1039 	struct sc_asn1_entry c_asn1_field_value[2] = {
1040 	        { "fieldValue", SC_ASN1_OCTET_STRING, 0, SC_ASN1_ALLOC, NULL, NULL },
1041 		{ NULL, 0, 0, 0, NULL, NULL }
1042 	};
1043 	struct sc_asn1_entry c_asn1_sdo_field[2] = {
1044 		{ "sdoField", SC_ASN1_STRUCT, 0, 0, NULL, NULL },
1045 		{ NULL, 0, 0, 0, NULL, NULL }
1046 	};
1047 	struct sc_asn1_entry c_asn1_class_data[2] = {
1048 		{ "classData", SC_ASN1_STRUCT, 0, 0, NULL, NULL },
1049 		{ NULL, 0, 0, 0, NULL, NULL }
1050 	};
1051 	struct sc_asn1_entry c_asn1_update_data[2] = {
1052 		{ "updateData", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_APP | SC_ASN1_CONS, 0, NULL, NULL },
1053 		{ NULL, 0, 0, 0, NULL, NULL }
1054 	};
1055 	struct sc_asn1_entry asn1_field_value[4], asn1_sdo_field[2], asn1_class_data[2], asn1_update_data[2];
1056 
1057 	LOG_FUNC_CALLED(ctx);
1058 
1059 	c_asn1_field_value[0].tag = iasecc_sdo_encode_asn1_tag(tlv->tag);
1060 	c_asn1_sdo_field[0].tag = iasecc_sdo_encode_asn1_tag(tlv->parent_tag) | SC_ASN1_CONS;
1061 
1062 	sdo_full_ref = (sdo_ref&0x3F)  + 0x100*(sdo_class | IASECC_OBJECT_REF_LOCAL) + 0x10000*IASECC_SDO_TAG_HEADER;
1063 	c_asn1_class_data[0].tag = iasecc_sdo_encode_asn1_tag(sdo_full_ref) | SC_ASN1_CONS;
1064 
1065 	sc_copy_asn1_entry(c_asn1_field_value, asn1_field_value);
1066 	sc_copy_asn1_entry(c_asn1_sdo_field, asn1_sdo_field);
1067 	sc_copy_asn1_entry(c_asn1_class_data, asn1_class_data);
1068 	sc_copy_asn1_entry(c_asn1_update_data, asn1_update_data);
1069 
1070 	sc_format_asn1_entry(asn1_field_value + 0, tlv->value, &tlv->size, 1);
1071 	sc_format_asn1_entry(asn1_sdo_field + 0, asn1_field_value, NULL, 1);
1072 	sc_format_asn1_entry(asn1_class_data + 0, asn1_sdo_field, NULL, 1);
1073 	sc_format_asn1_entry(asn1_update_data + 0, asn1_class_data, NULL, 1);
1074 
1075 	rv = sc_asn1_encode(ctx, asn1_update_data, out, &out_len);
1076 	LOG_TEST_RET(ctx, rv, "Encode update data error");
1077 
1078 	sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Data: %s", sc_dump_hex(tlv->value, tlv->size));
1079 	sc_debug(ctx, SC_LOG_DEBUG_ASN1,"Encoded: %s", sc_dump_hex(*out, out_len));
1080 	LOG_FUNC_RETURN(ctx, out_len);
1081 }
1082 
1083 
1084 int
iasecc_sdo_encode_rsa_update(struct sc_context * ctx,struct iasecc_sdo * sdo,struct sc_pkcs15_prkey_rsa * rsa,struct iasecc_sdo_update * sdo_update)1085 iasecc_sdo_encode_rsa_update(struct sc_context *ctx, struct iasecc_sdo *sdo, struct sc_pkcs15_prkey_rsa *rsa,
1086 		struct iasecc_sdo_update *sdo_update)
1087 {
1088 	LOG_FUNC_CALLED(ctx);
1089 
1090 	sc_log(ctx, "iasecc_sdo_encode_rsa_update() SDO class %X", sdo->sdo_class);
1091 	memset(sdo_update, 0, sizeof(*sdo_update));
1092 	if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PRIVATE)   {
1093 		int indx = 0;
1094 
1095 		sc_log(ctx, "iasecc_sdo_encode_rsa_update(IASECC_SDO_CLASS_RSA_PRIVATE)");
1096 		if (!rsa->p.len || !rsa->q.len || !rsa->iqmp.len || !rsa->dmp1.len || !rsa->dmq1.len)
1097 			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "need all private RSA key components");
1098 
1099 		sdo_update->magic = SC_CARDCTL_IASECC_SDO_MAGIC_PUT_DATA;
1100 		sdo_update->sdo_ref = sdo->sdo_ref;
1101 
1102 		sdo_update->sdo_class = IASECC_SDO_CLASS_RSA_PRIVATE;
1103 
1104 		sdo_update->fields[indx].parent_tag = IASECC_SDO_PRVKEY_TAG;
1105 		sdo_update->fields[indx].tag = IASECC_SDO_PRVKEY_TAG_P;
1106 		sdo_update->fields[indx].value = rsa->p.data;
1107 		sdo_update->fields[indx].size = rsa->p.len;
1108 		indx++;
1109 
1110 		sdo_update->fields[indx].parent_tag = IASECC_SDO_PRVKEY_TAG;
1111 		sdo_update->fields[indx].tag = IASECC_SDO_PRVKEY_TAG_Q;
1112 		sdo_update->fields[indx].value = rsa->q.data;
1113 		sdo_update->fields[indx].size = rsa->q.len;
1114 		indx++;
1115 
1116 		sdo_update->fields[indx].parent_tag = IASECC_SDO_PRVKEY_TAG;
1117 		sdo_update->fields[indx].tag = IASECC_SDO_PRVKEY_TAG_IQMP;
1118 		sdo_update->fields[indx].value = rsa->iqmp.data;
1119 		sdo_update->fields[indx].size = rsa->iqmp.len;
1120 		indx++;
1121 
1122 		sdo_update->fields[indx].parent_tag = IASECC_SDO_PRVKEY_TAG;
1123 		sdo_update->fields[indx].tag = IASECC_SDO_PRVKEY_TAG_DMP1;
1124 		sdo_update->fields[indx].value = rsa->dmp1.data;
1125 		sdo_update->fields[indx].size = rsa->dmp1.len;
1126 		indx++;
1127 
1128 		sdo_update->fields[indx].parent_tag = IASECC_SDO_PRVKEY_TAG;
1129 		sdo_update->fields[indx].tag = IASECC_SDO_PRVKEY_TAG_DMQ1;
1130 		sdo_update->fields[indx].value = rsa->dmq1.data;
1131 		sdo_update->fields[indx].size = rsa->dmq1.len;
1132 		indx++;
1133 
1134 		sc_log(ctx, "prv_key.compulsory.on_card %i", sdo->data.prv_key.compulsory.on_card);
1135 		if (!sdo->data.prv_key.compulsory.on_card)   {
1136 			if (sdo->data.prv_key.compulsory.value)   {
1137 				sc_log(ctx,
1138 				       "sdo_prvkey->data.prv_key.compulsory.size %"SC_FORMAT_LEN_SIZE_T"u",
1139 				       sdo->data.prv_key.compulsory.size);
1140 				sdo_update->fields[indx].parent_tag = IASECC_SDO_PRVKEY_TAG;
1141 				sdo_update->fields[indx].tag = IASECC_SDO_PRVKEY_TAG_COMPULSORY;
1142 				sdo_update->fields[indx].value = sdo->data.prv_key.compulsory.value;
1143 				sdo_update->fields[indx].size = sdo->data.prv_key.compulsory.size;
1144 				indx++;
1145 			}
1146 		}
1147 	}
1148 	else if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PUBLIC)   {
1149 		int indx = 0;
1150 		sc_log(ctx, "iasecc_sdo_encode_rsa_update(IASECC_SDO_CLASS_RSA_PUBLIC)");
1151 
1152 		sdo_update->magic = SC_CARDCTL_IASECC_SDO_MAGIC_PUT_DATA;
1153 		sdo_update->sdo_ref = sdo->sdo_ref;
1154 		sdo_update->sdo_class = sdo->sdo_class;
1155 
1156 		if (rsa->exponent.len)   {
1157 			sdo_update->fields[indx].parent_tag = IASECC_SDO_PUBKEY_TAG;
1158 			sdo_update->fields[indx].tag = IASECC_SDO_PUBKEY_TAG_E;
1159 			sdo_update->fields[indx].value = rsa->exponent.data;
1160 			sdo_update->fields[indx].size = rsa->exponent.len;
1161 			indx++;
1162 		}
1163 
1164 		if (rsa->modulus.len)   {
1165 			sdo_update->fields[indx].parent_tag = IASECC_SDO_PUBKEY_TAG;
1166 			sdo_update->fields[indx].tag = IASECC_SDO_PUBKEY_TAG_N;
1167 			sdo_update->fields[indx].value = rsa->modulus.data;
1168 			sdo_update->fields[indx].size = rsa->modulus.len;
1169 			indx++;
1170 		}
1171 
1172 		if (sdo->data.pub_key.cha.value)   {
1173 			sdo_update->fields[indx].parent_tag = IASECC_SDO_PUBKEY_TAG;
1174 			sdo_update->fields[indx].tag = IASECC_SDO_PUBKEY_TAG_CHA;
1175 			sdo_update->fields[indx].value = sdo->data.pub_key.cha.value;
1176 			sdo_update->fields[indx].size = sdo->data.pub_key.cha.size;
1177 			indx++;
1178 		}
1179 
1180 		if (sdo->data.pub_key.chr.value)   {
1181 			sdo_update->fields[indx].parent_tag = IASECC_SDO_PUBKEY_TAG;
1182 			sdo_update->fields[indx].tag = IASECC_SDO_PUBKEY_TAG_CHR;
1183 			sdo_update->fields[indx].value = sdo->data.pub_key.chr.value;
1184 			sdo_update->fields[indx].size = sdo->data.pub_key.chr.size;
1185 			indx++;
1186 		}
1187 
1188 		/* For ECC card 'compulsory' flag should be already here */
1189 		if (!sdo->data.pub_key.compulsory.on_card)   {
1190 			if (sdo->data.pub_key.compulsory.value)   {
1191 				sdo_update->fields[indx].parent_tag = IASECC_SDO_PUBKEY_TAG;
1192 				sdo_update->fields[indx].tag = IASECC_SDO_PUBKEY_TAG_COMPULSORY;
1193 				sdo_update->fields[indx].value = sdo->data.pub_key.compulsory.value;
1194 				sdo_update->fields[indx].size = sdo->data.pub_key.compulsory.size;
1195 				indx++;
1196 			}
1197 		}
1198 	}
1199 	else   {
1200 		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
1201 	}
1202 
1203 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
1204 }
1205 
1206 
1207 int
iasecc_sdo_parse_card_answer(struct sc_context * ctx,unsigned char * data,size_t data_len,struct iasecc_sm_card_answer * out)1208 iasecc_sdo_parse_card_answer(struct sc_context *ctx, unsigned char *data, size_t data_len,
1209 	struct iasecc_sm_card_answer *out)
1210 {
1211 	int have_mac = 0, have_status = 0;
1212 	size_t size = 0, size_size, offs;
1213 
1214 	LOG_FUNC_CALLED(ctx);
1215 	if (!data || !data_len || !out)
1216 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
1217 
1218 	memset(out, 0, sizeof(*out));
1219 	for (offs=0; offs<data_len; )   {
1220 		size_size = iasecc_parse_size(data + 1, &size);
1221 
1222 		if (*(data + offs) == IASECC_CARD_ANSWER_TAG_DATA )   {
1223 			if (size > sizeof(out->data))
1224 				LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "iasecc_sm_decode_answer() unbelievable !!!");
1225 
1226 			memcpy(out->data, data + offs + size_size + 1, size);
1227 			out->data_len = size;
1228 			offs += 1 + size_size + size;
1229 		}
1230 		else if (*(data + offs) == IASECC_CARD_ANSWER_TAG_SW )   {
1231 			if (*(data + offs + 1) != 2)
1232 				LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() SW length not 2");
1233 			out->sw = *(data + offs + 2) * 0x100 + *(data + offs + 3);
1234 
1235 			memcpy(out->ticket, data + offs, 4);
1236 
1237 			offs += 4;
1238 			have_status = 1;
1239 		}
1240 		else if (*(data + offs) == IASECC_CARD_ANSWER_TAG_MAC )   {
1241 			if (*(data + offs + 1) != 8)
1242 				LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() MAC length not 8");
1243 			memcpy(out->mac, data + offs + 2, 8);
1244 
1245 			memcpy(out->ticket + 4, data + offs, 10);
1246 
1247 			offs += 10;
1248 			have_mac = 1;
1249 		}
1250 		else   {
1251 			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() invalid card answer tag");
1252 		}
1253 	}
1254 
1255 	if (!have_mac || !have_status)
1256 		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_sm_decode_answer() absent MAC or SW ");
1257 
1258 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
1259 }
1260 
1261 
1262 static int
iasecc_tlv_copy(struct sc_context * ctx,struct iasecc_extended_tlv * in,struct iasecc_extended_tlv * out)1263 iasecc_tlv_copy(struct sc_context *ctx, struct iasecc_extended_tlv *in, struct iasecc_extended_tlv *out)
1264 {
1265 	if (!in || !out)
1266 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
1267 
1268 	memset(out, 0, sizeof(struct iasecc_extended_tlv));
1269 	out->tag = in->tag;
1270 	out->parent_tag = in->parent_tag;
1271 	out->on_card = in->on_card;
1272 	if (in->value && in->size)   {
1273 		out->value = calloc(1, in->size);
1274 		if (!out->value)
1275 			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
1276 
1277 		memcpy(out->value, in->value, in->size);
1278 		out->size = in->size;
1279 	}
1280 
1281 	return SC_SUCCESS;
1282 }
1283 
1284 
1285 int
iasecc_docp_copy(struct sc_context * ctx,struct iasecc_sdo_docp * in,struct iasecc_sdo_docp * out)1286 iasecc_docp_copy(struct sc_context *ctx, struct iasecc_sdo_docp *in, struct iasecc_sdo_docp *out)
1287 {
1288 	int rv;
1289 
1290 	LOG_FUNC_CALLED(ctx);
1291 	if (!in || !out)
1292 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
1293 
1294 	memset(out, 0, sizeof(struct iasecc_sdo_docp));
1295 
1296 	rv = iasecc_tlv_copy(ctx, &in->name, &out->name);
1297 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1298 
1299 	rv = iasecc_tlv_copy(ctx, &in->tries_maximum, &out->tries_maximum);
1300 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1301 
1302 	rv = iasecc_tlv_copy(ctx, &in->tries_remaining, &out->tries_remaining);
1303 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1304 
1305 	rv = iasecc_tlv_copy(ctx, &in->usage_maximum, &out->usage_maximum);
1306 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1307 
1308 	rv = iasecc_tlv_copy(ctx, &in->usage_remaining, &out->usage_remaining);
1309 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1310 
1311 	rv = iasecc_tlv_copy(ctx, &in->non_repudiation, &out->non_repudiation);
1312 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1313 
1314 	rv = iasecc_tlv_copy(ctx, &in->size, &out->size);
1315 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1316 
1317 	rv = iasecc_tlv_copy(ctx, &in->acls_contact, &out->acls_contact);
1318 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1319 
1320 	rv = iasecc_tlv_copy(ctx, &in->acls_contactless, &out->acls_contactless);
1321 	LOG_TEST_RET(ctx, rv, "TLV copy error");
1322 
1323 	out->amb = in->amb;
1324 	memcpy(out->scbs, in->scbs, sizeof(out->scbs));
1325 
1326 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
1327 }
1328 
1329 #else
1330 
1331 /* we need to define the functions below to export them */
1332 #include "errors.h"
1333 
1334 int
iasecc_sdo_encode_update_field()1335 iasecc_sdo_encode_update_field()
1336 {
1337 	return SC_ERROR_NOT_SUPPORTED;
1338 }
1339 
1340 int
iasecc_se_get_crt()1341 iasecc_se_get_crt()
1342 {
1343 	return SC_ERROR_NOT_SUPPORTED;
1344 }
1345 
1346 #endif /* ENABLE_OPENSSL */
1347