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