Coverage Report

Created: 2025-12-14 06:58

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
8.44k
{
74
8.44k
  int i = -1;
75
8.44k
  i = _sc_match_atr(card, rtecp_atrs, &card->type);
76
8.44k
  if (i >= 0) {
77
77
    card->name = rtecp_atrs[i].name;
78
77
    LOG_FUNC_RETURN(card->ctx, 1);
79
77
  }
80
8.36k
  LOG_FUNC_RETURN(card->ctx, 0);
81
8.36k
}
82
83
static int rtecp_init(sc_card_t *card)
84
77
{
85
77
  sc_algorithm_info_t info;
86
77
  unsigned long flags;
87
88
77
  if (!card || !card->ctx)
89
0
    return SC_ERROR_INVALID_ARGUMENTS;
90
91
77
  card->cla = 0;
92
93
77
  if (card->type == SC_CARD_TYPE_RUTOKEN_LITE
94
76
      || card->type == SC_CARD_TYPE_RUTOKEN_LITE_SC)
95
2
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
96
97
75
  card->caps |= SC_CARD_CAP_RNG;
98
99
75
  flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN
100
75
    | SC_ALGORITHM_RSA_PAD_NONE | SC_ALGORITHM_RSA_HASH_NONE;
101
102
75
  _sc_card_add_rsa_alg(card, 256, flags, 0);
103
75
  _sc_card_add_rsa_alg(card, 512, flags, 0);
104
75
  _sc_card_add_rsa_alg(card, 768, flags, 0);
105
75
  _sc_card_add_rsa_alg(card, 1024, flags, 0);
106
75
  _sc_card_add_rsa_alg(card, 1280, flags, 0);
107
75
  _sc_card_add_rsa_alg(card, 1536, flags, 0);
108
75
  _sc_card_add_rsa_alg(card, 1792, flags, 0);
109
75
  _sc_card_add_rsa_alg(card, 2048, flags, 0);
110
75
  _sc_card_add_rsa_alg(card, 4096, flags, 0);
111
112
75
  memset(&info, 0, sizeof(info));
113
75
  info.algorithm = SC_ALGORITHM_GOSTR3410;
114
75
  info.key_length = 256;
115
75
  info.flags = SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN
116
75
    | SC_ALGORITHM_GOSTR3410_HASH_NONE;
117
75
  _sc_card_add_algorithm(card, &info);
118
119
75
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
120
75
}
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
169
{
140
169
  if (attr == 0xFF)
141
37
    return SC_AC_NEVER;
142
132
  else if (attr == 0)
143
22
    return SC_AC_NONE;
144
110
  else if (attr & 0x03)
145
78
    return SC_AC_CHV;
146
32
  else
147
32
    return SC_AC_UNKNOWN;
148
169
}
149
150
static unsigned long sec_attr_to_key_ref(unsigned int attr)
151
169
{
152
169
  if (attr == 1 || attr == 2)
153
45
    return attr;
154
124
  return 0;
155
169
}
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
91
{
168
91
  unsigned int method;
169
91
  unsigned long key_ref;
170
171
91
  if (!card || !card->ctx || !file || !file->sec_attr
172
91
    || 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
91
  sc_file_add_acl_entry(file, SC_AC_OP_SELECT, SC_AC_NONE, SC_AC_KEY_REF_NONE);
179
91
  if (file->sec_attr[0] & 0x40) /* if AccessMode.6 */
180
58
  {
181
58
    method = sec_attr_to_method(file->sec_attr[1 + 6]);
182
58
    key_ref = sec_attr_to_key_ref(file->sec_attr[1 + 6]);
183
58
    sc_log(card->ctx,
184
58
      "SC_AC_OP_DELETE %i %lu\n",
185
58
      (int)method, key_ref);
186
58
    sc_file_add_acl_entry(file, SC_AC_OP_DELETE, method, key_ref);
187
58
  }
188
91
  if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */
189
71
  {
190
71
    method = sec_attr_to_method(file->sec_attr[1 + 0]);
191
71
    key_ref = sec_attr_to_key_ref(file->sec_attr[1 + 0]);
192
71
    sc_log(card->ctx,
193
71
      (file->type == SC_FILE_TYPE_DF) ?
194
71
        "SC_AC_OP_CREATE %i %lu\n"
195
71
        : "SC_AC_OP_READ %i %lu\n",
196
71
      (int)method, key_ref);
197
71
    sc_file_add_acl_entry(file, (file->type == SC_FILE_TYPE_DF) ?
198
67
        SC_AC_OP_CREATE : SC_AC_OP_READ, method, key_ref);
199
71
  }
200
91
  if (file->type == SC_FILE_TYPE_DF)
201
4
  {
202
4
    sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES,
203
4
        SC_AC_NONE, SC_AC_KEY_REF_NONE);
204
4
  }
205
87
  else
206
87
    if (file->sec_attr[0] & 0x02) /* if AccessMode.1 */
207
40
    {
208
40
      method = sec_attr_to_method(file->sec_attr[1 + 1]);
209
40
      key_ref = sec_attr_to_key_ref(file->sec_attr[1 + 1]);
210
40
      sc_log(card->ctx,
211
40
        "SC_AC_OP_UPDATE %i %lu\n",
212
40
        (int)method, key_ref);
213
40
      sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, method, key_ref);
214
40
      sc_log(card->ctx,
215
40
        "SC_AC_OP_WRITE %i %lu\n",
216
40
        (int)method, key_ref);
217
40
      sc_file_add_acl_entry(file, SC_AC_OP_WRITE, method, key_ref);
218
40
    }
219
91
}
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
371
{
286
371
  sc_file_t *file = NULL;
287
371
  int r = SC_SUCCESS;
288
289
371
  if (!card || !card->ctx || !in_path)
290
0
    return SC_ERROR_INVALID_ARGUMENTS;
291
292
371
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
293
294
371
  switch (in_path->type)
295
371
  {
296
118
  case SC_PATH_TYPE_DF_NAME:
297
118
  case SC_PATH_TYPE_FROM_CURRENT:
298
118
  case SC_PATH_TYPE_PARENT:
299
118
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
300
371
  }
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
253
  r = iso_ops->select_file(card, in_path, &file);
305
253
  if (r != SC_SUCCESS)
306
147
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
307
308
106
  if (file->sec_attr && file->sec_attr_len == SC_RTECP_SEC_ATTR_SIZE)
309
91
    set_acl_from_sec_attr(card, file);
310
15
  else
311
15
  {
312
15
    sc_file_free(file);
313
15
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
314
15
  }
315
316
91
  if (file_out)
317
77
    *file_out = file;
318
14
  else
319
14
    sc_file_free(file);
320
321
91
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
322
91
}
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
0
{
327
0
  sc_apdu_t apdu;
328
0
  int r, send_logout = 0;
329
330
0
  (void)type; /* no warning */
331
332
0
  if (!card || !card->ctx || !data)
333
0
    return SC_ERROR_INVALID_ARGUMENTS;
334
335
0
  for (;;)
336
0
  {
337
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT,
338
0
        0x20, 0, ref_qualifier);
339
0
    apdu.lc = data_len;
340
0
    apdu.data = data;
341
0
    apdu.datalen = data_len;
342
0
    r = sc_transmit_apdu(card, &apdu);
343
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
344
0
    if (send_logout++ == 0 && apdu.sw1 == 0x6F && apdu.sw2 == 0x86)
345
0
    {
346
0
       r = sc_logout(card);
347
0
       LOG_TEST_RET(card->ctx, r, "Logout failed");
348
0
    }
349
0
    else
350
0
      break;
351
0
  }
352
0
  if (apdu.sw1 == 0x63 && apdu.sw2 == 0)
353
0
  {
354
    /* Verification failed */
355
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0, ref_qualifier);
356
0
    r = sc_transmit_apdu(card, &apdu);
357
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
358
0
  }
359
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
360
0
  if (r == SC_ERROR_PIN_CODE_INCORRECT && tries_left)
361
0
    *tries_left = (int)(apdu.sw2 & 0x0F);
362
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
363
0
}
364
365
static int rtecp_logout(sc_card_t *card)
366
0
{
367
0
  sc_apdu_t apdu;
368
0
  int r;
369
370
0
  if (!card || !card->ctx)
371
0
    return SC_ERROR_INVALID_ARGUMENTS;
372
373
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0, 0);
374
0
  apdu.cla = 0x80;
375
0
  r = sc_transmit_apdu(card, &apdu);
376
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
377
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
378
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
379
0
}
380
381
static int rtecp_set_security_env(  struct sc_card *card,
382
                  const struct sc_security_env *env,
383
                  int se_num)
384
0
{
385
0
  struct sc_security_env se_env;
386
0
  if(!env)
387
0
    return SC_ERROR_INVALID_ARGUMENTS;
388
389
0
  se_env= *env;
390
0
  se_env.flags &= ~SC_SEC_ENV_FILE_REF_PRESENT;
391
0
  return iso_ops->set_security_env(card, &se_env, se_num);
392
0
}
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
0
{
397
0
  sc_apdu_t apdu;
398
0
  u8 *buf, *buf_out;
399
0
  size_t i;
400
0
  int r;
401
402
0
  if (!card || !card->ctx || !data || !out)
403
0
    return SC_ERROR_INVALID_ARGUMENTS;
404
405
0
  buf_out = malloc(out_len + 2);
406
0
  buf = malloc(data_len);
407
0
  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
0
  for (i = 0; i < data_len; ++i)
415
0
    buf[i] = data[data_len - 1 - i];
416
417
0
  if (sign)
418
0
    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
0
  apdu.lc = data_len;
422
0
  apdu.data = buf;
423
0
  apdu.datalen = data_len;
424
0
  apdu.resp = buf_out;
425
0
  apdu.resplen = out_len + 2;
426
0
  apdu.le = out_len > 256 ? 256 : out_len;
427
0
  if (apdu.lc > 255)
428
0
    apdu.flags |= SC_APDU_FLAGS_CHAINING;
429
0
  r = sc_transmit_apdu(card, &apdu);
430
0
  if (!sign)
431
0
    sc_mem_clear(buf, data_len);
432
433
0
  free(buf);
434
0
  if (r)
435
0
    sc_log(card->ctx,  "APDU transmit failed: %s\n", sc_strerror(r));
436
0
  else
437
0
  {
438
0
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
439
0
    {
440
0
      for (i = 0; i < apdu.resplen; ++i)
441
0
        out[i] = buf_out[apdu.resplen - 1 - i];
442
0
      r = (i > 0) ? (int)i : SC_ERROR_INTERNAL;
443
0
    }
444
0
    else
445
0
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
446
0
  }
447
0
  if (!sign)
448
0
    sc_mem_clear(buf_out, out_len + 2);
449
450
0
  free(buf_out);
451
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
452
453
0
}
454
455
static int rtecp_decipher(sc_card_t *card,
456
    const u8 *data, size_t data_len, u8 *out, size_t out_len)
457
0
{
458
0
  int r;
459
460
0
  if (!card || !card->ctx || !data || !out)
461
0
    return SC_ERROR_INVALID_ARGUMENTS;
462
463
0
  if (card->type == SC_CARD_TYPE_RUTOKEN_LITE
464
0
      || card->type == SC_CARD_TYPE_RUTOKEN_LITE_SC)
465
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
466
467
  /* decipher */
468
0
  r = rtecp_cipher(card, data, data_len, out, out_len, 0);
469
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
470
0
}
471
472
static int rtecp_compute_signature(sc_card_t *card,
473
    const u8 *data, size_t data_len, u8 *out, size_t out_len)
474
0
{
475
0
  int r;
476
477
0
  if (!card || !card->ctx || !data || !out)
478
0
    return SC_ERROR_INVALID_ARGUMENTS;
479
480
0
  if (card->type == SC_CARD_TYPE_RUTOKEN_LITE
481
0
      || card->type == SC_CARD_TYPE_RUTOKEN_LITE_SC)
482
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
483
484
  /* compute digital signature */
485
0
  r = rtecp_cipher(card, data, data_len, out, out_len, 1);
486
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
487
0
}
488
489
static int rtecp_change_reference_data(sc_card_t *card, unsigned int type,
490
    int ref_qualifier, const u8 *old, size_t oldlen,
491
    const u8 *newref, size_t newlen, int *tries_left)
492
0
{
493
0
  sc_apdu_t apdu;
494
0
  u8 rsf_length[2], *buf, *buf_end, *p;
495
0
  size_t val_length, buf_length, max_transmit_length, transmits_num;
496
0
  int r;
497
498
0
  if (!card || !card->ctx || !newref)
499
0
    return SC_ERROR_INVALID_ARGUMENTS;
500
501
0
  sc_log(card->ctx,
502
0
     "newlen = %"SC_FORMAT_LEN_SIZE_T"u\n", newlen);
503
0
  if (newlen > 0xFFFF)
504
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
505
0
  if (type == SC_AC_CHV && old && oldlen != 0)
506
0
  {
507
0
    r = sc_verify(card, type, ref_qualifier, old, oldlen, tries_left);
508
0
    LOG_TEST_RET(card->ctx, r, "Verify old pin failed");
509
0
  }
510
511
0
  max_transmit_length = sc_get_max_send_size(card);
512
0
  if (max_transmit_length <= 2)
513
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
514
  /*
515
   * (2 + sizeof(rsf_length) + newlen) - total length of data we need to transfer,
516
   * (max_transmit_length - 2) - amount of useful data we can transfer in one transmit (2 bytes for 0xA5 tag)
517
   */
518
0
  transmits_num = (2 + sizeof(rsf_length) + newlen) / (max_transmit_length - 2) + 1;
519
  /* buffer length = size of 0x80 TLV + size of RSF-file + (size of Tag and Length)*(number of APDUs) */
520
0
  buf_length = (2 + sizeof(rsf_length)) + newlen + 2*(transmits_num);
521
0
  p = buf = (u8 *)malloc(buf_length);
522
0
  if (buf == NULL)
523
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
524
0
  buf_end = buf + buf_length;
525
526
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
527
  /* put 0x80 TLV */
528
0
  rsf_length[0] = (newlen >> 8) & 0xFF;
529
0
  rsf_length[1] = newlen & 0xFF;
530
531
0
  if (buf_end - p < (int)(2 + sizeof(rsf_length))) {
532
0
    free(buf);
533
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
534
0
  }
535
536
0
  sc_asn1_put_tag(0x80, rsf_length, sizeof(rsf_length), p, buf_end - p, &p);
537
  /* put 0xA5 TLVs (one or more); each transmit must begin with 0xA5 TLV */
538
0
  while (newlen)
539
0
  {
540
0
    if (buf_end - p < (int)(newlen + 2)) {
541
0
      free(buf);
542
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
543
0
    }
544
0
    if ((p - buf) % max_transmit_length + newlen + 2 > max_transmit_length)
545
0
      val_length = max_transmit_length - (p - buf) % max_transmit_length - 2;
546
0
    else
547
0
      val_length = newlen;
548
    /* not using sc_asn1_put_tag(...) because rtecp do not support asn1 properly (when val_length > 127) */
549
0
    *p++ = 0xA5;
550
0
    *p++ = (u8)val_length;
551
0
    if (val_length > newlen) {
552
0
      free(buf);
553
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
554
0
    }
555
0
    memcpy(p, newref, val_length);
556
0
    p += val_length;
557
0
    newref += val_length;
558
0
    newlen -= val_length;
559
0
    if (newlen)
560
0
      apdu.flags |= SC_APDU_FLAGS_CHAINING;
561
0
  }
562
0
  apdu.lc = p - buf;
563
0
  apdu.data = buf;
564
0
  apdu.datalen = p - buf;
565
566
0
  r = sc_transmit_apdu(card, &apdu);
567
0
  sc_mem_clear(buf, buf_length);
568
0
  free(buf);
569
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
570
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
571
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
572
0
}
573
574
static int rtecp_reset_retry_counter(sc_card_t *card, unsigned int type,
575
    int ref_qualifier, const u8 *puk, size_t puklen,
576
    const u8 *newref, size_t newlen)
577
0
{
578
0
  sc_apdu_t apdu;
579
0
  int r;
580
581
0
  (void)type, (void)puk, (void)puklen; /* no warning */
582
583
0
  if (!card || !card->ctx)
584
0
    return SC_ERROR_INVALID_ARGUMENTS;
585
586
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2C, 0x03, ref_qualifier);
587
0
  r = sc_transmit_apdu(card, &apdu);
588
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
589
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
590
0
  LOG_TEST_RET(card->ctx, r, "Unblock card failed");
591
592
0
  if (newref && newlen)   {
593
0
          u8 tmp[2], buf[SC_MAX_APDU_BUFFER_SIZE];
594
0
    u8 *p = buf;
595
596
0
    tmp[0] = (newlen >> 8) & 0xFF;
597
0
    tmp[1] = newlen & 0xFF;
598
0
    sc_asn1_put_tag(0x80, tmp, sizeof(tmp), p, sizeof(buf) - (p - buf), &p);
599
0
    r = sc_asn1_put_tag(0xA5, newref, newlen, p, sizeof(buf) - (p - buf), &p);
600
0
    LOG_TEST_RET(card->ctx, r, "Invalid new PIN length");
601
602
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
603
0
    apdu.lc = p - buf;
604
0
    apdu.data = buf;
605
0
    apdu.datalen = p - buf;
606
607
0
    r = sc_transmit_apdu(card, &apdu);
608
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
609
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
610
0
    LOG_TEST_RET(card->ctx, r, "Set PIN failed");
611
0
  }
612
613
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
614
0
}
615
616
static int rtecp_create_file(sc_card_t *card, sc_file_t *file)
617
0
{
618
0
  int r;
619
620
0
  if (!card || !card->ctx || !file)
621
0
    return SC_ERROR_INVALID_ARGUMENTS;
622
623
0
  if (file->sec_attr_len == 0)
624
0
  {
625
0
    r = set_sec_attr_from_acl(card, file);
626
0
    LOG_TEST_RET(card->ctx, r, "Set sec_attr from ACL failed");
627
0
  }
628
629
0
  r = iso_ops->create_file(card, file);
630
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
631
0
}
632
633
static int rtecp_list_files(sc_card_t *card, u8 *buf, size_t buflen)
634
0
{
635
0
  sc_apdu_t apdu;
636
0
  u8 rbuf[SC_MAX_APDU_RESP_SIZE], previd[2];
637
0
  const u8 *tag;
638
0
  size_t taglen, len = 0;
639
0
  int r;
640
641
0
  if (!card || !card->ctx || !buf)
642
0
    return SC_ERROR_INVALID_ARGUMENTS;
643
644
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0, 0);
645
0
  for (;;)
646
0
  {
647
0
    apdu.resp = rbuf;
648
0
    apdu.resplen = sizeof(rbuf);
649
0
    apdu.le = sizeof(rbuf);
650
0
    r = sc_transmit_apdu(card, &apdu);
651
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
652
0
    if (apdu.sw1 == 0x6A  &&  apdu.sw2 == 0x82)
653
0
      break; /* Next file not found */
654
655
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
656
0
    LOG_TEST_RET(card->ctx, r, "");
657
658
0
    if (apdu.resplen <= 2)
659
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
660
661
    /* save first file(dir) ID */
662
0
    tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
663
0
        0x83, &taglen);
664
0
    if (!tag || taglen != sizeof(previd))
665
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
666
0
    memcpy(previd, tag, sizeof(previd));
667
668
0
    if (len + sizeof(previd) <= buflen)
669
0
    {
670
0
      memcpy(&buf[len], previd, sizeof(previd));
671
0
      len += sizeof(previd);
672
0
    }
673
674
0
    tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
675
0
        0x82, &taglen);
676
0
    if (!tag || taglen != 2)
677
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
678
0
    if (tag[0] == 0x38)
679
0
    {
680
      /* Select parent DF of the current DF */
681
0
      sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0);
682
      /* We should set le and resp buf to actually call Get Response for card on T0. */
683
0
      apdu.resp = rbuf;
684
0
      apdu.resplen = sizeof(rbuf);
685
0
      apdu.le = sizeof(rbuf);
686
0
      r = sc_transmit_apdu(card, &apdu);
687
0
      LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
688
0
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
689
0
      LOG_TEST_RET(card->ctx, r, "");
690
0
    }
691
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x02);
692
0
    apdu.lc = sizeof(previd);
693
0
    apdu.data = previd;
694
0
    apdu.datalen = sizeof(previd);
695
0
  }
696
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
697
0
}
698
699
static int rtecp_card_ctl(sc_card_t *card, unsigned long request, void *data)
700
11
{
701
11
  sc_apdu_t apdu;
702
11
  u8 buf[512];
703
11
  sc_rtecp_genkey_data_t *genkey_data = data;
704
11
  sc_serial_number_t *serial = data;
705
11
  int r;
706
707
11
  const unsigned char rsa_prop[] = {0xA6, 0x06, 0x94, 0x04, 0x01, 0x00, 0x01, 0x00};
708
709
11
  if (!card || !card->ctx)
710
0
    return SC_ERROR_INVALID_ARGUMENTS;
711
712
11
  switch (request)
713
11
  {
714
0
  case SC_CARDCTL_RTECP_INIT:
715
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x8A, 0, 0);
716
0
    apdu.cla = 0x80;
717
0
    break;
718
0
  case SC_CARDCTL_RTECP_INIT_END:
719
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x84, 0x4E, 0x19);
720
0
    apdu.cla = 0x80;
721
0
    break;
722
11
  case SC_CARDCTL_GET_SERIALNR:
723
11
    if (!serial)
724
11
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
725
11
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x81);
726
11
    apdu.resp = buf;
727
11
    apdu.resplen = sizeof(buf);
728
11
    apdu.le = 256;
729
11
    serial->len = sizeof(serial->value);
730
11
    break;
731
0
  case SC_CARDCTL_RTECP_GENERATE_KEY:
732
0
    if (!genkey_data)
733
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
734
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x46, 0x80,
735
0
        genkey_data->key_id);
736
0
    apdu.resp = buf;
737
0
    apdu.resplen = sizeof(buf);
738
0
    apdu.le = 256;
739
0
    if (genkey_data->type == SC_ALGORITHM_RSA) {
740
0
      apdu.cse = SC_APDU_CASE_4_SHORT;
741
0
      apdu.data = rsa_prop;
742
0
      apdu.datalen = sizeof(rsa_prop);
743
0
      apdu.lc = sizeof(rsa_prop);
744
0
    }
745
0
    break;
746
0
  case SC_CARDCTL_LIFECYCLE_SET:
747
0
    sc_log(card->ctx,  "%s\n",
748
0
        "SC_CARDCTL_LIFECYCLE_SET not supported");
749
    /* no call sc_debug (SC_FUNC_RETURN) */
750
0
    return SC_ERROR_NOT_SUPPORTED;
751
0
  default:
752
0
    sc_log(card->ctx,
753
0
      "request = 0x%lx\n", request);
754
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
755
11
  }
756
11
  r = sc_transmit_apdu(card, &apdu);
757
11
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
758
10
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
759
10
  if (!r && request == SC_CARDCTL_RTECP_GENERATE_KEY)
760
0
  {
761
0
    if (genkey_data->type == SC_ALGORITHM_RSA &&
762
0
        genkey_data->u.rsa.modulus_len >= apdu.resplen &&
763
0
        genkey_data->u.rsa.exponent_len >= 3)
764
0
    {
765
0
      memcpy(genkey_data->u.rsa.modulus, apdu.resp, apdu.resplen);
766
0
      genkey_data->u.rsa.modulus_len = apdu.resplen;
767
0
      reverse(genkey_data->u.rsa.modulus,
768
0
          genkey_data->u.rsa.modulus_len);
769
0
      memcpy(genkey_data->u.rsa.exponent, "\x01\x00\x01", 3);
770
0
      genkey_data->u.rsa.exponent_len = 3;
771
0
    }
772
0
    else if (genkey_data->type == SC_ALGORITHM_GOSTR3410 &&
773
0
        genkey_data->u.gostr3410.xy_len >= apdu.resplen)
774
0
    {
775
0
      memcpy(genkey_data->u.gostr3410.xy, apdu.resp, apdu.resplen);
776
0
      genkey_data->u.gostr3410.xy_len = apdu.resplen;
777
0
    }
778
0
    else
779
0
      r = SC_ERROR_BUFFER_TOO_SMALL;
780
0
  }
781
10
  else if (!r && request == SC_CARDCTL_GET_SERIALNR)
782
8
  {
783
8
    if (apdu.resplen <= sizeof(serial->value))
784
7
    {
785
7
      memcpy(serial->value, apdu.resp, apdu.resplen);
786
7
      serial->len = apdu.resplen;
787
7
    }
788
1
    else
789
1
      r = SC_ERROR_BUFFER_TOO_SMALL;
790
8
  }
791
10
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
792
10
}
793
794
static int rtecp_construct_fci(sc_card_t *card, const sc_file_t *file,
795
    u8 *out, size_t *outlen)
796
0
{
797
0
  u8 buf[64], *p = out;
798
799
0
  if (!card || !card->ctx || !file || !out || !outlen
800
0
    || (*outlen < (size_t)(p - out) + 2))
801
0
    return SC_ERROR_INVALID_ARGUMENTS;
802
803
0
  *p++ = 0x6F; /* FCI template */
804
0
  p++; /* for length */
805
806
  /* 0x80 - Number of data bytes in the file, excluding structural information */
807
0
  buf[0] = (file->size >> 8) & 0xFF;
808
0
  buf[1] = file->size & 0xFF;
809
0
  sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p);
810
811
  /* 0x82 - File descriptor byte */
812
0
  if (file->type_attr_len)
813
0
  {
814
0
    if (sizeof(buf) < file->type_attr_len)
815
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
816
0
    memcpy(buf, file->type_attr, file->type_attr_len);
817
0
    sc_asn1_put_tag(0x82, buf, file->type_attr_len,
818
0
        p, *outlen - (p - out), &p);
819
0
  }
820
0
  else
821
0
  {
822
0
    switch (file->type)
823
0
    {
824
0
    case SC_FILE_TYPE_WORKING_EF:
825
0
      buf[0] = 0x01;
826
0
      break;
827
0
    case SC_FILE_TYPE_DF:
828
0
      buf[0] = 0x38;
829
0
      break;
830
0
    case SC_FILE_TYPE_INTERNAL_EF:
831
0
    default:
832
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
833
0
    }
834
0
    buf[1] = 0;
835
0
    sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p);
836
0
  }
837
  /* 0x83 - File identifier */
838
0
  buf[0] = (file->id >> 8) & 0xFF;
839
0
  buf[1] = file->id & 0xFF;
840
0
  sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
841
842
0
  if (file->prop_attr_len)
843
0
  {
844
0
    if (sizeof(buf) < file->prop_attr_len)
845
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
846
0
    memcpy(buf, file->prop_attr, file->prop_attr_len);
847
0
    sc_asn1_put_tag(0x85, buf, file->prop_attr_len,
848
0
        p, *outlen - (p - out), &p);
849
0
  }
850
0
  if (file->sec_attr_len)
851
0
  {
852
0
    if (sizeof(buf) < file->sec_attr_len)
853
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
854
0
    memcpy(buf, file->sec_attr, file->sec_attr_len);
855
0
    sc_asn1_put_tag(0x86, buf, file->sec_attr_len,
856
0
        p, *outlen - (p - out), &p);
857
0
  }
858
0
  out[1] = p - out - 2; /* length */
859
0
  *outlen = p - out;
860
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
861
0
}
862
863
struct sc_card_driver * sc_get_rtecp_driver(void)
864
15.5k
{
865
15.5k
  if (iso_ops == NULL)
866
1
    iso_ops = sc_get_iso7816_driver()->ops;
867
15.5k
  rtecp_ops = *iso_ops;
868
869
15.5k
  rtecp_ops.match_card = rtecp_match_card;
870
15.5k
  rtecp_ops.init = rtecp_init;
871
  /* read_binary */
872
15.5k
  rtecp_ops.write_binary = NULL;
873
  /* update_binary */
874
15.5k
  rtecp_ops.read_record = NULL;
875
15.5k
  rtecp_ops.write_record = NULL;
876
15.5k
  rtecp_ops.append_record = NULL;
877
15.5k
  rtecp_ops.update_record = NULL;
878
15.5k
  rtecp_ops.select_file = rtecp_select_file;
879
  /* get_response */
880
  /* get_challenge */
881
15.5k
  rtecp_ops.verify = rtecp_verify;
882
15.5k
  rtecp_ops.logout = rtecp_logout;
883
  /* restore_security_env */
884
15.5k
  rtecp_ops.set_security_env = rtecp_set_security_env;
885
15.5k
  rtecp_ops.decipher = rtecp_decipher;
886
15.5k
  rtecp_ops.compute_signature = rtecp_compute_signature;
887
15.5k
  rtecp_ops.change_reference_data = rtecp_change_reference_data;
888
15.5k
  rtecp_ops.reset_retry_counter = rtecp_reset_retry_counter;
889
15.5k
  rtecp_ops.create_file = rtecp_create_file;
890
  /* delete_file */
891
15.5k
  rtecp_ops.list_files = rtecp_list_files;
892
  /* check_sw */
893
15.5k
  rtecp_ops.card_ctl = rtecp_card_ctl;
894
  /* process_fci */
895
15.5k
  rtecp_ops.construct_fci = rtecp_construct_fci;
896
  rtecp_ops.pin_cmd = NULL;
897
15.5k
  return &rtecp_drv;
898
15.5k
}