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

canokeys / canokey-core / 7190499538

13 Dec 2023 03:52AM UTC coverage: 79.565% (+0.03%) from 79.532%
7190499538

push

github

web-flow
Merge pull request #74 from canokeys/feature/fix_warnings

Feature/fix warnings

154 of 175 new or added lines in 10 files covered. (88.0%)

1 existing line in 1 file now uncovered.

6253 of 7859 relevant lines covered (79.56%)

590.78 hits per line

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

96.37
/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

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

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

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

21
static admin_device_config_t current_config;
22

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

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

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

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

47
uint8_t cfg_is_led_normally_on(void) { return current_config.led_normally_on; }
2,018✔
48

49
uint8_t cfg_is_kbd_interface_enable(void) { return current_config.kbd_interface_en; }
×
50

51
uint8_t cfg_is_ndef_enable(void) { return current_config.ndef_en; }
20✔
52

53
uint8_t cfg_is_webusb_landing_enable(void) { return current_config.webusb_landing_en; }
×
54

55
uint8_t cfg_is_kbd_with_return_enable(void) { return current_config.kbd_with_return_en; }
×
56

57
uint8_t cfg_is_piv_algo_extension_enable(void) { return current_config.piv_algo_ext_en; }
12✔
58

59
void admin_poweroff(void) { pin.is_validated = 0; }
68✔
60

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

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

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

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

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

111
  fill_sn(RDATA);
2✔
112
  LL = 4;
2✔
113

114
  return 0;
2✔
115
}
116

117
static int admin_config(const CAPDU *capdu, RAPDU *rapdu) {
28✔
118
  switch (P1) {
28✔
119
  case ADMIN_P1_CFG_LED_ON:
4✔
120
    current_config.led_normally_on = P2 & 1;
4✔
121
    break;
4✔
122
  case ADMIN_P1_CFG_KBDIFACE:
4✔
123
    current_config.kbd_interface_en = P2 & 1;
4✔
124
    break;
4✔
125
  case ADMIN_P1_CFG_NDEF:
6✔
126
    current_config.ndef_en = P2 & 1;
6✔
127
    break;
6✔
128
  case ADMIN_P1_CFG_WEBUSB_LANDING:
4✔
129
    current_config.webusb_landing_en = P2 & 1;
4✔
130
    break;
4✔
131
  case ADMIN_P1_CFG_KBD_WITH_RETURN:
4✔
132
    current_config.kbd_with_return_en = P2 & 1;
4✔
133
    break;
4✔
134
  case ADMIN_P1_CFG_PIV_ALGO_EXT:
2✔
135
    current_config.piv_algo_ext_en = P2 & 1;
2✔
136
    break;
2✔
137
  default:
4✔
138
    EXCEPT(SW_WRONG_P1P2);
4✔
139
  }
140
  const int ret = write_file(CFG_FILE, &current_config, 0, sizeof(current_config), 1);
24✔
141
  stop_blinking();
24✔
142
  return ret;
24✔
143
}
144

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

149
  RDATA[0] = current_config.led_normally_on;
24✔
150
  RDATA[1] = current_config.kbd_interface_en;
24✔
151
  RDATA[2] = ndef_get_read_only();
24✔
152
  RDATA[3] = current_config.ndef_en;
24✔
153
  RDATA[4] = current_config.webusb_landing_en;
24✔
154
  RDATA[5] = current_config.kbd_with_return_en;
24✔
155
  LL = 6;
24✔
156

157
  return 0;
24✔
158
}
159

160
static int admin_flash_usage(const CAPDU *capdu, RAPDU *rapdu) {
2✔
161
  if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
162
  if (LE < 2) EXCEPT(SW_WRONG_LENGTH);
2✔
163

164
  RDATA[0] = get_fs_usage();
2✔
165
  RDATA[1] = get_fs_size();
2✔
166
  LL = 2;
2✔
167

168
  return 0;
2✔
169
}
170

171
static int admin_factory_reset(const CAPDU *capdu, RAPDU *rapdu) {
2✔
172
  int ret;
173
  if (P1 != 0x00) EXCEPT(SW_WRONG_P1P2);
2✔
174
  if (LC != 5) EXCEPT(SW_WRONG_LENGTH);
2✔
175
  if (memcmp_s(DATA, "RESET", 5) != 0) EXCEPT(SW_WRONG_DATA);
2✔
176
#ifndef FUZZ
177
  ret = pin_get_retries(&pin);
2✔
178
  if (ret > 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
2✔
179

180
  if (is_nfc()) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);
2✔
181
  if (strong_user_presence_test() < 0) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED);
2✔
182
#endif
183

184
  DBG_MSG("factory reset begins\n");
2✔
185
  ret = openpgp_install(1);
2✔
186
  if (ret < 0) return ret;
2✔
187
  ret = piv_install(1);
2✔
188
  if (ret < 0) return ret;
2✔
189
  ret = oath_install(1);
2✔
190
  if (ret < 0) return ret;
2✔
191
  ret = ctap_install(1);
2✔
192
  if (ret < 0) return ret;
2✔
193
  ret = ndef_install(1);
2✔
194
  if (ret < 0) return ret;
2✔
195
  ret = admin_install(1);
2✔
196
  if (ret < 0) return ret;
2✔
197
  return 0;
2✔
198
}
199

200
void fill_sn(uint8_t *buf) {
201
  const int err = read_file(SN_FILE, buf, 0, 4);
321✔
202
  if (err != 4) memset(buf, 0, 4);
321✔
203
}
321✔
204

205
int admin_process_apdu(const CAPDU *capdu, RAPDU *rapdu) {
206
  LL = 0;
329✔
207
  SW = SW_NO_ERROR;
329✔
208

209
  int ret = 0;
329✔
210
  switch (INS) {
329✔
211
  case ADMIN_INS_SELECT:
54✔
212
    if (P1 != 0x04 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
54✔
213
    return 0;
54✔
214

215
  case ADMIN_INS_READ_VERSION:
9✔
216
    if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
9✔
217
    if (P1 == 0)
9✔
218
      ret = admin_vendor_version(capdu, rapdu);
7✔
219
    else if (P1 == 1)
2✔
220
      ret = admin_vendor_hw_variant(capdu, rapdu);
2✔
221
    goto done;
9✔
222

223
  case ADMIN_INS_READ_SN:
4✔
224
    if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
4✔
225
    if (P1 == 0)
4✔
226
      ret = admin_read_sn(capdu, rapdu);
2✔
227
    else if (P1 == 1)
2✔
228
      ret = admin_vendor_hw_sn(capdu, rapdu);
2✔
229
    goto done;
4✔
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:
105✔
236
    ret = admin_verify(capdu, rapdu);
105✔
237
    goto done;
105✔
238

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

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

247
  switch (INS) {
94✔
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_CHANGE_PIN:
7✔
270
    ret = admin_change_pin(capdu, rapdu);
7✔
271
    break;
7✔
272
  case ADMIN_INS_WRITE_SN:
1✔
273
    ret = admin_write_sn(capdu, rapdu);
1✔
274
    break;
1✔
275
  case ADMIN_INS_CONFIG:
28✔
276
    ret = admin_config(capdu, rapdu);
28✔
277
    break;
28✔
278
  case ADMIN_INS_FLASH_USAGE:
2✔
279
    ret = admin_flash_usage(capdu, rapdu);
2✔
280
    break;
2✔
281
  case ADMIN_INS_READ_CONFIG:
24✔
282
    ret = admin_read_config(capdu, rapdu);
24✔
283
    break;
24✔
284
  case ADMIN_INS_VENDOR_SPECIFIC:
1✔
285
    ret = admin_vendor_specific(capdu, rapdu);
1✔
286
    break;
1✔
287
  default:
1✔
288
    EXCEPT(SW_INS_NOT_SUPPORTED);
1✔
289
  }
290

291
done:
213✔
292
  if (ret < 0) EXCEPT(SW_UNABLE_TO_PROCESS);
213✔
293
  return 0;
213✔
294
}
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