fips140_lab_util.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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 <limits.h>
  27. #include <linux/if_alg.h>
  28. #include <stdarg.h>
  29. #include <stdbool.h>
  30. #include <stdint.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/ioctl.h>
  35. #include <sys/socket.h>
  36. #include <sys/stat.h>
  37. #include <sys/sysmacros.h>
  38. #include <unistd.h>
  39. #include "../../crypto/fips140-eval-testing-uapi.h"
  40. /* ---------------------------------------------------------------------------
  41. * Utility functions
  42. * ---------------------------------------------------------------------------*/
  43. #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
  44. static void __attribute__((noreturn))
  45. do_die(const char *format, va_list va, int err)
  46. {
  47. fputs("ERROR: ", stderr);
  48. vfprintf(stderr, format, va);
  49. if (err)
  50. fprintf(stderr, ": %s", strerror(err));
  51. putc('\n', stderr);
  52. exit(1);
  53. }
  54. static void __attribute__((noreturn, format(printf, 1, 2)))
  55. die_errno(const char *format, ...)
  56. {
  57. va_list va;
  58. va_start(va, format);
  59. do_die(format, va, errno);
  60. va_end(va);
  61. }
  62. static void __attribute__((noreturn, format(printf, 1, 2)))
  63. die(const char *format, ...)
  64. {
  65. va_list va;
  66. va_start(va, format);
  67. do_die(format, va, 0);
  68. va_end(va);
  69. }
  70. static void __attribute__((noreturn))
  71. assertion_failed(const char *expr, const char *file, int line)
  72. {
  73. die("Assertion failed: %s at %s:%d", expr, file, line);
  74. }
  75. #define ASSERT(e) ({ if (!(e)) assertion_failed(#e, __FILE__, __LINE__); })
  76. static void rand_bytes(uint8_t *bytes, size_t count)
  77. {
  78. size_t i;
  79. for (i = 0; i < count; i++)
  80. bytes[i] = rand();
  81. }
  82. static const char *booltostr(bool b)
  83. {
  84. return b ? "true" : "false";
  85. }
  86. static const char *bytes_to_hex(const uint8_t *bytes, size_t count)
  87. {
  88. static char hex[1025];
  89. size_t i;
  90. ASSERT(count <= 512);
  91. for (i = 0; i < count; i++)
  92. sprintf(&hex[2*i], "%02x", bytes[i]);
  93. return hex;
  94. }
  95. static void usage(void);
  96. /* ---------------------------------------------------------------------------
  97. * /dev/fips140 ioctls
  98. * ---------------------------------------------------------------------------*/
  99. static int get_fips140_device_number(void)
  100. {
  101. FILE *f;
  102. char line[128];
  103. int number;
  104. char name[32];
  105. f = fopen("/proc/devices", "r");
  106. if (!f)
  107. die_errno("Failed to open /proc/devices");
  108. while (fgets(line, sizeof(line), f)) {
  109. if (sscanf(line, "%d %31s", &number, name) == 2 &&
  110. strcmp(name, "fips140") == 0)
  111. return number;
  112. }
  113. fclose(f);
  114. die("fips140 device node is unavailable.\n"
  115. "The fips140 device node is only available when the fips140 module is loaded\n"
  116. "and has been built with evaluation testing support.");
  117. }
  118. static void create_fips140_node_if_needed(void)
  119. {
  120. struct stat stbuf;
  121. int major;
  122. if (stat("/dev/fips140", &stbuf) == 0)
  123. return;
  124. major = get_fips140_device_number();
  125. if (mknod("/dev/fips140", S_IFCHR | 0600, makedev(major, 1)) != 0)
  126. die_errno("Failed to create fips140 device node");
  127. }
  128. static int fips140_dev_fd = -1;
  129. static int fips140_ioctl(int cmd, const void *arg)
  130. {
  131. if (fips140_dev_fd < 0) {
  132. create_fips140_node_if_needed();
  133. fips140_dev_fd = open("/dev/fips140", O_RDONLY);
  134. if (fips140_dev_fd < 0)
  135. die_errno("Failed to open /dev/fips140");
  136. }
  137. return ioctl(fips140_dev_fd, cmd, arg);
  138. }
  139. static bool fips140_is_approved_service(const char *name)
  140. {
  141. int ret = fips140_ioctl(FIPS140_IOCTL_IS_APPROVED_SERVICE, name);
  142. if (ret < 0)
  143. die_errno("FIPS140_IOCTL_IS_APPROVED_SERVICE unexpectedly failed");
  144. if (ret == 1)
  145. return true;
  146. if (ret == 0)
  147. return false;
  148. die("FIPS140_IOCTL_IS_APPROVED_SERVICE returned unexpected value %d",
  149. ret);
  150. }
  151. static const char *fips140_module_version(void)
  152. {
  153. static char buf[256];
  154. int ret;
  155. memset(buf, 0, sizeof(buf));
  156. ret = fips140_ioctl(FIPS140_IOCTL_MODULE_VERSION, buf);
  157. if (ret < 0)
  158. die_errno("FIPS140_IOCTL_MODULE_VERSION unexpectedly failed");
  159. if (ret != 0)
  160. die("FIPS140_IOCTL_MODULE_VERSION returned unexpected value %d",
  161. ret);
  162. return buf;
  163. }
  164. /* ---------------------------------------------------------------------------
  165. * AF_ALG utilities
  166. * ---------------------------------------------------------------------------*/
  167. #define AF_ALG_MAX_RNG_REQUEST_SIZE 128
  168. static int get_alg_fd(const char *alg_type, const char *alg_name)
  169. {
  170. struct sockaddr_alg addr = {};
  171. int alg_fd;
  172. alg_fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
  173. if (alg_fd < 0)
  174. die("Failed to create AF_ALG socket.\n"
  175. "AF_ALG is only available when it has been enabled in the kernel.\n");
  176. strncpy((char *)addr.salg_type, alg_type, sizeof(addr.salg_type) - 1);
  177. strncpy((char *)addr.salg_name, alg_name, sizeof(addr.salg_name) - 1);
  178. if (bind(alg_fd, (void *)&addr, sizeof(addr)) != 0)
  179. die_errno("Failed to bind AF_ALG socket to %s %s",
  180. alg_type, alg_name);
  181. return alg_fd;
  182. }
  183. static int get_req_fd(int alg_fd, const char *alg_name)
  184. {
  185. int req_fd = accept(alg_fd, NULL, NULL);
  186. if (req_fd < 0)
  187. die_errno("Failed to get request file descriptor for %s",
  188. alg_name);
  189. return req_fd;
  190. }
  191. /* ---------------------------------------------------------------------------
  192. * show_invalid_inputs command
  193. * ---------------------------------------------------------------------------*/
  194. enum direction {
  195. UNSPECIFIED,
  196. DECRYPT,
  197. ENCRYPT,
  198. };
  199. static const struct invalid_input_test {
  200. const char *alg_type;
  201. const char *alg_name;
  202. const char *key;
  203. size_t key_size;
  204. const char *msg;
  205. size_t msg_size;
  206. const char *iv;
  207. size_t iv_size;
  208. enum direction direction;
  209. int setkey_error;
  210. int crypt_error;
  211. } invalid_input_tests[] = {
  212. {
  213. .alg_type = "skcipher",
  214. .alg_name = "cbc(aes)",
  215. .key_size = 16,
  216. }, {
  217. .alg_type = "skcipher",
  218. .alg_name = "cbc(aes)",
  219. .key_size = 17,
  220. .setkey_error = EINVAL,
  221. }, {
  222. .alg_type = "skcipher",
  223. .alg_name = "cbc(aes)",
  224. .key_size = 24,
  225. }, {
  226. .alg_type = "skcipher",
  227. .alg_name = "cbc(aes)",
  228. .key_size = 32,
  229. }, {
  230. .alg_type = "skcipher",
  231. .alg_name = "cbc(aes)",
  232. .key_size = 33,
  233. .setkey_error = EINVAL,
  234. }, {
  235. .alg_type = "skcipher",
  236. .alg_name = "cbc(aes)",
  237. .key_size = 16,
  238. .msg_size = 1,
  239. .direction = DECRYPT,
  240. .crypt_error = EINVAL,
  241. }, {
  242. .alg_type = "skcipher",
  243. .alg_name = "cbc(aes)",
  244. .key_size = 16,
  245. .msg_size = 16,
  246. .direction = ENCRYPT,
  247. }, {
  248. .alg_type = "skcipher",
  249. .alg_name = "cbc(aes)",
  250. .key_size = 16,
  251. .msg_size = 17,
  252. .direction = ENCRYPT,
  253. .crypt_error = EINVAL,
  254. }, {
  255. .alg_type = "hash",
  256. .alg_name = "cmac(aes)",
  257. .key_size = 29,
  258. .setkey_error = EINVAL,
  259. }, {
  260. .alg_type = "skcipher",
  261. .alg_name = "xts(aes)",
  262. .key_size = 32,
  263. }, {
  264. .alg_type = "skcipher",
  265. .alg_name = "xts(aes)",
  266. .key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  267. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
  268. .key_size = 32,
  269. .setkey_error = EINVAL,
  270. }
  271. };
  272. static const char *describe_crypt_op(const struct invalid_input_test *t)
  273. {
  274. if (t->direction == ENCRYPT)
  275. return "encryption";
  276. if (t->direction == DECRYPT)
  277. return "decryption";
  278. if (strcmp(t->alg_type, "hash") == 0)
  279. return "hashing";
  280. ASSERT(0);
  281. }
  282. static bool af_alg_setkey(const struct invalid_input_test *t, int alg_fd)
  283. {
  284. const uint8_t *key = (const uint8_t *)t->key;
  285. uint8_t _key[t->key_size];
  286. if (t->key_size == 0)
  287. return true;
  288. if (t->key == NULL) {
  289. rand_bytes(_key, t->key_size);
  290. key = _key;
  291. }
  292. if (setsockopt(alg_fd, SOL_ALG, ALG_SET_KEY, key, t->key_size) != 0) {
  293. printf("%s: setting %zu-byte key failed with error '%s'\n",
  294. t->alg_name, t->key_size, strerror(errno));
  295. printf("\tkey was %s\n\n", bytes_to_hex(key, t->key_size));
  296. ASSERT(t->setkey_error == errno);
  297. return false;
  298. }
  299. printf("%s: setting %zu-byte key succeeded\n",
  300. t->alg_name, t->key_size);
  301. printf("\tkey was %s\n\n", bytes_to_hex(key, t->key_size));
  302. ASSERT(t->setkey_error == 0);
  303. return true;
  304. }
  305. static void af_alg_process_msg(const struct invalid_input_test *t, int alg_fd)
  306. {
  307. struct iovec iov;
  308. struct msghdr hdr = {
  309. .msg_iov = &iov,
  310. .msg_iovlen = 1,
  311. };
  312. const uint8_t *msg = (const uint8_t *)t->msg;
  313. uint8_t *_msg = NULL;
  314. uint8_t *output = NULL;
  315. uint8_t *control = NULL;
  316. size_t controllen = 0;
  317. struct cmsghdr *cmsg;
  318. int req_fd;
  319. if (t->msg_size == 0)
  320. return;
  321. req_fd = get_req_fd(alg_fd, t->alg_name);
  322. if (t->msg == NULL) {
  323. _msg = malloc(t->msg_size);
  324. rand_bytes(_msg, t->msg_size);
  325. msg = _msg;
  326. }
  327. output = malloc(t->msg_size);
  328. iov.iov_base = (void *)msg;
  329. iov.iov_len = t->msg_size;
  330. if (t->direction != UNSPECIFIED)
  331. controllen += CMSG_SPACE(sizeof(uint32_t));
  332. if (t->iv_size)
  333. controllen += CMSG_SPACE(sizeof(struct af_alg_iv) + t->iv_size);
  334. control = calloc(1, controllen);
  335. hdr.msg_control = control;
  336. hdr.msg_controllen = controllen;
  337. cmsg = CMSG_FIRSTHDR(&hdr);
  338. if (t->direction != UNSPECIFIED) {
  339. cmsg->cmsg_level = SOL_ALG;
  340. cmsg->cmsg_type = ALG_SET_OP;
  341. cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
  342. *(uint32_t *)CMSG_DATA(cmsg) = t->direction == DECRYPT ?
  343. ALG_OP_DECRYPT : ALG_OP_ENCRYPT;
  344. cmsg = CMSG_NXTHDR(&hdr, cmsg);
  345. }
  346. if (t->iv_size) {
  347. struct af_alg_iv *alg_iv;
  348. cmsg->cmsg_level = SOL_ALG;
  349. cmsg->cmsg_type = ALG_SET_IV;
  350. cmsg->cmsg_len = CMSG_LEN(sizeof(*alg_iv) + t->iv_size);
  351. alg_iv = (struct af_alg_iv *)CMSG_DATA(cmsg);
  352. alg_iv->ivlen = t->iv_size;
  353. memcpy(alg_iv->iv, t->iv, t->iv_size);
  354. }
  355. if (sendmsg(req_fd, &hdr, 0) != t->msg_size)
  356. die_errno("sendmsg failed");
  357. if (read(req_fd, output, t->msg_size) != t->msg_size) {
  358. printf("%s: %s of %zu-byte message failed with error '%s'\n",
  359. t->alg_name, describe_crypt_op(t), t->msg_size,
  360. strerror(errno));
  361. printf("\tmessage was %s\n\n", bytes_to_hex(msg, t->msg_size));
  362. ASSERT(t->crypt_error == errno);
  363. } else {
  364. printf("%s: %s of %zu-byte message succeeded\n",
  365. t->alg_name, describe_crypt_op(t), t->msg_size);
  366. printf("\tmessage was %s\n\n", bytes_to_hex(msg, t->msg_size));
  367. ASSERT(t->crypt_error == 0);
  368. }
  369. free(_msg);
  370. free(output);
  371. free(control);
  372. close(req_fd);
  373. }
  374. static void test_invalid_input(const struct invalid_input_test *t)
  375. {
  376. int alg_fd = get_alg_fd(t->alg_type, t->alg_name);
  377. if (af_alg_setkey(t, alg_fd))
  378. af_alg_process_msg(t, alg_fd);
  379. close(alg_fd);
  380. }
  381. static int cmd_show_invalid_inputs(int argc, char *argv[])
  382. {
  383. int i;
  384. for (i = 0; i < ARRAY_SIZE(invalid_input_tests); i++)
  385. test_invalid_input(&invalid_input_tests[i]);
  386. return 0;
  387. }
  388. /* ---------------------------------------------------------------------------
  389. * show_module_version command
  390. * ---------------------------------------------------------------------------*/
  391. static int cmd_show_module_version(int argc, char *argv[])
  392. {
  393. printf("fips140_module_version() => \"%s\"\n",
  394. fips140_module_version());
  395. return 0;
  396. }
  397. /* ---------------------------------------------------------------------------
  398. * show_service_indicators command
  399. * ---------------------------------------------------------------------------*/
  400. static const char * const default_services_to_show[] = {
  401. "aes",
  402. "cbc(aes)",
  403. "cbcmac(aes)",
  404. "cmac(aes)",
  405. "ctr(aes)",
  406. "cts(cbc(aes))",
  407. "ecb(aes)",
  408. "essiv(cbc(aes),sha256)",
  409. "gcm(aes)",
  410. "hmac(sha1)",
  411. "hmac(sha224)",
  412. "hmac(sha256)",
  413. "hmac(sha384)",
  414. "hmac(sha512)",
  415. "jitterentropy_rng",
  416. "sha1",
  417. "sha224",
  418. "sha256",
  419. "sha384",
  420. "sha512",
  421. "stdrng",
  422. "xcbc(aes)",
  423. "xts(aes)",
  424. };
  425. static int cmd_show_service_indicators(int argc, char *argv[])
  426. {
  427. const char * const *services = default_services_to_show;
  428. int count = ARRAY_SIZE(default_services_to_show);
  429. int i;
  430. if (argc > 1) {
  431. services = (const char **)(argv + 1);
  432. count = argc - 1;
  433. }
  434. for (i = 0; i < count; i++) {
  435. printf("fips140_is_approved_service(\"%s\") => %s\n",
  436. services[i],
  437. booltostr(fips140_is_approved_service(services[i])));
  438. }
  439. return 0;
  440. }
  441. /* ---------------------------------------------------------------------------
  442. * main()
  443. * ---------------------------------------------------------------------------*/
  444. static const struct command {
  445. const char *name;
  446. int (*func)(int argc, char *argv[]);
  447. } commands[] = {
  448. { "show_invalid_inputs", cmd_show_invalid_inputs },
  449. { "show_module_version", cmd_show_module_version },
  450. { "show_service_indicators", cmd_show_service_indicators },
  451. };
  452. static void usage(void)
  453. {
  454. fprintf(stderr,
  455. "Usage:\n"
  456. " fips140_lab_util show_invalid_inputs\n"
  457. " fips140_lab_util show_module_version\n"
  458. " fips140_lab_util show_service_indicators [SERVICE]...\n"
  459. );
  460. }
  461. int main(int argc, char *argv[])
  462. {
  463. int i;
  464. if (argc < 2) {
  465. usage();
  466. return 2;
  467. }
  468. for (i = 1; i < argc; i++) {
  469. if (strcmp(argv[i], "--help") == 0) {
  470. usage();
  471. return 2;
  472. }
  473. }
  474. for (i = 0; i < ARRAY_SIZE(commands); i++) {
  475. if (strcmp(commands[i].name, argv[1]) == 0)
  476. return commands[i].func(argc - 1, argv + 1);
  477. }
  478. fprintf(stderr, "Unknown command: %s\n\n", argv[1]);
  479. usage();
  480. return 2;
  481. }