Coverage Report

Created: 2025-10-10 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/pkcs15-eoi.c
Line
Count
Source
1
/*
2
 * Support for the eOI card.
3
 *
4
 * Copyright (C) 2022 Luka Logar <luka.logar@iname.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 <string.h>
22
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
#include "log.h"
27
#include "pkcs15.h"
28
29
#if defined(ENABLE_SM) && defined(ENABLE_OPENPACE)
30
31
#include "cards.h"
32
#include "card-eoi.h"
33
34
int sc_pkcs15emu_eoi_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid)
35
7.29k
{
36
7.29k
  struct sc_card *card = p15card->card;
37
7.29k
  struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data;
38
7.29k
  struct sc_pkcs15_search_key sk;
39
7.29k
  struct sc_pkcs15_object *objs[MAX_OBJECTS];
40
7.29k
  int i, j, len;
41
42
7.29k
  LOG_FUNC_CALLED(card->ctx);
43
44
7.29k
  if (card->type != SC_CARD_TYPE_EOI && card->type != SC_CARD_TYPE_EOI_CONTACTLESS)
45
7.29k
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_CARD);
46
47
0
  if (!privdata)
48
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
49
50
  /*
51
   * Some of the data is not accessible over the unencrypted channel
52
   * when contactless reader is used. So start SM now (if not yet establisahed).
53
   */
54
0
  if (card->type == SC_CARD_TYPE_EOI_CONTACTLESS && card->sm_ctx.sm_mode == SM_MODE_NONE) {
55
0
    int r = card->sm_ctx.ops.open(card);
56
0
    if (r != SC_SUCCESS)
57
0
      LOG_FUNC_RETURN(card->ctx, r);
58
0
  }
59
60
  /*
61
   * Get the card objects, so we can manipulate them. See below
62
   */
63
0
  LOG_TEST_RET(card->ctx, sc_pkcs15_bind_internal(p15card, aid),
64
0
    "sc_pkcs15_bind_internal failed");
65
66
  /*
67
   * PIN objects:
68
   * 1) Find the "Card CAN" PIN and store it's path, so we'll be able to fetch the CAN and do the PACE auth
69
   * 2) Add PIN's auth_info->path to the list of paths that can fail on select. sc_pin_cmd would break otherwise
70
   */
71
0
  memset(&sk, 0, sizeof(sk));
72
0
  sk.class_mask = SC_PKCS15_SEARCH_CLASS_AUTH;
73
0
  len = sc_pkcs15_search_objects(p15card, &sk, (struct sc_pkcs15_object **)&objs, MAX_OBJECTS);
74
0
  for (i = 0, j = 0; i < len; i++) {
75
0
    struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)objs[i]->data;
76
0
    if (auth_info && auth_info->auth_id.len == 8 && !strcmp((char*)auth_info->auth_id.value, "Card CAN")) {
77
0
      auth_info->path.type = SC_PATH_TYPE_PATH;
78
      /* Read the file that contains serial and encrypted CAN */
79
0
      if (sc_pkcs15_read_file(p15card, &auth_info->path, &privdata->enc_can.value, &privdata->enc_can.len, 0) == SC_SUCCESS) {
80
        /* File should be 24 bytes long */
81
0
        if (privdata->enc_can.len != 24)
82
0
          LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA);
83
0
        if (strlen(p15card->tokeninfo->serial_number) != 20)
84
0
          LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA);
85
        /* First 8 bytes are used as serial number */
86
0
        sc_bin_to_hex(privdata->enc_can.value, 8, &p15card->tokeninfo->serial_number[4], 17, 0);
87
0
      }
88
      /* Do not add "Card CAN" to the list of PIN paths to ignore, otherwise the 2nd PKCS#15 app can not access it */
89
0
      auth_info = NULL;
90
      /* Mark "Card CAN" as NOT a PIN object, so that it doesn't get it's own PKCS#11 slot */
91
0
      objs[i]->type &= ~SC_PKCS15_TYPE_AUTH_PIN;
92
0
    }
93
    /*
94
     * For some reason QES app has "Norm PUK" not flagged as unblocking PIN and thus "Norm PUK" appears as a slot in
95
     * PKCS#11. Flag it as unblockingPin, so it doesn't appear as a separate slot.
96
     */
97
0
    if (auth_info && auth_info->auth_id.len == 8 && !strcmp((char*)auth_info->auth_id.value, "Norm PUK")) {
98
0
      auth_info->attrs.pin.flags |= SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN;
99
0
    }
100
0
    if (auth_info) {
101
0
      privdata->pin_paths[j++] = &auth_info->path;
102
0
    }
103
0
  }
104
105
  /*
106
   * Private key objects:
107
   * 1) Rename "Card PIN" to "Norm PIN" as it's the later name that is used throughout the PKCS#15 objects
108
   * 2) Add the key references to the prkey_mappings array, as it seems that eOI expects them counted from 0xA0 up (starting from 1 within each app)
109
   *    Currently there are 3 private keys on the card
110
   *     key_ref
111
   *       2 - for pinless entry (Prijava brez PIN-a), maps to 0xA1
112
   *       1 - for authentication in QES app (Podpis in prijava), maps to 0xA1
113
   *       3 - for signing in QES app (Podpis in prijava), maps to 0xA2
114
   */
115
0
  memset(&sk, 0, sizeof(sk));
116
0
  sk.class_mask = SC_PKCS15_SEARCH_CLASS_PRKEY;
117
0
  len = sc_pkcs15_search_objects(p15card, &sk, (struct sc_pkcs15_object **)&objs, MAX_OBJECTS);
118
  /*
119
   * If both PKCS#15 apps are enabled, prkey_mappings can already be partially filled up from the first PKCS#15 app
120
   * as the privdata is shared between both apps which use the same driver
121
    */
122
0
  for (j = 0; privdata->prkey_mappings[j][1] != 0; j++) {
123
    /* NOP */
124
0
  }
125
0
  for (i = 0; i < len; i++) {
126
0
    struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *)objs[i]->data;
127
0
    if ((objs[i]->auth_id.len == 8) && !strncmp((char*)objs[i]->auth_id.value, "Card PIN", 8)) {
128
0
      memcpy(objs[i]->auth_id.value, "Norm PIN", 8);
129
0
    }
130
0
    if (prkey_info) {
131
0
      privdata->prkey_mappings[j][0] = prkey_info->key_reference;
132
0
      privdata->prkey_mappings[j++][1] = 0xA0 + (i + 1);
133
0
    }
134
0
  }
135
136
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
137
0
}
138
139
#else
140
141
int sc_pkcs15emu_eoi_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid)
142
{
143
  LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_WRONG_CARD);
144
}
145
146
#endif