Coverage Report

Created: 2026-10-17 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-skeid.c
Line
Count
Source
1
/*
2
 * card-skeid.c: Support for (CardOS based) cards issued as identity documents in Slovakia
3
 *
4
 * Copyright (C) 2022 Juraj Ĺ arinay <juraj@sarinay.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
 * based on card-cardos.c
21
 */
22
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
27
#include <string.h>
28
#include "internal.h"
29
30
145
#define SKEID_KNOWN_URL_LEN 46
31
32
static const struct sc_card_operations *iso_ops = NULL;
33
34
static struct sc_card_operations skeid_ops;
35
static struct sc_card_driver skeid_drv = {
36
  "Slovak eID card",
37
  "skeid",
38
  &skeid_ops,
39
  NULL, 0, NULL
40
};
41
42
static const struct sc_atr_table skeid_atrs[] = {
43
  /* Slovak eID v3 - CardOS 5.4
44
   *
45
   * The ATR was intentionally omitted from minidriver_registration[] within win32/customactions.cpp
46
   * as it is identical to that of CardOS v5.4 and therefore already included.
47
   * Any new ATR may need an entry in minidriver_registration[]. */
48
  {"3b:d2:18:00:81:31:fe:58:c9:04:11", NULL, NULL, SC_CARD_TYPE_SKEID_V3, 0, NULL},
49
  {NULL, NULL, NULL, 0, 0, NULL}
50
};
51
52
static int skeid_known_url(sc_card_t * card)
53
60
{
54
60
  const struct sc_aid skeid_aid_eid = {{0xE8, 0x07, 0x04, 0x00, 0x7F, 0x00, 0x07, 0x03, 0x02}, 9};
55
60
  const char *known_url = "\x80\x01\x00\x5F\x50\x28http://www.minv.sk/cif/cif-sk-eid-v3.xml";
56
60
  u8 buf[SKEID_KNOWN_URL_LEN];
57
58
60
  sc_path_t url_path;
59
60
60
  int r = SC_ERROR_WRONG_CARD;
61
62
60
  sc_path_set(&url_path, SC_PATH_TYPE_DF_NAME, skeid_aid_eid.value, skeid_aid_eid.len, 0, 0);
63
64
60
  if (sc_select_file(card, &url_path, NULL) == SC_SUCCESS
65
34
    && sc_get_data(card, 0x7F62, buf, SKEID_KNOWN_URL_LEN) == SKEID_KNOWN_URL_LEN
66
17
    && !memcmp(buf, known_url, SKEID_KNOWN_URL_LEN))
67
13
    r = SC_SUCCESS;
68
69
60
  return r;
70
60
}
71
72
static int skeid_match_card(sc_card_t *card)
73
11.4k
{
74
11.4k
  if (_sc_match_atr(card, skeid_atrs, &card->type) < 0 || skeid_known_url(card) != SC_SUCCESS)
75
11.4k
    return 0;
76
77
13
  sc_log(card->ctx,  "Slovak eID card v3 (CardOS 5.4)");
78
79
13
  return 1;
80
11.4k
}
81
82
static int skeid_get_serialnr(sc_card_t *card)
83
13
{
84
13
  int r;
85
13
  sc_apdu_t apdu;
86
13
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
87
88
13
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x81);
89
13
  apdu.resp = rbuf;
90
13
  apdu.resplen = sizeof(rbuf);
91
13
  apdu.le = 256;
92
13
  r = sc_transmit_apdu(card, &apdu);
93
13
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
94
11
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
95
2
    return SC_ERROR_INTERNAL;
96
9
  if (apdu.resplen == 8) {
97
    /* cache serial number */
98
7
    memcpy(card->serialnr.value, rbuf, 8);
99
7
    card->serialnr.len = 8;
100
7
  } else {
101
2
    sc_log(card->ctx, "unexpected response to GET DATA serial number");
102
2
    return SC_ERROR_INTERNAL;
103
2
  }
104
7
  return SC_SUCCESS;
105
9
}
106
107
static int skeid_init(sc_card_t *card)
108
13
{
109
13
  const unsigned long flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE;
110
13
  const size_t data_field_length = 437;
111
13
  int r;
112
113
13
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
114
115
13
  card->name = "Slovak eID (CardOS)";
116
13
  card->type = SC_CARD_TYPE_SKEID_V3;
117
13
  card->cla = 0x00;
118
119
13
  r = skeid_get_serialnr(card);
120
13
  LOG_TEST_RET(card->ctx, r, "Error reading serial number.");
121
122
7
  card->caps |= SC_CARD_CAP_APDU_EXT | SC_CARD_CAP_ISO7816_PIN_INFO;
123
124
7
  card->max_send_size = data_field_length - 6;
125
#ifdef _WIN32
126
  /* see card-cardos.c */
127
  if (card->reader->max_send_size == 255 && card->reader->max_recv_size == 256) {
128
    sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "resetting reader to use data_field_length");
129
    card->reader->max_send_size = data_field_length - 6;
130
    card->reader->max_recv_size = data_field_length - 3;
131
  }
132
#endif
133
134
7
  card->max_send_size = sc_get_max_send_size(card); /* see card-cardos.c */
135
7
  card->max_recv_size = data_field_length - 2;
136
7
  card->max_recv_size = sc_get_max_recv_size(card);
137
138
7
  r = _sc_card_add_rsa_alg(card, 3072, flags, 0);
139
140
7
  LOG_FUNC_RETURN(card->ctx, r);
141
7
}
142
143
static int skeid_set_security_env(sc_card_t *card,
144
    const sc_security_env_t *env,
145
    int se_num)
146
0
{
147
0
  int key_id;
148
0
  int r;
149
150
0
  if (card == NULL || env == NULL)
151
0
    return SC_ERROR_INTERNAL;
152
153
0
  if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || env->key_ref_len != 1) {
154
0
    sc_log(card->ctx, "No or invalid key reference");
155
0
    return SC_ERROR_INVALID_ARGUMENTS;
156
0
  }
157
158
  /* here we follow the behaviour of the proprietary driver accompanying the card
159
   * where security operations are preceded by MSE RESTORE rather than MSE SET
160
   */
161
0
  key_id = env->key_ref[0];
162
0
  r = sc_restore_security_env(card, key_id);
163
164
0
  return r;
165
0
}
166
167
static int skeid_logout(sc_card_t *card)
168
0
{
169
0
  int r;
170
0
  sc_path_t path;
171
172
0
  sc_format_path("3F00", &path);
173
0
  r = sc_select_file(card, &path, NULL);
174
0
  return r;
175
176
0
}
177
178
struct sc_card_driver * sc_get_skeid_driver(void)
179
11.9k
{
180
11.9k
  if (iso_ops == NULL) iso_ops = sc_get_iso7816_driver()->ops;
181
11.9k
  skeid_ops = *iso_ops;
182
11.9k
  skeid_ops.match_card = skeid_match_card;
183
11.9k
  skeid_ops.init = skeid_init;
184
11.9k
  skeid_ops.set_security_env = skeid_set_security_env;
185
11.9k
  skeid_ops.logout = skeid_logout;
186
11.9k
  return &skeid_drv;
187
11.9k
}