Coverage Report

Created: 2026-02-15 06:26

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