Coverage Report

Created: 2025-07-11 06:59

/src/opensc/src/libopensc/card-nqApplet.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Support for the JCOP4 Cards with NQ-Applet
3
 *
4
 * Copyright (C) 2021 jozsefd <jozsef.dojcsak@gmail.com>
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
#include <stdlib.h>
22
#include <string.h>
23
24
#include "opensc.h"
25
#include "asn1.h"
26
#include "cardctl.h"
27
#include "internal.h"
28
#include "log.h"
29
30
0
#define APPLET_VERSION_LEN  2
31
0
#define APPLET_MEMTYPE_LEN  1
32
0
#define APPLET_SERIALNR_LEN 8
33
34
/* card constants */
35
static const struct sc_atr_table nqapplet_atrs[] = {
36
  {"3b:d5:18:ff:81:91:fe:1f:c3:80:73:c8:21:10:0a", NULL, NULL, SC_CARD_TYPE_NQ_APPLET, 0, NULL},
37
  {NULL, NULL, NULL, 0, 0, NULL}};
38
39
static const u8 nqapplet_aid[] = {0xd2, 0x76, 0x00, 0x01, 0x80, 0xBA, 0x01, 0x44, 0x02, 0x01, 0x00};
40
41
static struct sc_card_operations nqapplet_operations;
42
static struct sc_card_operations *iso_operations = NULL;
43
44
0
#define KEY_REFERENCE_NO_KEY   0x00
45
0
#define KEY_REFERENCE_AUTH_KEY 0x01
46
0
#define KEY_REFERENCE_ENCR_KEY 0x02
47
48
struct nqapplet_driver_data {
49
  u8 version_minor;
50
  u8 version_major;
51
  u8 key_reference;
52
};
53
typedef struct nqapplet_driver_data *nqapplet_driver_data_ptr;
54
55
static struct sc_card_driver nqapplet_driver = {
56
  "NQ-Applet",          // name
57
  "nqapplet",           // short name
58
  &nqapplet_operations, // operations
59
  NULL,                 // atr table
60
  0,                    // nr of atr
61
  NULL                  // dll?
62
};
63
64
static const struct sc_card_error nqapplet_errors[] = {
65
  {0x6700, SC_ERROR_WRONG_LENGTH, "Invalid LC or LE"},
66
  {0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied"}, // TODO MK/DK??
67
  {0x6985, SC_ERROR_NOT_ALLOWED, "Invalid PIN or key"},
68
  {0x6986, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied"},
69
  {0x6A80, SC_ERROR_INVALID_ARGUMENTS, "Invalid parameters"},
70
  {0x6A82, SC_ERROR_OBJECT_NOT_FOUND, "Data object not found"},
71
  {0x6A84, SC_ERROR_NOT_ENOUGH_MEMORY, "Not enough memory"},
72
  {0x6A86, SC_ERROR_INCORRECT_PARAMETERS, "Invalid P1 or P2"},
73
  {0x6A88, SC_ERROR_INVALID_ARGUMENTS, "Wrong key ID"},
74
  {0x6D00, SC_ERROR_FILE_NOT_FOUND, "Applet not found"}};
75
76
/* convenience functions */
77
78
static int init_driver_data(sc_card_t *card, u8 version_major, u8 version_minor)
79
0
{
80
0
  nqapplet_driver_data_ptr data = calloc(1, sizeof(struct nqapplet_driver_data));
81
0
  if (data == NULL) {
82
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
83
0
  }
84
85
0
  data->version_major = version_major;
86
0
  data->version_minor = version_minor;
87
0
  data->key_reference = KEY_REFERENCE_NO_KEY;
88
0
  card->drv_data = (void *)data;
89
0
  return SC_SUCCESS;
90
0
}
91
92
/**
93
 * SELECT NQ-Applet, on success it returns the applet version and card serial nr.
94
 *
95
 * @param[in]       card
96
 * @param[out,opt]  version_major Version major of the applet
97
 * @param[out,opt]  version_minor Version minor of the applet
98
 * @param[out,opt]  serial_nr   Buffer to receive serial number octets
99
 * @param[in]     cb_serial_nr  Size of buffer in octets
100
 * @param[out,opt]  serial_nr_len The actual number of octet copied into serial_nr buffer
101
 *
102
 * @return SC_SUCCESS: The applet is present and selected.
103
 *
104
 */
105
static int select_nqapplet(sc_card_t *card, u8 *version_major, u8 *version_minor, u8 *serial_nr,
106
                           size_t cb_serial_nr, size_t *serial_nr_len)
107
0
{
108
0
  int rv;
109
0
  sc_context_t *ctx = card->ctx;
110
0
  u8 buffer[APPLET_VERSION_LEN + APPLET_MEMTYPE_LEN + APPLET_SERIALNR_LEN + 2];
111
0
  size_t cb_buffer = sizeof(buffer);
112
0
  size_t cb_aid = sizeof(nqapplet_aid);
113
114
0
  LOG_FUNC_CALLED(card->ctx);
115
116
0
  rv = iso7816_select_aid(card, nqapplet_aid, cb_aid, buffer, &cb_buffer);
117
0
  LOG_TEST_RET(card->ctx, rv, "Failed to select NQ-Applet.");
118
119
0
  if (cb_buffer < APPLET_VERSION_LEN + APPLET_MEMTYPE_LEN + APPLET_SERIALNR_LEN) {
120
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_WRONG_LENGTH);
121
0
  }
122
123
0
  if (version_major != NULL) {
124
0
    *version_major = buffer[0];
125
0
  }
126
0
  if (version_minor != NULL) {
127
0
    *version_minor = buffer[1];
128
0
  }
129
0
  if (serial_nr != NULL && cb_serial_nr > 0 && serial_nr_len != NULL) {
130
0
    size_t cb = MIN(APPLET_SERIALNR_LEN, cb_serial_nr);
131
0
    memcpy(serial_nr, buffer + 3, cb);
132
0
    *serial_nr_len = cb;
133
0
  }
134
135
0
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
136
0
}
137
138
/* driver operations API */
139
static int nqapplet_match_card(struct sc_card *card)
140
2.28k
{
141
2.28k
  int rv = _sc_match_atr(card, nqapplet_atrs, &card->type);
142
2.28k
  return (rv >= 0);
143
2.28k
}
144
145
static int nqapplet_init(struct sc_card *card)
146
0
{
147
0
  u8 version_major;
148
0
  u8 version_minor;
149
0
  u8 serial_nr[APPLET_SERIALNR_LEN];
150
0
  size_t cb_serial_nr = sizeof(serial_nr);
151
0
  unsigned long rsa_flags = 0;
152
153
0
  LOG_FUNC_CALLED(card->ctx);
154
0
  int rv =
155
0
    select_nqapplet(card, &version_major, &version_minor, serial_nr, cb_serial_nr, &cb_serial_nr);
156
0
  if (rv != SC_SUCCESS) {
157
0
    LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "Cannot select NQ-Applet.");
158
0
  }
159
160
0
  rv = init_driver_data(card, version_major, version_minor);
161
0
  LOG_TEST_RET(card->ctx, rv, "Failed to initialize driver data.");
162
163
0
  card->max_send_size = 255;
164
0
  card->max_recv_size = 256;
165
0
  card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
166
0
  rsa_flags |= SC_ALGORITHM_RSA_RAW;
167
0
  _sc_card_add_rsa_alg(card, 3072, rsa_flags, 0);
168
169
0
  card->serialnr.len = MIN(sizeof(card->serialnr.value), cb_serial_nr);
170
0
  memcpy(card->serialnr.value, serial_nr, card->serialnr.len);
171
172
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
173
0
}
174
175
static int nqapplet_finish(struct sc_card *card)
176
0
{
177
0
  nqapplet_driver_data_ptr data = (nqapplet_driver_data_ptr)card->drv_data;
178
179
0
  LOG_FUNC_CALLED(card->ctx);
180
0
  if (data != NULL) {
181
0
    free(data);
182
0
    card->drv_data = NULL;
183
0
  }
184
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
185
0
}
186
187
static int
188
nqapplet_get_response(struct sc_card *card, size_t *cb_resp, u8 *resp)
189
0
{
190
0
  struct sc_apdu apdu = {0};
191
0
  int rv;
192
0
  size_t resplen;
193
194
0
  LOG_FUNC_CALLED(card->ctx);
195
0
  resplen = MIN(sc_get_max_recv_size(card), *cb_resp);
196
197
0
  sc_format_apdu_ex(&apdu, 0x80, 0xC0, 0x00, 0x00, NULL, 0, resp, resplen);
198
0
  apdu.flags |= SC_APDU_FLAGS_NO_GET_RESP;
199
200
0
  rv = sc_transmit_apdu(card, &apdu);
201
0
  LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
202
203
0
  *cb_resp = apdu.resplen;
204
205
0
  if (apdu.resplen == 0) {
206
0
    LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
207
0
  }
208
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
209
0
    rv = SC_SUCCESS;
210
0
  } else if (apdu.sw1 == 0x61) {
211
0
    rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
212
0
  } else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x82) {
213
0
    rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
214
0
  }
215
216
0
  LOG_FUNC_RETURN(card->ctx, rv);
217
0
}
218
219
static int nqapplet_get_challenge(struct sc_card *card, u8 *buf, size_t count)
220
0
{
221
0
  int r;
222
0
  struct sc_apdu apdu;
223
224
0
  LOG_FUNC_CALLED(card->ctx);
225
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x00);
226
0
  apdu.le = count;
227
0
  apdu.resp = buf;
228
0
  apdu.resplen = count;
229
230
0
  r = sc_transmit_apdu(card, &apdu);
231
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
232
233
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
234
0
  LOG_TEST_RET(card->ctx, r, "GET CHALLENGE failed");
235
236
0
  if (count < apdu.resplen) {
237
0
    return (int)count;
238
0
  }
239
240
0
  return (int)apdu.resplen;
241
0
}
242
243
static int nqapplet_logout(struct sc_card *card)
244
0
{
245
0
  LOG_FUNC_CALLED(card->ctx);
246
  /* selecting NQ-Applet again will reset the applet status and unauthorize PINs */
247
0
  int rv = select_nqapplet(card, NULL, NULL, NULL, 0, NULL);
248
0
  if (rv != SC_SUCCESS) {
249
0
    LOG_TEST_RET(card->ctx, rv, "Failed to logout");
250
0
  }
251
252
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
253
0
}
254
255
int nqapplet_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num)
256
0
{
257
  /* Note: the NQ-Applet does not have APDU for SET SECURITY ENV,
258
  this function checks the intended parameters and sets card_data.key_reference */
259
0
  nqapplet_driver_data_ptr data;
260
0
  u8 key_reference = KEY_REFERENCE_NO_KEY;
261
262
0
  LOG_FUNC_CALLED(card->ctx);
263
264
0
  data = (nqapplet_driver_data_ptr)card->drv_data;
265
0
  data->key_reference = KEY_REFERENCE_NO_KEY;
266
267
0
  if (se_num != 0) {
268
0
    LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED,
269
0
                 "Storing of security environment is not supported");
270
0
  }
271
0
  if (env->key_ref_len == 1) {
272
0
    key_reference = env->key_ref[0];
273
0
  }
274
275
0
  switch (env->operation) {
276
0
  case SC_SEC_OPERATION_DECIPHER:
277
0
    if (key_reference != KEY_REFERENCE_AUTH_KEY && key_reference != KEY_REFERENCE_ENCR_KEY) {
278
0
      LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
279
0
                   "Decipher operation is only supported with AUTH and ENCR keys.");
280
0
    }
281
0
    data->key_reference = key_reference;
282
0
    break;
283
0
  case SC_SEC_OPERATION_SIGN:
284
0
    if (key_reference != KEY_REFERENCE_AUTH_KEY) {
285
0
      LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
286
0
                   "Sign operation is only supported with AUTH key.");
287
0
    }
288
0
    data->key_reference = key_reference;
289
0
    break;
290
0
  default:
291
0
    LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported sec. operation.");
292
0
  }
293
294
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
295
0
}
296
297
static int nqapplet_decipher(struct sc_card *card, const u8 *data, size_t cb_data, u8 *out, size_t outlen)
298
0
{
299
0
  int rv;
300
0
  struct sc_apdu apdu;
301
0
  u8 p1 = 0x80;
302
0
  u8 p2 = 0x86;
303
0
  nqapplet_driver_data_ptr drv_data;
304
305
0
  LOG_FUNC_CALLED(card->ctx);
306
307
0
  drv_data = (nqapplet_driver_data_ptr)card->drv_data;
308
309
0
  if (drv_data->key_reference == KEY_REFERENCE_AUTH_KEY) {
310
0
    p1 = 0x9E;
311
0
    p2 = 0x9A;
312
0
  } else if (drv_data->key_reference != KEY_REFERENCE_ENCR_KEY) {
313
0
    LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
314
0
                 "Decipher operation is only supported with AUTH and ENCR keys.");
315
0
  }
316
317
  /* the applet supports only 3072 RAW RSA, input buffer size must be 384 octets,
318
  output buffer size must be at least 384 octets */
319
0
  sc_format_apdu_ex(&apdu, 0x80, 0x2A, p1, p2, data, cb_data, out, outlen);
320
0
  apdu.le = 256;
321
0
  apdu.flags |= SC_APDU_FLAGS_CHAINING;
322
0
  rv = sc_transmit_apdu(card, &apdu);
323
0
  LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
324
325
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
326
0
    rv = (int)apdu.resplen;
327
0
  } else if (apdu.sw1 == 0x61) {
328
0
    rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
329
0
  } else {
330
0
    rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
331
0
  }
332
333
0
  LOG_FUNC_RETURN(card->ctx, rv);
334
0
}
335
336
static int nqapplet_compute_signature(struct sc_card *card, const u8 *data, size_t cb_data, u8 *out,
337
                                      size_t outlen)
338
0
{
339
0
  int rv;
340
0
  struct sc_apdu apdu;
341
0
  nqapplet_driver_data_ptr drv_data;
342
343
0
  LOG_FUNC_CALLED(card->ctx);
344
0
  drv_data = (nqapplet_driver_data_ptr)card->drv_data;
345
346
0
  if (drv_data->key_reference != KEY_REFERENCE_AUTH_KEY) {
347
0
    LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
348
0
                 "Sign operation is only supported with AUTH key.");
349
0
  }
350
351
  /* the applet supports only 3072 RAW RSA, input buffer size must be 384 octets,
352
  output buffer size must be at least 384 octets */
353
0
  sc_format_apdu_ex(&apdu, 0x80, 0x2A, 0x9E, 0x9A, data, cb_data, out, outlen);
354
0
  apdu.le = 256;
355
0
  apdu.flags |= SC_APDU_FLAGS_CHAINING;
356
0
  rv = sc_transmit_apdu(card, &apdu);
357
0
  LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
358
359
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
360
0
    rv = (int)apdu.resplen;
361
0
  } else if (apdu.sw1 == 0x61) {
362
0
    rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
363
0
  } else {
364
0
    rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
365
0
  }
366
367
0
  LOG_FUNC_RETURN(card->ctx, rv);
368
0
}
369
370
static int nqapplet_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2)
371
0
{
372
0
  const int nqapplet_error_count = sizeof(nqapplet_errors) / sizeof(struct sc_card_error);
373
0
  int i;
374
375
0
  LOG_FUNC_CALLED(card->ctx);
376
0
  sc_log(card->ctx, "Checking sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
377
378
0
  for (i = 0; i < nqapplet_error_count; i++) {
379
0
    if (nqapplet_errors[i].SWs == ((sw1 << 8) | sw2)) {
380
0
      LOG_TEST_RET(card->ctx, nqapplet_errors[i].errorno, nqapplet_errors[i].errorstr);
381
0
    }
382
0
  }
383
384
0
  return iso_operations->check_sw(card, sw1, sw2);
385
0
}
386
387
static int nqapplet_get_data(struct sc_card *card, unsigned int id, u8 *resp, size_t cb_resp)
388
0
{
389
0
  struct sc_apdu apdu;
390
0
  int rv;
391
392
0
  LOG_FUNC_CALLED(card->ctx);
393
394
0
  sc_format_apdu_ex(&apdu, 0x80, 0xB0, 0x00, (u8)id, NULL, 0, resp, cb_resp);
395
0
  apdu.le = 256;
396
397
0
  rv = sc_transmit_apdu(card, &apdu);
398
0
  LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
399
400
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
401
0
    rv = (int)apdu.resplen;
402
0
  } else if (apdu.sw1 == 0x61) {
403
0
    rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
404
0
  } else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x82) {
405
0
    rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
406
0
  }
407
408
0
  LOG_FUNC_RETURN(card->ctx, rv);
409
0
}
410
411
static int nqapplet_select_file(struct sc_card *card, const struct sc_path *in_path,
412
                                struct sc_file **file_out)
413
0
{
414
0
  LOG_FUNC_CALLED(card->ctx);
415
416
  /* the applet does not support SELECT EF/DF except for SELECT APPLET.
417
  In order to enable opensc-explorer add support for virtually selecting MF only */
418
0
  if (in_path->type == SC_PATH_TYPE_PATH && in_path->len == 2 &&
419
0
      memcmp(in_path->value, "\x3F\x00", 2) == 0) {
420
0
    if (file_out != NULL) {
421
0
      struct sc_file *file = sc_file_new();
422
0
      if (file == NULL) {
423
0
        LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
424
0
      }
425
0
      file->path = *in_path;
426
0
      *file_out = file;
427
0
      LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
428
0
    }
429
0
  }
430
  // TODO allow selecting Applet AID
431
432
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
433
0
}
434
435
static int nqapplet_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
436
0
{
437
0
  switch (cmd) {
438
0
  case SC_CARDCTL_GET_SERIALNR:
439
0
    if (card->serialnr.len) {
440
0
      sc_serial_number_t *serial = (sc_serial_number_t *)ptr;
441
0
      memcpy(serial->value, card->serialnr.value, card->serialnr.len);
442
0
      serial->len = card->serialnr.len;
443
0
      return SC_SUCCESS;
444
0
    }
445
0
    break;
446
0
  }
447
0
  return SC_ERROR_NOT_SUPPORTED;
448
0
}
449
450
struct sc_card_driver *sc_get_nqApplet_driver(void)
451
13.8k
{
452
13.8k
  sc_card_driver_t *iso_driver = sc_get_iso7816_driver();
453
454
13.8k
  if (iso_operations == NULL) {
455
1
    iso_operations = iso_driver->ops;
456
1
  }
457
458
13.8k
  nqapplet_operations = *iso_driver->ops;
459
460
  /* supported operations */
461
13.8k
  nqapplet_operations.match_card = nqapplet_match_card;
462
13.8k
  nqapplet_operations.init = nqapplet_init;
463
13.8k
  nqapplet_operations.finish = nqapplet_finish;
464
13.8k
  nqapplet_operations.get_response = nqapplet_get_response;
465
13.8k
  nqapplet_operations.get_challenge = nqapplet_get_challenge;
466
13.8k
  nqapplet_operations.logout = nqapplet_logout;
467
13.8k
  nqapplet_operations.set_security_env = nqapplet_set_security_env;
468
13.8k
  nqapplet_operations.decipher = nqapplet_decipher;
469
13.8k
  nqapplet_operations.compute_signature = nqapplet_compute_signature;
470
13.8k
  nqapplet_operations.check_sw = nqapplet_check_sw;
471
13.8k
  nqapplet_operations.get_data = nqapplet_get_data;
472
13.8k
  nqapplet_operations.select_file = nqapplet_select_file;
473
13.8k
  nqapplet_operations.card_ctl = nqapplet_card_ctl;
474
475
  /* unsupported operations */
476
13.8k
  nqapplet_operations.read_binary = NULL;
477
13.8k
  nqapplet_operations.write_binary = NULL;
478
13.8k
  nqapplet_operations.update_binary = NULL;
479
13.8k
  nqapplet_operations.erase_binary = NULL;
480
13.8k
  nqapplet_operations.read_record = NULL;
481
13.8k
  nqapplet_operations.write_record = NULL;
482
13.8k
  nqapplet_operations.append_record = NULL;
483
13.8k
  nqapplet_operations.update_record = NULL;
484
485
13.8k
  nqapplet_operations.verify = NULL;
486
13.8k
  nqapplet_operations.restore_security_env = NULL;
487
13.8k
  nqapplet_operations.change_reference_data = NULL;
488
13.8k
  nqapplet_operations.reset_retry_counter = NULL;
489
13.8k
  nqapplet_operations.create_file = NULL;
490
13.8k
  nqapplet_operations.delete_file = NULL;
491
13.8k
  nqapplet_operations.list_files = NULL;
492
13.8k
  nqapplet_operations.process_fci = NULL;
493
13.8k
  nqapplet_operations.construct_fci = NULL;
494
13.8k
  nqapplet_operations.put_data = NULL;
495
13.8k
  nqapplet_operations.delete_record = NULL;
496
13.8k
  nqapplet_operations.read_public_key = NULL;
497
498
  /* let iso driver handle these operations
499
  nqapplet_operations.pin_cmd;
500
  nqapplet_operations.card_reader_lock_obtained;
501
  nqapplet_operations.wrap;
502
  nqapplet_operations.unwrap;
503
  */
504
505
13.8k
  return &nqapplet_driver;
506
13.8k
}