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

canokeys / canokey-core / 6560615590

18 Oct 2023 12:07PM UTC coverage: 78.769% (-0.06%) from 78.83%
6560615590

push

github

z4yx
prevent overrun in CTAP-HID

19 of 19 new or added lines in 2 files covered. (100.0%)

6129 of 7781 relevant lines covered (78.77%)

605.73 hits per line

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

48.98
/src/device.c
1
// SPDX-License-Identifier: Apache-2.0
2
#include "common.h"
3
#include <admin.h>
4
#include <ccid.h>
5
#include <ctaphid.h>
6
#include <device.h>
7
#include <kbdhid.h>
8
#include <webusb.h>
9

10
volatile static uint8_t touch_result;
11
static uint8_t has_rf;
12
static uint32_t last_blink = UINT32_MAX, blink_timeout, blink_interval;
13
static enum { ON, OFF } led_status;
14
typedef enum { WAIT_NONE = 1, WAIT_CCID, WAIT_CTAPHID, WAIT_DEEP, WAIT_DEEP_TOUCHED, WAIT_DEEP_CANCEL } wait_status_t;
15
volatile static wait_status_t wait_status = WAIT_NONE; // WAIT_NONE is not 0, hence inited
16

17
uint8_t device_is_blinking(void) { return last_blink != UINT32_MAX; }
873✔
18

19
void device_loop(uint8_t has_touch) {
20
  CCID_Loop();
×
21
  CTAPHID_Loop(0);
×
22
  WebUSB_Loop();
×
23
  if (has_touch &&                  // hardware features the touch pad
×
24
      !device_is_blinking() &&      // applets are not waiting for touch
×
25
      cfg_is_kbd_interface_enable() // keyboard emulation enabled
×
26
  )
27
    KBDHID_Loop();
×
28
}
×
29

30
uint8_t get_touch_result(void) {
31
#ifdef TEST // emulate user interaction in test mode
32
  testmode_emulate_user_presence();
422✔
33
#endif
34
  return touch_result;
422✔
35
}
36

37
void set_touch_result(uint8_t result) { touch_result = result; }
844✔
38

39
uint8_t wait_for_user_presence(uint8_t entry) {
40
  start_blinking(0);
386✔
41
  uint32_t start = device_get_tick();
386✔
42
  uint32_t last = start;
386✔
43
  DBG_MSG("start %u\n", start);
386✔
44

45
  wait_status_t shallow = wait_status;
386✔
46
  if (wait_status == WAIT_NONE) {
386✔
47
    switch (entry) {
386✔
48
    case WAIT_ENTRY_CCID:
4✔
49
      wait_status = WAIT_CCID;
4✔
50
      break;
4✔
51
    case WAIT_ENTRY_CTAPHID:
382✔
52
      wait_status = WAIT_CTAPHID;
382✔
53
      break;
382✔
54
    }
55
  } else
56
    wait_status = WAIT_DEEP;
×
57
  while (get_touch_result() == TOUCH_NO) {
386✔
58
    if (wait_status == WAIT_DEEP_TOUCHED || wait_status == WAIT_DEEP_CANCEL) break;
×
59
    if (wait_status == WAIT_CTAPHID) CCID_Loop();
×
60
    if (CTAPHID_Loop(wait_status != WAIT_CCID) == LOOP_CANCEL) {
×
61
      if (wait_status != WAIT_DEEP) {
×
62
        stop_blinking();
×
63
        wait_status = WAIT_NONE; // namely shallow
×
64
      } else
65
        wait_status = WAIT_DEEP_CANCEL;
×
66
      return USER_PRESENCE_CANCEL;
×
67
    }
68
    uint32_t now = device_get_tick();
×
69
    if (now - start >= 30000) {
×
70
      DBG_MSG("timeout at %u\n", now);
×
71
      if (wait_status != WAIT_DEEP) stop_blinking();
×
72
      wait_status = shallow;
×
73
      return USER_PRESENCE_TIMEOUT;
×
74
    }
75
    if (now - last >= 100) {
×
76
      last = now;
×
77
      if (wait_status != WAIT_CCID) CTAPHID_SendKeepAlive(KEEPALIVE_STATUS_UPNEEDED);
×
78
    }
79
  }
80
  set_touch_result(TOUCH_NO);
386✔
81
  if (wait_status != WAIT_DEEP) stop_blinking();
386✔
82
  if (wait_status == WAIT_DEEP)
386✔
83
    wait_status = WAIT_DEEP_TOUCHED;
×
84
  else if (wait_status == WAIT_DEEP_CANCEL) {
386✔
85
    wait_status = WAIT_NONE;
×
86
    return USER_PRESENCE_TIMEOUT;
×
87
  } else
88
    wait_status = WAIT_NONE;
386✔
89
  return USER_PRESENCE_OK;
386✔
90
}
91

92
__attribute__((weak)) int strong_user_presence_test(void) {
93
  for (int i = 0; i < 5; i++) {
×
94
    const uint8_t wait_sec = 2;
×
95
    start_blinking_interval(wait_sec, (i & 1) ? 200 : 50);
×
96
    uint32_t now, begin = device_get_tick();
×
97
    bool user_presence = false;
×
98
    do {
99
      if (get_touch_result() == TOUCH_SHORT) {
×
100
        user_presence = true;
×
101
        set_touch_result(TOUCH_NO);
×
102
        stop_blinking();
×
103
        // wait for some time before next user-precense test
104
        begin = device_get_tick();
×
105
      }
106
      now = device_get_tick();
×
107
    } while (now - begin < 1000 * wait_sec);
×
108
    if (!user_presence) {
×
109
      return -1;
×
110
    }
111
  }
112
  return 0;
×
113
}
114

115
void set_nfc_state(uint8_t val) { has_rf = val; }
1,070✔
116

117
uint8_t is_nfc(void) {
118
#ifdef TEST // read NFC emulation config from a file
119
  testmode_get_is_nfc_mode();
1,073✔
120
#endif
121
  return has_rf;
1,073✔
122
}
123

124
static void toggle_led(void) {
451✔
125
  if (led_status == ON) {
451✔
126
    led_off();
449✔
127
    led_status = OFF;
449✔
128
  } else {
129
    led_on();
2✔
130
    led_status = ON;
2✔
131
  }
132
}
451✔
133

134
void device_update_led(void) {
135
  uint32_t now = device_get_tick();
×
136
  if (now > blink_timeout) stop_blinking();
×
137
  if (now >= last_blink && now - last_blink >= blink_interval) {
×
138
    last_blink = now;
×
139
    toggle_led();
×
140
  }
141
}
×
142

143
void start_blinking_interval(uint8_t sec, uint32_t interval) {
144
  if (device_is_blinking()) return;
451✔
145
  last_blink = device_get_tick();
451✔
146
  blink_interval = interval;
451✔
147
  if (sec == 0) {
451✔
148
    blink_timeout = UINT32_MAX;
415✔
149
  } else {
150
    blink_timeout = last_blink + sec * 1000;
36✔
151
  }
152
  toggle_led();
451✔
153
}
154

155
void stop_blinking(void) {
156
  last_blink = UINT32_MAX;
2,048✔
157
  if (cfg_is_led_normally_on()) {
2,048✔
158
    led_on();
2,036✔
159
    led_status = ON;
2,036✔
160
  } else {
161
    led_off();
12✔
162
    led_status = OFF;
12✔
163
  }
164
}
2,048✔
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