ANDROID: fips140: add fips140_lab_util program
Add a sample program that supports various tests that the FIPS certification lab is required to do on fips140.ko. To do its work it uses AF_ALG, as well as the /dev/fips140 device node provided by a build of fips140.ko with CONFIG_CRYPTO_FIPS140_MOD_EVAL_TESTING enabled. Original commits: android12-5.10: 109f31ac23f5 ("ANDROID: fips140: add userspace interface for evaluation testing") a481d4352121 ("ANDROID: fips140: refactor and rename fips140_lab_test") 3a624c9ccdd7 ("ANDROID: fips140: add show_invalid_inputs command to fips140_lab_util") fe60669d0308 ("ANDROID: fips140: add dump_jitterentropy command to fips140_lab_util") Bug: 153614920 Bug: 188620248 Change-Id: Ide1875f39d439c3955d03a5f41160382544d47bd Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
parent
c6d5a76721
commit
41d708af25
638
samples/crypto/fips140_lab_util.c
Normal file
638
samples/crypto/fips140_lab_util.c
Normal file
@ -0,0 +1,638 @@
|
||||
// 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.
|
||||
* When possible, this program uses AF_ALG to access the crypto algorithms; this
|
||||
* requires that the kernel has AF_ALG enabled. Where AF_ALG isn't sufficient,
|
||||
* a custom device node /dev/fips140 is used instead; 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 <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <linux/if_alg.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/socket.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]))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
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 void __attribute__((noreturn))
|
||||
assertion_failed(const char *expr, const char *file, int line)
|
||||
{
|
||||
die("Assertion failed: %s at %s:%d", expr, file, line);
|
||||
}
|
||||
|
||||
#define ASSERT(e) ({ if (!(e)) assertion_failed(#e, __FILE__, __LINE__); })
|
||||
|
||||
static void rand_bytes(uint8_t *bytes, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
bytes[i] = rand();
|
||||
}
|
||||
|
||||
static const char *booltostr(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
static const char *bytes_to_hex(const uint8_t *bytes, size_t count)
|
||||
{
|
||||
static char hex[1025];
|
||||
size_t i;
|
||||
|
||||
ASSERT(count <= 512);
|
||||
for (i = 0; i < count; i++)
|
||||
sprintf(&hex[2*i], "%02x", bytes[i]);
|
||||
return hex;
|
||||
}
|
||||
|
||||
static void full_write(int fd, const void *buf, size_t count)
|
||||
{
|
||||
while (count) {
|
||||
ssize_t ret = write(fd, buf, count);
|
||||
|
||||
if (ret < 0)
|
||||
die_errno("write failed");
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
OPT_AMOUNT,
|
||||
OPT_ITERATIONS,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* AF_ALG utilities
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
#define AF_ALG_MAX_RNG_REQUEST_SIZE 128
|
||||
|
||||
static int get_alg_fd(const char *alg_type, const char *alg_name)
|
||||
{
|
||||
struct sockaddr_alg addr = {};
|
||||
int alg_fd;
|
||||
|
||||
alg_fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (alg_fd < 0)
|
||||
die("Failed to create AF_ALG socket.\n"
|
||||
"AF_ALG is only available when it has been enabled in the kernel.\n");
|
||||
|
||||
strncpy((char *)addr.salg_type, alg_type, sizeof(addr.salg_type) - 1);
|
||||
strncpy((char *)addr.salg_name, alg_name, sizeof(addr.salg_name) - 1);
|
||||
|
||||
if (bind(alg_fd, (void *)&addr, sizeof(addr)) != 0)
|
||||
die_errno("Failed to bind AF_ALG socket to %s %s",
|
||||
alg_type, alg_name);
|
||||
return alg_fd;
|
||||
}
|
||||
|
||||
static int get_req_fd(int alg_fd, const char *alg_name)
|
||||
{
|
||||
int req_fd = accept(alg_fd, NULL, NULL);
|
||||
|
||||
if (req_fd < 0)
|
||||
die_errno("Failed to get request file descriptor for %s",
|
||||
alg_name);
|
||||
return req_fd;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* dump_jitterentropy command
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
static void dump_from_jent_fd(int fd, size_t count)
|
||||
{
|
||||
uint8_t buf[AF_ALG_MAX_RNG_REQUEST_SIZE];
|
||||
|
||||
while (count) {
|
||||
ssize_t ret;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ret = read(fd, buf, MIN(count, sizeof(buf)));
|
||||
if (ret < 0)
|
||||
die_errno("error reading from jitterentropy_rng");
|
||||
full_write(STDOUT_FILENO, buf, ret);
|
||||
count -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_dump_jitterentropy(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "amount", required_argument, NULL, OPT_AMOUNT },
|
||||
{ "iterations", required_argument, NULL, OPT_ITERATIONS },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
size_t amount = 128;
|
||||
size_t iterations = 1;
|
||||
size_t i;
|
||||
int c;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case OPT_AMOUNT:
|
||||
amount = strtoul(optarg, NULL, 0);
|
||||
if (amount <= 0 || amount >= ULONG_MAX)
|
||||
die("invalid argument to --amount");
|
||||
break;
|
||||
case OPT_ITERATIONS:
|
||||
iterations = strtoul(optarg, NULL, 0);
|
||||
if (iterations <= 0 || iterations >= ULONG_MAX)
|
||||
die("invalid argument to --iterations");
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
int alg_fd = get_alg_fd("rng", "jitterentropy_rng");
|
||||
int req_fd = get_req_fd(alg_fd, "jitterentropy_rng");
|
||||
|
||||
dump_from_jent_fd(req_fd, amount);
|
||||
|
||||
close(req_fd);
|
||||
close(alg_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* show_invalid_inputs command
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
enum direction {
|
||||
UNSPECIFIED,
|
||||
DECRYPT,
|
||||
ENCRYPT,
|
||||
};
|
||||
|
||||
static const struct invalid_input_test {
|
||||
const char *alg_type;
|
||||
const char *alg_name;
|
||||
const char *key;
|
||||
size_t key_size;
|
||||
const char *msg;
|
||||
size_t msg_size;
|
||||
const char *iv;
|
||||
size_t iv_size;
|
||||
enum direction direction;
|
||||
int setkey_error;
|
||||
int crypt_error;
|
||||
} invalid_input_tests[] = {
|
||||
{
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 16,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 17,
|
||||
.setkey_error = EINVAL,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 24,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 32,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 33,
|
||||
.setkey_error = EINVAL,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 16,
|
||||
.msg_size = 1,
|
||||
.direction = DECRYPT,
|
||||
.crypt_error = EINVAL,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 16,
|
||||
.msg_size = 16,
|
||||
.direction = ENCRYPT,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "cbc(aes)",
|
||||
.key_size = 16,
|
||||
.msg_size = 17,
|
||||
.direction = ENCRYPT,
|
||||
.crypt_error = EINVAL,
|
||||
}, {
|
||||
.alg_type = "hash",
|
||||
.alg_name = "cmac(aes)",
|
||||
.key_size = 29,
|
||||
.setkey_error = EINVAL,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "xts(aes)",
|
||||
.key_size = 32,
|
||||
}, {
|
||||
.alg_type = "skcipher",
|
||||
.alg_name = "xts(aes)",
|
||||
.key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
.key_size = 32,
|
||||
.setkey_error = EINVAL,
|
||||
}
|
||||
};
|
||||
|
||||
static const char *describe_crypt_op(const struct invalid_input_test *t)
|
||||
{
|
||||
if (t->direction == ENCRYPT)
|
||||
return "encryption";
|
||||
if (t->direction == DECRYPT)
|
||||
return "decryption";
|
||||
if (strcmp(t->alg_type, "hash") == 0)
|
||||
return "hashing";
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
static bool af_alg_setkey(const struct invalid_input_test *t, int alg_fd)
|
||||
{
|
||||
const uint8_t *key = (const uint8_t *)t->key;
|
||||
uint8_t _key[t->key_size];
|
||||
|
||||
if (t->key_size == 0)
|
||||
return true;
|
||||
|
||||
if (t->key == NULL) {
|
||||
rand_bytes(_key, t->key_size);
|
||||
key = _key;
|
||||
}
|
||||
if (setsockopt(alg_fd, SOL_ALG, ALG_SET_KEY, key, t->key_size) != 0) {
|
||||
printf("%s: setting %zu-byte key failed with error '%s'\n",
|
||||
t->alg_name, t->key_size, strerror(errno));
|
||||
printf("\tkey was %s\n\n", bytes_to_hex(key, t->key_size));
|
||||
ASSERT(t->setkey_error == errno);
|
||||
return false;
|
||||
}
|
||||
printf("%s: setting %zu-byte key succeeded\n",
|
||||
t->alg_name, t->key_size);
|
||||
printf("\tkey was %s\n\n", bytes_to_hex(key, t->key_size));
|
||||
ASSERT(t->setkey_error == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void af_alg_process_msg(const struct invalid_input_test *t, int alg_fd)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct msghdr hdr = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
const uint8_t *msg = (const uint8_t *)t->msg;
|
||||
uint8_t *_msg = NULL;
|
||||
uint8_t *output = NULL;
|
||||
uint8_t *control = NULL;
|
||||
size_t controllen = 0;
|
||||
struct cmsghdr *cmsg;
|
||||
int req_fd;
|
||||
|
||||
if (t->msg_size == 0)
|
||||
return;
|
||||
|
||||
req_fd = get_req_fd(alg_fd, t->alg_name);
|
||||
|
||||
if (t->msg == NULL) {
|
||||
_msg = malloc(t->msg_size);
|
||||
rand_bytes(_msg, t->msg_size);
|
||||
msg = _msg;
|
||||
}
|
||||
output = malloc(t->msg_size);
|
||||
iov.iov_base = (void *)msg;
|
||||
iov.iov_len = t->msg_size;
|
||||
|
||||
if (t->direction != UNSPECIFIED)
|
||||
controllen += CMSG_SPACE(sizeof(uint32_t));
|
||||
if (t->iv_size)
|
||||
controllen += CMSG_SPACE(sizeof(struct af_alg_iv) + t->iv_size);
|
||||
control = calloc(1, controllen);
|
||||
hdr.msg_control = control;
|
||||
hdr.msg_controllen = controllen;
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
if (t->direction != UNSPECIFIED) {
|
||||
cmsg->cmsg_level = SOL_ALG;
|
||||
cmsg->cmsg_type = ALG_SET_OP;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
|
||||
*(uint32_t *)CMSG_DATA(cmsg) = t->direction == DECRYPT ?
|
||||
ALG_OP_DECRYPT : ALG_OP_ENCRYPT;
|
||||
cmsg = CMSG_NXTHDR(&hdr, cmsg);
|
||||
}
|
||||
if (t->iv_size) {
|
||||
struct af_alg_iv *alg_iv;
|
||||
|
||||
cmsg->cmsg_level = SOL_ALG;
|
||||
cmsg->cmsg_type = ALG_SET_IV;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(*alg_iv) + t->iv_size);
|
||||
alg_iv = (struct af_alg_iv *)CMSG_DATA(cmsg);
|
||||
alg_iv->ivlen = t->iv_size;
|
||||
memcpy(alg_iv->iv, t->iv, t->iv_size);
|
||||
}
|
||||
|
||||
if (sendmsg(req_fd, &hdr, 0) != t->msg_size)
|
||||
die_errno("sendmsg failed");
|
||||
|
||||
if (read(req_fd, output, t->msg_size) != t->msg_size) {
|
||||
printf("%s: %s of %zu-byte message failed with error '%s'\n",
|
||||
t->alg_name, describe_crypt_op(t), t->msg_size,
|
||||
strerror(errno));
|
||||
printf("\tmessage was %s\n\n", bytes_to_hex(msg, t->msg_size));
|
||||
ASSERT(t->crypt_error == errno);
|
||||
} else {
|
||||
printf("%s: %s of %zu-byte message succeeded\n",
|
||||
t->alg_name, describe_crypt_op(t), t->msg_size);
|
||||
printf("\tmessage was %s\n\n", bytes_to_hex(msg, t->msg_size));
|
||||
ASSERT(t->crypt_error == 0);
|
||||
}
|
||||
free(_msg);
|
||||
free(output);
|
||||
free(control);
|
||||
close(req_fd);
|
||||
}
|
||||
|
||||
static void test_invalid_input(const struct invalid_input_test *t)
|
||||
{
|
||||
int alg_fd = get_alg_fd(t->alg_type, t->alg_name);
|
||||
|
||||
if (af_alg_setkey(t, alg_fd))
|
||||
af_alg_process_msg(t, alg_fd);
|
||||
|
||||
close(alg_fd);
|
||||
}
|
||||
|
||||
static int cmd_show_invalid_inputs(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(invalid_input_tests); i++)
|
||||
test_invalid_input(&invalid_input_tests[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* 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[] = {
|
||||
{ "dump_jitterentropy", cmd_dump_jitterentropy },
|
||||
{ "show_invalid_inputs", cmd_show_invalid_inputs },
|
||||
{ "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 dump_jitterentropy [OPTION]...\n"
|
||||
" fips140_lab_util show_invalid_inputs\n"
|
||||
" fips140_lab_util show_module_version\n"
|
||||
" fips140_lab_util show_service_indicators [SERVICE]...\n"
|
||||
"\n"
|
||||
"Options for dump_jitterentropy:\n"
|
||||
" --amount=AMOUNT Amount to dump in bytes per iteration (default 128)\n"
|
||||
" --iterations=COUNT Number of start-up iterations (default 1)\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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user