Coverage Report

Created: 2025-10-13 07:02

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