Coverage Report

Created: 2026-08-31 06:13

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