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

canokeys / canokey-core / 6563827999

18 Oct 2023 04:30PM UTC coverage: 79.032% (+0.8%) from 78.269%
6563827999

push

github

z4yx
fix tests on CI

6174 of 7812 relevant lines covered (79.03%)

595.74 hits per line

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

96.32
/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 <pin.h>
11
#include <piv.h>
12
#include <string.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, .kbd_with_return_en = 1};
21

22
static admin_device_config_t current_config;
23

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

26
__attribute__((weak)) int admin_vendor_version(const CAPDU *capdu, RAPDU *rapdu) { return 0; }
×
27

28
__attribute__((weak)) int admin_vendor_hw_variant(const CAPDU *capdu, RAPDU *rapdu) { return 0; }
×
29

30
__attribute__((weak)) int admin_vendor_hw_sn(const CAPDU *capdu, RAPDU *rapdu) { return 0; }
×
31

32
uint8_t cfg_is_led_normally_on(void) { return current_config.led_normally_on; }
2,043✔
33

34
uint8_t cfg_is_kbd_interface_enable(void) { return current_config.kbd_interface_en; }
×
35

36
uint8_t cfg_is_ndef_enable(void) { return current_config.ndef_en; }
20✔
37

38
uint8_t cfg_is_webusb_landing_enable(void) { return current_config.webusb_landing_en; }
×
39

40
uint8_t cfg_is_kbd_with_return_enable(void) { return current_config.kbd_with_return_en; }
×
41

42
uint8_t cfg_is_piv_algo_extension_enable(void) { return current_config.piv_algo_ext_en; }
12✔
43

44
void admin_poweroff(void) { pin.is_validated = 0; }
45

46
int admin_install(uint8_t reset) {
47
  admin_poweroff();
3✔
48
  if (reset || get_file_size(CFG_FILE) != sizeof(admin_device_config_t)) {
3✔
49
    current_config = default_cfg;
3✔
50
    if (write_file(CFG_FILE, &current_config, 0, sizeof(current_config), 1) < 0) return -1;
3✔
51
  } else {
52
    if (read_file(CFG_FILE, &current_config, 0, sizeof(current_config)) < 0) return -1;
×
53
  }
54
  if (reset || get_file_size(pin.path) < 0) {
3✔
55
    if (pin_create(&pin, "123456", 6, PIN_RETRY_COUNTER) < 0) return -1;
3✔
56
  }
57
  return 0;
3✔
58
}
59

60
static int admin_verify(const CAPDU *capdu, RAPDU *rapdu) {
105✔
61
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
105✔
62
  if (LC == 0) {
105✔
63
    if (pin.is_validated) return 0;
26✔
64
    int retries = pin_get_retries(&pin);
26✔
65
    if (retries < 0) return -1;
26✔
66
    EXCEPT(SW_PIN_RETRIES + retries);
26✔
67
  }
68
  uint8_t ctr;
79✔
69
  int err = pin_verify(&pin, DATA, LC, &ctr);
79✔
70
  if (err == PIN_IO_FAIL) return -1;
79✔
71
  if (err == PIN_LENGTH_INVALID) EXCEPT(SW_WRONG_LENGTH);
79✔
72
  if (ctr == 0) EXCEPT(SW_AUTHENTICATION_BLOCKED);
54✔
73
  if (err == PIN_AUTH_FAIL) EXCEPT(SW_PIN_RETRIES + ctr);
51✔
74
  return 0;
44✔
75
}
76

77
static int admin_change_pin(const CAPDU *capdu, RAPDU *rapdu) {
7✔
78
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
7✔
79
  int err = pin_update(&pin, DATA, LC);
7✔
80
  if (err == PIN_IO_FAIL) return -1;
7✔
81
  if (err == PIN_LENGTH_INVALID) EXCEPT(SW_WRONG_LENGTH);
7✔
82
  return 0;
3✔
83
}
84

85
static int admin_write_sn(const CAPDU *capdu, RAPDU *rapdu) {
1✔
86
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
1✔
87
  if (LC != 0x04) EXCEPT(SW_WRONG_LENGTH);
1✔
88
  if (get_file_size(SN_FILE) >= 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
1✔
89
  return write_file(SN_FILE, DATA, 0, LC, 1);
1✔
90
}
91

92
static int admin_read_sn(const CAPDU *capdu, RAPDU *rapdu) {
2✔
93
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
94
  if (LE < 4) EXCEPT(SW_WRONG_LENGTH);
2✔
95

96
  fill_sn(RDATA);
2✔
97
  LL = 4;
2✔
98

99
  return 0;
2✔
100
}
101

102
static int admin_config(const CAPDU *capdu, RAPDU *rapdu) {
28✔
103
  switch (P1) {
28✔
104
  case ADMIN_P1_CFG_LED_ON:
4✔
105
    current_config.led_normally_on = P2 & 1;
4✔
106
    break;
4✔
107
  case ADMIN_P1_CFG_KBDIFACE:
4✔
108
    current_config.kbd_interface_en = P2 & 1;
4✔
109
    break;
4✔
110
  case ADMIN_P1_CFG_NDEF:
6✔
111
    current_config.ndef_en = P2 & 1;
6✔
112
    break;
6✔
113
  case ADMIN_P1_CFG_WEBUSB_LANDING:
4✔
114
    current_config.webusb_landing_en = P2 & 1;
4✔
115
    break;
4✔
116
  case ADMIN_P1_CFG_KBD_WITH_RETURN:
4✔
117
    current_config.kbd_with_return_en = P2 & 1;
4✔
118
    break;
4✔
119
  case ADMIN_P1_CFG_PIV_ALGO_EXT:
2✔
120
    current_config.piv_algo_ext_en = P2 & 1;
2✔
121
    break;
2✔
122
  default:
4✔
123
    EXCEPT(SW_WRONG_P1P2);
4✔
124
  }
125
  int ret = write_file(CFG_FILE, &current_config, 0, sizeof(current_config), 1);
24✔
126
  stop_blinking();
24✔
127
  return ret;
24✔
128
}
129

130
static int admin_read_config(const CAPDU *capdu, RAPDU *rapdu) {
24✔
131
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
24✔
132
  if (LE < 5) EXCEPT(SW_WRONG_LENGTH);
24✔
133

134
  RDATA[0] = current_config.led_normally_on;
24✔
135
  RDATA[1] = current_config.kbd_interface_en;
24✔
136
  RDATA[2] = ndef_get_read_only();
24✔
137
  RDATA[3] = current_config.ndef_en;
24✔
138
  RDATA[4] = current_config.webusb_landing_en;
24✔
139
  RDATA[5] = current_config.kbd_with_return_en;
24✔
140
  LL = 6;
24✔
141

142
  return 0;
24✔
143
}
144

145
static int admin_flash_usage(const CAPDU *capdu, RAPDU *rapdu) {
2✔
146
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
147
  if (LE < 2) EXCEPT(SW_WRONG_LENGTH);
2✔
148

149
  RDATA[0] = get_fs_usage();
2✔
150
  RDATA[1] = get_fs_size();
2✔
151
  LL = 2;
2✔
152

153
  return 0;
2✔
154
}
155

156
static int admin_factory_reset(const CAPDU *capdu, RAPDU *rapdu) {
2✔
157
  int ret;
158
  if (P1 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
159
  if (LC != 5) EXCEPT(SW_WRONG_LENGTH);
2✔
160
  if (memcmp_s(DATA, (const uint8_t *)"RESET", 5) != 0) EXCEPT(SW_WRONG_DATA);
2✔
161
#ifndef FUZZ
162
  ret = pin_get_retries(&pin);
2✔
163
  if (ret > 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
2✔
164

165
  if (is_nfc()) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
2✔
166
  if (strong_user_presence_test() < 0) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED);
2✔
167
#endif
168

169
  DBG_MSG("factory reset begins\n");
2✔
170
  ret = openpgp_install(1);
2✔
171
  if (ret < 0) return ret;
2✔
172
  ret = piv_install(1);
2✔
173
  if (ret < 0) return ret;
2✔
174
  ret = oath_install(1);
2✔
175
  if (ret < 0) return ret;
2✔
176
  ret = ctap_install(1);
2✔
177
  if (ret < 0) return ret;
2✔
178
  ret = ndef_install(1);
2✔
179
  if (ret < 0) return ret;
2✔
180
  ret = admin_install(1);
2✔
181
  if (ret < 0) return ret;
2✔
182
  return 0;
2✔
183
}
184

185
void fill_sn(uint8_t *buf) {
186
  int err = read_file(SN_FILE, buf, 0, 4);
314✔
187
  if (err != 4) memset(buf, 0, 4);
314✔
188
}
314✔
189

190
int admin_process_apdu(const CAPDU *capdu, RAPDU *rapdu) {
191
  LL = 0;
319✔
192
  SW = SW_NO_ERROR;
319✔
193

194
  int ret = 0;
319✔
195
  switch (INS) {
319✔
196
  case ADMIN_INS_SELECT:
49✔
197
    if (P1 != 0x04 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
49✔
198
    return 0;
49✔
199

200
  case ADMIN_INS_READ_VERSION:
4✔
201
    if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
4✔
202
    if (P1 == 0)
4✔
203
      ret = admin_vendor_version(capdu, rapdu);
2✔
204
    else if (P1 == 1)
2✔
205
      ret = admin_vendor_hw_variant(capdu, rapdu);
2✔
206
    goto done;
4✔
207

208
  case ADMIN_INS_READ_SN:
4✔
209
    if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
4✔
210
    if (P1 == 0)
4✔
211
      ret = admin_read_sn(capdu, rapdu);
2✔
212
    else if (P1 == 1)
2✔
213
      ret = admin_vendor_hw_sn(capdu, rapdu);
2✔
214
    goto done;
4✔
215

216
  case ADMIN_INS_FACTORY_RESET:
2✔
217
    ret = admin_factory_reset(capdu, rapdu);
2✔
218
    goto done;
2✔
219

220
  case ADMIN_INS_VERIFY:
105✔
221
    ret = admin_verify(capdu, rapdu);
105✔
222
    goto done;
105✔
223
  }
224

225
#ifndef FUZZ
226
  if (!pin.is_validated) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED);
155✔
227
#endif
228

229
  switch (INS) {
94✔
230
  case ADMIN_INS_WRITE_FIDO_PRIVATE_KEY:
1✔
231
    ret = ctap_install_private_key(capdu, rapdu);
1✔
232
    break;
1✔
233
  case ADMIN_INS_WRITE_FIDO_CERT:
1✔
234
    ret = ctap_install_cert(capdu, rapdu);
1✔
235
    break;
1✔
236
  case ADMIN_INS_RESET_OPENPGP:
1✔
237
    ret = openpgp_install(1);
1✔
238
    break;
1✔
239
  case ADMIN_INS_RESET_PIV:
1✔
240
    ret = piv_install(1);
1✔
241
    break;
1✔
242
  case ADMIN_INS_RESET_OATH:
1✔
243
    ret = oath_install(1);
1✔
244
    break;
1✔
245
  case ADMIN_INS_RESET_NDEF:
3✔
246
    ret = ndef_install(1);
3✔
247
    break;
3✔
248
  case ADMIN_INS_TOGGLE_NDEF_READ_ONLY:
22✔
249
    ret = ndef_toggle_read_only(capdu, rapdu);
22✔
250
    break;
22✔
251
  case ADMIN_INS_CHANGE_PIN:
7✔
252
    ret = admin_change_pin(capdu, rapdu);
7✔
253
    break;
7✔
254
  case ADMIN_INS_WRITE_SN:
1✔
255
    ret = admin_write_sn(capdu, rapdu);
1✔
256
    break;
1✔
257
  case ADMIN_INS_CONFIG:
28✔
258
    ret = admin_config(capdu, rapdu);
28✔
259
    break;
28✔
260
  case ADMIN_INS_FLASH_USAGE:
2✔
261
    ret = admin_flash_usage(capdu, rapdu);
2✔
262
    break;
2✔
263
  case ADMIN_INS_READ_CONFIG:
24✔
264
    ret = admin_read_config(capdu, rapdu);
24✔
265
    break;
24✔
266
  case ADMIN_INS_VENDOR_SPECIFIC:
1✔
267
    ret = admin_vendor_specific(capdu, rapdu);
1✔
268
    break;
1✔
269
  default:
1✔
270
    EXCEPT(SW_INS_NOT_SUPPORTED);
1✔
271
  }
272

273
done:
208✔
274
  if (ret < 0) EXCEPT(SW_UNABLE_TO_PROCESS);
208✔
275
  return 0;
208✔
276
}
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