Coverage Report

Created: 2026-08-13 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-rutoken.c
Line
Count
Source
1
/*
2
 * card-rutoken.c: Support for Rutoken S cards
3
 *
4
 * Copyright (C) 2007  Pavel Mironchik <rutoken@rutoken.ru>
5
 * Copyright (C) 2007  Eugene Hermann <rutoken@rutoken.ru>
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
26
#include <sys/types.h>
27
#include <assert.h>
28
#include <ctype.h>
29
#include <string.h>
30
#include <stdlib.h>
31
#include <stdio.h>
32
33
#include "internal.h"
34
#include "opensc.h"
35
#include "pkcs15.h"
36
#include "asn1.h"
37
#include "cardctl.h"
38
39
struct auth_senv {
40
  unsigned int algorithm;
41
};
42
typedef struct auth_senv auth_senv_t;
43
44
struct helper_acl_to_sec_attr
45
{
46
  unsigned int ac_op;
47
  size_t sec_attr_pos;
48
};
49
typedef struct helper_acl_to_sec_attr helper_acl_to_sec_attr_t;
50
51
static const helper_acl_to_sec_attr_t arr_convert_attr_df [] = {
52
  { SC_AC_OP_CREATE, 0 },
53
  { SC_AC_OP_CREATE, 1 },
54
  { SC_AC_OP_DELETE, 6 }
55
};
56
57
static const helper_acl_to_sec_attr_t arr_convert_attr_ef [] = {
58
  { SC_AC_OP_READ, 0 },
59
  { SC_AC_OP_UPDATE, 1 },
60
  { SC_AC_OP_WRITE, 1 },
61
  { SC_AC_OP_DELETE, 6 }
62
};
63
64
static const sc_SecAttrV2_t default_sec_attr = {
65
  0x42,
66
  0, 1, 0, 0, 0, 0, 1,
67
  0, 0, 0, 0,
68
  2, 0, 0, 0,
69
  0, 0, 0, 0,
70
  0, 0, 0, 0,
71
  0, 0, 0, 0,
72
  0, 0, 0, 0,
73
  2, 0, 0, 0,
74
  0, 0, 0, 0 /* reserve */
75
};
76
77
static const struct sc_card_operations *iso_ops = NULL;
78
static struct sc_card_operations rutoken_ops;
79
80
static struct sc_card_driver rutoken_drv = {
81
  "Rutoken driver",
82
  "rutoken",
83
  &rutoken_ops,
84
  NULL, 0, NULL
85
};
86
87
static const struct sc_atr_table rutoken_atrs[] = {
88
  { "3b:6f:00:ff:00:56:72:75:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_RUTOKENS, 0, NULL }, /* Aktiv Rutoken S */
89
  { "3b:6f:00:ff:00:56:75:61:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_RUTOKENS, 0, NULL }, /* Aktiv uaToken S */
90
  { NULL, NULL, NULL, 0, 0, NULL }
91
};
92
93
static int rutoken_finish(sc_card_t *card)
94
127
{
95
127
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
96
127
  if (!card->drv_data)
97
0
    return SC_ERROR_INTERNAL;
98
127
  free(card->drv_data);
99
127
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
100
127
}
101
102
static int rutoken_match_card(sc_card_t *card)
103
8.87k
{
104
8.87k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
105
8.87k
  if (_sc_match_atr(card, rutoken_atrs, &card->type) >= 0)
106
127
  {
107
127
    sc_log(card->ctx,  "ATR recognized as Rutoken\n");
108
127
    LOG_FUNC_RETURN(card->ctx, 1);
109
127
  }
110
8.74k
  LOG_FUNC_RETURN(card->ctx, 0);
111
8.74k
}
112
113
static int token_init(sc_card_t *card, const char *card_name)
114
127
{
115
127
  LOG_FUNC_CALLED(card->ctx);
116
117
127
  card->name = card_name;
118
127
  card->caps |= SC_CARD_CAP_RNG;
119
127
  card->drv_data = calloc(1, sizeof(auth_senv_t));
120
127
  if (card->drv_data == NULL)
121
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_OUT_OF_MEMORY);
122
123
127
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
124
127
}
125
126
static int rutoken_init(sc_card_t *card)
127
127
{
128
127
  int ret;
129
130
127
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
131
  /* &rutoken_atrs[1] : { uaToken S ATR, NULL ATR } */
132
127
  if (_sc_match_atr(card, &rutoken_atrs[1], &card->type) >= 0)
133
1
    ret = token_init(card, "uaToken S card");
134
126
  else
135
126
    ret = token_init(card, "Rutoken S card");
136
137
127
  if (ret != SC_SUCCESS) {
138
0
    ret = SC_ERROR_INVALID_CARD;
139
0
  }
140
127
  LOG_FUNC_RETURN(card->ctx, ret);
141
127
}
142
143
static const struct sc_card_error rutoken_errors[] = {
144
145
  { 0x6300, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
146
  { 0x63C1, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed. One tries left"},
147
  { 0x63C2, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed. Two tries left"},
148
  { 0x63C3, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
149
  { 0x63C4, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
150
  { 0x63C5, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
151
  { 0x63C6, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
152
  { 0x63C7, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
153
  { 0x63C8, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
154
  { 0x63C9, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
155
  { 0x63CA, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
156
  { 0x63CB, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
157
  { 0x63CC, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
158
  { 0x63CD, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
159
  { 0x63CE, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
160
  { 0x63CF, SC_ERROR_PIN_CODE_INCORRECT,  "Authentication failed"},
161
162
  { 0x6400, SC_ERROR_CARD_CMD_FAILED,     "Aborting"},
163
164
  { 0x6500, SC_ERROR_MEMORY_FAILURE,      "Memory failure"},
165
  { 0x6581, SC_ERROR_MEMORY_FAILURE,      "Memory failure"},
166
167
  { 0x6700, SC_ERROR_WRONG_LENGTH,        "Lc or Le invalid"},
168
169
  { 0x6883, SC_ERROR_CARD_CMD_FAILED,     "The finishing command of a chain is expected"},
170
171
  { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Required access right not granted"},
172
  { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "DO blocked"},
173
  { 0x6985, SC_ERROR_CARD_CMD_FAILED,     "Command not allowed (unsuitable conditions)"},
174
  { 0x6986, SC_ERROR_INCORRECT_PARAMETERS,"No current EF selected"},
175
176
  { 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Invalid parameters in data field"},
177
  { 0x6A81, SC_ERROR_NOT_SUPPORTED,       "Function/mode not supported"},
178
  { 0x6A82, SC_ERROR_FILE_NOT_FOUND,      "File (DO) not found"},
179
  { 0x6A84, SC_ERROR_CARD_CMD_FAILED,     "Not enough memory space in the token"},
180
  { 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"P1 or P2 invalid"},
181
  { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File (DO) already exists"},
182
183
  { 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Out of maximum file length"},
184
185
  { 0x6C00, SC_ERROR_WRONG_LENGTH,        "Le does not fit the data to be sent"},
186
187
  { 0x6D00, SC_ERROR_INS_NOT_SUPPORTED,   "Ins invalid (not supported)"},
188
189
  /* Own class of an error*/
190
  { 0x6F01, SC_ERROR_CARD_CMD_FAILED,     "Rutoken has the exchange protocol which is not supported by the USB-driver (newer, than in the driver)"},
191
  { 0x6F83, SC_ERROR_CARD_CMD_FAILED,     "Infringement of the exchange protocol with Rutoken is revealed"},
192
  { 0x6F84, SC_ERROR_CARD_CMD_FAILED,     "Rutoken is busy by processing of other command"},
193
  { 0x6F85, SC_ERROR_CARD_CMD_FAILED,     "In the current folder the maximum quantity of file system objects is already created"},
194
  { 0x6F86, SC_ERROR_CARD_CMD_FAILED,     "Invalid access right. Already login"},
195
196
  { 0x9000, SC_SUCCESS,                  NULL}
197
};
198
199
static int rutoken_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
200
793
{
201
793
  size_t i;
202
203
29.7k
  for (i = 0; i < sizeof(rutoken_errors)/sizeof(rutoken_errors[0]); ++i) {
204
29.7k
    if (rutoken_errors[i].SWs == ((sw1 << 8) | sw2)) {
205
765
      if ( rutoken_errors[i].errorstr )
206
241
        sc_log(card->ctx,  "%s\n", rutoken_errors[i].errorstr);
207
765
      sc_log(card->ctx,  "sw1 = %x, sw2 = %x", sw1, sw2);
208
765
      return rutoken_errors[i].errorno;
209
765
    }
210
29.7k
  }
211
28
  sc_log(card->ctx,  "Unknown SWs; SW1=%02X, SW2=%02X\n", sw1, sw2);
212
28
  return SC_ERROR_CARD_CMD_FAILED;
213
793
}
214
215
static void swap_pair(u8 *buf, size_t len)
216
354
{
217
354
  size_t i;
218
354
  u8 tmp;
219
220
743
  for (i = 0; i + 1 < len; i += 2)
221
389
  {
222
389
    tmp = buf[i];
223
389
    buf[i] = buf[i + 1];
224
389
    buf[i + 1] = tmp;
225
389
  }
226
354
}
227
228
static void swap_four(u8 *buf, size_t len)
229
0
{
230
0
  size_t i;
231
0
  u8 tmp;
232
233
0
  for (i = 0; i + 3 < len; i += 4)
234
0
  {
235
0
    tmp = buf[i];
236
0
    buf[i] = buf[i + 3];
237
0
    buf[i + 3] = tmp;
238
0
    swap_pair(&buf[i + 1], 2);
239
0
  }
240
0
}
241
242
static int rutoken_list_files(sc_card_t *card, u8 *buf, size_t buflen)
243
0
{
244
0
  sc_apdu_t apdu;
245
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], previd[2];
246
0
  const u8 *tag;
247
0
  size_t taglen, len = 0;
248
0
  int ret;
249
250
0
  if (!card || !card->ctx)
251
0
    return SC_ERROR_INTERNAL;
252
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
253
0
  if (!buf)
254
0
    return SC_ERROR_INTERNAL;
255
256
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0, 0);
257
0
  for (;;)
258
0
  {
259
0
    apdu.resp = rbuf;
260
0
    apdu.resplen = sizeof(rbuf);
261
0
    apdu.le = 256;
262
0
    ret = sc_transmit_apdu(card, &apdu);
263
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
264
0
    if (apdu.sw1 == 0x6A  &&  apdu.sw2 == 0x82)
265
0
      break; /* Next file not found */
266
267
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
268
0
    LOG_TEST_RET(card->ctx, ret, "");
269
270
0
    if (apdu.resplen <= 2)
271
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
272
273
    /* save first file(dir) ID */
274
0
    tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
275
0
        0x83, &taglen);
276
0
    if (!tag || taglen != sizeof(previd))
277
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
278
0
    memcpy(previd, tag, sizeof(previd));
279
280
0
    if (len + sizeof(previd) <= buflen)
281
0
    {
282
0
      buf[len++] = previd[1];
283
0
      buf[len++] = previd[0];
284
0
    }
285
286
0
    tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
287
0
        0x82, &taglen);
288
0
    if (!tag || taglen != 2)
289
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
290
0
    if (tag[0] == 0x38)
291
0
    {
292
      /* Select parent DF of the current DF */
293
0
      sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0);
294
0
      apdu.resp = rbuf;
295
0
      apdu.resplen = sizeof(rbuf);
296
0
      apdu.le = 256;
297
0
      ret = sc_transmit_apdu(card, &apdu);
298
0
      LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
299
0
      ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
300
0
      LOG_TEST_RET(card->ctx, ret, "");
301
0
    }
302
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x02);
303
0
    apdu.lc = sizeof(previd);
304
0
    apdu.data = previd;
305
0
    apdu.datalen = sizeof(previd);
306
0
  }
307
0
  LOG_FUNC_RETURN(card->ctx, (int)len);
308
0
}
309
310
static void set_acl_from_sec_attr(sc_card_t *card, sc_file_t *file)
311
70
{
312
70
  if (file->sec_attr  &&  file->sec_attr_len == sizeof(sc_SecAttrV2_t))
313
70
  {
314
70
    sc_file_add_acl_entry(file, SC_AC_OP_SELECT,
315
70
        SC_AC_NONE, SC_AC_KEY_REF_NONE);
316
70
    if (file->sec_attr[0] & 0x40) /* if AccessMode.6 */
317
57
    {
318
57
      sc_log(card->ctx,  "SC_AC_OP_DELETE %i %i",
319
57
          (int)(*(int8_t*)&file->sec_attr[1 +6]),
320
57
          file->sec_attr[1+7 +6*4]);
321
57
      sc_file_add_acl_entry(file, SC_AC_OP_DELETE,
322
57
          (int)(*(int8_t*)&file->sec_attr[1 +6]),
323
57
          file->sec_attr[1+7 +6*4]);
324
57
    }
325
70
    if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */
326
46
    {
327
46
      sc_log(card->ctx,  (file->type == SC_FILE_TYPE_DF) ?
328
46
          "SC_AC_OP_CREATE %i %i" : "SC_AC_OP_READ %i %i",
329
46
          (int)(*(int8_t*)&file->sec_attr[1 +0]),
330
46
          file->sec_attr[1+7 +0*4]);
331
46
      sc_file_add_acl_entry(file,
332
46
          (file->type == SC_FILE_TYPE_DF) ?
333
44
          SC_AC_OP_CREATE : SC_AC_OP_READ,
334
46
          (int)(*(int8_t*)&file->sec_attr[1 +0]),
335
46
          file->sec_attr[1+7 +0*4]);
336
46
    }
337
70
    if (file->type == SC_FILE_TYPE_DF)
338
3
    {
339
3
      sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES,
340
3
          SC_AC_NONE, SC_AC_KEY_REF_NONE);
341
3
    }
342
67
    else
343
67
      if (file->sec_attr[0] & 0x02) /* if AccessMode.1 */
344
50
      {
345
50
        sc_log(card->ctx,  "SC_AC_OP_UPDATE %i %i",
346
50
            (int)(*(int8_t*)&file->sec_attr[1 +1]),
347
50
            file->sec_attr[1+7 +1*4]);
348
50
        sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
349
50
            (int)(*(int8_t*)&file->sec_attr[1 +1]),
350
50
            file->sec_attr[1+7 +1*4]);
351
50
        sc_log(card->ctx,  "SC_AC_OP_WRITE %i %i",
352
50
            (int)(*(int8_t*)&file->sec_attr[1 +1]),
353
50
            file->sec_attr[1+7 +1*4]);
354
50
        sc_file_add_acl_entry(file, SC_AC_OP_WRITE,
355
50
            (int)(*(int8_t*)&file->sec_attr[1 +1]),
356
50
            file->sec_attr[1+7 +1*4]);
357
50
      }
358
70
  }
359
70
}
360
361
static int rutoken_select_file(sc_card_t *card,
362
      const sc_path_t *in_path, sc_file_t **file_out)
363
597
{
364
597
  sc_apdu_t apdu;
365
597
  u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
366
597
  sc_file_t *file = NULL;
367
597
  size_t pathlen;
368
597
  int ret;
369
370
597
  if (!card || !card->ctx)
371
0
    return SC_ERROR_INTERNAL;
372
597
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
373
374
597
  if (in_path == NULL || sizeof(pathbuf) < in_path->len)
375
0
    return SC_ERROR_INTERNAL;
376
597
  memcpy(path, in_path->value, in_path->len);
377
597
  pathlen = in_path->len;
378
379
  /* p2 = 0; first record, return FCP */
380
597
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
381
597
  switch (in_path->type)
382
597
  {
383
0
  case SC_PATH_TYPE_FILE_ID:
384
0
    if (pathlen != 2)
385
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
386
0
    break;
387
354
  case SC_PATH_TYPE_PATH:
388
354
    if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0)
389
321
    {
390
321
      if (pathlen == 2)
391
1
        break; /* only 3F00 supplied */
392
320
      path += 2;
393
320
      pathlen -= 2;
394
320
    }
395
353
    apdu.p1 = 0x08;
396
353
    break;
397
243
  case SC_PATH_TYPE_DF_NAME:
398
243
  case SC_PATH_TYPE_FROM_CURRENT:
399
243
  case SC_PATH_TYPE_PARENT:
400
243
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
401
0
  default:
402
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
403
597
  }
404
354
  swap_pair(path, pathlen);
405
354
  apdu.lc = pathlen;
406
354
  apdu.data = path;
407
354
  apdu.datalen = pathlen;
408
409
354
  apdu.resp = buf;
410
354
  apdu.resplen = sizeof(buf);
411
354
  apdu.le = 256;
412
413
354
  ret = sc_transmit_apdu(card, &apdu);
414
354
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
415
345
  if (file_out == NULL)
416
123
  {
417
123
    if (apdu.sw1 == 0x61)
418
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
419
123
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
420
123
  }
421
222
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
422
222
  LOG_TEST_RET(card->ctx, ret, "");
423
424
120
  if (apdu.resplen > 0 && apdu.resp[0] != 0x62) /* Tag 0x62 - FCP */
425
120
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
426
427
109
  file = sc_file_new();
428
109
  if (file == NULL)
429
109
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
430
109
  file->path = *in_path;
431
109
  if (card->ops->process_fci == NULL)
432
0
  {
433
0
    sc_file_free(file);
434
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
435
0
  }
436
109
  if (apdu.resplen > 1  &&  apdu.resplen >= (size_t)apdu.resp[1] + 2)
437
94
  {
438
94
    ret = card->ops->process_fci(card, file, apdu.resp+2, apdu.resp[1]);
439
94
  }
440
109
  if (file->sec_attr && file->sec_attr_len == sizeof(sc_SecAttrV2_t))
441
70
    set_acl_from_sec_attr(card, file);
442
39
  else
443
39
    ret = SC_ERROR_UNKNOWN_DATA_RECEIVED;
444
109
  if (ret != SC_SUCCESS)
445
39
    sc_file_free(file);
446
70
  else
447
70
  {
448
70
    *file_out = file;
449
70
  }
450
109
  LOG_FUNC_RETURN(card->ctx, ret);
451
109
}
452
453
static int rutoken_process_fci(struct sc_card *card, sc_file_t *file,
454
      const unsigned char *buf, size_t buflen)
455
94
{
456
94
  size_t taglen;
457
94
  int ret;
458
94
  const unsigned char *tag;
459
460
94
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
461
94
  ret = iso_ops->process_fci(card, file, buf, buflen);
462
94
  if (ret == SC_SUCCESS)
463
94
  {
464
    /* Rutoken S returns buffers in little-endian. */
465
    /* Set correct file id. */
466
94
    file->id = ((file->id & 0xFF) << 8) | ((file->id >> 8) & 0xFF);
467
94
    sc_log(card->ctx,  "  file identifier: 0x%04X", file->id);
468
    /* Determine file size. */
469
94
    tag = sc_asn1_find_tag(card->ctx, buf, buflen, 0x80, &taglen);
470
    /* Rutoken S always returns 2 bytes. */
471
94
    if (tag != NULL && taglen == 2)
472
20
    {
473
20
      file->size = (tag[1] << 8) | tag[0];
474
20
      sc_log(card->ctx,  "  bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", file->size);
475
20
    }
476
94
  }
477
94
  LOG_FUNC_RETURN(card->ctx, ret);
478
94
}
479
480
static int rutoken_construct_fci(sc_card_t *card, const sc_file_t *file,
481
      u8 *out, size_t *outlen)
482
0
{
483
0
  u8 buf[64], *p = out;
484
485
0
  if (!card || !card->ctx)
486
0
    return SC_ERROR_INTERNAL;
487
0
  LOG_FUNC_CALLED(card->ctx);
488
489
0
  if (!file || !out || !outlen)
490
0
    return SC_ERROR_INTERNAL;
491
0
  if (*outlen < (size_t)(p - out) + 2)
492
0
    return SC_ERROR_INTERNAL;
493
0
  *p++ = 0x62; /* FCP template */
494
0
  p++; /* for length */
495
496
  /* 0x80 - Number of data bytes in the file, excluding structural information */
497
0
  buf[1] = (file->size >> 8) & 0xFF;
498
0
  buf[0] = file->size & 0xFF;
499
0
  sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p);
500
501
  /* 0x82 - File descriptor byte */
502
0
  if (file->type_attr_len)
503
0
  {
504
0
    if (sizeof(buf) < file->type_attr_len)
505
0
      return SC_ERROR_INTERNAL;
506
0
    memcpy(buf, file->type_attr, file->type_attr_len);
507
0
    sc_asn1_put_tag(0x82, buf, file->type_attr_len,
508
0
        p, *outlen - (p - out), &p);
509
0
  }
510
0
  else
511
0
  {
512
0
    switch (file->type)
513
0
    {
514
0
    case SC_FILE_TYPE_WORKING_EF:
515
0
      buf[0] = 0x01;
516
0
      break;
517
0
    case SC_FILE_TYPE_DF:
518
0
      buf[0] = 0x38;
519
0
      break;
520
0
    case SC_FILE_TYPE_INTERNAL_EF:
521
0
    default:
522
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
523
0
    }
524
0
    buf[1] = 0;
525
0
    sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p);
526
0
  }
527
  /* 0x83 - File identifier */
528
0
  buf[1] = (file->id >> 8) & 0xFF;
529
0
  buf[0] = file->id & 0xFF;
530
0
  sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
531
532
0
  if (file->prop_attr_len)
533
0
  {
534
0
    if (sizeof(buf) < file->prop_attr_len)
535
0
      return SC_ERROR_INTERNAL;
536
0
    memcpy(buf, file->prop_attr, file->prop_attr_len);
537
0
    sc_asn1_put_tag(0x85, buf, file->prop_attr_len,
538
0
        p, *outlen - (p - out), &p);
539
0
  }
540
0
  if (file->sec_attr_len)
541
0
  {
542
0
    if (sizeof(buf) < file->sec_attr_len)
543
0
      return SC_ERROR_INTERNAL;
544
0
    memcpy(buf, file->sec_attr, file->sec_attr_len);
545
0
    sc_asn1_put_tag(0x86, buf, file->sec_attr_len,
546
0
        p, *outlen - (p - out), &p);
547
0
  }
548
0
  out[1] = p - out - 2; /* length */
549
0
  *outlen = p - out;
550
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
551
0
}
552
553
static int set_sec_attr_from_acl(sc_card_t *card, sc_file_t *file)
554
0
{
555
0
  const helper_acl_to_sec_attr_t *conv_attr;
556
0
  size_t i, n_conv_attr;
557
0
  const sc_acl_entry_t *entry;
558
0
  sc_SecAttrV2_t attr = { 0 };
559
0
  int ret = SC_SUCCESS;
560
561
0
  LOG_FUNC_CALLED(card->ctx);
562
563
0
  if (file->type == SC_FILE_TYPE_DF)
564
0
  {
565
0
    conv_attr = arr_convert_attr_df;
566
0
    n_conv_attr = sizeof(arr_convert_attr_df)/sizeof(arr_convert_attr_df[0]);
567
0
  }
568
0
  else
569
0
  {
570
0
    conv_attr = arr_convert_attr_ef;
571
0
    n_conv_attr = sizeof(arr_convert_attr_ef)/sizeof(arr_convert_attr_ef[0]);
572
0
  }
573
0
  sc_log(card->ctx,  "file->type = %i", file->type);
574
575
0
  for (i = 0; i < n_conv_attr; ++i)
576
0
  {
577
0
    entry = sc_file_get_acl_entry(file, conv_attr[i].ac_op);
578
0
    if (entry  &&  (entry->method == SC_AC_CHV || entry->method == SC_AC_NONE
579
0
        || entry->method == SC_AC_NEVER)
580
0
    )
581
0
    {
582
      /* AccessMode.[conv_attr[i].sec_attr_pos] */
583
0
      attr[0] |= 1 << conv_attr[i].sec_attr_pos;
584
0
      sc_log(card->ctx,
585
0
         "AccessMode.%"SC_FORMAT_LEN_SIZE_T"u, attr[0]=0x%x",
586
0
         conv_attr[i].sec_attr_pos, attr[0]);
587
0
      attr[1 + conv_attr[i].sec_attr_pos] = (u8)entry->method;
588
0
      sc_log(card->ctx,  "method %u", (u8)entry->method);
589
0
      if (entry->method == SC_AC_CHV)
590
0
      {
591
0
        attr[1+7 + conv_attr[i].sec_attr_pos*4] = (u8)entry->key_ref;
592
0
        sc_log(card->ctx,  "key_ref %u", (u8)entry->key_ref);
593
0
      }
594
0
    }
595
0
    else
596
0
    {
597
0
      sc_log(card->ctx,  "ACL (%u) not set, set default sec_attr",
598
0
          conv_attr[i].ac_op);
599
0
      memcpy(attr, default_sec_attr, sizeof(attr));
600
0
      break;
601
0
    }
602
0
  }
603
0
  ret = sc_file_set_sec_attr(file, attr, sizeof(attr));
604
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
605
0
}
606
607
static int rutoken_create_file(sc_card_t *card, sc_file_t *file)
608
0
{
609
0
  int ret;
610
611
0
  if (!card || !card->ctx)
612
0
    return SC_ERROR_INTERNAL;
613
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
614
615
0
  if (!file)
616
0
    return SC_ERROR_INTERNAL;
617
0
  if (file->sec_attr_len == 0)
618
0
  {
619
0
    ret = set_sec_attr_from_acl(card, file);
620
0
    LOG_TEST_RET(card->ctx, ret, "Set sec_attr from ACL failed");
621
0
  }
622
0
  if (!iso_ops || !iso_ops->create_file)
623
0
    return SC_ERROR_INTERNAL;
624
0
  ret = iso_ops->create_file(card, file);
625
0
  LOG_FUNC_RETURN(card->ctx, ret);
626
0
}
627
628
static int rutoken_delete_file(sc_card_t *card, const sc_path_t *path)
629
0
{
630
0
  u8 sbuf[2];
631
0
  sc_apdu_t apdu;
632
633
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
634
0
  if (!path || path->type != SC_PATH_TYPE_FILE_ID || (path->len != 0 && path->len != 2))
635
0
  {
636
0
    sc_log(card->ctx,  "File type has to be SC_PATH_TYPE_FILE_ID\n");
637
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
638
0
  }
639
0
  if (path->len == sizeof(sbuf))
640
0
  {
641
0
    sbuf[1] = path->value[0];
642
0
    sbuf[0] = path->value[1];
643
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
644
0
    apdu.lc = sizeof(sbuf);
645
0
    apdu.datalen = sizeof(sbuf);
646
0
    apdu.data = sbuf;
647
0
  }
648
0
  else /* No file ID given: means currently selected file */
649
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
650
0
  LOG_TEST_RET(card->ctx, sc_transmit_apdu(card, &apdu), "APDU transmit failed");
651
0
  LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
652
0
}
653
654
static int rutoken_verify(sc_card_t *card, unsigned int type, int ref_qualifier,
655
      const u8 *data, size_t data_len, int *tries_left)
656
0
{
657
0
  sc_apdu_t apdu;
658
0
  int ret;
659
660
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
661
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
662
0
  ret = sc_transmit_apdu(card, &apdu);
663
0
  if (ret == SC_SUCCESS  &&  ((apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
664
0
        ||  apdu.sw1 == 0x63)
665
0
  )
666
0
  {
667
    /* sw1 == 0x63  -  may be already login with other ref_qualifier
668
     * sw1 == 0x90 && sw2 == 0x00  -  already login with ref_qualifier
669
     */
670
    /* RESET ACCESS RIGHTS */
671
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
672
0
    apdu.cla = 0x80;
673
0
    ret = sc_transmit_apdu(card, &apdu);
674
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
675
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
676
0
    LOG_TEST_RET(card->ctx, ret, "Reset access rights failed");
677
0
  }
678
679
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, ref_qualifier);
680
0
  apdu.lc = data_len;
681
0
  apdu.datalen = data_len;
682
0
  apdu.data = data;
683
0
  ret = sc_transmit_apdu(card, &apdu);
684
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
685
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
686
0
  if (ret == SC_ERROR_PIN_CODE_INCORRECT  &&  tries_left)
687
0
  {
688
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
689
0
    ret = sc_transmit_apdu(card, &apdu);
690
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
691
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
692
0
    if (ret == SC_ERROR_PIN_CODE_INCORRECT)
693
0
      *tries_left = (int)(apdu.sw2 & 0x0f);
694
0
  }
695
0
  LOG_FUNC_RETURN(card->ctx, ret);
696
0
}
697
698
static int rutoken_logout(sc_card_t *card)
699
0
{
700
0
  sc_apdu_t apdu;
701
0
  sc_path_t path;
702
0
  int ret;
703
704
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
705
0
  sc_format_path("3F00", &path);
706
0
  ret = rutoken_select_file(card, &path, NULL);
707
0
  LOG_TEST_RET(card->ctx, ret, "Select MF failed");
708
709
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
710
0
  apdu.cla = 0x80;
711
0
  ret = sc_transmit_apdu(card, &apdu);
712
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
713
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
714
0
  LOG_FUNC_RETURN(card->ctx, ret);
715
0
}
716
717
static int rutoken_change_reference_data(sc_card_t *card, unsigned int type,
718
      int ref_qualifier, const u8 *old, size_t oldlen,
719
      const u8 *newref, size_t newlen, int *tries_left)
720
0
{
721
0
  sc_apdu_t apdu;
722
0
  int ret;
723
724
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
725
0
  if (old && oldlen)
726
0
  {
727
0
    ret = rutoken_verify(card, type, ref_qualifier, old, oldlen, tries_left);
728
0
    LOG_TEST_RET(card->ctx, ret, "Invalid 'old' pass");
729
0
  }
730
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
731
0
  apdu.lc = newlen;
732
0
  apdu.datalen = newlen;
733
0
  apdu.data = newref;
734
0
  ret = sc_transmit_apdu(card, &apdu);
735
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
736
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
737
0
  LOG_FUNC_RETURN(card->ctx, ret);
738
0
}
739
740
static int rutoken_reset_retry_counter(sc_card_t *card, unsigned int type,
741
      int ref_qualifier, const u8 *puk, size_t puklen,
742
      const u8 *newref, size_t newlen)
743
0
{
744
#ifdef FORCE_VERIFY_RUTOKEN
745
  int left;
746
#endif
747
0
  sc_apdu_t apdu;
748
0
  int ret;
749
750
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
751
#ifdef FORCE_VERIFY_RUTOKEN
752
  if (puk && puklen)
753
  {
754
    ret = rutoken_verify(card, type, ref_qualifier, puk, puklen, &left);
755
    sc_log(card->ctx,  "Tries left: %i\n", left);
756
    LOG_TEST_RET(card->ctx, ret, "Invalid 'puk' pass");
757
  }
758
#endif
759
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, ref_qualifier);
760
0
  ret = sc_transmit_apdu(card, &apdu);
761
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
762
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
763
0
  LOG_FUNC_RETURN(card->ctx, ret);
764
0
}
765
766
static int rutoken_restore_security_env(sc_card_t *card, int se_num)
767
0
{
768
0
  sc_apdu_t apdu;
769
0
  int ret;
770
771
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
772
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 3, se_num);
773
0
  ret = sc_transmit_apdu(card, &apdu);
774
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
775
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
776
0
  LOG_FUNC_RETURN(card->ctx, ret);
777
0
}
778
779
static int rutoken_set_security_env(sc_card_t *card,
780
      const sc_security_env_t *env,
781
      int se_num)
782
0
{
783
0
  sc_apdu_t apdu;
784
0
  auth_senv_t *senv;
785
0
  u8 data[3] = { 0x83, 0x01 };
786
0
  int ret;
787
788
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
789
0
  if (!env)
790
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
791
0
  senv = (auth_senv_t*)card->drv_data;
792
0
  if (!senv)
793
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
794
0
  if (env->algorithm != SC_ALGORITHM_GOST)
795
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
796
797
0
  senv->algorithm = SC_ALGORITHM_GOST;
798
0
  if (env->key_ref_len != 1)
799
0
  {
800
0
    sc_log(card->ctx,  "No or invalid key reference\n");
801
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
802
0
  }
803
0
  data[2] = env->key_ref[0];
804
  /*  select component  */
805
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 1, 0);
806
0
  apdu.lc = apdu.datalen = sizeof(data);
807
0
  apdu.data = data;
808
0
  switch (env->operation)
809
0
  {
810
0
    case SC_SEC_OPERATION_AUTHENTICATE:
811
0
      apdu.p2 = 0xA4;
812
0
      break;
813
0
    case SC_SEC_OPERATION_DECIPHER:
814
0
      apdu.p2 = 0xB8;
815
0
      break;
816
0
    case SC_SEC_OPERATION_SIGN:
817
0
      apdu.p2 = 0xAA;
818
0
      break;
819
0
    default:
820
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
821
0
  }
822
  /*  set SE  */
823
0
  ret = sc_transmit_apdu(card, &apdu);
824
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
825
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
826
0
  LOG_FUNC_RETURN(card->ctx, ret);
827
0
}
828
829
static void rutoken_set_do_hdr(u8 *data, size_t *data_len, sc_DOHdrV2_t *hdr)
830
0
{
831
0
  u8 buf[64], *p = data;
832
833
0
  if (!hdr || !data || !data_len)
834
0
    return;
835
836
  /* 0x80 - Number of data bytes in the file, excluding structural information */
837
0
  buf[1] = (hdr->wDOBodyLen >> 8) & 0xFF;
838
0
  buf[0] = hdr->wDOBodyLen & 0xFF;
839
0
  sc_asn1_put_tag(0x80, buf, 2, p, *data_len - (p - data), &p);
840
841
  /* 0x83 - Type and ID */
842
0
  buf[0] = hdr->OTID.byObjectType;
843
0
  buf[1] = hdr->OTID.byObjectID;
844
0
  sc_asn1_put_tag(0x83, buf, 2, p, *data_len - (p - data), &p);
845
846
  /* 0x85 - Options, Flags and Max count of try */
847
0
  buf[0] = hdr->OP.byObjectOptions;
848
0
  buf[1] = hdr->OP.byObjectFlags;
849
0
  buf[2] = hdr->OP.byObjectTry;
850
0
  sc_asn1_put_tag(0x85, buf, 3, p, *data_len - (p - data), &p);
851
852
0
  static_assert(sizeof(buf) >= sizeof(hdr->SA_V2), "internal error");
853
0
  memcpy(buf, hdr->SA_V2, sizeof(hdr->SA_V2));
854
0
  sc_asn1_put_tag(0x86, buf, sizeof(hdr->SA_V2), p, *data_len - (p - data), &p);
855
856
0
  if (*data_len < (size_t)(p - data))
857
0
    return;
858
0
  *data_len = p - data;
859
0
}
860
861
static int rutoken_key_gen(sc_card_t *card, sc_DOHdrV2_t *pHdr)
862
0
{
863
0
  u8 data[SC_MAX_APDU_BUFFER_SIZE];
864
0
  size_t data_len = sizeof(data);
865
0
  sc_apdu_t apdu;
866
0
  int ret;
867
868
0
  LOG_FUNC_CALLED(card->ctx);
869
0
  if (
870
0
       (pHdr->wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST) ||
871
0
       (pHdr->OTID.byObjectType != SC_RUTOKEN_TYPE_KEY) ||
872
0
       (pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) ||
873
0
       (pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_FULL_OPEN_DO) ||
874
0
       (pHdr->OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
875
0
       (pHdr->OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)
876
0
  )
877
0
  {
878
0
    ret = SC_ERROR_INVALID_ARGUMENTS;
879
0
  }
880
0
  else
881
0
  {
882
0
    pHdr->OP.byObjectTry = 0;
883
0
    rutoken_set_do_hdr(data, &data_len, pHdr);
884
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x65);
885
0
    apdu.data = data;
886
0
    apdu.datalen = apdu.lc = data_len;
887
0
    ret = sc_transmit_apdu(card, &apdu);
888
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
889
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
890
0
  }
891
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
892
0
}
893
894
static int rutoken_create_do(sc_card_t *card, sc_DO_V2_t * pDO)
895
0
{
896
0
  u8 data[SC_MAX_APDU_BUFFER_SIZE];
897
0
  size_t data_len = sizeof(data);
898
0
  sc_apdu_t apdu;
899
0
  int ret;
900
901
0
  LOG_FUNC_CALLED(card->ctx);
902
0
  if (
903
0
       ((pDO->HDR.OTID.byObjectType & SC_RUTOKEN_TYPE_CHV) &&
904
0
        (pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_USER) &&
905
0
        (pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_ADMIN)) ||
906
0
       ((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_GOST) &&
907
0
        (pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST)) ||
908
0
       ((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_SE) &&
909
0
        (pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_SE)) ||
910
0
       (pDO->HDR.OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
911
0
       (pDO->HDR.OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2) ||
912
0
       ((pDO->HDR.OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) &&
913
0
        (pDO->HDR.wDOBodyLen > SC_RUTOKEN_COMPACT_DO_MAX_LEN)) ||
914
0
       (pDO->HDR.wDOBodyLen > SC_RUTOKEN_DO_PART_BODY_LEN)
915
0
     )
916
0
  {
917
0
    ret = SC_ERROR_INVALID_ARGUMENTS;
918
0
  }
919
0
  else
920
0
  {
921
0
    rutoken_set_do_hdr(data, &data_len, &pDO->HDR);
922
0
    if (sizeof(data) < data_len + pDO->HDR.wDOBodyLen + 2)
923
0
      return SC_ERROR_INTERNAL;
924
0
    ret = sc_asn1_put_tag(0xA5, pDO->abyDOBody, pDO->HDR.wDOBodyLen,
925
0
        data + data_len, sizeof(data) - data_len, NULL);
926
0
    if (ret == SC_SUCCESS)
927
0
      data_len += pDO->HDR.wDOBodyLen + 2;
928
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x62);
929
0
    apdu.data = data;
930
0
    apdu.datalen = apdu.lc = data_len;
931
0
    ret = sc_transmit_apdu(card, &apdu);
932
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
933
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
934
0
  }
935
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
936
0
}
937
938
static int rutoken_get_do_info(sc_card_t *card, sc_DO_INFO_t * pInfo)
939
0
{
940
0
  u8 data[1];
941
0
  sc_apdu_t apdu;
942
0
  int ret;
943
944
0
  LOG_FUNC_CALLED(card->ctx);
945
0
  if ((pInfo->SelType != select_first) &&
946
0
      ((pInfo->DoId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
947
0
       (pInfo->DoId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)))
948
0
  {
949
0
    ret = SC_ERROR_INVALID_ARGUMENTS;
950
0
  }
951
0
  else
952
0
  {
953
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x30, 0x00, 0x00);
954
0
    apdu.cla = 0x80;
955
0
    apdu.resp = pInfo->pDoData;
956
0
    apdu.resplen = sizeof(pInfo->pDoData);
957
0
    apdu.le = 255;
958
0
    memset(apdu.resp, 0, apdu.resplen);
959
0
    switch(pInfo->SelType)
960
0
    {
961
0
    case select_first:
962
0
      apdu.cse = SC_APDU_CASE_2_SHORT;
963
0
      break;
964
0
    case select_next:
965
0
      apdu.p2 = 0x02;
966
      /* fall through */
967
0
    case select_by_id:
968
0
      data[0] = pInfo->DoId;
969
0
      apdu.data = data;
970
0
      apdu.datalen = sizeof(data);
971
0
      apdu.lc = sizeof(data);
972
0
      break;
973
0
    default:
974
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
975
0
      break;
976
0
    }
977
0
    ret = sc_transmit_apdu(card, &apdu);
978
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
979
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
980
0
  }
981
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
982
0
}
983
984
static int rutoken_delete_do(sc_card_t *card, u8 *pId)
985
0
{
986
0
  u8 data[1];
987
0
  sc_apdu_t apdu;
988
0
  int ret;
989
990
0
  LOG_FUNC_CALLED(card->ctx);
991
0
  if ((*pId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
992
0
      (*pId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2))
993
0
  {
994
0
    ret = SC_ERROR_INVALID_ARGUMENTS;
995
0
  }
996
0
  else
997
0
  {
998
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x64);
999
0
    data[0] = *pId;
1000
0
    apdu.data = data;
1001
0
    apdu.datalen = sizeof(data);
1002
0
    apdu.lc = sizeof(data);
1003
0
    ret = sc_transmit_apdu(card, &apdu);
1004
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
1005
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
1006
0
  }
1007
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
1008
0
}
1009
1010
/*  Both direction GOST cipher  */
1011
1012
static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_len,
1013
      u8 * out, size_t outlen, int p1, int p2, int isIV)
1014
0
{
1015
0
  u8 buf[248]; /* 248 (cipher_chunk) <= SC_MAX_APDU_BUFFER_SIZE  */
1016
0
  size_t len, outlen_tail = outlen;
1017
0
  int ret;
1018
0
  sc_apdu_t apdu;
1019
1020
0
  LOG_FUNC_CALLED(card->ctx);
1021
0
  sc_log(card->ctx,
1022
0
     ": crgram_len %"SC_FORMAT_LEN_SIZE_T"u; outlen %"SC_FORMAT_LEN_SIZE_T"u",
1023
0
     crgram_len, outlen);
1024
1025
0
  if (!out)
1026
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1027
0
  if (crgram_len < 16 || ((crgram_len) % 8))
1028
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_WRONG_LENGTH);
1029
1030
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, p1, p2);
1031
0
  do
1032
0
  {
1033
0
    len = (crgram_len > sizeof(buf)) ? sizeof(buf) : crgram_len;
1034
0
    apdu.lc = len;
1035
0
    apdu.datalen = len;
1036
0
    apdu.data = crgram;
1037
0
    crgram += len;
1038
0
    crgram_len -= len;
1039
1040
0
    apdu.cla = (crgram_len == 0) ? 0x00 : 0x10;
1041
0
    apdu.le = len;
1042
0
    apdu.resplen = len;
1043
0
    apdu.resp = buf;
1044
1045
0
    ret = sc_transmit_apdu(card, &apdu);
1046
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
1047
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
1048
0
    if (ret == SC_SUCCESS)
1049
0
    {
1050
0
      if (isIV)
1051
0
      {
1052
0
        apdu.resp += 8;
1053
0
        apdu.resplen -= 8;
1054
0
        isIV = 0;
1055
0
      }
1056
0
      if (apdu.resplen > outlen_tail)
1057
0
        ret = SC_ERROR_BUFFER_TOO_SMALL;
1058
0
      else
1059
0
      {
1060
0
        memcpy(out, apdu.resp, apdu.resplen);
1061
0
        out += apdu.resplen;
1062
0
        outlen_tail -= apdu.resplen;
1063
0
      }
1064
0
    }
1065
0
  } while (ret == SC_SUCCESS  &&  crgram_len != 0);
1066
0
  sc_log(card->ctx,
1067
0
     "len out cipher %"SC_FORMAT_LEN_SIZE_T"u\n",
1068
0
     outlen - outlen_tail);
1069
0
  if (ret == SC_SUCCESS)
1070
0
    ret = (outlen_tail == 0) ? (int)outlen : SC_ERROR_WRONG_LENGTH;
1071
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
1072
0
}
1073
1074
/*  Launcher for cipher  */
1075
1076
static int rutoken_cipher_gost(sc_card_t *card,
1077
      struct sc_rutoken_decipherinfo *ptr, char is_encipher)
1078
0
{
1079
0
  int ret;
1080
1081
0
  if (is_encipher)
1082
0
    ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
1083
0
        ptr->outbuf, ptr->outlen, 0x86, 0x80, 0);
1084
0
  else
1085
0
    ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
1086
0
        ptr->outbuf, ptr->outlen, 0x80, 0x86, 1);
1087
0
  if (ret > 0)
1088
0
  {
1089
0
    if ((size_t)ret == ptr->outlen)
1090
0
      ret = SC_SUCCESS;
1091
0
    else
1092
0
      ret = SC_ERROR_INTERNAL; /* SC_ERROR_DECRYPT_FAILED; */
1093
0
  }
1094
0
  return ret;
1095
1096
0
}
1097
1098
static int rutoken_compute_mac_gost(sc_card_t *card,
1099
      const u8 *in, size_t ilen,
1100
      u8 *out, size_t olen)
1101
0
{
1102
0
  const size_t signing_chunk = 248;
1103
0
  size_t len;
1104
0
  int ret;
1105
0
  sc_apdu_t apdu;
1106
1107
0
  LOG_FUNC_CALLED(card->ctx);
1108
0
  if (!in || !out || olen != 4 || ilen == 0)
1109
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1110
0
  do
1111
0
  {
1112
0
    sc_format_apdu(card, &apdu,
1113
0
        ilen > signing_chunk ?
1114
0
        SC_APDU_CASE_3_SHORT : SC_APDU_CASE_4_SHORT,
1115
0
        0x2A, 0x90, 0x80);
1116
0
    len = (ilen > signing_chunk) ? signing_chunk : ilen;
1117
0
    apdu.lc = len;
1118
0
    apdu.datalen = len;
1119
0
    apdu.data = in;
1120
0
    in += len;
1121
0
    ilen -= len;
1122
0
    if (ilen == 0)
1123
0
    {
1124
0
      apdu.cla = 0x00;
1125
0
      apdu.le = olen;
1126
0
      apdu.resplen = olen;
1127
0
      apdu.resp = out;
1128
0
    }
1129
0
    else
1130
0
      apdu.cla = 0x10;
1131
0
    ret = sc_transmit_apdu(card, &apdu);
1132
0
    LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
1133
0
    ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
1134
0
  } while (ret == SC_SUCCESS  &&  ilen != 0);
1135
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
1136
0
}
1137
1138
static int rutoken_compute_signature(struct sc_card *card,
1139
      const u8 * data, size_t datalen,
1140
      u8 * out, size_t outlen)
1141
0
{
1142
0
  int ret;
1143
0
  auth_senv_t *senv = (auth_senv_t *)card->drv_data;
1144
1145
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1146
0
  if (!senv)
1147
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
1148
1149
0
  if (senv->algorithm == SC_ALGORITHM_GOST)
1150
0
    ret = rutoken_compute_mac_gost(card, data, datalen, out, outlen);
1151
0
  else
1152
0
    ret = SC_ERROR_NOT_SUPPORTED;
1153
0
  LOG_FUNC_RETURN(card->ctx, ret);
1154
0
}
1155
1156
static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
1157
0
{
1158
0
  unsigned char rbuf[32];
1159
0
  size_t out_len;
1160
0
  int r;
1161
1162
0
  LOG_FUNC_CALLED(card->ctx);
1163
1164
0
  r = iso_ops->get_challenge(card, rbuf, sizeof rbuf);
1165
0
  LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed");
1166
1167
0
  if (len < (size_t) r) {
1168
0
    out_len = len;
1169
0
  } else {
1170
0
    out_len = (size_t) r;
1171
0
  }
1172
0
  memcpy(rnd, rbuf, out_len);
1173
1174
0
  LOG_FUNC_RETURN(card->ctx, (int)out_len);
1175
0
}
1176
1177
static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *serial)
1178
0
{
1179
0
  sc_apdu_t apdu;
1180
0
  int ret;
1181
1182
0
  LOG_FUNC_CALLED(card->ctx);
1183
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x81);
1184
0
  apdu.resp = serial->value;
1185
0
  apdu.resplen = sizeof(serial->value);
1186
0
  apdu.le = 4;
1187
0
  ret = sc_transmit_apdu(card, &apdu);
1188
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
1189
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
1190
0
  serial->len = apdu.resplen;
1191
0
  swap_four(serial->value, serial->len);
1192
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
1193
0
}
1194
1195
static int rutoken_get_info(sc_card_t *card, void *buff)
1196
0
{
1197
0
  sc_apdu_t apdu;
1198
0
  u8 rbuf[8];
1199
0
  int ret;
1200
1201
0
  LOG_FUNC_CALLED(card->ctx);
1202
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x89);
1203
0
  apdu.resp = rbuf;
1204
0
  apdu.resplen = sizeof(rbuf);
1205
0
  apdu.le = sizeof(rbuf);
1206
0
  ret = sc_transmit_apdu(card, &apdu);
1207
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
1208
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
1209
0
  if (ret == SC_SUCCESS)
1210
0
    memcpy(buff, apdu.resp, apdu.resplen);
1211
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
1212
0
}
1213
1214
static int rutoken_format(sc_card_t *card, int apdu_ins)
1215
0
{
1216
0
  int ret;
1217
0
  sc_apdu_t apdu;
1218
1219
0
  LOG_FUNC_CALLED(card->ctx);
1220
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, apdu_ins, 0x00, 0x00);
1221
0
  apdu.cla = 0x80;
1222
0
  ret = sc_transmit_apdu(card, &apdu);
1223
0
  LOG_TEST_RET(card->ctx, ret, "APDU transmit failed");
1224
0
  ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
1225
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
1226
0
}
1227
1228
static int rutoken_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
1229
0
{
1230
0
  int ret = (ptr != NULL
1231
      /*|| cmd == SC_CARDCTL_ERASE_CARD */
1232
0
      || cmd == SC_CARDCTL_RUTOKEN_FORMAT_INIT
1233
0
      || cmd == SC_CARDCTL_RUTOKEN_FORMAT_END
1234
0
    ) ? SC_SUCCESS : SC_ERROR_INVALID_ARGUMENTS;
1235
1236
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1237
1238
0
  if (ret == SC_SUCCESS)
1239
0
  {
1240
0
    switch (cmd)
1241
0
    {
1242
0
    case SC_CARDCTL_RUTOKEN_CREATE_DO:
1243
0
      ret = rutoken_create_do(card, ptr);
1244
0
      break;
1245
0
    case SC_CARDCTL_RUTOKEN_GENERATE_KEY_DO:
1246
0
      ret = rutoken_key_gen(card, ptr);
1247
0
      break;
1248
0
    case SC_CARDCTL_RUTOKEN_DELETE_DO:
1249
0
      ret = rutoken_delete_do(card, ptr);
1250
0
      break;
1251
0
    case SC_CARDCTL_RUTOKEN_GET_DO_INFO:
1252
0
      ret = rutoken_get_do_info(card, ptr);
1253
0
      break;
1254
0
    case SC_CARDCTL_GET_SERIALNR:
1255
0
      ret = rutoken_get_serial(card, ptr);
1256
0
      break;
1257
0
    case SC_CARDCTL_RUTOKEN_CHANGE_DO:
1258
0
      ret = SC_ERROR_NOT_SUPPORTED;
1259
0
      break;
1260
0
    case SC_CARDCTL_RUTOKEN_GET_INFO:
1261
0
      ret = rutoken_get_info(card, ptr);
1262
0
      break;
1263
0
    case SC_CARDCTL_RUTOKEN_GOST_ENCIPHER:
1264
0
      ret = rutoken_cipher_gost(card, ptr, 1);
1265
0
      break;
1266
0
    case SC_CARDCTL_RUTOKEN_GOST_DECIPHER:
1267
0
      ret = rutoken_cipher_gost(card, ptr, 0);
1268
0
      break;
1269
    /* case SC_CARDCTL_ERASE_CARD: */
1270
0
    case SC_CARDCTL_RUTOKEN_FORMAT_INIT:
1271
      /* ret = rutoken_format(card, 0x7a); *//*  APDU: INIT RUTOKEN */
1272
0
      ret = rutoken_format(card, 0x8a); /* APDU: NEW INIT RUTOKEN */
1273
0
      break;
1274
0
    case SC_CARDCTL_RUTOKEN_FORMAT_END:
1275
0
      ret = rutoken_format(card, 0x7b); /* APDU: FORMAT END */
1276
0
      break;
1277
0
    default:
1278
0
      sc_log(card->ctx,  "cmd = %lu", cmd);
1279
0
      ret = SC_ERROR_NOT_SUPPORTED;
1280
0
      break;
1281
0
    }
1282
0
  }
1283
0
  LOG_FUNC_RETURN(card->ctx, ret);
1284
0
}
1285
1286
static struct sc_card_driver* get_rutoken_driver(void)
1287
14.4k
{
1288
14.4k
  if (iso_ops == NULL)
1289
1
    iso_ops = sc_get_iso7816_driver()->ops;
1290
14.4k
  rutoken_ops = *iso_ops;
1291
1292
14.4k
  rutoken_ops.match_card = rutoken_match_card;
1293
14.4k
  rutoken_ops.init = rutoken_init;
1294
14.4k
  rutoken_ops.finish = rutoken_finish;
1295
  /* read_binary */
1296
14.4k
  rutoken_ops.write_binary = NULL;
1297
  /* update_binary */
1298
14.4k
  rutoken_ops.read_record = NULL;
1299
14.4k
  rutoken_ops.write_record = NULL;
1300
14.4k
  rutoken_ops.append_record = NULL;
1301
14.4k
  rutoken_ops.update_record = NULL;
1302
14.4k
  rutoken_ops.select_file = rutoken_select_file;
1303
14.4k
  rutoken_ops.get_response = NULL;
1304
14.4k
  rutoken_ops.get_challenge = rutoken_get_challenge;
1305
14.4k
  rutoken_ops.verify = rutoken_verify;
1306
14.4k
  rutoken_ops.logout = rutoken_logout;
1307
14.4k
  rutoken_ops.restore_security_env = rutoken_restore_security_env;
1308
14.4k
  rutoken_ops.set_security_env = rutoken_set_security_env;
1309
14.4k
  rutoken_ops.decipher = NULL;
1310
14.4k
  rutoken_ops.compute_signature = rutoken_compute_signature;
1311
14.4k
  rutoken_ops.change_reference_data = rutoken_change_reference_data;
1312
14.4k
  rutoken_ops.reset_retry_counter = rutoken_reset_retry_counter;
1313
14.4k
  rutoken_ops.create_file = rutoken_create_file;
1314
14.4k
  rutoken_ops.delete_file = rutoken_delete_file;
1315
14.4k
  rutoken_ops.list_files = rutoken_list_files;
1316
14.4k
  rutoken_ops.check_sw = rutoken_check_sw;
1317
14.4k
  rutoken_ops.card_ctl = rutoken_card_ctl;
1318
14.4k
  rutoken_ops.process_fci = rutoken_process_fci;
1319
14.4k
  rutoken_ops.construct_fci = rutoken_construct_fci;
1320
14.4k
  rutoken_ops.pin_cmd = NULL;
1321
1322
14.4k
  return &rutoken_drv;
1323
14.4k
}
1324
1325
struct sc_card_driver * sc_get_rutoken_driver(void)
1326
14.4k
{
1327
14.4k
  return get_rutoken_driver();
1328
14.4k
}
1329