Coverage Report

Created: 2025-07-01 06:08

/src/opensc/src/libopensc/card-belpic.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * card-belpic.c: Support for Belgium EID card
3
 *
4
 * Copyright (C) 2003, Zetes Belgium
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
/*     About the Belpic (Belgian Personal Identity Card) card
22
 *
23
 * The Belpic card is a Cyberflex Java card, so you normally communicate
24
 * with an applet running on the card. In order to support a pkcs15 file
25
 * structure, an  applet (the Belpic applet) has been build that emulates
26
 * this. So the card's behaviour is specific for this Belpic applet, that's
27
 * why a separate driver has been made.
28
 *
29
 * The card contains the citizen's ID data (name, address, photo, ...) and
30
 * her keys and certs. The ID data are in a separate directory on the card and
31
 * are not handled by this software. For the cryptographic data (keys and certs)
32
 * a pkcs#15 structure has been chosen and they can be accessed and used
33
 * by the OpenSC software.
34
 *
35
 * The current situation about the cryptographic data is: there is 1 PIN
36
 * that protects 2 private keys and corresponding certs. Then there is a
37
 * CA cert and the root cert. The first key (Auth Key) can be used for
38
 * authentication, the second one (NonRep Key) for non repudiation purposes
39
 * (so it can be used as an alternative to manual signatures).
40
 *
41
 * There are some special things to note, which all have some consequences:
42
 * (1) the SELECT FILE command doesn't return any FCI (file length, type, ...)
43
 * (2) the NonRep key needs a VERIFY PIN before a signature can be done with it
44
 * (3) pin pad readers had to be supported by a proprietary interface (as at
45
 *     that moment no other solution was known/available/ready)
46
 * The consequences are:
47
 *
48
 * For (1): we let the SELECT FILE command return that the file length is
49
 * a fixed large number and that each file is a transparent working EF
50
 * (except the root dir 3F 00). This way however, there is a problem with the
51
 * sc_read_binary() function that will only stop reading until it receives
52
 * a 0. Therefore, we use the 'next_idx' trick. Or, if that might fail
53
 * and so a READ BINARY past the end of file is done, length 0 is returned
54
 * instead of an error code.
55
 *
56
 * For (2), we decided that a GUI for asking the PIN would be the best
57
 * thing to do (another option would be to make 2 virtual slots but that
58
 * causes other problems and is less user-friendly). A GUI being popped up
59
 * by the pkcs11 lib before each NonRep signature has another important
60
 * security advantage: applications that cache the PIN can't silently do
61
 * a NonRep signature because there will always be the GUI.
62
 *
63
 * For (3), we link dynamically against a pin pad lib (DLL) that implements the
64
 * proprietary API for a specific pin pad. For each pin pad reader (identified
65
 * by it's PC/SC reader name), a pin pad lib corresponds. Some reader/lib
66
 * name pairs are hardcoded, and others can be added in the config file.
67
 * Note that there's also a GUI used in this case: if a signature with the
68
 * NonRep key is done: a dialog box is shown that asks the user to enter
69
 * her PIN on the pin pad reader in order to make a legally valid signature.
70
 *
71
 * Further the (current) Belpic card as quite some limitations:
72
 * no key pair generation or update of data except after establishing a Secure
73
 * Channel or CTV-authentication (which can only be done at the municipalities),
74
 * no encryption. The result is that only a very limited amount of functions
75
 * is/had to be implemented to get the pkcs11 library working.
76
 *
77
 * About the belpic_set_language: the RA-PC software (including the pkcs11 lib)
78
 * in the Brussels' communities should be able to change the language of the GUI
79
 * messages. So the language set by this function takes priority on all other
80
 * language-selection  functionality.
81
 */
82
83
#ifdef HAVE_CONFIG_H
84
#include "config.h"
85
#endif
86
87
#include <stdlib.h>
88
#include <string.h>
89
90
#include "internal.h"
91
#include "log.h"
92
93
/* To be removed */
94
#include <time.h>
95
static long t1, t2, tot_read = 0, tot_dur = 0, dur;
96
97
0
#define BELPIC_VERSION      "1.4"
98
99
/* Most of the #defines here are also present in the pkcs15 files, but
100
 * because this driver has no access to them, it's hardcoded here. If
101
 * other Belpic cards with other 'settings' appear, we'll have to move
102
 * these #defines to the struct belpic_priv_data */
103
0
#define BELPIC_MAX_FILE_SIZE    65535
104
#define BELPIC_PIN_BUF_SIZE   8
105
0
#define BELPIC_MIN_USER_PIN_LEN   4
106
0
#define BELPIC_MAX_USER_PIN_LEN   12
107
0
#define BELPIC_PIN_ENCODING   SC_PIN_ENCODING_GLP
108
0
#define BELPIC_PAD_CHAR     0xFF
109
0
#define BELPIC_KEY_REF_NONREP   0x83
110
111
/* Data in the return value for the GET CARD DATA command:
112
 * All fields are one byte, except when noted otherwise.
113
 *
114
 * See ยง6.9 in
115
 * https://github.com/Fedict/eid-mw/blob/master/doc/sdk/documentation/Public_Belpic_Applet_v1%207_Ref_Manual%20-%20A01.pdf
116
 * for the full documentation on the GET CARD DATA command.
117
 */
118
// Card serial number (16 bytes)
119
#define BELPIC_CARDDATA_OFF_SERIALNUM 0
120
// "Component code"
121
#define BELPIC_CARDDATA_OFF_COMPCODE 16
122
// "OS number"
123
#define BELPIC_CARDDATA_OFF_OSNUM 17
124
// "OS version"
125
#define BELPIC_CARDDATA_OFF_OSVER 18
126
// "Softmask number"
127
#define BELPIC_CARDDATA_OFF_SMNUM 19
128
// "Softmask version"
129
#define BELPIC_CARDDATA_OFF_SMVER 20
130
// Applet version
131
0
#define BELPIC_CARDDATA_OFF_APPLETVERS 21
132
// Global OS version (2 bytes)
133
#define BELPIC_CARDDATA_OFF_GL_OSVE 22
134
// Applet interface version
135
#define BELPIC_CARDDATA_OFF_APPINTVERS 24
136
// PKCS#1 support version
137
#define BELPIC_CARDDATA_OFF_PKCS1 25
138
// Key exchange version
139
#define BELPIC_CARDDATA_OFF_KEYX 26
140
// Applet life cycle (Should always be 0F for released cards, is 07 when not issued yet)
141
#define BELPIC_CARDDATA_OFF_APPLCYCLE 27
142
// Full length of reply
143
#define BELPIC_CARDDATA_RESP_LEN 28
144
145
/* Used for a trick in select file and read binary */
146
static size_t next_idx = (size_t)-1;
147
148
static const struct sc_atr_table belpic_atrs[] = {
149
    /* Applet V1.8 */
150
    {"3B:7F:96:00:00:80:31:80:65:B0:85:04:01:20:12:0F:FF:82:90:00", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL},
151
    /* Applet V1.1 */
152
    {"3B:98:13:40:0A:A5:03:01:01:01:AD:13:11",         NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL},
153
    /* Applet V1.0 with new EMV-compatible ATR */
154
    {"3B:98:94:40:0A:A5:03:01:01:01:AD:13:10",         NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL},
155
    /* Applet beta 5 + V1.0 */
156
    {"3B:98:94:40:FF:A5:03:01:01:01:AD:13:10",         NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL},
157
    {NULL,                NULL, NULL, 0,            0, NULL}
158
};
159
160
static struct sc_card_operations belpic_ops;
161
static struct sc_card_driver belpic_drv = {
162
  "Belpic cards",
163
  "belpic",
164
  &belpic_ops,
165
  NULL, 0, NULL
166
};
167
static const struct sc_card_operations *iso_ops = NULL;
168
169
static int get_carddata(sc_card_t *card, u8* carddata_loc, unsigned int carddataloc_len)
170
0
{
171
0
  sc_apdu_t apdu;
172
0
  u8 carddata_cmd[] = { 0x80, 0xE4, 0x00, 0x00, 0x1C };
173
0
  int r;
174
175
0
  assert(carddataloc_len == BELPIC_CARDDATA_RESP_LEN);
176
177
0
  r = sc_bytes2apdu(card->ctx, carddata_cmd, sizeof(carddata_cmd), &apdu);
178
0
  if(r) {
179
0
    sc_log(card->ctx,  "bytes to APDU conversion failed: %d\n", r);
180
0
    return r;
181
0
  }
182
183
0
  apdu.resp = carddata_loc;
184
0
  apdu.resplen = carddataloc_len;
185
186
0
  r = sc_transmit_apdu(card, &apdu);
187
0
  if(r) {
188
0
    sc_log(card->ctx,  "GetCardData command failed: %d\n", r);
189
0
    return r;
190
0
  }
191
192
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
193
0
  if(r) {
194
0
    sc_log(card->ctx,  "GetCardData: card returned %d\n", r);
195
0
    return r;
196
0
  }
197
0
  if(apdu.resplen < carddataloc_len) {
198
0
    sc_log(card->ctx,
199
0
       "GetCardData: card returned %"SC_FORMAT_LEN_SIZE_T"u bytes rather than expected %d\n",
200
0
       apdu.resplen, carddataloc_len);
201
0
    return SC_ERROR_WRONG_LENGTH;
202
0
  }
203
204
0
  return 0;
205
0
}
206
207
static int belpic_match_card(sc_card_t *card)
208
0
{
209
0
  int i;
210
211
0
  i = _sc_match_atr(card, belpic_atrs, &card->type);
212
0
  if (i < 0)
213
0
    return 0;
214
0
  return 1;
215
0
}
216
217
static int belpic_init(sc_card_t *card)
218
0
{
219
0
  int key_size = 1024;
220
0
  unsigned long flags = 0;
221
222
0
  sc_log(card->ctx,  "Belpic V%s\n", BELPIC_VERSION);
223
224
0
  if (card->type < 0)
225
0
    card->type = SC_CARD_TYPE_BELPIC_EID; /* Unknown card: assume it's the Belpic Card */
226
227
0
  card->cla = 0x00;
228
0
  if (card->type == SC_CARD_TYPE_BELPIC_EID) {
229
0
    u8 carddata[BELPIC_CARDDATA_RESP_LEN];
230
0
    memset(carddata, 0, sizeof(carddata));
231
232
0
    if(get_carddata(card, carddata, sizeof(carddata)) < 0) {
233
0
      return SC_ERROR_INVALID_CARD;
234
0
    }
235
0
    if (carddata[BELPIC_CARDDATA_OFF_APPLETVERS] >= 0x18) {
236
0
      flags = SC_ALGORITHM_ECDSA_HASH_NONE | SC_ALGORITHM_ECDSA_RAW;
237
0
      _sc_card_add_ec_alg(card, 256, flags, 0, NULL);
238
0
      _sc_card_add_ec_alg(card, 384, flags, 0, NULL);
239
0
      _sc_card_add_ec_alg(card, 512, flags, 0, NULL);
240
0
      _sc_card_add_ec_alg(card, 521, flags, 0, NULL);
241
0
    } else {
242
0
      if (carddata[BELPIC_CARDDATA_OFF_APPLETVERS] >= 0x17) {
243
0
        key_size = 2048;
244
0
      }
245
0
      _sc_card_add_rsa_alg(card, key_size,
246
0
          SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE, 0);
247
0
    }
248
0
  }
249
250
  /* State that we have an RNG */
251
0
  card->caps |= SC_CARD_CAP_RNG;
252
253
0
  card->max_pin_len = BELPIC_MAX_USER_PIN_LEN;
254
255
0
  return 0;
256
0
}
257
258
static int belpic_select_file(sc_card_t *card,
259
            const sc_path_t *in_path, sc_file_t **file_out)
260
0
{
261
0
  sc_apdu_t apdu;
262
0
  u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
263
0
  int r;
264
0
  size_t pathlen;
265
0
  sc_file_t *file = NULL;
266
267
0
  assert(card != NULL && in_path != NULL);
268
0
  memcpy(path, in_path->value, in_path->len);
269
0
  pathlen = in_path->len;
270
271
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C);
272
273
0
  apdu.lc = pathlen;
274
0
  apdu.data = path;
275
0
  apdu.datalen = pathlen;
276
277
0
  apdu.resplen = 0;
278
0
  apdu.le = 0;
279
280
0
  r = sc_transmit_apdu(card, &apdu);
281
282
0
  LOG_TEST_RET(card->ctx, r, "Select File APDU transmit failed");
283
284
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
285
0
  if (r)
286
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
287
288
0
  next_idx = (size_t)-1;    /* reset */
289
290
0
  if (file_out != NULL) {
291
0
    file = sc_file_new();
292
0
    file->path = *in_path;
293
0
    if (pathlen >= 2)
294
0
      file->id = (in_path->value[pathlen - 2] << 8) | in_path->value[pathlen - 1];
295
0
    file->size = BELPIC_MAX_FILE_SIZE;
296
0
    file->shareable = 1;
297
0
    file->ef_structure = SC_FILE_EF_TRANSPARENT;
298
0
    if (pathlen == 2 && memcmp("\x3F\x00", in_path->value, 2) == 0)
299
0
      file->type = SC_FILE_TYPE_DF;
300
0
    else
301
0
      file->type = SC_FILE_TYPE_WORKING_EF;
302
0
    *file_out = file;
303
0
  }
304
305
0
  return 0;
306
0
}
307
308
static int belpic_read_binary(sc_card_t *card,
309
            unsigned int idx, u8 * buf, size_t count, unsigned long *flags)
310
0
{
311
0
  int r;
312
313
0
  if (next_idx == idx)
314
0
    return 0; /* File was already read entirely */
315
316
0
  t1 = clock();
317
0
  r = iso_ops->read_binary(card, idx, buf, count, flags);
318
0
  t2 = clock();
319
320
  /* If the 'next_idx trick' shouldn't work, we hope this error
321
   * means that an attempt was made to read beyond the file's
322
   * contents, so we'll return 0 to end the loop in sc_read_binary()*/
323
0
  if (r == SC_ERROR_INCORRECT_PARAMETERS)
324
0
    return 0;
325
326
0
  if (r >= 0 && (size_t)r < count)
327
0
    next_idx = idx + (size_t)r;
328
329
0
  dur = t2 - t1;
330
0
  tot_dur += dur;
331
0
  tot_read += r;
332
0
  return r;
333
0
}
334
335
static int belpic_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left)
336
0
{
337
0
  data->pin1.encoding = data->pin2.encoding = BELPIC_PIN_ENCODING;
338
0
  data->pin1.pad_char = data->pin2.pad_char = BELPIC_PAD_CHAR;
339
0
  data->pin1.min_length = data->pin2.min_length = BELPIC_MIN_USER_PIN_LEN;
340
0
  data->pin1.max_length = data->pin2.max_length = BELPIC_MAX_USER_PIN_LEN;
341
0
  data->apdu = NULL;
342
343
0
  return iso_ops->pin_cmd(card, data, tries_left);
344
0
}
345
346
static int belpic_set_security_env(sc_card_t *card,
347
           const sc_security_env_t *env, int se_num)
348
0
{
349
0
  sc_apdu_t apdu;
350
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
351
0
  int r;
352
353
0
  sc_log(card->ctx,  "belpic_set_security_env(), keyRef = 0x%0x, algo = 0x%0lx\n",
354
0
     *env->key_ref, env->algorithm_flags);
355
356
0
  assert(card != NULL && env != NULL);
357
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
358
0
  switch (env->operation) {
359
0
  case SC_SEC_OPERATION_SIGN:
360
0
    apdu.p1 = 0x41;
361
0
    apdu.p2 = 0xB6;
362
0
    sbuf[0] = 0x04; /* length of the following data */
363
0
    sbuf[1] = 0x80; /* tag for algorithm reference */
364
0
    if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01)
365
0
      sbuf[2] = 0x01;
366
0
    else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
367
0
      sbuf[2] = 0x02;
368
0
    else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
369
0
      sbuf[2] = 0x04;
370
0
    else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA256)
371
0
      sbuf[2] = 0x01;
372
0
    else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA384)
373
0
      sbuf[2] = 0x02;
374
0
    else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA512)
375
0
      sbuf[2] = 0x04;
376
0
    else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW)
377
0
      sbuf[2] = 0x40;
378
0
    else {
379
0
      sc_log(card->ctx,  "Set Sec Env: unsupported algo 0X%0lX\n",
380
0
         env->algorithm_flags);
381
0
      return SC_ERROR_INVALID_ARGUMENTS;
382
0
    }
383
0
    sbuf[3] = 0x84; /* tag for private key reference */
384
0
    sbuf[4] = *env->key_ref;  /* key reference */
385
0
    apdu.lc = 5;
386
0
    apdu.datalen = 5;
387
0
    break;
388
0
  default:
389
0
    return SC_ERROR_INVALID_ARGUMENTS;
390
0
  }
391
0
  apdu.le = 0;
392
0
  apdu.data = sbuf;
393
0
  apdu.resplen = 0;
394
395
0
  r = sc_transmit_apdu(card, &apdu);
396
0
  LOG_TEST_RET(card->ctx, r, "Set Security Env APDU transmit failed");
397
398
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
399
0
  LOG_TEST_RET(card->ctx, r, "Card's Set Security Env command returned error");
400
401
  /* If a NonRep signature will be done, ask to enter a PIN. It would be more
402
   * logical to put the code below into the compute signature function because
403
   * a Verify Pin call must immediately precede a Compute Signature call.
404
   * It's not done because the Compute Signature is completely ISO7816 compliant
405
   * so we use the iso7816_compute_signature() function, and because this function
406
   * doesn't know about the key reference.
407
   * It's not a problem either, because this function is (for pkcs11) only called
408
   * by sc_pkcs15_compute_signature(), where the card is already locked, and
409
   * the next function to be executed will be the compute_signature function.
410
   */
411
0
  if (*env->key_ref == BELPIC_KEY_REF_NONREP) {
412
0
    sc_log(card->ctx,  "No GUI for NonRep key present, signature cancelled\n");
413
0
    return SC_ERROR_NOT_SUPPORTED;
414
0
  }
415
416
0
  return r;
417
0
}
418
419
static struct sc_card_driver *sc_get_driver(void)
420
0
{
421
0
  if (iso_ops == NULL)
422
0
    iso_ops = sc_get_iso7816_driver()->ops;
423
424
0
  belpic_ops.match_card = belpic_match_card;
425
0
  belpic_ops.init = belpic_init;
426
427
0
  belpic_ops.update_binary = iso_ops->update_binary;
428
0
  belpic_ops.select_file = belpic_select_file;
429
0
  belpic_ops.read_binary = belpic_read_binary;
430
0
  belpic_ops.pin_cmd = belpic_pin_cmd;
431
0
  belpic_ops.set_security_env = belpic_set_security_env;
432
433
0
  belpic_ops.compute_signature = iso_ops->compute_signature;
434
0
  belpic_ops.get_challenge = iso_ops->get_challenge;
435
0
  belpic_ops.get_response = iso_ops->get_response;
436
0
  belpic_ops.check_sw = iso_ops->check_sw;
437
438
0
  return &belpic_drv;
439
0
}
440
441
#if 1
442
struct sc_card_driver *sc_get_belpic_driver(void)
443
0
{
444
0
  return sc_get_driver();
445
0
}
446
#endif