• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

canokeys / canokey-core / 12325704235

14 Dec 2024 01:37AM UTC coverage: 78.407% (-0.3%) from 78.707%
12325704235

push

github

web-flow
Merge pull request #107 from canokeys/dev

Fix state of current_cmd_src

2 of 8 new or added lines in 2 files covered. (25.0%)

103 existing lines in 11 files now uncovered.

6467 of 8248 relevant lines covered (78.41%)

571.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.68
/applets/admin/admin.c
1
// SPDX-License-Identifier: Apache-2.0
2
#include <admin.h>
3
#include <crypto-util.h>
4
#include <ctap.h>
5
#include <device.h>
6
#include <fs.h>
7
#include <ndef.h>
8
#include <oath.h>
9
#include <openpgp.h>
10
#include <pass.h>
11
#include <pin.h>
12
#include <piv.h>
13

14
#define PIN_RETRY_COUNTER 3
15
#define SN_FILE "sn"
16
#define CFG_FILE "admin_cfg"
17

18
static pin_t pin = {.min_length = 6, .max_length = PIN_MAX_LENGTH, .is_validated = 0, .path = "admin-pin"};
19

20
static const admin_device_config_t default_cfg = {.led_normally_on = 1, .ndef_en = 1, .webusb_landing_en = 1};
21

22
static admin_device_config_t current_config;
23

24
__attribute__((weak)) int admin_vendor_specific(const CAPDU *capdu, RAPDU *rapdu) {
25
  UNUSED(capdu);
26
  UNUSED(rapdu);
27
  return 0;
1✔
28
}
29

30
__attribute__((weak)) int admin_vendor_version(const CAPDU *capdu, RAPDU *rapdu) {
31
  UNUSED(capdu);
32
  UNUSED(rapdu);
33
  return 0;
×
34
}
35

36
__attribute__((weak)) int admin_vendor_hw_variant(const CAPDU *capdu, RAPDU *rapdu) {
37
  UNUSED(capdu);
38
  UNUSED(rapdu);
39
  return 0;
×
40
}
41

42
__attribute__((weak)) int admin_vendor_hw_sn(const CAPDU *capdu, RAPDU *rapdu) {
43
  UNUSED(capdu);
44
  UNUSED(rapdu);
45
  return 0;
×
46
}
47

48
__attribute__((weak)) int admin_vendor_nfc_enable(const CAPDU *capdu, RAPDU *rapdu, bool pin_validated) {
49
  UNUSED(capdu);
50
  UNUSED(rapdu);
51
  UNUSED(pin_validated);
UNCOV
52
  return 0;
×
53
}
54

55
uint8_t cfg_is_led_normally_on(void) { return current_config.led_normally_on; }
2,205✔
56

57
uint8_t cfg_is_ndef_enable(void) { return current_config.ndef_en; }
20✔
58

UNCOV
59
uint8_t cfg_is_webusb_landing_enable(void) { return current_config.webusb_landing_en; }
×
60

61
void admin_poweroff(void) { pin.is_validated = 0; }
47✔
62

63
int admin_install(const uint8_t reset) {
64
  admin_poweroff();
3✔
65
  if (reset || get_file_size(CFG_FILE) != sizeof(admin_device_config_t)) {
3✔
66
    current_config = default_cfg;
3✔
67
    if (write_file(CFG_FILE, &current_config, 0, sizeof(current_config), 1) < 0) return -1;
3✔
68
  } else {
UNCOV
69
    if (read_file(CFG_FILE, &current_config, 0, sizeof(current_config)) < 0) return -1;
×
70
  }
71
  if (reset || get_file_size(pin.path) < 0) {
3✔
72
    if (pin_create(&pin, "123456", 6, PIN_RETRY_COUNTER) < 0) return -1;
3✔
73
  }
74
  return 0;
3✔
75
}
76

77
static int admin_verify(const CAPDU *capdu, RAPDU *rapdu) {
108✔
78
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
108✔
79
  if (LC == 0) {
108✔
80
    if (pin.is_validated) return 0;
28✔
81
    const int retries = pin_get_retries(&pin);
28✔
82
    if (retries < 0) return -1;
28✔
83
    EXCEPT(SW_PIN_RETRIES + retries);
28✔
84
  }
85
  uint8_t ctr;
80✔
86
  const int err = pin_verify(&pin, DATA, LC, &ctr);
80✔
87
  if (err == PIN_IO_FAIL) return -1;
80✔
88
  if (err == PIN_LENGTH_INVALID) EXCEPT(SW_WRONG_LENGTH);
80✔
89
  if (ctr == 0) EXCEPT(SW_AUTHENTICATION_BLOCKED);
53✔
90
  if (err == PIN_AUTH_FAIL) EXCEPT(SW_PIN_RETRIES + ctr);
50✔
91
  return 0;
43✔
92
}
93

94
static int admin_change_pin(const CAPDU *capdu, RAPDU *rapdu) {
7✔
95
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
7✔
96
  const int err = pin_update(&pin, DATA, LC);
7✔
97
  if (err == PIN_IO_FAIL) return -1;
7✔
98
  if (err == PIN_LENGTH_INVALID) EXCEPT(SW_WRONG_LENGTH);
7✔
99
  return 0;
3✔
100
}
101

102
static int admin_write_sn(const CAPDU *capdu, RAPDU *rapdu) {
1✔
103
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
1✔
104
  if (LC != 0x04) EXCEPT(SW_WRONG_LENGTH);
1✔
105
  if (get_file_size(SN_FILE) >= 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
1✔
106
  return write_file(SN_FILE, DATA, 0, LC, 1);
1✔
107
}
108

109
static int admin_read_sn(const CAPDU *capdu, RAPDU *rapdu) {
2✔
110
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
111
  if (LE < 4) EXCEPT(SW_WRONG_LENGTH);
2✔
112

113
  fill_sn(RDATA);
2✔
114
  LL = 4;
2✔
115

116
  return 0;
2✔
117
}
118

119
static int admin_config(const CAPDU *capdu, RAPDU *rapdu) {
18✔
120
  switch (P1) {
18✔
121
  case ADMIN_P1_CFG_LED_ON:
4✔
122
    current_config.led_normally_on = P2 & 1;
4✔
123
    break;
4✔
124
  case ADMIN_P1_CFG_NDEF:
6✔
125
    current_config.ndef_en = P2 & 1;
6✔
126
    break;
6✔
127
  case ADMIN_P1_CFG_WEBUSB_LANDING:
4✔
128
    current_config.webusb_landing_en = P2 & 1;
4✔
129
    break;
4✔
130
  default:
4✔
131
    EXCEPT(SW_WRONG_P1P2);
4✔
132
  }
133
  const int ret = write_file(CFG_FILE, &current_config, 0, sizeof(current_config), 1);
14✔
134
  stop_blinking();
14✔
135
  return ret;
14✔
136
}
137

138
static int admin_read_config(const CAPDU *capdu, RAPDU *rapdu) {
16✔
139
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
16✔
140
  if (LE < 5) EXCEPT(SW_WRONG_LENGTH);
16✔
141

142
  RDATA[0] = current_config.led_normally_on;
16✔
143
  RDATA[1] = 0; // reserved
16✔
144
  RDATA[2] = ndef_get_read_only();
16✔
145
  RDATA[3] = current_config.ndef_en;
16✔
146
  RDATA[4] = current_config.webusb_landing_en;
16✔
147
  RDATA[5] = 0; // reserved
16✔
148
  LL = 6;
16✔
149

150
  return 0;
16✔
151
}
152

153
static int admin_flash_usage(const CAPDU *capdu, RAPDU *rapdu) {
2✔
154
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
155
  if (LE < 2) EXCEPT(SW_WRONG_LENGTH);
2✔
156

157
  RDATA[0] = get_fs_usage();
2✔
158
  RDATA[1] = get_fs_size();
2✔
159
  LL = 2;
2✔
160

161
  return 0;
2✔
162
}
163

164
static int admin_factory_reset(const CAPDU *capdu, RAPDU *rapdu) {
2✔
165
  int ret;
166
  if (P1 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
167
  if (LC != 5) EXCEPT(SW_WRONG_LENGTH);
2✔
168
  if (memcmp_s(DATA, "RESET", 5) != 0) EXCEPT(SW_WRONG_DATA);
2✔
169
#ifndef FUZZ
170
  ret = pin_get_retries(&pin);
2✔
171
  if (ret > 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
2✔
172

173
  if (is_nfc()) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
2✔
174
  if (strong_user_presence_test() < 0) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED);
2✔
175
#endif
176

177
  DBG_MSG("factory reset begins\n");
2✔
178
  ret = openpgp_install(1);
2✔
179
  if (ret < 0) return ret;
2✔
180
  ret = piv_install(1);
2✔
181
  if (ret < 0) return ret;
2✔
182
  ret = oath_install(1);
2✔
183
  if (ret < 0) return ret;
2✔
184
  ret = ctap_install(1);
2✔
185
  if (ret < 0) return ret;
2✔
186
  ret = ndef_install(1);
2✔
187
  if (ret < 0) return ret;
2✔
188
  ret = pass_install(1);
2✔
189
  if (ret < 0) return ret;
2✔
190
  ret = admin_install(1);
2✔
191
  if (ret < 0) return ret;
2✔
192

193
  return 0;
2✔
194
}
195

196
void fill_sn(uint8_t *buf) {
197
  const int err = read_file(SN_FILE, buf, 0, 4);
419✔
198
  if (err != 4) memset(buf, 0, 4);
419✔
199
}
419✔
200

201
int admin_process_apdu(const CAPDU *capdu, RAPDU *rapdu) {
202
  LL = 0;
305✔
203
  SW = SW_NO_ERROR;
305✔
204

205
  int ret = 0;
305✔
206
  switch (INS) {
305✔
207
  case ADMIN_INS_SELECT:
49✔
208
    if (P1 != 0x04 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
49✔
209
    return 0;
49✔
210

211
  case ADMIN_INS_READ_VERSION:
4✔
212
    if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
4✔
213
    if (P1 == 0)
4✔
214
      ret = admin_vendor_version(capdu, rapdu);
2✔
215
    else if (P1 == 1)
2✔
216
      ret = admin_vendor_hw_variant(capdu, rapdu);
2✔
217
    goto done;
4✔
218

219
  case ADMIN_INS_READ_SN:
4✔
220
    if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
4✔
221
    if (P1 == 0)
4✔
222
      ret = admin_read_sn(capdu, rapdu);
2✔
223
    else if (P1 == 1)
2✔
224
      ret = admin_vendor_hw_sn(capdu, rapdu);
2✔
225
    goto done;
4✔
226

UNCOV
227
  case ADMIN_INS_NFC_ENABLE:
×
UNCOV
228
    ret = admin_vendor_nfc_enable(capdu, rapdu, pin.is_validated);
×
UNCOV
229
    goto done;
×
230

231
  case ADMIN_INS_FACTORY_RESET:
2✔
232
    ret = admin_factory_reset(capdu, rapdu);
2✔
233
    goto done;
2✔
234

235
  case ADMIN_INS_VERIFY:
108✔
236
    ret = admin_verify(capdu, rapdu);
108✔
237
    goto done;
108✔
238

239
  default:
138✔
240
    break;
138✔
241
  }
242

243
#ifndef FUZZ
244
  if (!pin.is_validated) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED);
138✔
245
#endif
246

247
  switch (INS) {
92✔
248
  case ADMIN_INS_WRITE_FIDO_PRIVATE_KEY:
1✔
249
    ret = ctap_install_private_key(capdu, rapdu);
1✔
250
    break;
1✔
251
  case ADMIN_INS_WRITE_FIDO_CERT:
1✔
252
    ret = ctap_install_cert(capdu, rapdu);
1✔
253
    break;
1✔
254
  case ADMIN_INS_RESET_OPENPGP:
1✔
255
    ret = openpgp_install(1);
1✔
256
    break;
1✔
257
  case ADMIN_INS_RESET_PIV:
1✔
258
    ret = piv_install(1);
1✔
259
    break;
1✔
260
  case ADMIN_INS_RESET_OATH:
1✔
261
    ret = oath_install(1);
1✔
262
    break;
1✔
263
  case ADMIN_INS_RESET_NDEF:
3✔
264
    ret = ndef_install(1);
3✔
265
    break;
3✔
266
  case ADMIN_INS_TOGGLE_NDEF_READ_ONLY:
22✔
267
    ret = ndef_toggle_read_only(capdu, rapdu);
22✔
268
    break;
22✔
269
  case ADMIN_INS_RESET_PASS:
×
270
    ret = pass_install(1);
×
271
    break;
×
272
  case ADMIN_INS_RESET_CTAP:
×
UNCOV
273
    ret = ctap_install(1);
×
UNCOV
274
    break;
×
275
  case ADMIN_INS_READ_CTAP_SM2_CONFIG:
1✔
276
    ret = ctap_read_sm2_config(capdu, rapdu);
1✔
277
    break;
1✔
278
  case ADMIN_INS_WRITE_CTAP_SM2_CONFIG:
1✔
279
    ret = ctap_write_sm2_config(capdu, rapdu);
1✔
280
    break;
1✔
281
  case ADMIN_INS_CHANGE_PIN:
7✔
282
    ret = admin_change_pin(capdu, rapdu);
7✔
283
    break;
7✔
284
  case ADMIN_INS_WRITE_SN:
1✔
285
    ret = admin_write_sn(capdu, rapdu);
1✔
286
    break;
1✔
287
  case ADMIN_INS_CONFIG:
18✔
288
    ret = admin_config(capdu, rapdu);
18✔
289
    break;
18✔
290
  case ADMIN_INS_FLASH_USAGE:
2✔
291
    ret = admin_flash_usage(capdu, rapdu);
2✔
292
    break;
2✔
293
  case ADMIN_INS_READ_CONFIG:
16✔
294
    ret = admin_read_config(capdu, rapdu);
16✔
295
    break;
16✔
296
  case ADMIN_INS_READ_PASS_CONFIG:
4✔
297
    ret = pass_read_config(capdu, rapdu);
4✔
298
    break;
4✔
299
  case ADMIN_INS_WRITE_PASS_CONFIG:
10✔
300
    ret = pass_write_config(capdu, rapdu);
10✔
301
    break;
10✔
302
  case ADMIN_INS_VENDOR_SPECIFIC:
1✔
303
    ret = admin_vendor_specific(capdu, rapdu);
1✔
304
    break;
1✔
305
  default:
1✔
306
    EXCEPT(SW_INS_NOT_SUPPORTED);
1✔
307
  }
308

309
done:
209✔
310
  if (ret < 0) EXCEPT(SW_UNABLE_TO_PROCESS);
209✔
311
  return 0;
209✔
312
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc