Coverage Report

Created: 2026-07-24 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-rtecp.c
Line
Count
Source
1
/*
2
 * card-rtecp.c: Support for Rutoken ECP and Rutoken Lite cards
3
 *
4
 * Copyright (C) 2009  Aleksey Samsonov <samsonov@guardant.ru>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#ifdef HAVE_CONFIG_H
22
#include "config.h"
23
#endif
24
25
#include <stddef.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include "internal.h"
30
#include "asn1.h"
31
#include "cardctl.h"
32
33
static const struct sc_card_operations *iso_ops = NULL;
34
static struct sc_card_operations rtecp_ops;
35
36
static struct sc_card_driver rtecp_drv = {
37
  "Rutoken ECP and Lite driver",
38
  "rutoken_ecp",
39
  &rtecp_ops,
40
  NULL, 0, NULL
41
};
42
43
static const struct sc_atr_table rtecp_atrs[] = {
44
  /* Rutoken ECP */
45
  { "3B:8B:01:52:75:74:6F:6B:65:6E:20:45:43:50:A0",
46
    NULL, "Rutoken ECP", SC_CARD_TYPE_RUTOKEN_ECP, 0, NULL },
47
  /* Rutoken ECP (DS) */
48
  { "3B:8B:01:52:75:74:6F:6B:65:6E:20:44:53:20:C1",
49
    NULL, "Rutoken ECP (DS)", SC_CARD_TYPE_RUTOKEN_ECP, 0, NULL },
50
  /* Rutoken ECP SC T0 */
51
  { "3B:9C:96:00:52:75:74:6F:6B:65:6E:45:43:50:73:63",
52
    "00:00:00:00:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF",
53
    "Rutoken ECP SC", SC_CARD_TYPE_RUTOKEN_ECP_SC, 0, NULL },
54
  /* Rutoken ECP SC T1 */
55
  { "3B:9C:94:80:11:40:52:75:74:6F:6B:65:6E:45:43:50:73:63:C3",
56
    "00:00:00:00:00:00:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00",
57
    "Rutoken ECP SC", SC_CARD_TYPE_RUTOKEN_ECP_SC, 0, NULL },
58
  /* Rutoken ECP SC NFC */
59
  { "3B:88:80:01:52:74:53:43:77:81:83:20:6A",
60
    "00:00:00:00:FF:FF:FF:FF:00:00:00:00:00",
61
    "Rutoken ECP SC NFC", SC_CARD_TYPE_RUTOKEN_ECP_SC, 0, NULL },
62
  /* Rutoken Lite */
63
  { "3B:8B:01:52:75:74:6F:6B:65:6E:6C:69:74:65:C2",
64
    NULL, "Rutoken Lite", SC_CARD_TYPE_RUTOKEN_LITE, 0, NULL },
65
  /* Rutoken Lite SC*/
66
  { "3B:9E:96:00:52:75:74:6F:6B:65:6E:4C:69:74:65:53:43:32",
67
    "00:00:00:00:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF",
68
    "Rutoken Lite SC", SC_CARD_TYPE_RUTOKEN_LITE_SC, 0, NULL },
69
  { NULL, NULL, NULL, 0, 0, NULL }
70
};
71
72
static int rtecp_match_card(sc_card_t *card)
73
9.47k
{
74
9.47k
  int i = -1;
75
9.47k
  i = _sc_match_atr(card, rtecp_atrs, &card->type);
76
9.47k
  if (i >= 0) {
77
347
    card->name = rtecp_atrs[i].name;
78
347
    LOG_FUNC_RETURN(card->ctx, 1);
79
347
  }
80
9.12k
  LOG_FUNC_RETURN(card->ctx, 0);
81
9.12k
}
82
83
static int rtecp_init(sc_card_t *card)
84
347
{
85
347
  sc_algorithm_info_t info;
86
347
  unsigned long flags;
87
88
347
  if (!card || !card->ctx)
89
0
    return SC_ERROR_INVALID_ARGUMENTS;
90
91
347
  card->cla = 0;
92
93
347
  if (card->type == SC_CARD_TYPE_RUTOKEN_LITE
94
347
      || card->type == SC_CARD_TYPE_RUTOKEN_LITE_SC)
95
1
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
96
97
346
  card->caps |= SC_CARD_CAP_RNG;
98
99
346
  flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN
100
346
    | SC_ALGORITHM_RSA_PAD_NONE | SC_ALGORITHM_RSA_HASH_NONE;
101
102
346
  _sc_card_add_rsa_alg(card, 256, flags, 0);
103
346
  _sc_card_add_rsa_alg(card, 512, flags, 0);
104
346
  _sc_card_add_rsa_alg(card, 768, flags, 0);
105
346
  _sc_card_add_rsa_alg(card, 1024, flags, 0);
106
346
  _sc_card_add_rsa_alg(card, 1280, flags, 0);
107
346
  _sc_card_add_rsa_alg(card, 1536, flags, 0);
108
346
  _sc_card_add_rsa_alg(card, 1792, flags, 0);
109
346
  _sc_card_add_rsa_alg(card, 2048, flags, 0);
110
346
  _sc_card_add_rsa_alg(card, 4096, flags, 0);
111
112
346
  memset(&info, 0, sizeof(info));
113
346
  info.algorithm = SC_ALGORITHM_GOSTR3410;
114
346
  info.key_length = 256;
115
346
  info.flags = SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN
116
346
    | SC_ALGORITHM_GOSTR3410_HASH_NONE;
117
346
  _sc_card_add_algorithm(card, &info);
118
119
346
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
120
346
}
121
122
static void reverse(unsigned char *buf, size_t len)
123
0
{
124
0
  unsigned char tmp;
125
0
  size_t i;
126
127
0
  if (!buf && len != 0)
128
0
    return;
129
130
0
  for (i = 0; i < len / 2; ++i)
131
0
  {
132
0
    tmp = buf[i];
133
0
    buf[i] = buf[len - 1 - i];
134
0
    buf[len - 1 - i] = tmp;
135
0
  }
136
0
}
137
138
static unsigned int sec_attr_to_method(unsigned int attr)
139
320
{
140
320
  if (attr == 0xFF)
141
81
    return SC_AC_NEVER;
142
239
  else if (attr == 0)
143
135
    return SC_AC_NONE;
144
104
  else if (attr & 0x03)
145
80
    return SC_AC_CHV;
146
24
  else
147
24
    return SC_AC_UNKNOWN;
148
320
}
149
150
static unsigned long sec_attr_to_key_ref(unsigned int attr)
151
320
{
152
320
  if (attr == 1 || attr == 2)
153
25
    return attr;
154
295
  return 0;
155
320
}
156
157
static unsigned int to_sec_attr(unsigned int method, unsigned int key_ref)
158
0
{
159
0
  if (method == SC_AC_NEVER || method == SC_AC_NONE)
160
0
    return method;
161
0
  if (method == SC_AC_CHV  &&  (key_ref == 1 || key_ref == 2))
162
0
    return key_ref;
163
0
  return 0;
164
0
}
165
166
static void set_acl_from_sec_attr(sc_card_t *card, sc_file_t *file)
167
1.17k
{
168
1.17k
  unsigned int method;
169
1.17k
  unsigned long key_ref;
170
171
1.17k
  if (!card || !card->ctx || !file || !file->sec_attr
172
1.17k
    || file->sec_attr_len != SC_RTECP_SEC_ATTR_SIZE
173
0
    || 1 + 6 >= SC_RTECP_SEC_ATTR_SIZE)
174
0
  {
175
0
    return;
176
0
  }
177
178
1.17k
  sc_file_add_acl_entry(file, SC_AC_OP_SELECT, SC_AC_NONE, SC_AC_KEY_REF_NONE);
179
1.17k
  if (file->sec_attr[0] & 0x40) /* if AccessMode.6 */
180
117
  {
181
117
    method = sec_attr_to_method(file->sec_attr[1 + 6]);
182
117
    key_ref = sec_attr_to_key_ref(file->sec_attr[1 + 6]);
183
117
    sc_log(card->ctx,
184
117
      "SC_AC_OP_DELETE %i %lu\n",
185
117
      (int)method, key_ref);
186
117
    sc_file_add_acl_entry(file, SC_AC_OP_DELETE, method, key_ref);
187
117
  }
188
1.17k
  if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */
189
109
  {
190
109
    method = sec_attr_to_method(file->sec_attr[1 + 0]);
191
109
    key_ref = sec_attr_to_key_ref(file->sec_attr[1 + 0]);
192
109
    sc_log(card->ctx,
193
109
      (file->type == SC_FILE_TYPE_DF) ?
194
109
        "SC_AC_OP_CREATE %i %lu\n"
195
109
        : "SC_AC_OP_READ %i %lu\n",
196
109
      (int)method, key_ref);
197
109
    sc_file_add_acl_entry(file, (file->type == SC_FILE_TYPE_DF) ?
198
94
        SC_AC_OP_CREATE : SC_AC_OP_READ, method, key_ref);
199
109
  }
200
1.17k
  if (file->type == SC_FILE_TYPE_DF)
201
73
  {
202
73
    sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES,
203
73
        SC_AC_NONE, SC_AC_KEY_REF_NONE);
204
73
  }
205
1.10k
  else
206
1.10k
    if (file->sec_attr[0] & 0x02) /* if AccessMode.1 */
207
94
    {
208
94
      method = sec_attr_to_method(file->sec_attr[1 + 1]);
209
94
      key_ref = sec_attr_to_key_ref(file->sec_attr[1 + 1]);
210
94
      sc_log(card->ctx,
211
94
        "SC_AC_OP_UPDATE %i %lu\n",
212
94
        (int)method, key_ref);
213
94
      sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, method, key_ref);
214
94
      sc_log(card->ctx,
215
94
        "SC_AC_OP_WRITE %i %lu\n",
216
94
        (int)method, key_ref);
217
94
      sc_file_add_acl_entry(file, SC_AC_OP_WRITE, method, key_ref);
218
94
    }
219
1.17k
}
220
221
static int set_sec_attr_from_acl(sc_card_t *card, sc_file_t *file)
222
0
{
223
0
  const sc_acl_entry_t *entry;
224
0
  u8 sec_attr[SC_RTECP_SEC_ATTR_SIZE] = { 0 };
225
0
  int r;
226
227
0
  if (!card || !card->ctx || !file
228
0
    || file->sec_attr || file->sec_attr_len != 0)
229
0
    return SC_ERROR_INVALID_ARGUMENTS;
230
231
0
  entry = sc_file_get_acl_entry(file, SC_AC_OP_DELETE);
232
0
  if (entry)
233
0
  {
234
0
    sec_attr[0] |= 0x40;
235
0
    sec_attr[1 + 6] = to_sec_attr(entry->method, entry->key_ref);
236
0
  }
237
0
  if (file->type == SC_FILE_TYPE_DF)
238
0
  {
239
0
    entry = sc_file_get_acl_entry(file, SC_AC_OP_CREATE);
240
0
    if (entry)
241
0
    {
242
      /* ATTR: Create DF/EF file */
243
0
      sec_attr[0] |= 0x01;
244
0
      sec_attr[1 + 0] = to_sec_attr(entry->method, entry->key_ref);
245
      /* ATTR: Create Internal EF (RSF) file */
246
0
      sec_attr[0] |= 0x02;
247
0
      sec_attr[1 + 1] = to_sec_attr(entry->method, entry->key_ref);
248
0
    }
249
0
  }
250
0
  else
251
0
  {
252
0
    entry = sc_file_get_acl_entry(file, SC_AC_OP_READ);
253
0
    if (entry)
254
0
    {
255
0
      sec_attr[0] |= 0x01;
256
0
      sec_attr[1 + 0] = to_sec_attr(entry->method, entry->key_ref);
257
0
    }
258
0
    entry = sc_file_get_acl_entry(file, SC_AC_OP_WRITE);
259
0
    if (entry)
260
0
    {
261
0
      sec_attr[0] |= 0x02;
262
0
      sec_attr[1 + 1] = to_sec_attr(entry->method, entry->key_ref);
263
0
    }
264
0
    entry = sc_file_get_acl_entry(file, SC_AC_OP_UPDATE);
265
0
    if (entry)
266
0
    {
267
      /* rewrite if sec_attr[1 + 1] already set */
268
0
      sec_attr[0] |= 0x02;
269
0
      sec_attr[1 + 1] = to_sec_attr(entry->method, entry->key_ref);
270
0
    }
271
0
  }
272
  /* FIXME: Find the best solution */
273
0
  if (file->path.len == 2 && !memcmp(file->path.value, "\x3F\x00", 2))
274
0
  {
275
    /* ATTR: Put data */
276
0
    sec_attr[0] |= 0x04;
277
0
    sec_attr[1 + 2] = 1; /* so-pin reference */
278
0
  }
279
0
  r = sc_file_set_sec_attr(file, sec_attr, sizeof(sec_attr));
280
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
281
0
}
282
283
static int rtecp_select_file(sc_card_t *card,
284
    const sc_path_t *in_path, sc_file_t **file_out)
285
2.69k
{
286
2.69k
  sc_file_t *file = NULL;
287
2.69k
  int r = SC_SUCCESS;
288
289
2.69k
  if (!card || !card->ctx || !in_path)
290
0
    return SC_ERROR_INVALID_ARGUMENTS;
291
292
2.69k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
293
294
2.69k
  switch (in_path->type)
295
2.69k
  {
296
95
  case SC_PATH_TYPE_DF_NAME:
297
95
  case SC_PATH_TYPE_FROM_CURRENT:
298
95
  case SC_PATH_TYPE_PARENT:
299
95
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
300
2.69k
  }
301
302
  // Card Rutoken ECP SC T0 doesn't support SELECT FILE without return a file info.
303
  // So here we request a file and then assign/free it depending on file_out.
304
2.59k
  r = iso_ops->select_file(card, in_path, &file);
305
2.59k
  if (r != SC_SUCCESS)
306
1.23k
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
307
308
1.35k
  if (file->sec_attr && file->sec_attr_len == SC_RTECP_SEC_ATTR_SIZE)
309
1.17k
    set_acl_from_sec_attr(card, file);
310
179
  else
311
179
  {
312
179
    sc_file_free(file);
313
179
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
314
179
  }
315
316
1.17k
  if (file_out)
317
1.03k
    *file_out = file;
318
144
  else
319
144
    sc_file_free(file);
320
321
1.17k
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
322
1.17k
}
323
324
static int rtecp_verify(sc_card_t *card, unsigned int type, int ref_qualifier,
325
    const u8 *data, size_t data_len, int *tries_left)
326
39
{
327
39
  sc_apdu_t apdu;
328
39
  int r, send_logout = 0;
329
330
39
  (void)type; /* no warning */
331
332
39
  if (!card || !card->ctx || !data)
333
0
    return SC_ERROR_INVALID_ARGUMENTS;
334
335
39
  for (;;)
336
40
  {
337
40
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT,
338
40
        0x20, 0, ref_qualifier);
339
40
    apdu.lc = data_len;
340
40
    apdu.data = data;
341
40
    apdu.datalen = data_len;
342
40
    r = sc_transmit_apdu(card, &apdu);
343
40
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
344
39
    if (send_logout++ == 0 && apdu.sw1 == 0x6F && apdu.sw2 == 0x86)
345
3
    {
346
3
       r = sc_logout(card);
347
3
       LOG_TEST_RET(card->ctx, r, "Logout failed");
348
3
    }
349
36
    else
350
36
      break;
351
39
  }
352
36
  if (apdu.sw1 == 0x63 && apdu.sw2 == 0)
353
2
  {
354
    /* Verification failed */
355
2
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0, ref_qualifier);
356
2
    r = sc_transmit_apdu(card, &apdu);
357
2
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
358
2
  }
359
35
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
360
35
  if (r == SC_ERROR_PIN_CODE_INCORRECT && tries_left)
361
1
    *tries_left = (int)(apdu.sw2 & 0x0F);
362
35
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
363
35
}
364
365
static int rtecp_logout(sc_card_t *card)
366
3
{
367
3
  sc_apdu_t apdu;
368
3
  int r;
369
370
3
  if (!card || !card->ctx)
371
0
    return SC_ERROR_INVALID_ARGUMENTS;
372
373
3
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0, 0);
374
3
  apdu.cla = 0x80;
375
3
  r = sc_transmit_apdu(card, &apdu);
376
3
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
377
2
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
378
2
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
379
2
}
380
381
static int rtecp_set_security_env(  struct sc_card *card,
382
                  const struct sc_security_env *env,
383
                  int se_num)
384
40
{
385
40
  struct sc_security_env se_env;
386
40
  if(!env)
387
0
    return SC_ERROR_INVALID_ARGUMENTS;
388
389
40
  se_env= *env;
390
40
  se_env.flags &= ~SC_SEC_ENV_FILE_REF_PRESENT;
391
40
  return iso_ops->set_security_env(card, &se_env, se_num);
392
40
}
393
394
static int rtecp_cipher(sc_card_t *card, const u8 *data, size_t data_len,
395
    u8 *out, size_t out_len, int sign)
396
40
{
397
40
  sc_apdu_t apdu;
398
40
  u8 *buf, *buf_out;
399
40
  size_t i;
400
40
  int r;
401
402
40
  if (!card || !card->ctx || !data || !out)
403
0
    return SC_ERROR_INVALID_ARGUMENTS;
404
405
40
  buf_out = malloc(out_len + 2);
406
40
  buf = malloc(data_len);
407
40
  if (!buf || !buf_out)
408
0
  {
409
0
    free(buf);
410
0
    free(buf_out);
411
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
412
0
  }
413
414
3.46k
  for (i = 0; i < data_len; ++i)
415
3.42k
    buf[i] = data[data_len - 1 - i];
416
417
40
  if (sign)
418
40
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
419
0
  else
420
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
421
40
  apdu.lc = data_len;
422
40
  apdu.data = buf;
423
40
  apdu.datalen = data_len;
424
40
  apdu.resp = buf_out;
425
40
  apdu.resplen = out_len + 2;
426
40
  apdu.le = out_len > 256 ? 256 : out_len;
427
40
  if (apdu.lc > 255)
428
2
    apdu.flags |= SC_APDU_FLAGS_CHAINING;
429
40
  r = sc_transmit_apdu(card, &apdu);
430
40
  if (!sign)
431
0
    sc_mem_clear(buf, data_len);
432
433
40
  free(buf);
434
40
  if (r)
435
2
    sc_log(card->ctx,  "APDU transmit failed: %s\n", sc_strerror(r));
436
38
  else
437
38
  {
438
38
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
439
12
    {
440
12
      if (apdu.resplen > out_len) {
441
2
        free(buf_out);
442
2
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,
443
2
            SC_ERROR_BUFFER_TOO_SMALL);
444
2
      }
445
745
      for (i = 0; i < apdu.resplen; ++i)
446
735
        out[i] = buf_out[apdu.resplen - 1 - i];
447
10
      r = (i > 0) ? (int)i : SC_ERROR_INTERNAL;
448
10
    }
449
26
    else
450
26
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
451
38
  }
452
38
  if (!sign)
453
0
    sc_mem_clear(buf_out, out_len + 2);
454
455
38
  free(buf_out);
456
38
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
457
458
38
}
459
460
static int rtecp_decipher(sc_card_t *card,
461
    const u8 *data, size_t data_len, u8 *out, size_t out_len)
462
0
{
463
0
  int r;
464
465
0
  if (!card || !card->ctx || !data || !out)
466
0
    return SC_ERROR_INVALID_ARGUMENTS;
467
468
0
  if (card->type == SC_CARD_TYPE_RUTOKEN_LITE
469
0
      || card->type == SC_CARD_TYPE_RUTOKEN_LITE_SC)
470
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
471
472
  /* decipher */
473
0
  r = rtecp_cipher(card, data, data_len, out, out_len, 0);
474
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
475
0
}
476
477
static int rtecp_compute_signature(sc_card_t *card,
478
    const u8 *data, size_t data_len, u8 *out, size_t out_len)
479
40
{
480
40
  int r;
481
482
40
  if (!card || !card->ctx || !data || !out)
483
0
    return SC_ERROR_INVALID_ARGUMENTS;
484
485
40
  if (card->type == SC_CARD_TYPE_RUTOKEN_LITE
486
40
      || card->type == SC_CARD_TYPE_RUTOKEN_LITE_SC)
487
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
488
489
  /* compute digital signature */
490
40
  r = rtecp_cipher(card, data, data_len, out, out_len, 1);
491
40
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
492
40
}
493
494
static int rtecp_change_reference_data(sc_card_t *card, unsigned int type,
495
    int ref_qualifier, const u8 *old, size_t oldlen,
496
    const u8 *newref, size_t newlen, int *tries_left)
497
0
{
498
0
  sc_apdu_t apdu;
499
0
  u8 rsf_length[2], *buf, *buf_end, *p;
500
0
  size_t val_length, buf_length, max_transmit_length, transmits_num;
501
0
  int r;
502
503
0
  if (!card || !card->ctx || !newref)
504
0
    return SC_ERROR_INVALID_ARGUMENTS;
505
506
0
  sc_log(card->ctx,
507
0
     "newlen = %"SC_FORMAT_LEN_SIZE_T"u\n", newlen);
508
0
  if (newlen > 0xFFFF)
509
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
510
0
  if (type == SC_AC_CHV && old && oldlen != 0)
511
0
  {
512
0
    r = sc_verify(card, type, ref_qualifier, old, oldlen, tries_left);
513
0
    LOG_TEST_RET(card->ctx, r, "Verify old pin failed");
514
0
  }
515
516
0
  max_transmit_length = sc_get_max_send_size(card);
517
0
  if (max_transmit_length <= 2)
518
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
519
  /*
520
   * (2 + sizeof(rsf_length) + newlen) - total length of data we need to transfer,
521
   * (max_transmit_length - 2) - amount of useful data we can transfer in one transmit (2 bytes for 0xA5 tag)
522
   */
523
0
  transmits_num = (2 + sizeof(rsf_length) + newlen) / (max_transmit_length - 2) + 1;
524
  /* buffer length = size of 0x80 TLV + size of RSF-file + (size of Tag and Length)*(number of APDUs) */
525
0
  buf_length = (2 + sizeof(rsf_length)) + newlen + 2*(transmits_num);
526
0
  p = buf = (u8 *)malloc(buf_length);
527
0
  if (buf == NULL)
528
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
529
0
  buf_end = buf + buf_length;
530
531
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
532
  /* put 0x80 TLV */
533
0
  rsf_length[0] = (newlen >> 8) & 0xFF;
534
0
  rsf_length[1] = newlen & 0xFF;
535
536
0
  if (buf_end - p < (int)(2 + sizeof(rsf_length))) {
537
0
    free(buf);
538
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
539
0
  }
540
541
0
  sc_asn1_put_tag(0x80, rsf_length, sizeof(rsf_length), p, buf_end - p, &p);
542
  /* put 0xA5 TLVs (one or more); each transmit must begin with 0xA5 TLV */
543
0
  while (newlen)
544
0
  {
545
0
    if (buf_end - p < (int)(newlen + 2)) {
546
0
      free(buf);
547
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
548
0
    }
549
0
    if ((p - buf) % max_transmit_length + newlen + 2 > max_transmit_length)
550
0
      val_length = max_transmit_length - (p - buf) % max_transmit_length - 2;
551
0
    else
552
0
      val_length = newlen;
553
    /* not using sc_asn1_put_tag(...) because rtecp do not support asn1 properly (when val_length > 127) */
554
0
    *p++ = 0xA5;
555
0
    *p++ = (u8)val_length;
556
0
    if (val_length > newlen) {
557
0
      free(buf);
558
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
559
0
    }
560
0
    memcpy(p, newref, val_length);
561
0
    p += val_length;
562
0
    newref += val_length;
563
0
    newlen -= val_length;
564
0
    if (newlen)
565
0
      apdu.flags |= SC_APDU_FLAGS_CHAINING;
566
0
  }
567
0
  apdu.lc = p - buf;
568
0
  apdu.data = buf;
569
0
  apdu.datalen = p - buf;
570
571
0
  r = sc_transmit_apdu(card, &apdu);
572
0
  sc_mem_clear(buf, buf_length);
573
0
  free(buf);
574
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
575
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
576
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
577
0
}
578
579
static int rtecp_reset_retry_counter(sc_card_t *card, unsigned int type,
580
    int ref_qualifier, const u8 *puk, size_t puklen,
581
    const u8 *newref, size_t newlen)
582
0
{
583
0
  sc_apdu_t apdu;
584
0
  int r;
585
586
0
  (void)type, (void)puk, (void)puklen; /* no warning */
587
588
0
  if (!card || !card->ctx)
589
0
    return SC_ERROR_INVALID_ARGUMENTS;
590
591
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2C, 0x03, ref_qualifier);
592
0
  r = sc_transmit_apdu(card, &apdu);
593
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
594
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
595
0
  LOG_TEST_RET(card->ctx, r, "Unblock card failed");
596
597
0
  if (newref && newlen)   {
598
0
          u8 tmp[2], buf[SC_MAX_APDU_BUFFER_SIZE];
599
0
    u8 *p = buf;
600
601
0
    tmp[0] = (newlen >> 8) & 0xFF;
602
0
    tmp[1] = newlen & 0xFF;
603
0
    sc_asn1_put_tag(0x80, tmp, sizeof(tmp), p, sizeof(buf) - (p - buf), &p);
604
0
    r = sc_asn1_put_tag(0xA5, newref, newlen, p, sizeof(buf) - (p - buf), &p);
605
0
    LOG_TEST_RET(card->ctx, r, "Invalid new PIN length");
606
607
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
608
0
    apdu.lc = p - buf;
609
0
    apdu.data = buf;
610
0
    apdu.datalen = p - buf;
611
612
0
    r = sc_transmit_apdu(card, &apdu);
613
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
614
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
615
0
    LOG_TEST_RET(card->ctx, r, "Set PIN failed");
616
0
  }
617
618
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
619
0
}
620
621
static int rtecp_create_file(sc_card_t *card, sc_file_t *file)
622
0
{
623
0
  int r;
624
625
0
  if (!card || !card->ctx || !file)
626
0
    return SC_ERROR_INVALID_ARGUMENTS;
627
628
0
  if (file->sec_attr_len == 0)
629
0
  {
630
0
    r = set_sec_attr_from_acl(card, file);
631
0
    LOG_TEST_RET(card->ctx, r, "Set sec_attr from ACL failed");
632
0
  }
633
634
0
  r = iso_ops->create_file(card, file);
635
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
636
0
}
637
638
static int rtecp_list_files(sc_card_t *card, u8 *buf, size_t buflen)
639
0
{
640
0
  sc_apdu_t apdu;
641
0
  u8 rbuf[SC_MAX_APDU_RESP_SIZE], previd[2];
642
0
  const u8 *tag;
643
0
  size_t taglen, len = 0;
644
0
  int r;
645
646
0
  if (!card || !card->ctx || !buf)
647
0
    return SC_ERROR_INVALID_ARGUMENTS;
648
649
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0, 0);
650
0
  for (;;)
651
0
  {
652
0
    apdu.resp = rbuf;
653
0
    apdu.resplen = sizeof(rbuf);
654
0
    apdu.le = sizeof(rbuf);
655
0
    r = sc_transmit_apdu(card, &apdu);
656
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
657
0
    if (apdu.sw1 == 0x6A  &&  apdu.sw2 == 0x82)
658
0
      break; /* Next file not found */
659
660
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
661
0
    LOG_TEST_RET(card->ctx, r, "");
662
663
0
    if (apdu.resplen <= 2)
664
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
665
666
    /* save first file(dir) ID */
667
0
    tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
668
0
        0x83, &taglen);
669
0
    if (!tag || taglen != sizeof(previd))
670
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
671
0
    memcpy(previd, tag, sizeof(previd));
672
673
0
    if (len + sizeof(previd) <= buflen)
674
0
    {
675
0
      memcpy(&buf[len], previd, sizeof(previd));
676
0
      len += sizeof(previd);
677
0
    }
678
679
0
    tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
680
0
        0x82, &taglen);
681
0
    if (!tag || taglen != 2)
682
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
683
0
    if (tag[0] == 0x38)
684
0
    {
685
      /* Select parent DF of the current DF */
686
0
      sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0);
687
      /* We should set le and resp buf to actually call Get Response for card on T0. */
688
0
      apdu.resp = rbuf;
689
0
      apdu.resplen = sizeof(rbuf);
690
0
      apdu.le = sizeof(rbuf);
691
0
      r = sc_transmit_apdu(card, &apdu);
692
0
      LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
693
0
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
694
0
      LOG_TEST_RET(card->ctx, r, "");
695
0
    }
696
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x02);
697
0
    apdu.lc = sizeof(previd);
698
0
    apdu.data = previd;
699
0
    apdu.datalen = sizeof(previd);
700
0
  }
701
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
702
0
}
703
704
static int rtecp_card_ctl(sc_card_t *card, unsigned long request, void *data)
705
335
{
706
335
  sc_apdu_t apdu;
707
335
  u8 buf[512];
708
335
  sc_rtecp_genkey_data_t *genkey_data = data;
709
335
  sc_serial_number_t *serial = data;
710
335
  int r;
711
712
335
  const unsigned char rsa_prop[] = {0xA6, 0x06, 0x94, 0x04, 0x01, 0x00, 0x01, 0x00};
713
714
335
  if (!card || !card->ctx)
715
0
    return SC_ERROR_INVALID_ARGUMENTS;
716
717
335
  switch (request)
718
335
  {
719
0
  case SC_CARDCTL_RTECP_INIT:
720
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x8A, 0, 0);
721
0
    apdu.cla = 0x80;
722
0
    break;
723
0
  case SC_CARDCTL_RTECP_INIT_END:
724
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x84, 0x4E, 0x19);
725
0
    apdu.cla = 0x80;
726
0
    break;
727
21
  case SC_CARDCTL_GET_SERIALNR:
728
21
    if (!serial)
729
21
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
730
21
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x81);
731
21
    apdu.resp = buf;
732
21
    apdu.resplen = sizeof(buf);
733
21
    apdu.le = 256;
734
21
    serial->len = sizeof(serial->value);
735
21
    break;
736
0
  case SC_CARDCTL_RTECP_GENERATE_KEY:
737
0
    if (!genkey_data)
738
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
739
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x46, 0x80,
740
0
        genkey_data->key_id);
741
0
    apdu.resp = buf;
742
0
    apdu.resplen = sizeof(buf);
743
0
    apdu.le = 256;
744
0
    if (genkey_data->type == SC_ALGORITHM_RSA) {
745
0
      apdu.cse = SC_APDU_CASE_4_SHORT;
746
0
      apdu.data = rsa_prop;
747
0
      apdu.datalen = sizeof(rsa_prop);
748
0
      apdu.lc = sizeof(rsa_prop);
749
0
    }
750
0
    break;
751
8
  case SC_CARDCTL_LIFECYCLE_SET:
752
8
    sc_log(card->ctx,  "%s\n",
753
8
        "SC_CARDCTL_LIFECYCLE_SET not supported");
754
    /* no call sc_debug (SC_FUNC_RETURN) */
755
8
    return SC_ERROR_NOT_SUPPORTED;
756
306
  default:
757
306
    sc_log(card->ctx,
758
306
      "request = 0x%lx\n", request);
759
306
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
760
335
  }
761
21
  r = sc_transmit_apdu(card, &apdu);
762
21
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
763
20
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
764
20
  if (!r && request == SC_CARDCTL_RTECP_GENERATE_KEY)
765
0
  {
766
0
    if (genkey_data->type == SC_ALGORITHM_RSA &&
767
0
        genkey_data->u.rsa.modulus_len >= apdu.resplen &&
768
0
        genkey_data->u.rsa.exponent_len >= 3)
769
0
    {
770
0
      memcpy(genkey_data->u.rsa.modulus, apdu.resp, apdu.resplen);
771
0
      genkey_data->u.rsa.modulus_len = apdu.resplen;
772
0
      reverse(genkey_data->u.rsa.modulus,
773
0
          genkey_data->u.rsa.modulus_len);
774
0
      memcpy(genkey_data->u.rsa.exponent, "\x01\x00\x01", 3);
775
0
      genkey_data->u.rsa.exponent_len = 3;
776
0
    }
777
0
    else if (genkey_data->type == SC_ALGORITHM_GOSTR3410 &&
778
0
        genkey_data->u.gostr3410.xy_len >= apdu.resplen)
779
0
    {
780
0
      memcpy(genkey_data->u.gostr3410.xy, apdu.resp, apdu.resplen);
781
0
      genkey_data->u.gostr3410.xy_len = apdu.resplen;
782
0
    }
783
0
    else
784
0
      r = SC_ERROR_BUFFER_TOO_SMALL;
785
0
  }
786
20
  else if (!r && request == SC_CARDCTL_GET_SERIALNR)
787
13
  {
788
13
    if (apdu.resplen <= sizeof(serial->value))
789
10
    {
790
10
      memcpy(serial->value, apdu.resp, apdu.resplen);
791
10
      serial->len = apdu.resplen;
792
10
    }
793
3
    else
794
3
      r = SC_ERROR_BUFFER_TOO_SMALL;
795
13
  }
796
20
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
797
20
}
798
799
static int rtecp_construct_fci(sc_card_t *card, const sc_file_t *file,
800
    u8 *out, size_t *outlen)
801
0
{
802
0
  u8 buf[64], *p = out;
803
804
0
  if (!card || !card->ctx || !file || !out || !outlen
805
0
    || (*outlen < (size_t)(p - out) + 2))
806
0
    return SC_ERROR_INVALID_ARGUMENTS;
807
808
0
  *p++ = 0x6F; /* FCI template */
809
0
  p++; /* for length */
810
811
  /* 0x80 - Number of data bytes in the file, excluding structural information */
812
0
  buf[0] = (file->size >> 8) & 0xFF;
813
0
  buf[1] = file->size & 0xFF;
814
0
  sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p);
815
816
  /* 0x82 - File descriptor byte */
817
0
  if (file->type_attr_len)
818
0
  {
819
0
    if (sizeof(buf) < file->type_attr_len)
820
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
821
0
    memcpy(buf, file->type_attr, file->type_attr_len);
822
0
    sc_asn1_put_tag(0x82, buf, file->type_attr_len,
823
0
        p, *outlen - (p - out), &p);
824
0
  }
825
0
  else
826
0
  {
827
0
    switch (file->type)
828
0
    {
829
0
    case SC_FILE_TYPE_WORKING_EF:
830
0
      buf[0] = 0x01;
831
0
      break;
832
0
    case SC_FILE_TYPE_DF:
833
0
      buf[0] = 0x38;
834
0
      break;
835
0
    case SC_FILE_TYPE_INTERNAL_EF:
836
0
    default:
837
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
838
0
    }
839
0
    buf[1] = 0;
840
0
    sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p);
841
0
  }
842
  /* 0x83 - File identifier */
843
0
  buf[0] = (file->id >> 8) & 0xFF;
844
0
  buf[1] = file->id & 0xFF;
845
0
  sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
846
847
0
  if (file->prop_attr_len)
848
0
  {
849
0
    if (sizeof(buf) < file->prop_attr_len)
850
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
851
0
    memcpy(buf, file->prop_attr, file->prop_attr_len);
852
0
    sc_asn1_put_tag(0x85, buf, file->prop_attr_len,
853
0
        p, *outlen - (p - out), &p);
854
0
  }
855
0
  if (file->sec_attr_len)
856
0
  {
857
0
    if (sizeof(buf) < file->sec_attr_len)
858
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
859
0
    memcpy(buf, file->sec_attr, file->sec_attr_len);
860
0
    sc_asn1_put_tag(0x86, buf, file->sec_attr_len,
861
0
        p, *outlen - (p - out), &p);
862
0
  }
863
0
  out[1] = p - out - 2; /* length */
864
0
  *outlen = p - out;
865
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
866
0
}
867
868
struct sc_card_driver * sc_get_rtecp_driver(void)
869
15.8k
{
870
15.8k
  if (iso_ops == NULL)
871
1
    iso_ops = sc_get_iso7816_driver()->ops;
872
15.8k
  rtecp_ops = *iso_ops;
873
874
15.8k
  rtecp_ops.match_card = rtecp_match_card;
875
15.8k
  rtecp_ops.init = rtecp_init;
876
  /* read_binary */
877
15.8k
  rtecp_ops.write_binary = NULL;
878
  /* update_binary */
879
15.8k
  rtecp_ops.read_record = NULL;
880
15.8k
  rtecp_ops.write_record = NULL;
881
15.8k
  rtecp_ops.append_record = NULL;
882
15.8k
  rtecp_ops.update_record = NULL;
883
15.8k
  rtecp_ops.select_file = rtecp_select_file;
884
  /* get_response */
885
  /* get_challenge */
886
15.8k
  rtecp_ops.verify = rtecp_verify;
887
15.8k
  rtecp_ops.logout = rtecp_logout;
888
  /* restore_security_env */
889
15.8k
  rtecp_ops.set_security_env = rtecp_set_security_env;
890
15.8k
  rtecp_ops.decipher = rtecp_decipher;
891
15.8k
  rtecp_ops.compute_signature = rtecp_compute_signature;
892
15.8k
  rtecp_ops.change_reference_data = rtecp_change_reference_data;
893
15.8k
  rtecp_ops.reset_retry_counter = rtecp_reset_retry_counter;
894
15.8k
  rtecp_ops.create_file = rtecp_create_file;
895
  /* delete_file */
896
15.8k
  rtecp_ops.list_files = rtecp_list_files;
897
  /* check_sw */
898
15.8k
  rtecp_ops.card_ctl = rtecp_card_ctl;
899
  /* process_fci */
900
15.8k
  rtecp_ops.construct_fci = rtecp_construct_fci;
901
  rtecp_ops.pin_cmd = NULL;
902
15.8k
  return &rtecp_drv;
903
15.8k
}