fips140_lab_util.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2021 Google LLC
  4. *
  5. * This program provides commands that dump certain types of output from the
  6. * fips140 kernel module, as required by the FIPS lab for evaluation purposes.
  7. *
  8. * While the fips140 kernel module can only be accessed directly by other kernel
  9. * code, an easy-to-use userspace utility program was desired for lab testing.
  10. * When possible, this program uses AF_ALG to access the crypto algorithms; this
  11. * requires that the kernel has AF_ALG enabled. Where AF_ALG isn't sufficient,
  12. * a custom device node /dev/fips140 is used instead; this requires that the
  13. * fips140 module is loaded and has evaluation testing support compiled in.
  14. *
  15. * This program can be compiled and run on an Android device as follows:
  16. *
  17. * NDK_DIR=$HOME/android-ndk-r23b # adjust directory path as needed
  18. * $NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang \
  19. * fips140_lab_util.c -O2 -Wall -o fips140_lab_util
  20. * adb push fips140_lab_util /data/local/tmp/
  21. * adb root
  22. * adb shell /data/local/tmp/fips140_lab_util
  23. */
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <getopt.h>
  27. #include <limits.h>
  28. #include <linux/if_alg.h>
  29. #include <stdarg.h>
  30. #include <stdbool.h>
  31. #include <stdint.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sys/ioctl.h>
  36. #include <sys/socket.h>
  37. #include <sys/stat.h>
  38. #include <sys/sysmacros.h>
  39. #include <unistd.h>
  40. #include "../../crypto/fips140-eval-testing-uapi.h"
  41. /* ---------------------------------------------------------------------------
  42. * Utility functions
  43. * ---------------------------------------------------------------------------*/
  44. #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
  45. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  46. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  47. static void __attribute__((noreturn))
  48. do_die(const char *format, va_list va, int err)
  49. {
  50. fputs("ERROR: ", stderr);
  51. vfprintf(stderr, format, va);
  52. if (err)
  53. fprintf(stderr, ": %s", strerror(err));
  54. putc('\n', stderr);
  55. exit(1);
  56. }
  57. static void __attribute__((noreturn, format(printf, 1, 2)))
  58. die_errno(const char *format, ...)
  59. {
  60. va_list va;
  61. va_start(va, format);
  62. do_die(format, va, errno);
  63. va_end(va);
  64. }
  65. static void __attribute__((noreturn, format(printf, 1, 2)))
  66. die(const char *format, ...)
  67. {
  68. va_list va;
  69. va_start(va, format);
  70. do_die(format, va, 0);
  71. va_end(va);
  72. }
  73. static void __attribute__((noreturn))
  74. assertion_failed(const char *expr, const char *file, int line)
  75. {
  76. die("Assertion failed: %s at %s:%d", expr, file, line);
  77. }
  78. #define ASSERT(e) ({ if (!(e)) assertion_failed(#e, __FILE__, __LINE__); })
  79. static void rand_bytes(uint8_t *bytes, size_t count)
  80. {
  81. size_t i;
  82. for (i = 0; i < count; i++)
  83. bytes[i] = rand();
  84. }
  85. static const char *booltostr(bool b)
  86. {
  87. return b ? "true" : "false";
  88. }
  89. static const char *bytes_to_hex(const uint8_t *bytes, size_t count)
  90. {
  91. static char hex[1025];
  92. size_t i;
  93. ASSERT(count <= 512);
  94. for (i = 0; i < count; i++)
  95. sprintf(&hex[2*i], "%02x", bytes[i]);
  96. return hex;
  97. }
  98. static void full_write(int fd, const void *buf, size_t count)
  99. {
  100. while (count) {
  101. ssize_t ret = write(fd, buf, count);
  102. if (ret < 0)
  103. die_errno("write failed");
  104. buf += ret;
  105. count -= ret;
  106. }
  107. }
  108. enum {
  109. OPT_AMOUNT,
  110. OPT_ITERATIONS,
  111. };
  112. static void usage(void);
  113. /* ---------------------------------------------------------------------------
  114. * /dev/fips140 ioctls
  115. * ---------------------------------------------------------------------------*/
  116. static int get_fips140_device_number(void)
  117. {
  118. FILE *f;
  119. char line[128];
  120. int number;
  121. char name[32];
  122. f = fopen("/proc/devices", "r");
  123. if (!f)
  124. die_errno("Failed to open /proc/devices");
  125. while (fgets(line, sizeof(line), f)) {
  126. if (sscanf(line, "%d %31s", &number, name) == 2 &&
  127. strcmp(name, "fips140") == 0)
  128. return number;
  129. }
  130. fclose(f);
  131. die("fips140 device node is unavailable.\n"
  132. "The fips140 device node is only available when the fips140 module is loaded\n"
  133. "and has been built with evaluation testing support.");
  134. }
  135. static void create_fips140_node_if_needed(void)
  136. {
  137. struct stat stbuf;
  138. int major;
  139. if (stat("/dev/fips140", &stbuf) == 0)
  140. return;
  141. major = get_fips140_device_number();
  142. if (mknod("/dev/fips140", S_IFCHR | 0600, makedev(major, 1)) != 0)
  143. die_errno("Failed to create fips140 device node");
  144. }
  145. static int fips140_dev_fd = -1;
  146. static int fips140_ioctl(int cmd, const void *arg)
  147. {
  148. if (fips140_dev_fd < 0) {
  149. create_fips140_node_if_needed();
  150. fips140_dev_fd = open("/dev/fips140", O_RDONLY);
  151. if (fips140_dev_fd < 0)
  152. die_errno("Failed to open /dev/fips140");
  153. }
  154. return ioctl(fips140_dev_fd, cmd, arg);
  155. }
  156. static bool fips140_is_approved_service(const char *name)
  157. {
  158. int ret = fips140_ioctl(FIPS140_IOCTL_IS_APPROVED_SERVICE, name);
  159. if (ret < 0)
  160. die_errno("FIPS140_IOCTL_IS_APPROVED_SERVICE unexpectedly failed");
  161. if (ret == 1)
  162. return true;
  163. if (ret == 0)
  164. return false;
  165. die("FIPS140_IOCTL_IS_APPROVED_SERVICE returned unexpected value %d",
  166. ret);
  167. }
  168. static const char *fips140_module_version(void)
  169. {
  170. static char buf[256];
  171. int ret;
  172. memset(buf, 0, sizeof(buf));
  173. ret = fips140_ioctl(FIPS140_IOCTL_MODULE_VERSION, buf);
  174. if (ret < 0)
  175. die_errno("FIPS140_IOCTL_MODULE_VERSION unexpectedly failed");
  176. if (ret != 0)
  177. die("FIPS140_IOCTL_MODULE_VERSION returned unexpected value %d",
  178. ret);
  179. return buf;
  180. }
  181. /* ---------------------------------------------------------------------------
  182. * AF_ALG utilities
  183. * ---------------------------------------------------------------------------*/
  184. #define AF_ALG_MAX_RNG_REQUEST_SIZE 128
  185. static int get_alg_fd(const char *alg_type, const char *alg_name)
  186. {
  187. struct sockaddr_alg addr = {};
  188. int alg_fd;
  189. alg_fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
  190. if (alg_fd < 0)
  191. die("Failed to create AF_ALG socket.\n"
  192. "AF_ALG is only available when it has been enabled in the kernel.\n");
  193. strncpy((char *)addr.salg_type, alg_type, sizeof(addr.salg_type) - 1);
  194. strncpy((char *)addr.salg_name, alg_name, sizeof(addr.salg_name) - 1);
  195. if (bind(alg_fd, (void *)&addr, sizeof(addr)) != 0)
  196. die_errno("Failed to bind AF_ALG socket to %s %s",
  197. alg_type, alg_name);
  198. return alg_fd;
  199. }
  200. static int get_req_fd(int alg_fd, const char *alg_name)
  201. {
  202. int req_fd = accept(alg_fd, NULL, NULL);
  203. if (req_fd < 0)
  204. die_errno("Failed to get request file descriptor for %s",
  205. alg_name);
  206. return req_fd;
  207. }
  208. /* ---------------------------------------------------------------------------
  209. * dump_jitterentropy command
  210. * ---------------------------------------------------------------------------*/
  211. static void dump_from_jent_fd(int fd, size_t count)
  212. {
  213. uint8_t buf[AF_ALG_MAX_RNG_REQUEST_SIZE];
  214. while (count) {
  215. ssize_t ret;
  216. memset(buf, 0, sizeof(buf));
  217. ret = read(fd, buf, MIN(count, sizeof(buf)));
  218. if (ret < 0)
  219. die_errno("error reading from jitterentropy_rng");
  220. full_write(STDOUT_FILENO, buf, ret);
  221. count -= ret;
  222. }
  223. }
  224. static int cmd_dump_jitterentropy(int argc, char *argv[])
  225. {
  226. static const struct option longopts[] = {
  227. { "amount", required_argument, NULL, OPT_AMOUNT },
  228. { "iterations", required_argument, NULL, OPT_ITERATIONS },
  229. { NULL, 0, NULL, 0 },
  230. };
  231. size_t amount = 128;
  232. size_t iterations = 1;
  233. size_t i;
  234. int c;
  235. while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
  236. switch (c) {
  237. case OPT_AMOUNT:
  238. amount = strtoul(optarg, NULL, 0);
  239. if (amount <= 0 || amount >= ULONG_MAX)
  240. die("invalid argument to --amount");
  241. break;
  242. case OPT_ITERATIONS:
  243. iterations = strtoul(optarg, NULL, 0);
  244. if (iterations <= 0 || iterations >= ULONG_MAX)
  245. die("invalid argument to --iterations");
  246. break;
  247. default:
  248. usage();
  249. return 1;
  250. }
  251. }
  252. for (i = 0; i < iterations; i++) {
  253. int alg_fd = get_alg_fd("rng", "jitterentropy_rng");
  254. int req_fd = get_req_fd(alg_fd, "jitterentropy_rng");
  255. dump_from_jent_fd(req_fd, amount);
  256. close(req_fd);
  257. close(alg_fd);
  258. }
  259. return 0;
  260. }
  261. /* ---------------------------------------------------------------------------
  262. * show_invalid_inputs command
  263. * ---------------------------------------------------------------------------*/
  264. enum direction {
  265. UNSPECIFIED,
  266. DECRYPT,
  267. ENCRYPT,
  268. };
  269. static const struct invalid_input_test {
  270. const char *alg_type;
  271. const char *alg_name;
  272. const char *key;
  273. size_t key_size;
  274. const char *msg;
  275. size_t msg_size;
  276. const char *iv;
  277. size_t iv_size;
  278. enum direction direction;
  279. int setkey_error;
  280. int crypt_error;
  281. } invalid_input_tests[] = {
  282. {
  283. .alg_type = "skcipher",
  284. .alg_name = "cbc(aes)",
  285. .key_size = 16,
  286. }, {
  287. .alg_type = "skcipher",
  288. .alg_name = "cbc(aes)",
  289. .key_size = 17,
  290. .setkey_error = EINVAL,
  291. }, {
  292. .alg_type = "skcipher",
  293. .alg_name = "cbc(aes)",
  294. .key_size = 24,
  295. }, {
  296. .alg_type = "skcipher",
  297. .alg_name = "cbc(aes)",
  298. .key_size = 32,
  299. }, {
  300. .alg_type = "skcipher",
  301. .alg_name = "cbc(aes)",
  302. .key_size = 33,
  303. .setkey_error = EINVAL,
  304. }, {
  305. .alg_type = "skcipher",
  306. .alg_name = "cbc(aes)",
  307. .key_size = 16,
  308. .msg_size = 1,
  309. .direction = DECRYPT,
  310. .crypt_error = EINVAL,
  311. }, {
  312. .alg_type = "skcipher",
  313. .alg_name = "cbc(aes)",
  314. .key_size = 16,
  315. .msg_size = 16,
  316. .direction = ENCRYPT,
  317. }, {
  318. .alg_type = "skcipher",
  319. .alg_name = "cbc(aes)",
  320. .key_size = 16,
  321. .msg_size = 17,
  322. .direction = ENCRYPT,
  323. .crypt_error = EINVAL,
  324. }, {
  325. .alg_type = "hash",
  326. .alg_name = "cmac(aes)",
  327. .key_size = 29,
  328. .setkey_error = EINVAL,
  329. }, {
  330. .alg_type = "skcipher",
  331. .alg_name = "xts(aes)",
  332. .key_size = 32,
  333. }, {
  334. .alg_type = "skcipher",
  335. .alg_name = "xts(aes)",
  336. .key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  337. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
  338. .key_size = 32,
  339. .setkey_error = EINVAL,
  340. }
  341. };
  342. static const char *describe_crypt_op(const struct invalid_input_test *t)
  343. {
  344. if (t->direction == ENCRYPT)
  345. return "encryption";
  346. if (t->direction == DECRYPT)
  347. return "decryption";
  348. if (strcmp(t->alg_type, "hash") == 0)
  349. return "hashing";
  350. ASSERT(0);
  351. }
  352. static bool af_alg_setkey(const struct invalid_input_test *t, int alg_fd)
  353. {
  354. const uint8_t *key = (const uint8_t *)t->key;
  355. uint8_t _key[t->key_size];
  356. if (t->key_size == 0)
  357. return true;
  358. if (t->key == NULL) {
  359. rand_bytes(_key, t->key_size);
  360. key = _key;
  361. }
  362. if (setsockopt(alg_fd, SOL_ALG, ALG_SET_KEY, key, t->key_size) != 0) {
  363. printf("%s: setting %zu-byte key failed with error '%s'\n",
  364. t->alg_name, t->key_size, strerror(errno));
  365. printf("\tkey was %s\n\n", bytes_to_hex(key, t->key_size));
  366. ASSERT(t->setkey_error == errno);
  367. return false;
  368. }
  369. printf("%s: setting %zu-byte key succeeded\n",
  370. t->alg_name, t->key_size);
  371. printf("\tkey was %s\n\n", bytes_to_hex(key, t->key_size));
  372. ASSERT(t->setkey_error == 0);
  373. return true;
  374. }
  375. static void af_alg_process_msg(const struct invalid_input_test *t, int alg_fd)
  376. {
  377. struct iovec iov;
  378. struct msghdr hdr = {
  379. .msg_iov = &iov,
  380. .msg_iovlen = 1,
  381. };
  382. const uint8_t *msg = (const uint8_t *)t->msg;
  383. uint8_t *_msg = NULL;
  384. uint8_t *output = NULL;
  385. uint8_t *control = NULL;
  386. size_t controllen = 0;
  387. struct cmsghdr *cmsg;
  388. int req_fd;
  389. if (t->msg_size == 0)
  390. return;
  391. req_fd = get_req_fd(alg_fd, t->alg_name);
  392. if (t->msg == NULL) {
  393. _msg = malloc(t->msg_size);
  394. rand_bytes(_msg, t->msg_size);
  395. msg = _msg;
  396. }
  397. output = malloc(t->msg_size);
  398. iov.iov_base = (void *)msg;
  399. iov.iov_len = t->msg_size;
  400. if (t->direction != UNSPECIFIED)
  401. controllen += CMSG_SPACE(sizeof(uint32_t));
  402. if (t->iv_size)
  403. controllen += CMSG_SPACE(sizeof(struct af_alg_iv) + t->iv_size);
  404. control = calloc(1, controllen);
  405. hdr.msg_control = control;
  406. hdr.msg_controllen = controllen;
  407. cmsg = CMSG_FIRSTHDR(&hdr);
  408. if (t->direction != UNSPECIFIED) {
  409. cmsg->cmsg_level = SOL_ALG;
  410. cmsg->cmsg_type = ALG_SET_OP;
  411. cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
  412. *(uint32_t *)CMSG_DATA(cmsg) = t->direction == DECRYPT ?
  413. ALG_OP_DECRYPT : ALG_OP_ENCRYPT;
  414. cmsg = CMSG_NXTHDR(&hdr, cmsg);
  415. }
  416. if (t->iv_size) {
  417. struct af_alg_iv *alg_iv;
  418. cmsg->cmsg_level = SOL_ALG;
  419. cmsg->cmsg_type = ALG_SET_IV;
  420. cmsg->cmsg_len = CMSG_LEN(sizeof(*alg_iv) + t->iv_size);
  421. alg_iv = (struct af_alg_iv *)CMSG_DATA(cmsg);
  422. alg_iv->ivlen = t->iv_size;
  423. memcpy(alg_iv->iv, t->iv, t->iv_size);
  424. }
  425. if (sendmsg(req_fd, &hdr, 0) != t->msg_size)
  426. die_errno("sendmsg failed");
  427. if (read(req_fd, output, t->msg_size) != t->msg_size) {
  428. printf("%s: %s of %zu-byte message failed with error '%s'\n",
  429. t->alg_name, describe_crypt_op(t), t->msg_size,
  430. strerror(errno));
  431. printf("\tmessage was %s\n\n", bytes_to_hex(msg, t->msg_size));
  432. ASSERT(t->crypt_error == errno);
  433. } else {
  434. printf("%s: %s of %zu-byte message succeeded\n",
  435. t->alg_name, describe_crypt_op(t), t->msg_size);
  436. printf("\tmessage was %s\n\n", bytes_to_hex(msg, t->msg_size));
  437. ASSERT(t->crypt_error == 0);
  438. }
  439. free(_msg);
  440. free(output);
  441. free(control);
  442. close(req_fd);
  443. }
  444. static void test_invalid_input(const struct invalid_input_test *t)
  445. {
  446. int alg_fd = get_alg_fd(t->alg_type, t->alg_name);
  447. if (af_alg_setkey(t, alg_fd))
  448. af_alg_process_msg(t, alg_fd);
  449. close(alg_fd);
  450. }
  451. static int cmd_show_invalid_inputs(int argc, char *argv[])
  452. {
  453. int i;
  454. for (i = 0; i < ARRAY_SIZE(invalid_input_tests); i++)
  455. test_invalid_input(&invalid_input_tests[i]);
  456. return 0;
  457. }
  458. /* ---------------------------------------------------------------------------
  459. * show_module_version command
  460. * ---------------------------------------------------------------------------*/
  461. static int cmd_show_module_version(int argc, char *argv[])
  462. {
  463. printf("fips140_module_version() => \"%s\"\n",
  464. fips140_module_version());
  465. return 0;
  466. }
  467. /* ---------------------------------------------------------------------------
  468. * show_service_indicators command
  469. * ---------------------------------------------------------------------------*/
  470. static const char * const default_services_to_show[] = {
  471. "aes",
  472. "cbc(aes)",
  473. "cbcmac(aes)",
  474. "cmac(aes)",
  475. "ctr(aes)",
  476. "cts(cbc(aes))",
  477. "ecb(aes)",
  478. "essiv(cbc(aes),sha256)",
  479. "gcm(aes)",
  480. "hmac(sha1)",
  481. "hmac(sha224)",
  482. "hmac(sha256)",
  483. "hmac(sha384)",
  484. "hmac(sha512)",
  485. "jitterentropy_rng",
  486. "sha1",
  487. "sha224",
  488. "sha256",
  489. "sha384",
  490. "sha512",
  491. "stdrng",
  492. "xcbc(aes)",
  493. "xts(aes)",
  494. };
  495. static int cmd_show_service_indicators(int argc, char *argv[])
  496. {
  497. const char * const *services = default_services_to_show;
  498. int count = ARRAY_SIZE(default_services_to_show);
  499. int i;
  500. if (argc > 1) {
  501. services = (const char **)(argv + 1);
  502. count = argc - 1;
  503. }
  504. for (i = 0; i < count; i++) {
  505. printf("fips140_is_approved_service(\"%s\") => %s\n",
  506. services[i],
  507. booltostr(fips140_is_approved_service(services[i])));
  508. }
  509. return 0;
  510. }
  511. /* ---------------------------------------------------------------------------
  512. * main()
  513. * ---------------------------------------------------------------------------*/
  514. static const struct command {
  515. const char *name;
  516. int (*func)(int argc, char *argv[]);
  517. } commands[] = {
  518. { "dump_jitterentropy", cmd_dump_jitterentropy },
  519. { "show_invalid_inputs", cmd_show_invalid_inputs },
  520. { "show_module_version", cmd_show_module_version },
  521. { "show_service_indicators", cmd_show_service_indicators },
  522. };
  523. static void usage(void)
  524. {
  525. fprintf(stderr,
  526. "Usage:\n"
  527. " fips140_lab_util dump_jitterentropy [OPTION]...\n"
  528. " fips140_lab_util show_invalid_inputs\n"
  529. " fips140_lab_util show_module_version\n"
  530. " fips140_lab_util show_service_indicators [SERVICE]...\n"
  531. "\n"
  532. "Options for dump_jitterentropy:\n"
  533. " --amount=AMOUNT Amount to dump in bytes per iteration (default 128)\n"
  534. " --iterations=COUNT Number of start-up iterations (default 1)\n"
  535. );
  536. }
  537. int main(int argc, char *argv[])
  538. {
  539. int i;
  540. if (argc < 2) {
  541. usage();
  542. return 2;
  543. }
  544. for (i = 1; i < argc; i++) {
  545. if (strcmp(argv[i], "--help") == 0) {
  546. usage();
  547. return 2;
  548. }
  549. }
  550. for (i = 0; i < ARRAY_SIZE(commands); i++) {
  551. if (strcmp(commands[i].name, argv[1]) == 0)
  552. return commands[i].func(argc - 1, argv + 1);
  553. }
  554. fprintf(stderr, "Unknown command: %s\n\n", argv[1]);
  555. usage();
  556. return 2;
  557. }