Coverage Report

Created: 2026-06-06 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-lteid.c
Line
Count
Source
1
/*
2
 * This library is free software; you can redistribute it and/or
3
 * modify it under the terms of the GNU Lesser General Public
4
 * License as published by the Free Software Foundation; either
5
 * version 2.1 of the License, or (at your option) any later version.
6
 *
7
 * This library is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10
 * Lesser General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU Lesser General Public
13
 * License along with this library; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
 */
16
17
#ifdef HAVE_CONFIG_H
18
#include "config.h"
19
#endif
20
21
#if defined(ENABLE_SM) && defined(ENABLE_OPENPACE)
22
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "asn1.h"
27
#include "common/compat_strlcat.h"
28
#include "internal.h"
29
#include "opensc.h"
30
#include "sm/sm-eac.h"
31
32
static const struct sc_card_operations *iso_ops = NULL;
33
static struct sc_card_operations lteid_ops;
34
35
static struct sc_card_driver lteid_drv = {
36
    "Lithuanian eID card (asmens tapatybÄ—s kortelÄ—)", "lteid",
37
    &lteid_ops, NULL, 0, NULL};
38
39
0
#define DRVDATA(card)  ((struct lteid_drv_data *)((card)->drv_data))
40
0
#define LTEID_CAN_LENGTH 6
41
42
struct lteid_drv_data {
43
  unsigned char pace;
44
  unsigned char pace_pin_ref;
45
  unsigned char can[LTEID_CAN_LENGTH];
46
  unsigned char can_from_cache;
47
};
48
49
void
50
lteid_get_can_cache_path(sc_card_t *card, char *buf, size_t buf_len)
51
0
{
52
0
  sc_get_cache_dir(card->ctx, buf, buf_len);
53
54
#ifdef _WIN32
55
  strlcat(buf, "\\", buf_len);
56
#else
57
0
  strlcat(buf, "/", buf_len);
58
0
#endif
59
60
0
  strlcat(buf, "lteid_can", buf_len);
61
0
}
62
63
static int
64
lteid_get_cached_can(sc_card_t *card, unsigned char *can)
65
0
{
66
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
67
0
  char path[PATH_MAX];
68
69
0
  lteid_get_can_cache_path(card, path, sizeof(path));
70
71
0
  FILE *fd = fopen(path, "r");
72
73
0
  if (!fd) {
74
0
    LOG_FUNC_RETURN(card->ctx, 0);
75
0
  }
76
77
0
  if (LTEID_CAN_LENGTH != fread(can, 1, LTEID_CAN_LENGTH, fd)) {
78
0
    LOG_FUNC_RETURN(card->ctx, 0);
79
0
  }
80
81
0
  fclose(fd);
82
83
0
  LOG_FUNC_RETURN(card->ctx, 1);
84
0
}
85
86
static int
87
lteid_cache_can(sc_card_t *card, const char *can)
88
0
{
89
0
  int rv;
90
0
  char path[PATH_MAX];
91
92
0
  lteid_get_can_cache_path(card, path, sizeof(path));
93
94
0
  FILE *fd = fopen(path, "w");
95
96
0
  if (!fd && errno == ENOENT) {
97
0
    if ((rv = sc_make_cache_dir(card->ctx)) < 0)
98
0
      return rv;
99
100
0
    fd = fopen(path, "w");
101
0
  }
102
103
0
  if (!fd) {
104
0
    return SC_ERROR_INTERNAL;
105
0
  }
106
107
0
  fwrite(can, 1, 6, fd);
108
0
  fclose(fd);
109
110
0
  return SC_SUCCESS;
111
0
}
112
113
static int
114
lteid_clear_cached_can(sc_card_t *card)
115
0
{
116
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
117
118
0
  char path[PATH_MAX];
119
120
0
  lteid_get_can_cache_path(card, path, sizeof(path));
121
122
0
  if (!unlink(path)) {
123
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
124
0
  }
125
126
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
127
0
}
128
129
static int
130
lteid_get_can(sc_card_t *card, struct establish_pace_channel_input *pace_input)
131
0
{
132
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
133
0
  struct lteid_drv_data *drv_data = DRVDATA(card);
134
0
  int got_can = 0;
135
136
0
  drv_data->can_from_cache = 0;
137
138
  // Try env variables first
139
0
  const char *can_from_env = getenv("LTEID_CAN");
140
0
  if (can_from_env && strlen(can_from_env) == LTEID_CAN_LENGTH) {
141
0
    got_can = 1;
142
0
    memcpy(drv_data->can, can_from_env, LTEID_CAN_LENGTH);
143
0
  }
144
145
  // Try getting one from the cache
146
0
  if (!got_can && lteid_get_cached_can(card, drv_data->can)) {
147
0
    got_can = 1;
148
0
    drv_data->can_from_cache = 1;
149
0
  }
150
151
  // Finally see if there is a default in configuration
152
0
  if (!got_can) {
153
0
    const char *can_from_config = NULL;
154
155
0
    for (size_t i = 0; card->ctx->conf_blocks[i]; ++i) {
156
0
      scconf_block **blocks = scconf_find_blocks(card->ctx->conf, card->ctx->conf_blocks[i], "card_driver", "lteid");
157
0
      if (!blocks)
158
0
        continue;
159
0
      for (size_t j = 0; blocks[j]; ++j)
160
0
        if ((can_from_config = scconf_get_str(blocks[j], "can", NULL)))
161
0
          break;
162
0
      free(blocks);
163
0
    }
164
165
0
    if (can_from_config && strlen(can_from_config) == LTEID_CAN_LENGTH) {
166
0
      got_can = 1;
167
0
      memcpy(drv_data->can, can_from_config, LTEID_CAN_LENGTH);
168
0
    }
169
0
  }
170
171
0
  if (!got_can) {
172
0
    sc_log(card->ctx, "Missing or invalid CAN. 6 digits required.");
173
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN);
174
0
  }
175
176
0
  pace_input->pin_id = PACE_PIN_ID_CAN;
177
0
  pace_input->pin = drv_data->can;
178
0
  pace_input->pin_length = LTEID_CAN_LENGTH;
179
180
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
181
0
}
182
183
static int
184
lteid_perform_pace(struct sc_card *card, const int ref, const unsigned char *pin, size_t pinlen, int *tries_left)
185
0
{
186
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
187
188
0
  struct lteid_drv_data *drv_data = DRVDATA(card);
189
0
  struct establish_pace_channel_input pace_input = {0};
190
0
  struct establish_pace_channel_output pace_output = {0};
191
192
0
  if (drv_data->pace) {
193
0
    sc_sm_stop(card);
194
0
    drv_data->pace = 0;
195
0
    drv_data->pace_pin_ref = 0;
196
0
  }
197
198
0
  if (ref == PACE_PIN_ID_CAN && !pin) {
199
0
    if (SC_SUCCESS != lteid_get_can(card, &pace_input)) {
200
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN);
201
0
    }
202
0
  } else {
203
0
    pace_input.pin_id = ref;
204
0
    pace_input.pin = pin;
205
0
    pace_input.pin_length = pinlen;
206
0
  }
207
208
0
  int rv = perform_pace(card, pace_input, &pace_output, EAC_TR_VERSION_2_02);
209
0
  if (rv != SC_SUCCESS) {
210
0
    sc_log(card->ctx, "Error performing PACE for pin ref 0x%02x.", ref);
211
212
0
    drv_data->pace = 0;
213
0
    drv_data->pace_pin_ref = 0;
214
215
    // Special case after entering incorrect PACE PIN twice. Card locks with 1 PIN attempt remaining.
216
0
    if (ref == PACE_PIN_ID_PIN && rv == SC_ERROR_NO_CARD_SUPPORT) {
217
0
      rv = SC_ERROR_AUTH_METHOD_BLOCKED;
218
0
    }
219
220
    // When CAN code authentication fails and CAN code comes from cache - clear it.
221
    // We don't want to make multiple attempts if code is wrong. User should run lteid-tool
222
    // again to set up the card.
223
0
    if (ref == PACE_PIN_ID_CAN && drv_data->can_from_cache && rv != SC_ERROR_INTERNAL) {
224
0
      if (lteid_clear_cached_can(card)) {
225
0
        drv_data->can_from_cache = 0;
226
0
      }
227
0
    }
228
229
0
    LOG_FUNC_RETURN(card->ctx, rv);
230
0
  }
231
232
  // If caller provided CAN is valid - cache it.
233
0
  if (ref == PACE_PIN_ID_CAN && pin) {
234
0
    lteid_cache_can(card, (const char *)pin);
235
0
  }
236
237
  // Track PACE status
238
0
  drv_data->pace = 1;
239
0
  drv_data->pace_pin_ref = ref;
240
241
0
  free(pace_output.ef_cardaccess);
242
0
  free(pace_output.recent_car);
243
0
  free(pace_output.previous_car);
244
0
  free(pace_output.id_icc);
245
0
  free(pace_output.id_pcd);
246
247
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
248
0
}
249
250
static int
251
lteid_unlock(sc_card_t *card)
252
0
{
253
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
254
255
0
  if (SC_SUCCESS != lteid_perform_pace(card, PACE_PIN_ID_CAN, NULL, 0, NULL)) {
256
0
    sc_log(card->ctx, "Unlock with CAN code failed. No CAN found in environment, opensc.conf nor cache.");
257
0
  }
258
259
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
260
0
}
261
262
static int
263
lteid_init(sc_card_t *card)
264
0
{
265
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
266
0
  int rv;
267
268
0
  struct lteid_drv_data *drv_data = calloc(1, sizeof(struct lteid_drv_data));
269
270
0
  if (drv_data == NULL)
271
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
272
273
0
  drv_data->pace = 0;
274
0
  drv_data->pace_pin_ref = 0;
275
0
  card->drv_data = drv_data;
276
277
0
  memset(&card->sm_ctx, 0, sizeof card->sm_ctx);
278
279
0
  card->max_send_size = 65535;
280
0
  card->max_recv_size = 65535;
281
0
  card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO | SC_CARD_CAP_APDU_EXT;
282
283
0
  _sc_card_add_ec_alg(card, 384, SC_ALGORITHM_ECDSA_HASH_NONE | SC_ALGORITHM_ECDSA_RAW, 0, NULL);
284
285
0
  rv = sc_enum_apps(card);
286
0
  LOG_TEST_RET(card->ctx, rv, "Enumerate apps failed");
287
288
0
  rv = lteid_unlock(card);
289
0
  LOG_TEST_RET(card->ctx, rv, "Unlock card failed");
290
291
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
292
0
}
293
294
static int
295
lteid_finish(sc_card_t *card)
296
0
{
297
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
298
299
0
  sc_sm_stop(card);
300
301
0
  free(card->drv_data);
302
0
  card->drv_data = NULL;
303
304
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
305
0
}
306
307
static int
308
lteid_logout(sc_card_t *card)
309
0
{
310
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
311
312
0
  sc_sm_stop(card);
313
314
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
315
0
}
316
317
static int
318
lteid_pin_cmd_verify(struct sc_card *card, struct sc_pin_cmd_data *data)
319
0
{
320
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
321
322
0
  int rv;
323
324
  // Authentication key refers to PACE PIN -> 0x03
325
  // Meanwhile, signing key refers to PIN.QES -> 0x81. This pin is verifiable via regular iso7816 cmd verify call.
326
0
  switch (data->pin_reference) {
327
0
  case PACE_PIN_ID_CAN:
328
0
  case PACE_PIN_ID_PIN:
329
0
  case PACE_PIN_ID_PUK:
330
0
    rv = lteid_perform_pace(card, data->pin_reference, data->pin1.data, data->pin1.len, &data->pin1.tries_left);
331
0
    break;
332
0
  default:
333
0
    rv = iso_ops->pin_cmd(card, data);
334
0
    break;
335
0
  }
336
337
0
  LOG_FUNC_RETURN(card->ctx, rv);
338
0
}
339
340
static int
341
lteid_pin_cmd_get_info(struct sc_card *card, struct sc_pin_cmd_data *data)
342
0
{
343
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
344
345
0
  struct lteid_drv_data *drv_data = DRVDATA(card);
346
0
  int rv;
347
348
  // PACE CAN code info: as far as we know there's no limit to CAN verification attempts
349
0
  if (data->pin_reference == PACE_PIN_ID_CAN) {
350
0
    data->pin1.max_tries = -1;
351
0
    data->pin1.tries_left = -1;
352
353
0
    LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
354
0
  }
355
356
  // PACE PIN and PUK codes: max and remaining attempts are stored in ACE3 and ACE4 files.
357
0
  if (data->pin_reference == PACE_PIN_ID_PIN || data->pin_reference == PACE_PIN_ID_PUK) {
358
0
    struct sc_apdu apdu;
359
0
    unsigned char buf[0xbe] = {0};
360
0
    u8 id[] = {0xac, 0x00};
361
0
    size_t taglen = 0;
362
363
0
    switch (data->pin_reference) {
364
0
    case PACE_PIN_ID_PIN:
365
0
      id[1] = 0xe3;
366
0
      break;
367
0
    case PACE_PIN_ID_PUK:
368
0
      id[1] = 0xe4;
369
0
      break;
370
0
    default:
371
0
      break;
372
0
    }
373
374
0
    sc_format_apdu_ex(&apdu, 0x00, 0xa4, 0x00, 0x04, id, sizeof(id), buf, sizeof(buf));
375
376
0
    rv = sc_transmit_apdu(card, &apdu);
377
0
    LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
378
379
0
    const u8 *tag = sc_asn1_find_tag(card->ctx, buf, apdu.resplen, 0x62, &taglen);
380
0
    tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0xa5, &taglen);
381
0
    tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0xa2, &taglen);
382
0
    tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0xa3, &taglen);
383
0
    tag = sc_asn1_find_tag(card->ctx, tag, taglen, 0x82, &taglen);
384
385
0
    if (tag && taglen == 2) {
386
0
      data->pin1.tries_left = tag[0];
387
0
      data->pin1.max_tries = tag[1];
388
0
    } else {
389
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND);
390
0
    }
391
392
0
    if (drv_data->pace_pin_ref == data->pin_reference) {
393
0
      data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN;
394
0
    } else {
395
0
      data->pin1.logged_in = SC_PIN_STATE_LOGGED_OUT;
396
0
    }
397
398
0
    LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
399
0
  }
400
401
  // PIN.QES is a regular iso7816 pin
402
0
  if (data->pin_reference == 0x81) {
403
0
    rv = iso_ops->pin_cmd(card, data);
404
0
    LOG_FUNC_RETURN(card->ctx, rv);
405
0
  }
406
407
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND);
408
0
}
409
410
static int
411
lteid_pin_cmd_unblock(struct sc_card *card, struct sc_pin_cmd_data *data)
412
0
{
413
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
414
415
0
  int rv;
416
417
  // PACE PIN for unblocking command is known as pin ref 0x07
418
0
  if (data->pin_reference == PACE_PIN_ID_PIN) {
419
0
    struct sc_pin_cmd_data with_changed_pin_ref = *data;
420
421
0
    with_changed_pin_ref.pin_reference = 0x07;
422
0
    rv = iso_ops->pin_cmd(card, &with_changed_pin_ref);
423
0
    LOG_FUNC_RETURN(card->ctx, rv);
424
0
  }
425
426
  // PIN.QES is a regular iso7816 pin
427
0
  if (data->pin_reference == 0x81) {
428
0
    rv = iso_ops->pin_cmd(card, data);
429
0
    LOG_FUNC_RETURN(card->ctx, rv);
430
0
  }
431
432
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND);
433
0
}
434
435
static int
436
lteid_pin_cmd_change(struct sc_card *card, struct sc_pin_cmd_data *data)
437
0
{
438
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
439
440
0
  int rv;
441
442
  // PACE PIN for unblocking command is known as pin ref 0x07
443
0
  if (data->pin_reference == PACE_PIN_ID_PIN) {
444
0
    struct sc_pin_cmd_data with_changed_pin_ref = *data;
445
446
0
    with_changed_pin_ref.pin_reference = 0x07;
447
0
    rv = iso_ops->pin_cmd(card, &with_changed_pin_ref);
448
0
    LOG_FUNC_RETURN(card->ctx, rv);
449
0
  }
450
451
  // PIN.QES is a regular iso7816 pin
452
0
  if (data->pin_reference == 0x81) {
453
0
    rv = iso_ops->pin_cmd(card, data);
454
0
    LOG_FUNC_RETURN(card->ctx, rv);
455
0
  }
456
457
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_OBJECT_NOT_FOUND);
458
0
}
459
460
static int
461
lteid_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data)
462
0
{
463
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
464
465
0
  int rv;
466
467
0
  switch (data->cmd) {
468
0
  case SC_PIN_CMD_VERIFY:
469
0
    rv = lteid_pin_cmd_verify(card, data);
470
0
    break;
471
0
  case SC_PIN_CMD_GET_INFO:
472
0
    rv = lteid_pin_cmd_get_info(card, data);
473
0
    break;
474
0
  case SC_PIN_CMD_UNBLOCK:
475
0
    rv = lteid_pin_cmd_unblock(card, data);
476
0
    break;
477
0
  case SC_PIN_CMD_CHANGE:
478
0
    rv = lteid_pin_cmd_change(card, data);
479
0
    break;
480
0
  default:
481
0
    rv = SC_ERROR_NOT_SUPPORTED;
482
0
    break;
483
0
  }
484
485
0
  LOG_FUNC_RETURN(card->ctx, rv);
486
0
}
487
488
static int
489
lteid_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num)
490
0
{
491
0
  LOG_FUNC_CALLED(card->ctx);
492
493
0
  struct sc_apdu apdu;
494
0
  int rv;
495
496
0
  if (env == NULL || env->key_ref_len != 1)
497
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
498
499
0
  sc_log(card->ctx, "algo: %lu operation: %d keyref: %d", env->algorithm, env->operation, env->key_ref[0]);
500
501
0
  if (env->algorithm != SC_ALGORITHM_EC || env->operation != SC_SEC_OPERATION_SIGN)
502
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
503
504
0
  const u8 data[] = {0x84, 0x01, env->key_ref[0]};
505
0
  sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x41, 0xB6, data, sizeof(data), NULL, 0);
506
507
0
  rv = sc_transmit_apdu(card, &apdu);
508
0
  LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
509
510
0
  rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
511
0
  LOG_TEST_RET(card->ctx, rv, "SET SECURITY ENV failed");
512
513
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
514
0
}
515
516
static int
517
lteid_compute_signature(struct sc_card *card, const u8 *data, size_t data_len, u8 *out, size_t outlen)
518
0
{
519
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
520
521
  // Usually this is called with 104 bytes buffer. But we expect card to return 96 byte hash.
522
0
  if (outlen < 96)
523
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL);
524
525
0
  memset(out, 0, outlen);
526
527
0
  const int rv = iso_ops->compute_signature(card, data, data_len, out, 96);
528
529
0
  LOG_FUNC_RETURN(card->ctx, rv);
530
0
}
531
532
static int
533
lteid_process_fci(struct sc_card *card, struct sc_file *file, const u8 *buf, size_t buflen)
534
0
{
535
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
536
537
0
  int rv = iso_ops->process_fci(card, file, buf, buflen);
538
539
0
  if (rv != SC_SUCCESS) {
540
0
    LOG_FUNC_RETURN(card->ctx, rv);
541
0
  }
542
543
  // Card reports most of the file size as 0, even if they're not empty.
544
  // This confuses PKCS#15 loader, and it fails to load/init keys/certs/pins/etc.
545
  // As a quick workaround - lets report size to be something large enough to fit any object.
546
0
  if (file->size == 0) {
547
0
    file->size = 2048;
548
0
  }
549
550
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
551
0
}
552
553
struct sc_card_driver *
554
sc_get_lteid_driver(void)
555
13.3k
{
556
13.3k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
557
558
13.3k
  if (iso_ops == NULL)
559
1
    iso_ops = iso_drv->ops;
560
561
13.3k
  lteid_ops = *iso_ops;
562
13.3k
  lteid_ops.init = lteid_init;
563
13.3k
  lteid_ops.finish = lteid_finish;
564
13.3k
  lteid_ops.set_security_env = lteid_set_security_env;
565
13.3k
  lteid_ops.compute_signature = lteid_compute_signature;
566
13.3k
  lteid_ops.pin_cmd = lteid_pin_cmd;
567
13.3k
  lteid_ops.logout = lteid_logout;
568
13.3k
  lteid_ops.process_fci = lteid_process_fci;
569
570
13.3k
  return &lteid_drv;
571
13.3k
}
572
573
#else
574
575
#include "opensc.h"
576
577
struct sc_card_driver *
578
sc_get_lteid_driver(void)
579
{
580
  return NULL;
581
}
582
583
#endif