ui.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /* Motenpoche
  2. *
  3. * (c) 2023 Daniele Lacamera <root@danielinux.net>
  4. *
  5. *
  6. * Motenpoche is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Motenpoche is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  19. *
  20. */
  21. #include <stdint.h>
  22. #include "ui.h"
  23. #include "display.h"
  24. #include "bsp/board.h"
  25. #include "hardware/gpio.h"
  26. #include "cryptoengine.h"
  27. #include "wolfssl/wolfcrypt/settings.h"
  28. #include "wolfssl/wolfcrypt/misc.h"
  29. #include "fsm.h"
  30. #include "display.h"
  31. #include "flash.h"
  32. #include "hid.h"
  33. #define PASSPHRASE_MAX 128
  34. #ifndef GREEN_LED
  35. #define GREEN_LED 16
  36. #endif
  37. static const char welcome_message0[]= " There is no ";
  38. static const char welcome_message1[]= "knowledge that ";
  39. static const char welcome_message2[]= " is not power. ";
  40. extern void system_reboot(void);
  41. static uint16_t service_list_selected = 0;
  42. static uint16_t service_list_count = 0;
  43. static void ui_service_list(uint32_t count);
  44. /* UI current state globals */
  45. static int current_row = 1;
  46. static int current_char_pos = 0;
  47. static char current_char = ' ';
  48. static char passphrase[PASSPHRASE_MAX];
  49. static int blinking = 0;
  50. void ui_event_cb(enum vault_state old_st, enum vault_state st)
  51. {
  52. int result = 0;
  53. int ret = -1;
  54. current_char = ' ';
  55. (void)old_st;
  56. switch (st) {
  57. case VAULT_BOOTUP:
  58. display_clear();
  59. display_text(0, "Type Passphrase");
  60. ForceZero(passphrase, PASSPHRASE_MAX);
  61. current_char_pos = 0;
  62. break;
  63. case VAULT_VERIFY_PASSPHRASE:
  64. char msg[17];
  65. display_text(0, "Authenticating..");
  66. display_text(1, " ");
  67. display_text(2, " ");
  68. display_text(3," ");
  69. ret = cryptoengine_verify_passphrase(passphrase, &result);
  70. if ((ret != 0) || (result != 1)) {
  71. fsm_set(VAULT_VERIFY_FAILED);
  72. return;
  73. }
  74. fsm_set(VAULT_MAIN_MENU);
  75. return; /* State changed, avoid non-tail recursion */
  76. case VAULT_MAIN_MENU:
  77. display_text(0," ");
  78. display_text(1," ");
  79. display_text(2," ");
  80. display_text(3," ");
  81. display_text_inverse(0, 2, "[Main Menu]");
  82. gpio_put(GREEN_LED, 0);
  83. break;
  84. case VAULT_SETTINGS_MENU:
  85. display_text(0," ");
  86. display_text(1," ");
  87. display_text(2," ");
  88. display_text(3," ");
  89. display_text_inverse(0, 3, "[Settings]");
  90. break;
  91. case VAULT_SERVICE_LIST:
  92. uint16_t count, spot;
  93. cryptoengine_service_count(&count, &spot);
  94. service_list_count = count;
  95. display_text(0," ");
  96. display_text(1," ");
  97. display_text(2," ");
  98. display_text(3," ");
  99. display_text_inverse(0, 3, "[Services]");
  100. break;
  101. }
  102. ui_task();
  103. }
  104. static const char main_menu_entry[3][17] = {
  105. "[~ Services ~]",
  106. "[~ Settings ~]",
  107. "[~ Reboot ~]"
  108. };
  109. #define MAINMENU_ENTRIES 3
  110. static const char settings_menu_entry[3][17] = {
  111. "[~ Keyb map ~]",
  112. "[~ Paste mode ~]",
  113. "[~ Forget All ~]"
  114. };
  115. #define SETTINGSMENU_ENTRIES 3
  116. static int menu_sel = 0;
  117. static int old_menu_sel = 0xFF;
  118. static const char Keymaps[][17] = {
  119. " [US]",
  120. " [FR]",
  121. " [DE]",
  122. " [UK]",
  123. " [IT]"
  124. };
  125. static int cur_keymap = 0;
  126. #define KEYMAPS_ENTRIES 5
  127. #define PASTEMODE_PASS_ONLY 0
  128. #define PASTEMODE_PASS_ENTER 1
  129. #define PASTEMODE_USER_TAB_PASS_ENTER 2
  130. #define PASTEMODE_USER_ENTER_PASS_ENTER 3
  131. static const char PasteModes[][17] = {
  132. "[Password only ]",
  133. "[Password+Enter]",
  134. "[UserTabPswdEnt]",
  135. "[UserEntPswdEnt]"
  136. };
  137. static int cur_pastemode = 0;
  138. #define PASTEMODE_ENTRIES 4
  139. static const char Are_you_sure[][17] = {
  140. "Sure? NO ",
  141. "Sure? Cancel",
  142. "Sure? My mistake",
  143. "Sure? Whut?",
  144. "Sure? YES DO IT!"
  145. };
  146. static int cur_wipe_choice = 0;
  147. #define AREYOUSURE_ENTRIES 5
  148. static void mainmenu_action(void)
  149. {
  150. switch (menu_sel) {
  151. case 0: /* Services */
  152. fsm_set(VAULT_SERVICE_LIST);
  153. break;
  154. case 1: /* Settings */
  155. fsm_set(VAULT_SETTINGS_MENU);
  156. break;
  157. case 2: /* Reboot */
  158. system_reboot();
  159. break;
  160. }
  161. }
  162. static void settingsmenu_action(void)
  163. {
  164. switch (menu_sel) {
  165. case 0: /* Keymap */
  166. cur_keymap++;
  167. if (cur_keymap == KEYMAPS_ENTRIES)
  168. cur_keymap = 0;
  169. break;
  170. case 1: /* Paste mode */
  171. cur_pastemode++;
  172. if (cur_pastemode == PASTEMODE_ENTRIES)
  173. cur_pastemode = 0;
  174. break;
  175. case 2: /* Forget */
  176. cur_wipe_choice++;
  177. if (cur_wipe_choice == AREYOUSURE_ENTRIES)
  178. cur_wipe_choice = 0;
  179. break;
  180. }
  181. /* Force redraw */
  182. old_menu_sel = 0xFF;
  183. }
  184. static void settingsmenu_confirm(void)
  185. {
  186. int i;
  187. if ((menu_sel == 2) && (cur_wipe_choice == 4)) {
  188. for (i = 0; i < VAULT_FLASH_SIZE; i+= SPI_FLASH_SECTOR_SIZE)
  189. flash_sector_erase(i);
  190. system_reboot();
  191. } else
  192. settingsmenu_action();
  193. }
  194. static void ui_service_list(uint32_t count)
  195. {
  196. static int old_selected = -1;
  197. int i = 0;
  198. uint32_t address = SVC_FLASH_OFFSET;
  199. uint32_t a_sel, a_prev = 0, a_next = 0;
  200. struct vault_service svc;
  201. if (old_selected == (int)service_list_selected)
  202. return;
  203. old_selected = service_list_selected;
  204. if (count == 0)
  205. return;
  206. flash_read(address + service_list_selected * SVC_SIZE,
  207. (void *)&svc, SVC_SIZE);
  208. if (svc.flags != SVC_FLAG_ACTIVE) {
  209. i = 0;
  210. while (address < VAULT_FLASH_SIZE) {
  211. flash_read(address + i * SVC_SIZE, &svc, SVC_SIZE);
  212. if (svc.flags == SVC_FLAG_ACTIVE) {
  213. service_list_selected = i;
  214. break;
  215. }
  216. i += SVC_SIZE;
  217. }
  218. }
  219. a_sel = SVC_FLASH_OFFSET + service_list_selected * SVC_SIZE;
  220. a_next = 0;
  221. a_prev = 0;
  222. /* Find previous entry */
  223. if (service_list_selected != 0) {
  224. i = 1;
  225. address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected - i);
  226. while (address >= SVC_FLASH_OFFSET) {
  227. flash_read(address, (void *)&svc, SVC_SIZE);
  228. if (svc.flags == SVC_FLAG_ACTIVE) {
  229. a_prev = address;
  230. break;
  231. }
  232. i++;
  233. address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected - i);
  234. }
  235. }
  236. /* Find next entry */
  237. i = 1;
  238. address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected + i);
  239. while (address < VAULT_FLASH_SIZE) {
  240. flash_read(address, (void *)&svc, SVC_SIZE);
  241. if (svc.flags == SVC_FLAG_ACTIVE) {
  242. a_next = address;
  243. break;
  244. } else if (svc.flags == SVC_FLAG_UNUSED) {
  245. break;
  246. }
  247. i++;
  248. address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected + i);
  249. }
  250. display_text(1," ");
  251. display_text(2," ");
  252. display_text(3," ");
  253. if (a_prev != 0) {
  254. flash_decrypt_read_svc(&svc, a_prev);
  255. display_text(1, svc.name);
  256. }
  257. if (a_next != 0) {
  258. flash_decrypt_read_svc(&svc, a_next);
  259. display_text(3, svc.name);
  260. }
  261. flash_decrypt_read_svc(&svc, a_sel);
  262. display_text_inverse(2, 0, svc.name);
  263. }
  264. static void paste_password(void)
  265. {
  266. struct vault_service svc;
  267. uint32_t address;
  268. if (fsm_get() != VAULT_SERVICE_LIST)
  269. return;
  270. if (flash_decrypt_read_svc(&svc, SVC_FLASH_OFFSET +
  271. service_list_selected * SVC_SIZE) < 0)
  272. return;
  273. switch(cur_pastemode) {
  274. case PASTEMODE_PASS_ONLY:
  275. hid_keys_string_send(svc.pass);
  276. break;
  277. case PASTEMODE_PASS_ENTER:
  278. hid_keys_string_send(svc.pass);
  279. hid_keys_string_send("\r");
  280. break;
  281. case PASTEMODE_USER_TAB_PASS_ENTER:
  282. hid_keys_string_send(svc.user);
  283. hid_keys_string_send("\t");
  284. hid_keys_string_send(svc.pass);
  285. hid_keys_string_send("\r");
  286. break;
  287. case PASTEMODE_USER_ENTER_PASS_ENTER:
  288. hid_keys_string_send(svc.user);
  289. hid_keys_string_send("\t");
  290. hid_keys_string_send(svc.pass);
  291. hid_keys_string_send("\r");
  292. break;
  293. }
  294. }
  295. void ui_task(void)
  296. {
  297. const uint32_t interval_ms = 500;
  298. static uint32_t start_ms = 0;
  299. if ( board_millis() - start_ms >= interval_ms) {
  300. blinking ^= 1;
  301. start_ms = board_millis();
  302. }
  303. switch(fsm_get()) {
  304. case VAULT_TOFU:
  305. gpio_put(17, blinking ^ 1);
  306. display_text(0, " Welcome!");
  307. display_text(1, "Run tools on PC ");
  308. display_text(2, " to initialize ");
  309. break;
  310. case VAULT_BOOTUP:
  311. char pass_prompt[16];
  312. int i;
  313. int sz;
  314. gpio_put(17, blinking ^ 1);
  315. sz = current_char_pos;
  316. if (sz > 15)
  317. sz = 15;
  318. memset(pass_prompt, 0, 16);
  319. for (i = 0; i < sz; i++) {
  320. pass_prompt[i] = '*';
  321. }
  322. if (!blinking)
  323. pass_prompt[sz] = current_char;
  324. display_text(1, pass_prompt);
  325. if (blinking) {
  326. char cursor[2] = {current_char, 0};
  327. display_text_inverse(1, sz, cursor);
  328. }
  329. break;
  330. case VAULT_VERIFY_PASSPHRASE:
  331. display_text(2, "Verifying...");
  332. gpio_put(17, blinking ^ 1);
  333. break;
  334. case VAULT_VERIFY_FAILED:
  335. display_text(0, " Bad Passphrase ");
  336. gpio_put(17, 0);
  337. if (blinking) {
  338. display_text(1," ");
  339. display_text(2," ");
  340. display_text_inverse(1, 4, "(x_x)");
  341. display_text_inverse(2, 3, "Try again");
  342. } else {
  343. display_text(1, " (x_x) ");
  344. display_text(2, " ");
  345. }
  346. break;
  347. case VAULT_MAIN_MENU:
  348. display_text(2,main_menu_entry[menu_sel]);
  349. break;
  350. case VAULT_SETTINGS_MENU:
  351. if (old_menu_sel != menu_sel) {
  352. old_menu_sel = menu_sel;
  353. display_text(1, " ");
  354. display_text(2, " ");
  355. display_text(3, " ");
  356. display_text(2,settings_menu_entry[menu_sel]);
  357. switch(menu_sel) {
  358. case 0: /* Keymap */
  359. display_text(3, Keymaps[cur_keymap]);
  360. break;
  361. case 1:
  362. display_text(3, PasteModes[cur_pastemode]);
  363. break;
  364. case 2:
  365. display_text(3, Are_you_sure[cur_wipe_choice]);
  366. break;
  367. }
  368. }
  369. break;
  370. case VAULT_SERVICE_LIST:
  371. if (service_list_count == 0) {
  372. display_text(2, " No Services ");
  373. break;
  374. } else {
  375. ui_service_list(service_list_count);
  376. }
  377. break;
  378. }
  379. }
  380. void ui_key_button(void)
  381. {
  382. static int alter = 0;
  383. enum vault_state vs = fsm_get();
  384. if (vs == VAULT_BOOTUP) {
  385. passphrase[current_char_pos] = current_char;
  386. current_char_pos++;
  387. if(current_char_pos >= PASSPHRASE_MAX) {
  388. fsm_set(VAULT_VERIFY_FAILED);
  389. return;
  390. }
  391. passphrase[current_char_pos] = 0;
  392. gpio_put(17, alter);
  393. alter ^=1;
  394. } else if (vs == VAULT_MAIN_MENU)
  395. mainmenu_action();
  396. else if (vs == VAULT_SETTINGS_MENU)
  397. settingsmenu_action();
  398. else if (vs == VAULT_SERVICE_LIST)
  399. paste_password();
  400. }
  401. void ui_back_button(void)
  402. {
  403. enum vault_state vault_state = fsm_get();
  404. if (vault_state == VAULT_BOOTUP) {
  405. if (current_char_pos > 0) {
  406. passphrase[current_char_pos] = '\0';
  407. current_char_pos--;
  408. }
  409. display_text(1, " ");
  410. }
  411. else if (vault_state == VAULT_VERIFY_FAILED) {
  412. current_char_pos = 0;
  413. fsm_set(VAULT_BOOTUP);
  414. }
  415. else if (vault_state == VAULT_SETTINGS_MENU)
  416. fsm_set(VAULT_MAIN_MENU);
  417. else if (vault_state == VAULT_SERVICE_LIST)
  418. fsm_set(VAULT_MAIN_MENU);
  419. }
  420. void ui_confirm_button(void)
  421. {
  422. enum vault_state vault_state = fsm_get();
  423. if (vault_state == VAULT_BOOTUP) {
  424. current_char_pos = 0;
  425. fsm_set(VAULT_VERIFY_PASSPHRASE);
  426. }
  427. else if (vault_state == VAULT_MAIN_MENU)
  428. mainmenu_action();
  429. else if (vault_state == VAULT_SETTINGS_MENU)
  430. settingsmenu_confirm();
  431. else if (vault_state == VAULT_SERVICE_LIST)
  432. paste_password();
  433. }
  434. void ui_rot_up(void)
  435. {
  436. enum vault_state vault_state = fsm_get();
  437. if (vault_state == VAULT_BOOTUP) {
  438. current_char++;
  439. if (current_char > 126)
  440. current_char = ' ';
  441. }
  442. else if (vault_state == VAULT_MAIN_MENU) {
  443. menu_sel++;
  444. if (menu_sel == MAINMENU_ENTRIES)
  445. menu_sel = 0;
  446. }
  447. else if (vault_state == VAULT_SETTINGS_MENU) {
  448. menu_sel++;
  449. cur_wipe_choice = 0;
  450. if (menu_sel == MAINMENU_ENTRIES)
  451. menu_sel = 0;
  452. }
  453. else if (vault_state == VAULT_SERVICE_LIST) {
  454. if (service_list_selected > 0)
  455. service_list_selected --;
  456. }
  457. }
  458. void ui_rot_down(void)
  459. {
  460. enum vault_state vault_state = fsm_get();
  461. if (vault_state == VAULT_BOOTUP) {
  462. current_char--;
  463. if (current_char < ' ')
  464. current_char = 126;
  465. }
  466. else if (vault_state == VAULT_MAIN_MENU) {
  467. menu_sel--;
  468. if (menu_sel < 0)
  469. menu_sel = MAINMENU_ENTRIES - 1;
  470. }
  471. else if (vault_state == VAULT_SETTINGS_MENU) {
  472. menu_sel--;
  473. cur_wipe_choice = 0;
  474. if (menu_sel < 0)
  475. menu_sel = SETTINGSMENU_ENTRIES - 1;
  476. }
  477. else if (vault_state == VAULT_SERVICE_LIST) {
  478. struct vault_service svc;
  479. int next = service_list_selected + 1;
  480. while (1) {
  481. flash_read(SVC_FLASH_OFFSET + next * SVC_SIZE, &svc, SVC_SIZE);
  482. if (svc.flags == SVC_FLAG_UNUSED)
  483. return; /* Keep old value */
  484. else if (svc.flags == SVC_FLAG_ERASED) {
  485. next++;
  486. } else {
  487. service_list_selected = next;
  488. break;
  489. }
  490. }
  491. }
  492. }
  493. void ui_init(i2c_inst_t *i2c)
  494. {
  495. int i;
  496. display_init(i2c);
  497. display_clear();
  498. #ifdef SHOW_MOTD
  499. display_scroll(0x3f);
  500. display_text(0, welcome_message0);
  501. display_text(1, welcome_message1);
  502. display_text(2, welcome_message2);
  503. for (i = 0x3f; i >= 0x20; i--) {
  504. display_scroll(i);
  505. sleep_us(50000);
  506. }
  507. for (i = display_getcontrast(); i >= 0; i--) {
  508. display_setcontrast(i);
  509. sleep_us(10000);
  510. }
  511. display_scroll(0);
  512. display_clear();
  513. #endif
  514. display_setcontrast(0xcf);
  515. current_char_pos = 0;
  516. sleep_us(50000);
  517. display_scroll(0x20);
  518. if (cryptoengine_check_vault() < 0)
  519. fsm_set(VAULT_TOFU);
  520. else
  521. fsm_set(VAULT_BOOTUP);
  522. }
  523. void ui_event(uint32_t ev)
  524. {
  525. }