mep.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. #include <stdint.h>
  2. #include <wolfssl/options.h>
  3. #include <wolfssl/wolfcrypt/settings.h>
  4. #include <wolfssl/wolfcrypt/ecc.h>
  5. #include <wolfssl/wolfcrypt/pwdbased.h>
  6. #include <wolfssl/wolfcrypt/sha512.h>
  7. #include <wolfssl/wolfcrypt/chacha.h>
  8. #include "../src/cryptoengine.h"
  9. #include <fcntl.h>
  10. #include <err.h>
  11. #include <termio.h>
  12. #include <linux/serial.h>
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #include <sys/poll.h>
  16. #define HOMEPATH_PREFIX "~/.pvault"
  17. //#define HOMEPATH_PREFIX "/root/.pvault"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #define MAX_SVC_NAME_LEN 16
  22. static char pass_prompt[200] = "";
  23. static char pass_confirm[200] = "";
  24. static const char pass_prompt_phrase[] = "Enter your passphrase: ";
  25. static const char pass_confirm_phrase[] = "Confirm your passphrase : ";
  26. static const char pass_prompt_svc[] = "Password: ";
  27. static const char pass_confirm_svc[] = "Confirm Password: ";
  28. static int sfd = -1;;
  29. static int pk_fd = -1;
  30. static struct vault_status Status = { };
  31. static int get_vault_status(void);
  32. struct __attribute__((packed)) tofu_packet {
  33. uint32_t cdc_magic; /* 0x5afeca5e */
  34. uint16_t cdc_cmd;
  35. uint16_t cdc_len;
  36. struct vault_header vh;
  37. };
  38. void clearScreen() {
  39. system("clear");
  40. }
  41. void disableEcho() {
  42. struct termios term;
  43. tcgetattr(0, &term);
  44. term.c_lflag &= ~ECHO;
  45. tcsetattr(0, TCSANOW, &term);
  46. }
  47. void enableEcho() {
  48. struct termios term;
  49. tcgetattr(0, &term);
  50. term.c_lflag |= ECHO;
  51. tcsetattr(0, TCSANOW, &term);
  52. }
  53. void printPrompt() {
  54. printf(pass_prompt);
  55. }
  56. static void getPassword(char *password, int size) {
  57. int i = 0;
  58. char c;
  59. while (i < size - 1) {
  60. c = getchar();
  61. if (c == '\n') {
  62. break;
  63. }
  64. password[i++] = c;
  65. if (i >= 99)
  66. break;
  67. }
  68. password[i] = '\0';
  69. }
  70. int confirmPassphrase(const char *passphrase) {
  71. char confirmation[100];
  72. printf(pass_confirm);
  73. getPassword(confirmation, sizeof(confirmation));
  74. return strcmp(passphrase, confirmation) == 0;
  75. }
  76. static char passphrase[100];
  77. static int askpass(void)
  78. {
  79. int ret = 0;
  80. disableEcho();
  81. printPrompt();
  82. getPassword(passphrase, sizeof(passphrase));
  83. printf("\n");
  84. if (confirmPassphrase(passphrase)) {
  85. printf("\nConfirmed.\n");
  86. ret = 1;
  87. } else {
  88. printf("These passwords don't match. Please try again.\n");
  89. }
  90. enableEcho();
  91. return ret;
  92. }
  93. static int rate_to_constant(int baudrate) {
  94. #ifdef __MACH__
  95. #define B(x) case x: return x
  96. #else
  97. #define B(x) case x: return B##x
  98. #endif
  99. switch(baudrate) {
  100. B(50); B(75); B(110); B(134); B(150);
  101. B(200); B(300); B(600); B(1200); B(1800);
  102. B(2400); B(4800); B(9600); B(19200); B(38400);
  103. B(57600); B(115200); B(230400); B(460800); B(500000);
  104. B(576000); B(921600); B(1000000);B(1152000);B(1500000);
  105. default: return 0;
  106. }
  107. #undef B
  108. }
  109. /* Open serial port in raw mode, with custom baudrate if necessary */
  110. static int serial_open(const char *device, int rate)
  111. {
  112. struct termios options;
  113. int fd;
  114. int speed = 0;
  115. /* Open and configure serial port */
  116. if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1)
  117. return -1;
  118. speed = rate_to_constant(rate);
  119. #ifndef __MACH__
  120. if (speed == 0) {
  121. /* Custom divisor */
  122. struct serial_struct serinfo;
  123. serinfo.reserved_char[0] = 0;
  124. if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
  125. return -1;
  126. serinfo.flags &= ~ASYNC_SPD_MASK;
  127. serinfo.flags |= ASYNC_SPD_CUST;
  128. serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate;
  129. if (serinfo.custom_divisor < 1)
  130. serinfo.custom_divisor = 1;
  131. if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
  132. return -1;
  133. if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
  134. return -1;
  135. if (serinfo.custom_divisor * rate != serinfo.baud_base) {
  136. warnx("actual baudrate is %d / %d = %f",
  137. serinfo.baud_base, serinfo.custom_divisor,
  138. (float)serinfo.baud_base / serinfo.custom_divisor);
  139. }
  140. }
  141. #endif
  142. fcntl(fd, F_SETFL, 0);
  143. tcgetattr(fd, &options);
  144. cfsetispeed(&options, speed ?: 460800);
  145. cfsetospeed(&options, speed ?: 460800);
  146. cfmakeraw(&options);
  147. options.c_cflag |= (CLOCAL | CREAD);
  148. options.c_cflag &= ~CRTSCTS;
  149. if (tcsetattr(fd, TCSANOW, &options) != 0)
  150. return -1;
  151. return fd;
  152. }
  153. static int tofu(const char *password)
  154. {
  155. int ret = 0, i;
  156. int outlen = CRYPTO_KEY_SIZE;
  157. int siglen = PK_SIGNATURE_SIZE;
  158. uint8_t clr_sig[PK_SIGNATURE_SIZE];
  159. struct tofu_packet tofu;
  160. uint8_t Ke[CRYPTO_KEY_SIZE], Sm[CRYPTO_KEY_SIZE];
  161. uint8_t resp[256];
  162. char privkey_fname[32];
  163. uint32_t mgc = 0xffffffff;
  164. int hash, hash_len;
  165. uint8_t iv[24];
  166. uint8_t sig_dec_verify[64];
  167. struct pollfd pfd;
  168. uint32_t qxLen = CRYPTO_KEY_SIZE, qyLen = CRYPTO_KEY_SIZE,
  169. dLen = CRYPTO_KEY_SIZE;
  170. tofu.cdc_magic = VAULT_MAGIC;
  171. tofu.cdc_cmd = CDC_TOFU_INIT;
  172. tofu.cdc_len = sizeof(struct tofu_packet) - 8;
  173. tofu.vh.magic = VAULT_MAGIC;
  174. tofu.vh.size = sizeof(struct tofu_packet) - 8;
  175. ecc_key ecc;
  176. ChaCha cha;
  177. RNG rng;
  178. Sha512 sha;
  179. /* Initialize Rng (needed for master key + salt + secret */
  180. wc_InitRng(&rng);
  181. /* Generate ID */
  182. wc_RNG_GenerateBlock(&rng, (void *)tofu.vh.id, 8);
  183. sprintf(privkey_fname, "%08x-%08x.der", tofu.vh.id[0], tofu.vh.id[1]);
  184. printf("ID: %s\n", privkey_fname);
  185. /* Generate salt */
  186. wc_RNG_GenerateBlock(&rng, tofu.vh.host_salt, SALT_LEN);
  187. printf("Salt: ");
  188. for (i = 0; i < SALT_LEN; i++) {
  189. printf("%02x", tofu.vh.host_salt[i]);
  190. }
  191. printf("\n");
  192. /* Derive device key (password based) to create encryption key */
  193. ret = wc_PBKDF2(Ke, password, strlen(password), tofu.vh.host_salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512);
  194. wc_Chacha_SetKey(&cha, Ke, CRYPTO_KEY_SIZE);
  195. wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0);
  196. /* Generate master signing key */
  197. wc_ecc_init(&ecc);
  198. wc_ecc_make_key(&rng, CRYPTO_KEY_SIZE, &ecc);
  199. qxLen = CRYPTO_KEY_SIZE;
  200. qyLen = CRYPTO_KEY_SIZE;
  201. wc_ecc_export_public_raw(&ecc, tofu.vh.auth_pubkey, &qxLen, tofu.vh.auth_pubkey + CRYPTO_KEY_SIZE, &qyLen);
  202. printf("Public signing key %d: ", qxLen + qyLen);
  203. for (i = 0; i < qxLen + qyLen; i++) {
  204. printf("%02x", tofu.vh.auth_pubkey[i]);
  205. }
  206. printf("\n");
  207. /* Generate key seed */
  208. wc_RNG_GenerateBlock(&rng, tofu.vh.host_seed, SEED_LEN);
  209. printf("Seed: ");
  210. for (i = 0; i < SEED_LEN; i++) {
  211. printf("%02x", tofu.vh.host_seed[i]);
  212. }
  213. printf("\n");
  214. wc_InitSha512(&sha);
  215. for (hash = 0; hash < SHA_PAYLOAD_SIZE;) {
  216. hash_len = WC_SHA512_BLOCK_SIZE;
  217. if ((SHA_PAYLOAD_SIZE - hash) < hash_len)
  218. hash_len = SHA_PAYLOAD_SIZE - hash;
  219. wc_Sha512Update(&sha, ((uint8_t*)&tofu.vh) + hash, hash_len);
  220. hash += hash_len;
  221. printf("update %d/%d\n", hash, SHA_PAYLOAD_SIZE);
  222. }
  223. wc_Sha512Final(&sha, tofu.vh.digest);
  224. printf("Digest (%d): ", sizeof(tofu.vh.digest));
  225. for (i = 0; i < sizeof(tofu.vh.digest); i++) {
  226. printf("%02x ", tofu.vh.digest[i]);
  227. if ((i % 16) == 15)
  228. printf("\n");
  229. }
  230. printf("\n");
  231. wc_Sha512Free(&sha);
  232. {
  233. mp_int r, s;
  234. mp_init(&r); mp_init(&s);
  235. ret = wc_ecc_sign_hash_ex(tofu.vh.digest, VAULT_DIGEST_SIZE, &rng, &ecc,
  236. &r, &s);
  237. mp_to_unsigned_bin(&r, &clr_sig[0]);
  238. mp_to_unsigned_bin(&s, &clr_sig[CRYPTO_KEY_SIZE]);
  239. mp_clear(&r);
  240. mp_clear(&s);
  241. }
  242. printf("Signature (%d) returned %d:\n", PK_SIGNATURE_SIZE, ret);
  243. for (i = 0; i < PK_SIGNATURE_SIZE; i++) {
  244. printf("%02x ", clr_sig[i]);
  245. if ((i % 16) == 15)
  246. printf("\n");
  247. }
  248. printf("\n");
  249. {
  250. int vr, vres;
  251. mp_int r, s;
  252. mp_init(&r); mp_init(&s);
  253. mp_read_unsigned_bin(&r, &clr_sig[0], CRYPTO_KEY_SIZE);
  254. mp_read_unsigned_bin(&s, &clr_sig[CRYPTO_KEY_SIZE], CRYPTO_KEY_SIZE);
  255. vr = wc_ecc_verify_hash_ex(&r, &s, tofu.vh.digest, VAULT_DIGEST_SIZE,
  256. &vres, &ecc);
  257. mp_clear(&r);
  258. mp_clear(&s);
  259. printf("sanity check verify ret %d res %d\n", vr, vres);
  260. }
  261. wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0);
  262. wc_Chacha_Process(&cha, tofu.vh.signature, clr_sig, siglen);
  263. wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0);
  264. wc_Chacha_Process(&cha, sig_dec_verify, tofu.vh.signature, siglen);
  265. if (memcmp(clr_sig, sig_dec_verify, siglen) != 0) {
  266. printf("Error verifying chacha encryption\n");
  267. return 4;
  268. }
  269. printf("Packet (%d): ", sizeof(tofu));
  270. for (i = 0; i < sizeof(tofu); i++) {
  271. printf("%02x ", *(((uint8_t*)(&tofu)) + i));
  272. if ((i % 16) == 15)
  273. printf("\n");
  274. }
  275. printf("\n");
  276. pfd.fd = sfd;
  277. pfd.events = POLLIN;
  278. for(i = 0; i < 10; i++) {
  279. char buf[8];
  280. ret = poll(&pfd, 1, 100);
  281. if (ret > 0) {
  282. read(sfd, buf, 8);
  283. }
  284. }
  285. ret = write(sfd, &tofu, sizeof(tofu));
  286. printf("Sent %d/%d bvtes (tofu) \r\n", ret, sizeof(tofu));
  287. do {
  288. ret = read(sfd, &mgc, 4);
  289. } while (mgc != 0x5afeca5e);
  290. memcpy (resp, &mgc, 4);
  291. ret = read(sfd, resp + 4, 64 + 4);
  292. if (ret >= 4) {
  293. uint16_t code = *((uint16_t *)(resp + 4));
  294. uint16_t len = *((uint16_t *)(resp + 6));
  295. printf("received %d bytes: resp %04x len %04x\n", ret + 4, *((uint16_t *)(resp + 4)), *((uint16_t *)(resp + 6)));
  296. if (ret > 4) {
  297. printf("MSG: %s\r\n", resp + 8);
  298. }
  299. if (code == CDC_OK) {
  300. int fd;
  301. uint8_t privkey_buf[2 * CRYPTO_KEY_SIZE];
  302. char pkfname[MAX_PATH];
  303. char *homedir;
  304. homedir = getenv("HOME");
  305. if (!homedir || strlen(homedir) == 0) {
  306. perror("getenv(HOME)");
  307. exit(1);
  308. }
  309. snprintf(pkfname, MAX_PATH - 1, "%s/.pvault/%s", homedir, privkey_fname);
  310. printf("Saving private key %s\n", privkey_fname);
  311. fd = open(pkfname, O_WRONLY | O_CREAT | O_EXCL, 0600);
  312. if (fd < 0) {
  313. printf("FATAL Error opening private key: %s\n", strerror(errno));
  314. return 6;
  315. }
  316. outlen = 2 * CRYPTO_KEY_SIZE;
  317. if (wc_ecc_export_private_raw(&ecc, privkey_buf, &qxLen,
  318. privkey_buf + qxLen, &qyLen,
  319. privkey_buf + qxLen + qyLen, &dLen) != 0) {
  320. fprintf(stderr, "Unable to export private key to DER\n");
  321. exit(2);
  322. }
  323. outlen = qxLen + qyLen + dLen;
  324. printf("Exporting private key (%d bytes)\n", outlen);
  325. write(fd, privkey_buf, outlen);
  326. wc_ecc_free(&ecc);
  327. close(fd);
  328. }
  329. }
  330. return 0;
  331. }
  332. static void addservice(struct vault_service *vs, uint8_t *Ke)
  333. {
  334. struct vault_service vs_local;
  335. char gadget_passphrase[64];
  336. int ret;
  337. uint8_t Ke_local[CRYPTO_KEY_SIZE];
  338. uint8_t eccRawKey[CRYPTO_KEY_SIZE * 3];
  339. uint8_t snd_buffer[sizeof(struct cdc_packet_hdr) + SVC_SIZE];
  340. struct cdc_packet_hdr *hdr = (struct cdc_packet_hdr *)snd_buffer;
  341. int i;
  342. struct pollfd pfd;
  343. uint32_t mgc = 0;
  344. int interactive = 0;
  345. uint32_t slot = 0;
  346. Sha512 sha;
  347. ecc_key ecc;
  348. ChaCha cha;
  349. RNG rng;
  350. strcpy(pass_prompt, pass_prompt_svc);
  351. strcpy(pass_confirm, pass_confirm_svc);
  352. if (!vs) {
  353. vs = &vs_local;
  354. Ke = Ke_local;
  355. interactive = 1;
  356. printf("Service name (max 16 char.) : ");
  357. scanf("%s", vs->name);
  358. printf("\n");
  359. printf("Username (empty = none) : ");
  360. if (scanf("%s", vs->user) <= 0)
  361. vs->user[0] = '\0';
  362. getchar();
  363. while(!askpass()) {
  364. printf("Press a key to continue...\r\n");
  365. getchar();
  366. }
  367. strcpy((char *)(vs->pass), passphrase);
  368. }
  369. vs->flags = SVC_FLAG_ACTIVE;
  370. vs->reserved = 0;
  371. if (!Ke) {
  372. printf("Unspecified key\n");
  373. return;
  374. }
  375. wc_InitSha512(&sha);
  376. wc_Sha512Update(&sha, (uint8_t *)vs, WC_SHA512_BLOCK_SIZE);
  377. wc_Sha512Final(&sha, vs->dig);
  378. printf("\n----- RECAP -----\n");
  379. printf("Service name: %s\n", vs->name);
  380. printf("Username: %s\n", vs->user);
  381. printf("Password: ******\n");
  382. printf("Sha: ");
  383. for (i = 0; i < VAULT_DIGEST_SIZE; i++) {
  384. printf("%02x", vs->dig[i]);
  385. }
  386. printf("\n-----------------\n\n");
  387. if (interactive) {
  388. printf("Service configured, press a key to send, ctrl+c to abort...\r\n");
  389. disableEcho();
  390. printf("Enter gadget passphrase to encrypt and send info: ");
  391. getPassword(gadget_passphrase, 64);
  392. enableEcho();
  393. printf("\n");
  394. /* Derive device key (password based) to create encryption key */
  395. ret = wc_PBKDF2(Ke, gadget_passphrase, strlen(gadget_passphrase),
  396. Status.salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512);
  397. if (ret < 0) {
  398. printf("Failed to derive password.\n");
  399. return;
  400. }
  401. }
  402. lseek(pk_fd, SEEK_SET, 0);
  403. ret = read(pk_fd, eccRawKey, CRYPTO_KEY_SIZE * 3);
  404. if (ret != CRYPTO_KEY_SIZE * 3) {
  405. printf("Error reading signing key\n");
  406. return;
  407. }
  408. wc_ecc_init(&ecc);
  409. if (wc_ecc_import_unsigned(&ecc, eccRawKey, eccRawKey + CRYPTO_KEY_SIZE,
  410. eccRawKey + 2 * CRYPTO_KEY_SIZE, ECC_SECP256R1) < 0) {
  411. printf("Failed importing signing key\n");
  412. return;
  413. }
  414. slot = Status.first_avail;
  415. /* Initialize Rng (needed for sign)*/
  416. wc_InitRng(&rng);
  417. printf("Slot is %u\n", slot);
  418. {
  419. mp_int r, s;
  420. mp_init(&r); mp_init(&s);
  421. ret = wc_ecc_sign_hash_ex(vs->dig, VAULT_DIGEST_SIZE, &rng, &ecc,
  422. &r, &s);
  423. mp_to_unsigned_bin(&r, &vs->sig[0]);
  424. mp_to_unsigned_bin(&s, &vs->sig[CRYPTO_KEY_SIZE]);
  425. mp_clear(&r);
  426. mp_clear(&s);
  427. }
  428. printf("Signature (%d):\n", PK_SIGNATURE_SIZE);
  429. for (i = 0; i < PK_SIGNATURE_SIZE; i++) {
  430. printf("%02x ", vs->sig[i]);
  431. if ((i % 16) == 15)
  432. printf("\n");
  433. }
  434. printf("\n");
  435. wc_ecc_free(&ecc);
  436. /* Copy the part in clear (flags, reserved) */
  437. memcpy(snd_buffer + sizeof(struct cdc_packet_hdr), vs, SVC_ENC_OFF);
  438. /* Set Key and IV */
  439. wc_Chacha_SetKey(&cha, Ke, CRYPTO_KEY_SIZE);
  440. wc_Chacha_SetIV(&cha, Status.seed, SVC_FLASH_OFFSET + slot * SVC_SIZE);
  441. wc_Chacha_Process(&cha, snd_buffer + sizeof(struct cdc_packet_hdr) + SVC_ENC_OFF,
  442. ((uint8_t *)(vs)) + SVC_ENC_OFF, SVC_ENC_SIZE);
  443. hdr->magic = VAULT_MAGIC;
  444. hdr->cmd = CDC_ADDSERV;
  445. hdr->len = SVC_SIZE;
  446. pfd.fd = sfd;
  447. pfd.events = POLLIN;
  448. for (i = 0; i < 10; i++) {
  449. char buf[8];
  450. ret = poll(&pfd, 1, 10);
  451. if (ret > 0) {
  452. read(sfd, buf, 8);
  453. }
  454. }
  455. printf("Packet (%d): ", sizeof(snd_buffer));
  456. for (i = 0; i < sizeof(snd_buffer); i++) {
  457. printf("%02x ", snd_buffer[i]);
  458. if ((i % 16) == 15)
  459. printf("\n");
  460. }
  461. printf("\n");
  462. printf("Sending svc packet... \n");
  463. write(sfd, snd_buffer, sizeof(snd_buffer));
  464. for (i = 0; i < 3; i++) {
  465. char buf[256];
  466. ret = poll(&pfd, 1, 5000);
  467. if (ret > 0) {
  468. uint16_t code;
  469. do {
  470. ret = read(sfd, &mgc, 4);
  471. } while (mgc != 0x5afeca5e);
  472. ret = read(sfd, buf, 256);
  473. code = *((uint16_t *)(buf));
  474. printf("Received response (code %02x, len %d): %s\n",
  475. code, ret, (code == CDC_FAIL)?(buf + 4):"");
  476. if ((code == CDC_FAIL) || ((code == CDC_OK) && ret == 4))
  477. break;
  478. }
  479. }
  480. }
  481. char* removeQuotes(char* str) {
  482. int len = strlen(str);
  483. int i;
  484. for (i = 0; i < len; i++)
  485. if (str[i] != '\"')
  486. break;
  487. str = str + i;
  488. len = strlen(str);
  489. for (i = len -1; i > 0; i--)
  490. if (str[i] == '\"')
  491. str[i] = '\0';
  492. return str;
  493. }
  494. static void parseCSV(const char* filename) {
  495. struct vault_service svc;
  496. FILE* file = fopen(filename, "r");
  497. uint8_t cKe[CRYPTO_KEY_SIZE];
  498. int ret;
  499. char gadget_passphrase[64 + 1];
  500. char line[1024];
  501. int header_line_skipped = 0;
  502. if (file == NULL) {
  503. printf("Failed to open the file.\n");
  504. return;
  505. }
  506. printf("Enter gadget passphrase to encrypt and send info: ");
  507. disableEcho();
  508. getPassword(gadget_passphrase, 64);
  509. enableEcho();
  510. printf("\n");
  511. /* Derive device key (password based) to create encryption key */
  512. ret = wc_PBKDF2(cKe, gadget_passphrase, strlen(gadget_passphrase),
  513. Status.salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512);
  514. if (ret < 0) {
  515. printf("Failed to derive password.\n");
  516. return;
  517. }
  518. while (fgets(line, sizeof(line), file)) {
  519. int i;
  520. // Skip header line
  521. if (!header_line_skipped) {
  522. header_line_skipped = 1;
  523. continue;
  524. }
  525. // Parse each line of the CSV
  526. char* token = strtok(line, ",");
  527. if (token == NULL) {
  528. continue;
  529. }
  530. // Remove quotes from the fields
  531. token = removeQuotes(token);
  532. char* url = token;
  533. // Strip "https:" if present
  534. if (strncmp(url, "https:", 6) == 0) {
  535. url += 6;
  536. }
  537. // Strip "http:" if present
  538. if (strncmp(url, "http:", 5) == 0) {
  539. url += 6;
  540. }
  541. // Strip slashes ("/") if present
  542. while (*url == '/') {
  543. url++;
  544. }
  545. // Strip content after the domain name if present
  546. char* slash = strchr(url, '/');
  547. if (slash != NULL) {
  548. *slash = '\0';
  549. }
  550. // Parse the domain from right to left
  551. char* domainStart = NULL;
  552. char domain[MAX_SVC_NAME_LEN + 1] = "";
  553. char *domainDot = strrchr(url, '.');
  554. if (domainDot != NULL) {
  555. *domainDot=',';
  556. domainStart = strrchr(url, '.');
  557. *domainDot='.';
  558. }
  559. if (domainStart == NULL) {
  560. strncpy(domain, url, MAX_SVC_NAME_LEN);
  561. domain[strlen(url)] = '\0';
  562. } else {
  563. int domainLen = strlen(domainStart + 1);
  564. strncpy(domain, domainStart + 1, domainLen);
  565. }
  566. // Store the extracted domain, user, and pass fields
  567. memset(&svc, 0, sizeof(svc));
  568. printf("Domain: %s\n", domain);
  569. strncpy(svc.name,domain, 16);
  570. token = strtok(NULL, ",");
  571. if (token != NULL) {
  572. token = removeQuotes(token);
  573. strncpy(svc.user, token, sizeof(svc.user) - 1);
  574. }
  575. token = strtok(NULL, ",");
  576. if (token != NULL) {
  577. token = removeQuotes(token);
  578. strncpy(svc.pass, token, sizeof(svc.pass));
  579. }
  580. for (i = 0; i < 3; i++) {
  581. ret = get_vault_status();
  582. if (ret == 0)
  583. break;
  584. }
  585. if (ret < 0) {
  586. printf("Adding service: failed.\n");
  587. getchar();
  588. return;
  589. }
  590. addservice(&svc, cKe);
  591. }
  592. fclose(file);
  593. }
  594. void printMenu() {
  595. printf("\n");
  596. printf("0) Device status\n");
  597. printf("1) TOFU\n");
  598. printf("2) Add service\n");
  599. printf("3) Import passwords from CSV\n");
  600. printf("q) Quit\n\n");
  601. }
  602. char getUserInput() {
  603. char input;
  604. printf("Choice: ");
  605. scanf(" %c", &input);
  606. getchar(); // Consume the newline character
  607. return input;
  608. }
  609. void processChoice(char choice) {
  610. char csv_filename[PATH_MAX];
  611. switch (choice) {
  612. case '0':
  613. // Handle option 0 (Device status)
  614. clearScreen();
  615. printf("Device status selected.\n");
  616. break;
  617. case '1':
  618. // Handle option 1 (TOFU)
  619. clearScreen();
  620. printf("TOFU selected.\n");
  621. strcpy(pass_prompt, pass_prompt_phrase);
  622. strcpy(pass_confirm, pass_confirm_phrase);
  623. memset(passphrase, 0, sizeof(passphrase));
  624. while(!askpass()) {
  625. printf("Press a key to continue...\r\n");
  626. getchar();
  627. }
  628. tofu(passphrase);
  629. break;
  630. case '2':
  631. // Handle option 2 (Add service)
  632. clearScreen();
  633. printf("Add service selected.\n");
  634. strcpy(pass_prompt, pass_prompt_phrase);
  635. strcpy(pass_confirm, pass_confirm_phrase);
  636. if (Status.state < 0x02) {
  637. printf("Cannot add service: device not initialized.\n");
  638. break;
  639. }
  640. if (pk_fd < 0) {
  641. printf("Cannot add service: private key not present for this device.\n");
  642. break;
  643. }
  644. addservice(NULL, NULL);
  645. break;
  646. case '3':
  647. // Handle option 3 (Import CSV)
  648. clearScreen();
  649. printf("CSV file: ");
  650. scanf("%s", csv_filename);
  651. getchar();
  652. parseCSV(csv_filename);
  653. break;
  654. case 'q':
  655. case 'Q':
  656. // Quit the program
  657. printf("Quitting...\n");
  658. exit(0);
  659. default:
  660. printf("Invalid choice.\n");
  661. break;
  662. }
  663. printf("Press Enter to continue...\n");
  664. getchar(); // Wait for Enter key
  665. }
  666. static int get_vault_status(void)
  667. {
  668. uint32_t rcount = 0;
  669. struct cdc_packet_hdr hdr;
  670. int ret;
  671. int i;
  672. struct pollfd pfd;
  673. uint8_t rxbuf[sizeof(struct cdc_packet_hdr) + sizeof(struct vault_status)];
  674. pfd.fd = sfd;
  675. pfd.events = POLLIN;
  676. hdr.magic = VAULT_MAGIC;
  677. hdr.cmd = CDC_STATUS;
  678. hdr.len = 0;
  679. for (i = 0; i < 3; i++) {
  680. ret = write(sfd, &hdr, sizeof(hdr));
  681. if (ret <= 0)
  682. return ret;
  683. ret = poll(&pfd, 1, 1000);
  684. if (ret == 0) {
  685. printf("Get status: timeout");
  686. continue;
  687. }
  688. if (ret < 0) {
  689. perror("get_status(): polling device");
  690. return -1;
  691. }
  692. do {
  693. ret = read(sfd, rxbuf + rcount, sizeof(rxbuf) - rcount);
  694. if (ret < 0) {
  695. return -1;
  696. }
  697. rcount += ret;
  698. } while (rcount < sizeof(rxbuf));
  699. break;
  700. }
  701. if (rcount > 0) {
  702. if (*(uint32_t *)(rxbuf) != VAULT_MAGIC)
  703. return -2;
  704. if (*(uint16_t *)(rxbuf + 4) != CDC_STATUS)
  705. return -3;
  706. memcpy(&Status, rxbuf + sizeof(struct cdc_packet_hdr), sizeof(Status));
  707. return 0;
  708. }
  709. return -1;
  710. }
  711. static const char vstatenames[][32] = {
  712. "OFF",
  713. "TOFU",
  714. "BOOTUP",
  715. "VERIFY_PASSPHRASE",
  716. "VERIFY_FAILED",
  717. "MAIN_MENU",
  718. "SETTINGS_MENU",
  719. "SERVICE_LIST"
  720. };
  721. int main(int argc, char *argv[])
  722. {
  723. clearScreen();
  724. system("mkdir -p " HOMEPATH_PREFIX);
  725. if (argc != 2) {
  726. fprintf(stderr, "Usage: %s TTY\n", argv[0]);
  727. return 2;
  728. }
  729. sfd = serial_open(argv[1], 115200);
  730. if (sfd < 0) {
  731. perror("serial_open");
  732. if (errno == EACCES) {
  733. printf("\n\nPerhaps you should review your permission for %s, or 'sudo adduser $YOUR_USER dialout'\r\n", argv[1]);
  734. }
  735. return 1;
  736. }
  737. while (1) {
  738. char choice;
  739. if (get_vault_status() < 0) {
  740. printf("Not connected\n");
  741. } else {
  742. char pkfname[MAX_PATH];
  743. char *homedir;
  744. homedir = getenv("HOME");
  745. if (!homedir || strlen(homedir) == 0) {
  746. perror("getenv(HOME)");
  747. exit(1);
  748. }
  749. snprintf(pkfname, MAX_PATH - 1, "%s/.pvault/%08x-%08x.der", homedir, Status.id[0], Status.id[1]);
  750. printf("Device %08x-%08x Connected.\n", Status.id[0], Status.id[1]);
  751. pk_fd = open(pkfname, O_RDONLY);
  752. if (pk_fd < 0) {
  753. perror("open");
  754. printf(pkfname);
  755. printf("\n");
  756. printf("Private key not available.\n");
  757. } else {
  758. printf("Private key loaded.\n");
  759. }
  760. printf("State: %s - Services: %hu. Spot: %hu\n",
  761. vstatenames[Status.state], Status.services_active, Status.first_avail);
  762. }
  763. printMenu();
  764. choice = getUserInput();
  765. processChoice(choice);
  766. }
  767. return 0;
  768. }