Coverage Report

Created: 2025-08-26 06:43

/src/opensc/src/libopensc/iasecc-sdo.c
Line
Count
Source (jump to first uncovered line)
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
6
{
45
6
  struct sc_context *ctx = card->ctx;
46
6
  struct iasecc_extended_tlv *acls = &docp->acls_contact;
47
6
  int ii;
48
6
  size_t offs;
49
6
  unsigned char mask = 0x40;
50
51
6
  if (flags)
52
0
    acls = &docp->acls_contactless;
53
54
6
  if (!acls->size)
55
6
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
56
57
5
  docp->amb = *(acls->value + 0);
58
5
  memset(docp->scbs, 0xFF, sizeof(docp->scbs));
59
40
  for (ii=0, offs = 1; ii<7; ii++, mask >>= 1)
60
35
    if (mask & docp->amb) {
61
23
      if (offs >= acls->size) {
62
0
        LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
63
0
      }
64
23
      docp->scbs[ii] = *(acls->value + offs++);
65
23
    }
66
67
5
  sc_log(ctx, "iasecc_parse_docp() SCBs %02X:%02X:%02X:%02X:%02X:%02X:%02X",
68
5
      docp->scbs[0],docp->scbs[1],docp->scbs[2],docp->scbs[3],
69
5
      docp->scbs[4],docp->scbs[5],docp->scbs[6]);
70
5
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
71
5
}
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
69
{
151
69
  free(sdo->docp.tries_maximum.value);
152
69
  free(sdo->docp.tries_remaining.value);
153
69
  free(sdo->docp.usage_remaining.value);
154
69
  free(sdo->docp.non_repudiation.value);
155
69
  free(sdo->docp.acls_contact.value);
156
69
  free(sdo->docp.acls_contactless.value);
157
69
  free(sdo->docp.size.value);
158
69
  free(sdo->docp.name.value);
159
69
  free(sdo->docp.issuer_data.value);
160
161
69
  if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PUBLIC)   {
162
1
    free(sdo->data.pub_key.n.value);
163
1
    free(sdo->data.pub_key.e.value);
164
1
    free(sdo->data.pub_key.compulsory.value);
165
1
    free(sdo->data.pub_key.chr.value);
166
1
    free(sdo->data.pub_key.cha.value);
167
1
  }
168
68
  else if (sdo->sdo_class == IASECC_SDO_CLASS_RSA_PRIVATE)   {
169
11
    free(sdo->data.prv_key.p.value);
170
11
    free(sdo->data.prv_key.q.value);
171
11
    free(sdo->data.prv_key.iqmp.value);
172
11
    free(sdo->data.prv_key.dmp1.value);
173
11
    free(sdo->data.prv_key.dmq1.value);
174
11
    free(sdo->data.prv_key.compulsory.value);
175
11
  }
176
57
  else if (sdo->sdo_class == IASECC_SDO_CLASS_CHV)   {
177
43
    free(sdo->data.chv.size_max.value);
178
43
    free(sdo->data.chv.size_min.value);
179
43
    free(sdo->data.chv.value.value);
180
43
  }
181
  /* invalidate all the other members too */
182
69
  memset(sdo, 0, sizeof(struct iasecc_sdo));
183
69
}
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
1.13k
{
197
1.13k
  struct sc_context *ctx = card->ctx;
198
1.13k
  struct sc_crt crt;
199
1.13k
  int ii, offs, len, parsed_len = -1;
200
201
1.13k
  sc_log(ctx, "iasecc_crt_parse(0x%X) called", *data);
202
203
1.13k
  if (data_len < 2)
204
1.13k
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
205
206
1.13k
  memset(&crt, 0, sizeof(crt));
207
1.13k
  crt.tag = *(data + 0);
208
1.13k
  len = *(data + 1);
209
210
1.27k
  for(offs = 2; offs < len + 2; offs += 3)   {
211
175
    if ((size_t) offs + 2 >= data_len)
212
175
      LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
213
174
    sc_log(ctx, "iasecc_crt_parse(0x%X) CRT %X -> %X", *data, *(data + offs), *(data + offs + 2));
214
174
    if (*(data + offs) == IASECC_CRT_TAG_USAGE)   {
215
36
      crt.usage = *(data + offs + 2);
216
36
    }
217
138
    else if (*(data + offs) == IASECC_CRT_TAG_REFERENCE)   {
218
42
      int nn_refs = sizeof(crt.refs) / sizeof(crt.refs[0]);
219
220
132
      for (ii=0; ii<nn_refs && crt.refs[ii]; ii++)
221
90
        ;
222
42
      if (ii == nn_refs)
223
42
        LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
224
225
41
      crt.refs[ii] = *(data + offs + 2);
226
41
    }
227
96
    else if (*(data + offs) == IASECC_CRT_TAG_ALGO)   {
228
65
      crt.algo = *(data + offs + 2);
229
65
    }
230
31
    else   {
231
31
      LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
232
31
    }
233
174
  }
234
235
3.57k
  for (ii=0; ii<SC_MAX_CRTS_IN_SE; ii++)
236
3.57k
    if (!se->crts[ii].tag)
237
1.10k
      break;
238
239
1.10k
  if (ii==SC_MAX_CRTS_IN_SE)
240
1.10k
    LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_crt_parse() error: too much CRTs in SE");
241
242
1.10k
  memcpy(&se->crts[ii], &crt, sizeof(crt));
243
1.10k
  parsed_len = len + 2;
244
1.10k
  LOG_FUNC_RETURN(ctx, parsed_len);
245
1.10k
}
246
247
248
int
249
iasecc_se_get_crt(struct sc_card *card, struct iasecc_se_info *se, struct sc_crt *crt)
250
10
{
251
10
  struct sc_context *ctx = card->ctx;
252
10
  int ii;
253
254
10
  LOG_FUNC_CALLED(ctx);
255
10
  if (!se || !crt)
256
10
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
257
10
  sc_log(ctx, "CRT search template: %X:%X:%X, refs %X:%X:...",
258
10
      crt->tag, crt->algo, crt->usage, crt->refs[0], crt->refs[1]);
259
260
61
  for (ii=0; ii<SC_MAX_CRTS_IN_SE && se->crts[ii].tag; ii++)   {
261
51
    if (crt->tag != se->crts[ii].tag)
262
35
      continue;
263
16
    if (crt->algo && crt->algo != se->crts[ii].algo)
264
0
      continue;
265
16
    if (crt->usage && crt->usage != se->crts[ii].usage)
266
16
      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
10
  sc_log(ctx, "iasecc_se_get_crt() CRT is not found");
278
10
  return SC_ERROR_DATA_OBJECT_NOT_FOUND;
279
10
}
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
63
{
314
63
  struct sc_context *ctx = card->ctx;
315
63
  size_t size, offs;
316
63
  int size_size;
317
63
  int rv;
318
319
63
  LOG_FUNC_CALLED(ctx);
320
321
63
  if (data_len < 1)
322
63
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
323
324
62
  if (*data == IASECC_SDO_TEMPLATE_TAG)   {
325
6
    size_size = iasecc_parse_size(data + 1, data_len - 1, &size);
326
6
    LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE");
327
328
5
    if (data_len - 1 < size)
329
5
      LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
330
331
4
    data += size_size + 1;
332
4
    data_len = size;
333
4
    sc_log(ctx,
334
4
           "IASECC_SDO_TEMPLATE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %d",
335
4
           size, size_size);
336
337
4
    if (data_len < 3)
338
4
      LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
339
340
3
    if (*data != IASECC_SDO_TAG_HEADER)
341
3
      LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
342
343
0
    if ((*(data + 1) & 0x7F) != IASECC_SDO_CLASS_SE)
344
0
       LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
345
346
0
    size_size = iasecc_parse_size(data + 3, data_len - 3, &size);
347
0
    LOG_TEST_RET(ctx, size_size, "parse error: invalid SDO SE data size");
348
349
0
    if (data_len != size + size_size + 3)
350
0
      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
56
  if (*data != IASECC_SDO_CLASS_SE)   {
360
4
    sc_log(ctx,
361
4
           "Invalid SE tag 0x%X; data length %"SC_FORMAT_LEN_SIZE_T"u",
362
4
           *data, data_len);
363
4
    LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
364
4
  }
365
366
52
  size_size = iasecc_parse_size(data + 1, data_len - 1, &size);
367
52
  LOG_TEST_RET(ctx, size_size, "parse error: invalid size data");
368
369
51
  if (data_len != size + size_size + 1)
370
51
    LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SE data size");
371
372
45
  offs = 1 + size_size;
373
1.14k
  for (; offs < data_len;)   {
374
1.13k
    rv = iasecc_crt_parse(card, data + offs, data_len - offs, se);
375
1.13k
    LOG_TEST_RET(ctx, rv, "parse error: invalid SE data");
376
377
1.10k
    offs += rv;
378
1.10k
  }
379
380
10
  if (offs != data_len)
381
10
    LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: not totally parsed");
382
383
10
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
384
10
}
385
386
387
static int
388
iasecc_parse_size(unsigned char *data, size_t data_len, size_t *out)
389
244
{
390
244
  if (data_len > 0 && *data < 0x80) {
391
219
    *out = *data;
392
219
    return 1;
393
219
  }
394
25
  else if (data_len > 1 && *data == 0x81) {
395
5
    *out = *(data + 1);
396
5
    return 2;
397
5
  }
398
20
  else if (data_len > 2 && *data == 0x82) {
399
4
    *out = *(data + 1) * 0x100 + *(data + 2);
400
4
    return 3;
401
4
  }
402
403
16
  return SC_ERROR_INVALID_DATA;
404
244
}
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
121
{
410
121
  struct sc_context *ctx = card->ctx;
411
121
  int size_len, tag_len;
412
413
121
  memset(tlv, 0, sizeof(*tlv));
414
121
  sc_log(ctx, "iasecc_parse_get_tlv() called for tag 0x%X", *data);
415
121
  if (data_len < 1)
416
121
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
417
121
  if ((*data == 0x7F) || (*data == 0x5F))   {
418
7
    if (data_len < 2)
419
7
      LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
420
7
    tlv->tag = *data * 0x100 + *(data + 1);
421
7
    tag_len = 2;
422
7
  }
423
114
  else   {
424
114
    tlv->tag = *data;
425
114
    tag_len = 1;
426
114
  }
427
428
121
  sc_log(ctx, "iasecc_parse_get_tlv() tlv->tag 0x%X", tlv->tag);
429
121
  size_len = iasecc_parse_size(data + tag_len, data_len - tag_len, &tlv->size);
430
121
  LOG_TEST_RET(ctx, size_len, "parse error: invalid size data");
431
111
  if (tag_len + size_len + tlv->size > data_len) {
432
4
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
433
4
  }
434
435
107
  tlv->value = calloc(1, tlv->size);
436
107
  if (!tlv->value)
437
107
    LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
438
107
  memcpy(tlv->value, data + size_len + tag_len, tlv->size);
439
440
107
  tlv->on_card = 1;
441
442
107
  sc_log(ctx,
443
107
         "iasecc_parse_get_tlv() parsed %"SC_FORMAT_LEN_SIZE_T"u bytes",
444
107
         tag_len + size_len + tlv->size);
445
107
  return (int)(tag_len + size_len + tlv->size);
446
107
}
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
3
{
452
3
  struct sc_context *ctx = card->ctx;
453
3
  size_t offs = 0;
454
3
  int rv;
455
456
3
  LOG_FUNC_CALLED(ctx);
457
3
  while(offs < data_len)   {
458
2
    struct iasecc_extended_tlv tlv;
459
460
2
    rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv);
461
2
    LOG_TEST_RET(ctx, rv, "iasecc_parse_chv() get and parse TLV error");
462
463
1
    sc_log(ctx,
464
1
           "iasecc_parse_chv() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
465
1
           rv, tlv.tag, tlv.size);
466
467
1
    if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MAX) {
468
0
      free(chv->size_max.value);
469
0
      chv->size_max = tlv;
470
1
    } else if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MIN) {
471
0
      free(chv->size_min.value);
472
0
      chv->size_min = tlv;
473
1
    } else if (tlv.tag == IASECC_SDO_CHV_TAG_VALUE) {
474
0
      free(chv->value.value);
475
0
      chv->value = tlv;
476
1
    } else {
477
1
      free(tlv.value);
478
1
      LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non CHV SDO tag");
479
1
    }
480
481
0
    offs += rv;
482
0
  }
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
26
{
602
26
  struct sc_context *ctx = card->ctx;
603
26
  size_t offs = 0;
604
26
  int rv;
605
606
26
  LOG_FUNC_CALLED(ctx);
607
68
  while(offs < data_len)   {
608
62
    struct iasecc_extended_tlv tlv;
609
610
62
    rv = iasecc_parse_get_tlv(card, data + offs, data_len - offs, &tlv);
611
62
    LOG_TEST_RET(ctx, rv, "iasecc_parse_get_tlv() get and parse TLV error");
612
613
53
    sc_log(ctx,
614
53
           "iasecc_parse_docp() parse_get_tlv returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
615
53
           rv, tlv.tag, tlv.size);
616
617
53
    if (tlv.tag == IASECC_DOCP_TAG_ACLS)   {
618
3
      int _rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo);
619
3
      free(tlv.value);
620
3
      LOG_TEST_RET(ctx, _rv, "parse error: cannot parse DOCP");
621
3
    }
622
50
    else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACT)   {
623
5
      free(sdo->docp.acls_contact.value);
624
5
      sdo->docp.acls_contact = tlv;
625
5
    }
626
45
    else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACTLESS)   {
627
1
      free(sdo->docp.acls_contactless.value);
628
1
      sdo->docp.acls_contactless = tlv;
629
1
    }
630
44
    else if (tlv.tag == IASECC_DOCP_TAG_SIZE)   {
631
9
      free(sdo->docp.size.value);
632
9
      sdo->docp.size = tlv;
633
9
    }
634
35
    else if (tlv.tag == IASECC_DOCP_TAG_NAME)   {
635
12
      free(sdo->docp.name.value);
636
12
      sdo->docp.name = tlv;
637
12
    }
638
23
    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
19
    else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION)   {
643
3
      free(sdo->docp.non_repudiation.value);
644
3
      sdo->docp.non_repudiation = tlv;
645
3
    }
646
16
    else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING)   {
647
4
      free(sdo->docp.usage_remaining.value);
648
4
      sdo->docp.usage_remaining = tlv;
649
4
    }
650
12
    else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM)   {
651
1
      free(sdo->docp.tries_maximum.value);
652
1
      sdo->docp.tries_maximum = tlv;
653
1
    }
654
11
    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
8
    else   {
659
8
      free(tlv.value);
660
8
      LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_parse_get_tlv() parse error: non DOCP tag");
661
8
    }
662
663
42
    offs += rv;
664
42
  }
665
666
6
  rv = iasecc_parse_acls(card, &sdo->docp, 0);
667
6
  LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP");
668
669
5
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
670
5
}
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
57
{
676
57
  struct sc_context *ctx = card->ctx;
677
57
  struct iasecc_extended_tlv tlv;
678
57
  int tlv_size, rv;
679
680
57
  LOG_FUNC_CALLED(ctx);
681
57
  sc_log(ctx, "iasecc_sdo_parse_data() class %X; ref %X", sdo->sdo_class, sdo->sdo_ref);
682
683
57
  tlv_size = iasecc_parse_get_tlv(card, data, data_len, &tlv);
684
57
  LOG_TEST_RET(ctx, tlv_size, "parse error: get TLV");
685
686
53
  sc_log(ctx, "iasecc_sdo_parse_data() tlv.tag 0x%X", tlv.tag);
687
53
  if (tlv.tag == IASECC_DOCP_TAG)   {
688
23
    sc_log(ctx,
689
23
           "iasecc_sdo_parse_data() parse IASECC_DOCP_TAG: 0x%X; size %"SC_FORMAT_LEN_SIZE_T"u",
690
23
           tlv.tag, tlv.size);
691
23
    rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo);
692
23
    sc_log(ctx, "iasecc_sdo_parse_data() parsed IASECC_DOCP_TAG rv %i", rv);
693
23
    free(tlv.value);
694
23
    LOG_TEST_RET(ctx, rv, "parse error: cannot parse DOCP");
695
23
  }
696
30
  else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDIATION)   {
697
1
    free(sdo->docp.non_repudiation.value);
698
1
    sdo->docp.non_repudiation = tlv;
699
1
  }
700
29
  else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING)   {
701
1
    free(sdo->docp.usage_remaining.value);
702
1
    sdo->docp.usage_remaining = tlv;
703
1
  }
704
28
  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
27
  else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING)   {
709
5
    free(sdo->docp.tries_remaining.value);
710
5
    sdo->docp.tries_remaining = tlv;
711
5
  }
712
22
  else if (tlv.tag == IASECC_SDO_CHV_TAG)   {
713
3
    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
3
    rv = iasecc_parse_chv(card, tlv.value, tlv.size, &sdo->data.chv);
719
3
    free(tlv.value);
720
3
    LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO CHV data");
721
3
  }
722
19
  else if (tlv.tag == IASECC_SDO_PUBKEY_TAG)   {
723
0
    if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PUBLIC) {
724
0
      free(tlv.value);
725
0
      LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PUBLIC_KEY tag in non PUBLIC_KEY SDO");
726
0
    }
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
19
  else if (tlv.tag == IASECC_SDO_PRVKEY_TAG)   {
733
0
    if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PRIVATE) {
734
0
      free(tlv.value);
735
0
      LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PRIVATE_KEY tag in non PRIVATE_KEY SDO");
736
0
    }
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
19
  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
18
  else   {
753
18
    sc_log(ctx, "iasecc_sdo_parse_data() non supported tag 0x%X", tlv.tag);
754
18
    free(tlv.value);
755
18
    LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
756
18
  }
757
758
14
  return tlv_size;
759
53
}
760
761
762
int
763
iasecc_sdo_parse(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo)
764
95
{
765
95
  struct sc_context *ctx = card->ctx;
766
95
  size_t size, offs;
767
95
  int size_size;
768
95
  int rv;
769
770
95
  LOG_FUNC_CALLED(ctx);
771
772
95
  if (data == NULL || data_len < 2)
773
95
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
774
775
78
  if (*data == IASECC_SDO_TEMPLATE_TAG)   {
776
5
    size_size = iasecc_parse_size(data + 1, data_len - 1, &size);
777
5
    LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE");
778
779
2
    data += size_size + 1;
780
2
    data_len = size;
781
2
    sc_log(ctx,
782
2
           "IASECC_SDO_TEMPLATE: size %"SC_FORMAT_LEN_SIZE_T"u, size_size %d",
783
2
           size, size_size);
784
2
  }
785
786
75
  if (*data != IASECC_SDO_TAG_HEADER)
787
75
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
788
789
65
  if (sdo->sdo_class != (*(data + 1) & 0x7F))
790
65
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
791
792
64
  if (sdo->sdo_ref != (*(data + 2) & 0x3F))
793
64
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
794
795
60
  size_size = iasecc_parse_size(data + 3, data_len - 3, &size);
796
60
  LOG_TEST_RET(ctx, size_size, "parse error: invalid size data");
797
798
59
  if (data_len != size + size_size + 3)
799
59
    LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: invalid SDO data size");
800
801
44
  sc_log(ctx,
802
44
         "sz %"SC_FORMAT_LEN_SIZE_T"u, sz_size %d",
803
44
         size, size_size);
804
805
44
  offs = 3 + size_size;
806
58
  for (; offs < data_len;)   {
807
57
    rv = iasecc_sdo_parse_data(card, data + offs, data_len - offs, sdo);
808
57
    if (rv != SC_SUCCESS) {
809
57
      iasecc_sdo_free_fields(card, sdo);
810
57
      LOG_TEST_RET(ctx, rv, "parse error: invalid SDO data");
811
57
    }
812
813
14
    offs += rv;
814
14
  }
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
11
{
831
11
  struct sc_context *ctx = card->ctx;
832
11
  struct iasecc_sdo *sdo = NULL;
833
11
  size_t size, offs;
834
11
  int size_size;
835
11
  int rv;
836
837
11
  LOG_FUNC_CALLED(ctx);
838
839
11
  if (*data != IASECC_SDO_TAG_HEADER)
840
11
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
841
842
11
  if (data_len < 3)
843
11
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
844
845
11
  sdo = calloc(1, sizeof(struct iasecc_sdo));
846
11
  if (!sdo)
847
0
    return SC_ERROR_OUT_OF_MEMORY;
848
11
  *out = sdo;
849
850
11
  sdo->sdo_class = *(data + 1) & 0x7F;
851
11
  sdo->sdo_ref = *(data + 2) & 0x3F;
852
853
11
  sc_log(ctx, "sdo_class 0x%X, sdo_ref 0x%X", sdo->sdo_class, sdo->sdo_ref);
854
11
  if (data_len == 3)
855
11
    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
90
{
1312
90
  if (!in || !out)
1313
90
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
1314
1315
90
  memset(out, 0, sizeof(struct iasecc_extended_tlv));
1316
90
  out->tag = in->tag;
1317
90
  out->parent_tag = in->parent_tag;
1318
90
  out->on_card = in->on_card;
1319
90
  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
90
  return SC_SUCCESS;
1329
90
}
1330
1331
1332
int
1333
iasecc_docp_copy(struct sc_context *ctx, struct iasecc_sdo_docp *in, struct iasecc_sdo_docp *out)
1334
10
{
1335
10
  int rv;
1336
1337
10
  LOG_FUNC_CALLED(ctx);
1338
10
  if (!in || !out)
1339
10
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
1340
1341
10
  memset(out, 0, sizeof(struct iasecc_sdo_docp));
1342
1343
10
  rv = iasecc_tlv_copy(ctx, &in->name, &out->name);
1344
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1345
1346
10
  rv = iasecc_tlv_copy(ctx, &in->tries_maximum, &out->tries_maximum);
1347
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1348
1349
10
  rv = iasecc_tlv_copy(ctx, &in->tries_remaining, &out->tries_remaining);
1350
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1351
1352
10
  rv = iasecc_tlv_copy(ctx, &in->usage_maximum, &out->usage_maximum);
1353
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1354
1355
10
  rv = iasecc_tlv_copy(ctx, &in->usage_remaining, &out->usage_remaining);
1356
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1357
1358
10
  rv = iasecc_tlv_copy(ctx, &in->non_repudiation, &out->non_repudiation);
1359
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1360
1361
10
  rv = iasecc_tlv_copy(ctx, &in->size, &out->size);
1362
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1363
1364
10
  rv = iasecc_tlv_copy(ctx, &in->acls_contact, &out->acls_contact);
1365
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1366
1367
10
  rv = iasecc_tlv_copy(ctx, &in->acls_contactless, &out->acls_contactless);
1368
10
  LOG_TEST_RET(ctx, rv, "TLV copy error");
1369
1370
10
  out->amb = in->amb;
1371
10
  memcpy(out->scbs, in->scbs, sizeof(out->scbs));
1372
1373
10
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
1374
10
}
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 */