ANDROID: fips140: refactor and rename fips140_lab_test
fips140_lab_test doesn't really do any tests per se, but rather is a utility program that dumps some output. The actual "test" is when the lab checks the output; we aren't allowed to check it ourselves. We also need to add some new functionality, which would work well as sub-commands. Also, the original idea was that this was just sample code which the lab would modify, but that's not actually happening. Therefore, rename fips140_lab_test to fips140_lab_util, and refactor its functionality into sub-commands 'show_module_version' and 'show_service_indicators'. This fits better with what is needed. Bug: 188620248 Change-Id: I7da84a139283f185f79b8d866547151169f26415 Signed-off-by: Eric Biggers <ebiggers@google.com> (cherry picked from commit 6ed33b82eaf8352574ba9ac7cff351a678fbe8e6)
This commit is contained in:
@@ -1,187 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* This is a sample program which calls some ioctls on /dev/fips140 and prints
|
||||
* the results. The purpose of this program is to allow the FIPS certification
|
||||
* lab to test some services of fips140.ko, which they are required to do. This
|
||||
* is a sample program only, and it can be modified by the lab as needed. This
|
||||
* program must be run as root, and it only works if the system has loaded a
|
||||
* build of fips140.ko with evaluation testing support enabled.
|
||||
*
|
||||
* This program can be compiled and run on an Android device as follows:
|
||||
*
|
||||
* NDK_DIR=$HOME/android-ndk-r23b # adjust directory path as needed
|
||||
* $NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang \
|
||||
* fips140_lab_test.c -O2 -Wall -o fips140_lab_test
|
||||
* adb push fips140_lab_test /data/local/tmp/
|
||||
* adb root
|
||||
* adb shell /data/local/tmp/fips140_lab_test
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../../crypto/fips140-eval-testing-uapi.h"
|
||||
|
||||
static int fips140_dev_fd = -1;
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
|
||||
|
||||
static const char *booltostr(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
do_die(const char *format, va_list va, int err)
|
||||
{
|
||||
fputs("ERROR: ", stderr);
|
||||
vfprintf(stderr, format, va);
|
||||
if (err)
|
||||
fprintf(stderr, ": %s", strerror(err));
|
||||
putc('\n', stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn, format(printf, 1, 2)))
|
||||
die_errno(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, format);
|
||||
do_die(format, va, errno);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn, format(printf, 1, 2)))
|
||||
die(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, format);
|
||||
do_die(format, va, 0);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static int get_fips140_device_number(void)
|
||||
{
|
||||
FILE *f;
|
||||
char line[128];
|
||||
int number;
|
||||
char name[32];
|
||||
|
||||
f = fopen("/proc/devices", "r");
|
||||
if (!f)
|
||||
die_errno("failed to open /proc/devices");
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (sscanf(line, "%d %31s", &number, name) == 2 &&
|
||||
strcmp(name, "fips140") == 0)
|
||||
return number;
|
||||
}
|
||||
fclose(f);
|
||||
die("fips140 device node is unavailable.\n"
|
||||
"The fips140 device node is only available when the fips140 module is loaded\n"
|
||||
"and has been built with evaluation testing support.");
|
||||
}
|
||||
|
||||
static void create_fips140_node_if_needed(void)
|
||||
{
|
||||
struct stat stbuf;
|
||||
int major;
|
||||
|
||||
if (stat("/dev/fips140", &stbuf) == 0)
|
||||
return;
|
||||
|
||||
major = get_fips140_device_number();
|
||||
if (mknod("/dev/fips140", S_IFCHR | 0600, makedev(major, 1)) != 0)
|
||||
die_errno("failed to create fips140 device node");
|
||||
}
|
||||
|
||||
static bool fips140_is_approved_service(const char *name)
|
||||
{
|
||||
int ret = ioctl(fips140_dev_fd, FIPS140_IOCTL_IS_APPROVED_SERVICE, name);
|
||||
|
||||
if (ret < 0)
|
||||
die_errno("FIPS140_IOCTL_IS_APPROVED_SERVICE unexpectedly failed");
|
||||
if (ret == 1)
|
||||
return true;
|
||||
if (ret == 0)
|
||||
return false;
|
||||
die("FIPS140_IOCTL_IS_APPROVED_SERVICE returned unexpected value %d",
|
||||
ret);
|
||||
}
|
||||
|
||||
static const char *fips140_module_version(void)
|
||||
{
|
||||
char buf[256];
|
||||
char *str;
|
||||
int ret = ioctl(fips140_dev_fd, FIPS140_IOCTL_MODULE_VERSION, buf);
|
||||
|
||||
if (ret < 0)
|
||||
die_errno("FIPS140_IOCTL_MODULE_VERSION unexpectedly failed");
|
||||
if (ret != 0)
|
||||
die("FIPS140_IOCTL_MODULE_VERSION returned unexpected value %d", ret);
|
||||
str = strdup(buf);
|
||||
if (!str)
|
||||
die("out of memory");
|
||||
return str;
|
||||
}
|
||||
|
||||
static const char * const services_to_check[] = {
|
||||
"aes",
|
||||
"cbc(aes)",
|
||||
"cbcmac(aes)",
|
||||
"cmac(aes)",
|
||||
"ctr(aes)",
|
||||
"cts(cbc(aes))",
|
||||
"ecb(aes)",
|
||||
"essiv(cbc(aes),sha256)",
|
||||
"gcm(aes)",
|
||||
"hmac(sha1)",
|
||||
"hmac(sha224)",
|
||||
"hmac(sha256)",
|
||||
"hmac(sha384)",
|
||||
"hmac(sha512)",
|
||||
"jitterentropy_rng",
|
||||
"sha1",
|
||||
"sha224",
|
||||
"sha256",
|
||||
"sha384",
|
||||
"sha512",
|
||||
"stdrng",
|
||||
"xcbc(aes)",
|
||||
"xts(aes)",
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (getuid() != 0)
|
||||
die("This program requires root. Run 'adb root' first.");
|
||||
|
||||
create_fips140_node_if_needed();
|
||||
|
||||
fips140_dev_fd = open("/dev/fips140", O_RDONLY);
|
||||
if (fips140_dev_fd < 0)
|
||||
die_errno("failed to open /dev/fips140");
|
||||
|
||||
printf("fips140_module_version() => \"%s\"\n", fips140_module_version());
|
||||
for (i = 0; i < ARRAY_SIZE(services_to_check); i++) {
|
||||
const char *service = services_to_check[i];
|
||||
|
||||
printf("fips140_is_approved_service(\"%s\") => %s\n", service,
|
||||
booltostr(fips140_is_approved_service(service)));
|
||||
}
|
||||
return 0;
|
||||
}
|
265
samples/crypto/fips140_lab_util.c
Normal file
265
samples/crypto/fips140_lab_util.c
Normal file
@@ -0,0 +1,265 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* This program provides commands that dump certain types of output from the
|
||||
* fips140 kernel module, as required by the FIPS lab for evaluation purposes.
|
||||
*
|
||||
* While the fips140 kernel module can only be accessed directly by other kernel
|
||||
* code, an easy-to-use userspace utility program was desired for lab testing.
|
||||
* For this, a custom device node /dev/fips140 is used; this requires that the
|
||||
* fips140 module is loaded and has evaluation testing support compiled in.
|
||||
*
|
||||
* This program can be compiled and run on an Android device as follows:
|
||||
*
|
||||
* NDK_DIR=$HOME/android-ndk-r23b # adjust directory path as needed
|
||||
* $NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang \
|
||||
* fips140_lab_util.c -O2 -Wall -o fips140_lab_util
|
||||
* adb push fips140_lab_util /data/local/tmp/
|
||||
* adb root
|
||||
* adb shell /data/local/tmp/fips140_lab_util
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../../crypto/fips140-eval-testing-uapi.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Utility functions
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
|
||||
|
||||
static void __attribute__((noreturn))
|
||||
do_die(const char *format, va_list va, int err)
|
||||
{
|
||||
fputs("ERROR: ", stderr);
|
||||
vfprintf(stderr, format, va);
|
||||
if (err)
|
||||
fprintf(stderr, ": %s", strerror(err));
|
||||
putc('\n', stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn, format(printf, 1, 2)))
|
||||
die_errno(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, format);
|
||||
do_die(format, va, errno);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn, format(printf, 1, 2)))
|
||||
die(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, format);
|
||||
do_die(format, va, 0);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static const char *booltostr(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
static void usage(void);
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* /dev/fips140 ioctls
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
static int get_fips140_device_number(void)
|
||||
{
|
||||
FILE *f;
|
||||
char line[128];
|
||||
int number;
|
||||
char name[32];
|
||||
|
||||
f = fopen("/proc/devices", "r");
|
||||
if (!f)
|
||||
die_errno("Failed to open /proc/devices");
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (sscanf(line, "%d %31s", &number, name) == 2 &&
|
||||
strcmp(name, "fips140") == 0)
|
||||
return number;
|
||||
}
|
||||
fclose(f);
|
||||
die("fips140 device node is unavailable.\n"
|
||||
"The fips140 device node is only available when the fips140 module is loaded\n"
|
||||
"and has been built with evaluation testing support.");
|
||||
}
|
||||
|
||||
static void create_fips140_node_if_needed(void)
|
||||
{
|
||||
struct stat stbuf;
|
||||
int major;
|
||||
|
||||
if (stat("/dev/fips140", &stbuf) == 0)
|
||||
return;
|
||||
|
||||
major = get_fips140_device_number();
|
||||
if (mknod("/dev/fips140", S_IFCHR | 0600, makedev(major, 1)) != 0)
|
||||
die_errno("Failed to create fips140 device node");
|
||||
}
|
||||
|
||||
static int fips140_dev_fd = -1;
|
||||
|
||||
static int fips140_ioctl(int cmd, const void *arg)
|
||||
{
|
||||
if (fips140_dev_fd < 0) {
|
||||
create_fips140_node_if_needed();
|
||||
fips140_dev_fd = open("/dev/fips140", O_RDONLY);
|
||||
if (fips140_dev_fd < 0)
|
||||
die_errno("Failed to open /dev/fips140");
|
||||
}
|
||||
return ioctl(fips140_dev_fd, cmd, arg);
|
||||
}
|
||||
|
||||
static bool fips140_is_approved_service(const char *name)
|
||||
{
|
||||
int ret = fips140_ioctl(FIPS140_IOCTL_IS_APPROVED_SERVICE, name);
|
||||
|
||||
if (ret < 0)
|
||||
die_errno("FIPS140_IOCTL_IS_APPROVED_SERVICE unexpectedly failed");
|
||||
if (ret == 1)
|
||||
return true;
|
||||
if (ret == 0)
|
||||
return false;
|
||||
die("FIPS140_IOCTL_IS_APPROVED_SERVICE returned unexpected value %d",
|
||||
ret);
|
||||
}
|
||||
|
||||
static const char *fips140_module_version(void)
|
||||
{
|
||||
static char buf[256];
|
||||
int ret;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ret = fips140_ioctl(FIPS140_IOCTL_MODULE_VERSION, buf);
|
||||
if (ret < 0)
|
||||
die_errno("FIPS140_IOCTL_MODULE_VERSION unexpectedly failed");
|
||||
if (ret != 0)
|
||||
die("FIPS140_IOCTL_MODULE_VERSION returned unexpected value %d",
|
||||
ret);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* show_module_version command
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
static int cmd_show_module_version(int argc, char *argv[])
|
||||
{
|
||||
printf("fips140_module_version() => \"%s\"\n",
|
||||
fips140_module_version());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* show_service_indicators command
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
static const char * const default_services_to_show[] = {
|
||||
"aes",
|
||||
"cbc(aes)",
|
||||
"cbcmac(aes)",
|
||||
"cmac(aes)",
|
||||
"ctr(aes)",
|
||||
"cts(cbc(aes))",
|
||||
"ecb(aes)",
|
||||
"essiv(cbc(aes),sha256)",
|
||||
"gcm(aes)",
|
||||
"hmac(sha1)",
|
||||
"hmac(sha224)",
|
||||
"hmac(sha256)",
|
||||
"hmac(sha384)",
|
||||
"hmac(sha512)",
|
||||
"jitterentropy_rng",
|
||||
"sha1",
|
||||
"sha224",
|
||||
"sha256",
|
||||
"sha384",
|
||||
"sha512",
|
||||
"stdrng",
|
||||
"xcbc(aes)",
|
||||
"xts(aes)",
|
||||
};
|
||||
|
||||
static int cmd_show_service_indicators(int argc, char *argv[])
|
||||
{
|
||||
const char * const *services = default_services_to_show;
|
||||
int count = ARRAY_SIZE(default_services_to_show);
|
||||
int i;
|
||||
|
||||
if (argc > 1) {
|
||||
services = (const char **)(argv + 1);
|
||||
count = argc - 1;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
printf("fips140_is_approved_service(\"%s\") => %s\n",
|
||||
services[i],
|
||||
booltostr(fips140_is_approved_service(services[i])));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* main()
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
static const struct command {
|
||||
const char *name;
|
||||
int (*func)(int argc, char *argv[]);
|
||||
} commands[] = {
|
||||
{ "show_module_version", cmd_show_module_version },
|
||||
{ "show_service_indicators", cmd_show_service_indicators },
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
" fips140_lab_util show_module_version\n"
|
||||
" fips140_lab_util show_service_indicators [SERVICE]...\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 2;
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--help") == 0) {
|
||||
usage();
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
||||
if (strcmp(commands[i].name, argv[1]) == 0)
|
||||
return commands[i].func(argc - 1, argv + 1);
|
||||
}
|
||||
fprintf(stderr, "Unknown command: %s\n\n", argv[1]);
|
||||
usage();
|
||||
return 2;
|
||||
}
|
Reference in New Issue
Block a user