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