summaryrefslogtreecommitdiff
path: root/tests/secure
diff options
context:
space:
mode:
authorDrashna Jaelre <drashna@live.com>2022-05-14 15:07:08 -0700
committerGitHub <noreply@github.com>2022-05-14 23:07:08 +0100
commitdb887e63d708925ad759e3504a6bc9ceef4aeb8f (patch)
tree7366242dc8834ff5ddb761ff162fa444bf64653f /tests/secure
parentbaa8d07fdb32a35f9ff5020d655271b01e057ddc (diff)
Enhancement and fixes of "Secure" feature (#16958)
Diffstat (limited to 'tests/secure')
-rw-r--r--tests/secure/config.h32
-rw-r--r--tests/secure/test.mk20
-rw-r--r--tests/secure/test_secure.cpp278
3 files changed, 330 insertions, 0 deletions
diff --git a/tests/secure/config.h b/tests/secure/config.h
new file mode 100644
index 0000000000..3cfbc6cb14
--- /dev/null
+++ b/tests/secure/config.h
@@ -0,0 +1,32 @@
1/* Copyright 2021 Stefan Kerkmann
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "test_common.h"
20
21// clang-format off
22#define SECURE_UNLOCK_SEQUENCE \
23 { \
24 {0, 1}, \
25 {0, 2}, \
26 {0, 3}, \
27 {0, 4} \
28 }
29// clang-format on
30
31#define SECURE_UNLOCK_TIMEOUT 20
32#define SECURE_IDLE_TIMEOUT 50
diff --git a/tests/secure/test.mk b/tests/secure/test.mk
new file mode 100644
index 0000000000..ea406493be
--- /dev/null
+++ b/tests/secure/test.mk
@@ -0,0 +1,20 @@
1# Copyright 2021 Stefan Kerkmann
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16# --------------------------------------------------------------------------------
17# Keep this file, even if it is empty, as a marker that this folder contains tests
18# --------------------------------------------------------------------------------
19
20SECURE_ENABLE = yes
diff --git a/tests/secure/test_secure.cpp b/tests/secure/test_secure.cpp
new file mode 100644
index 0000000000..87055ebb7f
--- /dev/null
+++ b/tests/secure/test_secure.cpp
@@ -0,0 +1,278 @@
1/* Copyright 2021 Stefan Kerkmann
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "gtest/gtest.h"
18#include "keyboard_report_util.hpp"
19#include "test_common.hpp"
20
21using testing::_;
22using testing::AnyNumber;
23using testing::InSequence;
24
25class Secure : public TestFixture {
26 public:
27 void SetUp() override {
28 secure_lock();
29 }
30 // Convenience function to tap `key`.
31 void TapKey(KeymapKey key) {
32 key.press();
33 run_one_scan_loop();
34 key.release();
35 run_one_scan_loop();
36 }
37
38 // Taps in order each key in `keys`.
39 template <typename... Ts>
40 void TapKeys(Ts... keys) {
41 for (KeymapKey key : {keys...}) {
42 TapKey(key);
43 }
44 }
45};
46
47TEST_F(Secure, test_lock) {
48 TestDriver driver;
49
50 // Allow any number of empty reports.
51 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
52
53 EXPECT_FALSE(secure_is_unlocked());
54 secure_unlock();
55 EXPECT_TRUE(secure_is_unlocked());
56 run_one_scan_loop();
57 EXPECT_TRUE(secure_is_unlocked());
58 secure_lock();
59 EXPECT_FALSE(secure_is_unlocked());
60
61 testing::Mock::VerifyAndClearExpectations(&driver);
62}
63
64TEST_F(Secure, test_unlock_timeout) {
65 TestDriver driver;
66
67 // Allow any number of empty reports.
68 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
69
70 EXPECT_FALSE(secure_is_unlocked());
71 secure_unlock();
72 EXPECT_TRUE(secure_is_unlocked());
73 idle_for(SECURE_IDLE_TIMEOUT+1);
74 EXPECT_FALSE(secure_is_unlocked());
75
76 testing::Mock::VerifyAndClearExpectations(&driver);
77}
78
79TEST_F(Secure, test_unlock_request) {
80 TestDriver driver;
81 auto key_mo = KeymapKey(0, 0, 0, MO(1));
82 auto key_a = KeymapKey(0, 1, 0, KC_A);
83 auto key_b = KeymapKey(0, 2, 0, KC_B);
84 auto key_c = KeymapKey(0, 3, 0, KC_C);
85 auto key_d = KeymapKey(0, 4, 0, KC_D);
86
87 set_keymap({key_mo, key_a, key_b, key_c, key_d});
88
89 // Allow any number of empty reports.
90 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
91
92 EXPECT_TRUE(secure_is_locked());
93 secure_request_unlock();
94 EXPECT_TRUE(secure_is_unlocking());
95 TapKeys(key_a, key_b, key_c, key_d);
96 EXPECT_TRUE(secure_is_unlocked());
97
98 testing::Mock::VerifyAndClearExpectations(&driver);
99}
100
101TEST_F(Secure, test_unlock_request_fail) {
102 TestDriver driver;
103 auto key_e = KeymapKey(0, 0, 0, KC_E);
104 auto key_a = KeymapKey(0, 1, 0, KC_A);
105 auto key_b = KeymapKey(0, 2, 0, KC_B);
106 auto key_c = KeymapKey(0, 3, 0, KC_C);
107 auto key_d = KeymapKey(0, 4, 0, KC_D);
108
109 set_keymap({key_e, key_a, key_b, key_c, key_d});
110
111 // Allow any number of empty reports.
112 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(AnyNumber());
113 { // Expect the following reports in this order.
114 InSequence s;
115 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A)));
116 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B)));
117 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C)));
118 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_D)));
119 }
120 EXPECT_TRUE(secure_is_locked());
121 secure_request_unlock();
122 EXPECT_TRUE(secure_is_unlocking());
123 TapKeys(key_e, key_a, key_b, key_c, key_d);
124 EXPECT_FALSE(secure_is_unlocked());
125
126 testing::Mock::VerifyAndClearExpectations(&driver);
127}
128
129TEST_F(Secure, test_unlock_request_timeout) {
130 TestDriver driver;
131
132 // Allow any number of empty reports.
133 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
134
135 EXPECT_FALSE(secure_is_unlocked());
136 secure_request_unlock();
137 EXPECT_TRUE(secure_is_unlocking());
138 idle_for(SECURE_UNLOCK_TIMEOUT+1);
139 EXPECT_FALSE(secure_is_unlocking());
140 EXPECT_FALSE(secure_is_unlocked());
141
142 testing::Mock::VerifyAndClearExpectations(&driver);
143}
144
145
146TEST_F(Secure, test_unlock_request_fail_mid) {
147 TestDriver driver;
148 auto key_e = KeymapKey(0, 0, 0, KC_E);
149 auto key_a = KeymapKey(0, 1, 0, KC_A);
150 auto key_b = KeymapKey(0, 2, 0, KC_B);
151 auto key_c = KeymapKey(0, 3, 0, KC_C);
152 auto key_d = KeymapKey(0, 4, 0, KC_D);
153
154 set_keymap({key_e, key_a, key_b, key_c, key_d});
155
156 // Allow any number of empty reports.
157 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(AnyNumber());
158 { // Expect the following reports in this order.
159 InSequence s;
160 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C)));
161 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_D)));
162 }
163 EXPECT_FALSE(secure_is_unlocked());
164 secure_request_unlock();
165 EXPECT_TRUE(secure_is_unlocking());
166 TapKeys(key_a, key_b, key_e, key_c, key_d);
167 EXPECT_FALSE(secure_is_unlocking());
168 EXPECT_FALSE(secure_is_unlocked());
169
170 testing::Mock::VerifyAndClearExpectations(&driver);
171}
172
173TEST_F(Secure, test_unlock_request_fail_out_of_order) {
174 TestDriver driver;
175 auto key_e = KeymapKey(0, 0, 0, KC_E);
176 auto key_a = KeymapKey(0, 1, 0, KC_A);
177 auto key_b = KeymapKey(0, 2, 0, KC_B);
178 auto key_c = KeymapKey(0, 3, 0, KC_C);
179 auto key_d = KeymapKey(0, 4, 0, KC_D);
180
181 set_keymap({key_e, key_a, key_b, key_c, key_d});
182
183 // Allow any number of empty reports.
184 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(AnyNumber());
185 { // Expect the following reports in this order.
186 InSequence s;
187 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B)));
188 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C)));
189 }
190 EXPECT_FALSE(secure_is_unlocked());
191 secure_request_unlock();
192 EXPECT_TRUE(secure_is_unlocking());
193 TapKeys(key_a, key_d, key_b, key_c);
194 EXPECT_TRUE(secure_is_locked());
195 EXPECT_FALSE(secure_is_unlocking());
196 EXPECT_FALSE(secure_is_unlocked());
197
198 testing::Mock::VerifyAndClearExpectations(&driver);
199}
200
201TEST_F(Secure, test_unlock_request_on_layer) {
202 TestDriver driver;
203 auto key_mo = KeymapKey(0, 0, 0, MO(1));
204 auto key_a = KeymapKey(0, 1, 0, KC_A);
205 auto key_b = KeymapKey(0, 2, 0, KC_B);
206 auto key_c = KeymapKey(0, 3, 0, KC_C);
207 auto key_d = KeymapKey(0, 4, 0, KC_D);
208
209 set_keymap({key_mo, key_a, key_b, key_c, key_d});
210
211 // Allow any number of empty reports.
212 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
213
214 EXPECT_TRUE(secure_is_locked());
215 key_mo.press();
216 run_one_scan_loop();
217 secure_request_unlock();
218 key_mo.release();
219 run_one_scan_loop();
220 EXPECT_TRUE(secure_is_unlocking());
221 TapKeys(key_a, key_b, key_c, key_d);
222 EXPECT_TRUE(secure_is_unlocked());
223 EXPECT_FALSE(layer_state_is(1));
224
225 testing::Mock::VerifyAndClearExpectations(&driver);
226}
227
228TEST_F(Secure, test_unlock_request_mid_stroke) {
229 TestDriver driver;
230 auto key_e = KeymapKey(0, 0, 0, KC_E);
231 auto key_a = KeymapKey(0, 1, 0, KC_A);
232 auto key_b = KeymapKey(0, 2, 0, KC_B);
233 auto key_c = KeymapKey(0, 3, 0, KC_C);
234 auto key_d = KeymapKey(0, 4, 0, KC_D);
235
236 set_keymap({key_e, key_a, key_b, key_c, key_d});
237
238 // Allow any number of empty reports.
239 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_E)));
240 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
241 EXPECT_TRUE(secure_is_locked());
242 key_e.press();
243 run_one_scan_loop();
244 secure_request_unlock();
245 key_e.release();
246 run_one_scan_loop();
247 EXPECT_TRUE(secure_is_unlocking());
248 TapKeys(key_a, key_b, key_c, key_d);
249 EXPECT_TRUE(secure_is_unlocked());
250
251 testing::Mock::VerifyAndClearExpectations(&driver);
252}
253
254TEST_F(Secure, test_unlock_request_mods) {
255 TestDriver driver;
256 auto key_lsft = KeymapKey(0, 0, 0, KC_LSFT);
257 auto key_a = KeymapKey(0, 1, 0, KC_A);
258 auto key_b = KeymapKey(0, 2, 0, KC_B);
259 auto key_c = KeymapKey(0, 3, 0, KC_C);
260 auto key_d = KeymapKey(0, 4, 0, KC_D);
261
262 set_keymap({key_lsft, key_a, key_b, key_c, key_d});
263
264 // Allow any number of empty reports.
265 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(key_lsft.report_code)));
266 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
267 EXPECT_TRUE(secure_is_locked());
268 key_lsft.press();
269 run_one_scan_loop();
270 secure_request_unlock();
271 key_lsft.release();
272 run_one_scan_loop();
273 EXPECT_TRUE(secure_is_unlocking());
274 TapKeys(key_a, key_b, key_c, key_d);
275 EXPECT_TRUE(secure_is_unlocked());
276
277 testing::Mock::VerifyAndClearExpectations(&driver);
278}