From f50805b30323155755393ac6639aaae1067452c1 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Thu, 21 May 2015 13:47:12 -0400 Subject: Add test harness: no useful tests yet, just the framework. Add human-readable error strings for hal_error_t codes. --- Makefile.in | 15 ++++- aes_keywrap.c | 2 + configure | 5 +- configure.ac | 2 +- cryptech.h | 43 ++++++++------ errorstrings.c | 25 +++++++++ tests/Makefile.in | 24 ++++++++ tests/test-aes-key-wrap.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 234 insertions(+), 22 deletions(-) create mode 100644 errorstrings.c create mode 100644 tests/Makefile.in create mode 100644 tests/test-aes-key-wrap.c diff --git a/Makefile.in b/Makefile.in index b984151..bc60029 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,7 +2,7 @@ INC = cryptech.h LIB = libcryptech.a -OBJ = ${IO_OBJ} csprng.o hash.o aes_keywrap.o +OBJ = ${IO_OBJ} csprng.o hash.o aes_keywrap.o errorstrings.o IO_OBJ = ${IO_OBJ_@FPGA_BUS@} IO_OBJ_EIM = hal_io_eim.o novena-eim.o @@ -24,6 +24,9 @@ ${OBJ}: ${INC} ${LIB}: ${OBJ} ar rcs $@ $^ +test: all + cd tests; ${MAKE} -k $@ + install: ${LIB} ${INC} install ${LIB} ${libdir} install ${INC} ${includedir} @@ -34,3 +37,13 @@ uninstall: clean: rm -f ${OBJ} ${LIB} + cd tests; ${MAKE} $@ + +distclean: clean + cd tests; ${MAKE} $@ + rm -f config.log config.status TAGS Makefile + +tags: TAGS + +TAGS: *.[ch] + etags $^ diff --git a/aes_keywrap.c b/aes_keywrap.c index b8f505f..cc62676 100644 --- a/aes_keywrap.c +++ b/aes_keywrap.c @@ -53,6 +53,8 @@ static hal_error_t load_kek(const uint8_t *K, const size_t K_len, const kek_acti case bitsToBytes(256): config[3] |= AES_CONFIG_KEYLEN; break; + case bitsToBytes(192): + return HAL_ERROR_UNSUPPORTED_KEY; default: return HAL_ERROR_BAD_ARGUMENTS; } diff --git a/configure b/configure index 9c91f97..de3ba04 100755 --- a/configure +++ b/configure @@ -1699,14 +1699,12 @@ case $CC in #( *) : ;; esac - case $CFLAGS in #( "") : CFLAGS="-g -Wall -fPIC" ;; #( *) : ;; esac - case $LDFLAGS in #( "") : LDFLAGS="-g" ;; #( @@ -1723,7 +1721,7 @@ $as_echo "$as_me: C compiler flags: $CFLAGS" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Linker flags: $LDFLAGS" >&5 $as_echo "$as_me: Linker flags: $LDFLAGS" >&6;} -ac_config_files="$ac_config_files Makefile" +ac_config_files="$ac_config_files Makefile tests/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -2431,6 +2429,7 @@ for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index 07cd236..f7e4dd5 100644 --- a/configure.ac +++ b/configure.ac @@ -29,5 +29,5 @@ AC_MSG_NOTICE([C compiler: $CC]) AC_MSG_NOTICE([C compiler flags: $CFLAGS]) AC_MSG_NOTICE([Linker flags: $LDFLAGS]) -AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([Makefile tests/Makefile]) AC_OUTPUT diff --git a/cryptech.h b/cryptech.h index 8218aa2..3ceab95 100644 --- a/cryptech.h +++ b/cryptech.h @@ -425,30 +425,39 @@ /* - * C API error codes. + * C API error codes. Defined in this form so we can keep the tokens + * and error strings together. See errorstrings.c. */ -typedef enum { - HAL_OK, /* All's well */ - HAL_ERROR_MEMORY, /* malloc() failure or similar */ - HAL_ERROR_BAD_ARGUMENTS, /* Bad arguments given */ - HAL_ERROR_IO_SETUP_FAILED, /* Could not set up I/O with FPGA */ - HAL_ERROR_IO_TIMEOUT, /* I/O with FPGA timed out */ - HAL_ERROR_IO_UNEXPECTED, /* Unexpected response from FPGA */ - HAL_ERROR_IO_OS_ERROR, /* Operating system error talking to FPGA */ - HAL_ERROR_IO_BAD_COUNT, /* Bad byte count */ - HAL_ERROR_CSPRNG_BROKEN, /* CSPRNG is returning nonsense (perhaps core not present?) */ - HAL_ERROR_KEYWRAP_BAD_MAGIC, /* Bad magic number while unwrapping key */ - HAL_ERROR_KEYWRAP_BAD_LENGTH, /* Length out of range while unwrapping key */ - HAL_ERROR_KEYWRAP_BAD_PADDING, /* Nonzero padding detected while unwrapping key */ - N_HAL_ERRORS /* Number of error codes (must be last) */ -} hal_error_t; - +#define HAL_ERROR_LIST \ + DEFINE_HAL_ERROR(HAL_OK, "No error") \ + DEFINE_HAL_ERROR(HAL_ERROR_BAD_ARGUMENTS, "Bad arguments given") \ + DEFINE_HAL_ERROR(HAL_ERROR_UNSUPPORTED_KEY, "Unsupported key type or key length") \ + DEFINE_HAL_ERROR(HAL_ERROR_IO_SETUP_FAILED, "Could not set up I/O with FPGA") \ + DEFINE_HAL_ERROR(HAL_ERROR_IO_TIMEOUT, "I/O with FPGA timed out") \ + DEFINE_HAL_ERROR(HAL_ERROR_IO_UNEXPECTED, "Unexpected response from FPGA") \ + DEFINE_HAL_ERROR(HAL_ERROR_IO_OS_ERROR, "Operating system error talking to FPGA") \ + DEFINE_HAL_ERROR(HAL_ERROR_IO_BAD_COUNT, "Bad byte count") \ + DEFINE_HAL_ERROR(HAL_ERROR_CSPRNG_BROKEN, "CSPRNG is returning nonsense") \ + DEFINE_HAL_ERROR(HAL_ERROR_KEYWRAP_BAD_MAGIC, "Bad magic number while unwrapping key") \ + DEFINE_HAL_ERROR(HAL_ERROR_KEYWRAP_BAD_LENGTH, "Length out of range while unwrapping key") \ + DEFINE_HAL_ERROR(HAL_ERROR_KEYWRAP_BAD_PADDING, "Non-zero padding detected unwrapping key") \ + END_OF_HAL_ERROR_LIST + +/* Marker to forestall silly line continuation errors */ +#define END_OF_HAL_ERROR_LIST + +/* Define the error code enum here. See errorstrings.c for the text strings. */ +#define DEFINE_HAL_ERROR(_code_,_text_) _code_, +typedef enum { HAL_ERROR_LIST N_HAL_ERRORS } hal_error_t; +#undef DEFINE_HAL_ERROR /* * Public functions. */ +extern const char *hal_error_string(const hal_error_t err); + /* * Public I/O functions. */ diff --git a/errorstrings.c b/errorstrings.c new file mode 100644 index 0000000..9686eab --- /dev/null +++ b/errorstrings.c @@ -0,0 +1,25 @@ +/* + * Translate HAL error codes to strings. + */ + +#include +#include +#include +#include +#include + +#include "cryptech.h" + +#define DEFINE_HAL_ERROR(_code_,_text_) \ + case _code_: return _text_; + +const char *hal_error_string(const hal_error_t code) +{ + switch (code) { + HAL_ERROR_LIST; + default: + return "Unknown HAL error code"; + } +} + +#undef DEFINE_HAL_ERROR diff --git a/tests/Makefile.in b/tests/Makefile.in new file mode 100644 index 0000000..f63e4fc --- /dev/null +++ b/tests/Makefile.in @@ -0,0 +1,24 @@ +# @configure_input@ + +INC = ../cryptech.h +LIB = ../libcryptech.a +BIN = test-aes-key-wrap + +CC = @CC@ +CFLAGS = @CFLAGS@ -I.. +LDFLAGS = @LDFLAGS@ ${LIB} + +all: ${BIN} + +*.o: ${INC} + +${BIN}: ${LIB} + +test: all + for i in ${BIN}; do ./$$i; done + +clean: + rm -f *.o ${BIN} + +distclean: clean + rm -f Makefile diff --git a/tests/test-aes-key-wrap.c b/tests/test-aes-key-wrap.c new file mode 100644 index 0000000..cc31011 --- /dev/null +++ b/tests/test-aes-key-wrap.c @@ -0,0 +1,140 @@ +/* + * Test code for AES Key Wrap. + */ + +#include +#include +#include +#include +#include + +#include + +#ifndef TC_BUFSIZE +#define TC_BUFSIZE 4096 +#endif + +/* + * Test cases from RFC 5649...which all use a 192-bit key, which our + * AES implementation doesn't support, to these will never pass. Feh. + * + * Have to write our own, I guess, using our Python implementation or + * something. + */ + +typedef struct { + const char *K; /* Key-encryption-key */ + const char *Q; /* Plaintext */ + const char *C; /* Ciphertext */ +} test_case_t; + +static const test_case_t test_case[] = { + + { "5840df6e29b02af1 ab493b705bf16ea1 ae8338f4dcc176a8", /* K */ + "c37b7e6492584340 bed1220780894115 5068f738", /* Q */ + "138bdeaa9b8fa7fc 61f97742e72248ee 5ae6ae5360d1ae6a 5f54f373fa543b6a"}, /* C */ + + { "5840df6e29b02af1 ab493b705bf16ea1 ae8338f4dcc176a8", /* K */ + "466f7250617369", /* Q */ + "afbeb0f07dfbf541 9200f2ccb50bb24f" } /* C */ + +}; + +static int parse_hex(const char *hex, uint8_t *bin, size_t *len, const size_t max) +{ + static const char whitespace[] = " \t\r\n"; + size_t i; + + assert(hex != NULL && bin != NULL && len != NULL); + + hex += strspn(hex, whitespace); + + for (i = 0; *hex != '\0' && i < max; i++, hex += 2 + strspn(hex + 2, whitespace)) + if (sscanf(hex, "%2hhx", &bin[i]) != 1) + return 0; + + *len = i; + + return *hex == '\0'; +} + +static const char *format_hex(const uint8_t *bin, const size_t len, char *hex, const size_t max) +{ + size_t i; + + assert(bin != NULL && hex != NULL && len * 3 < max); + + if (len == 0) + return ""; + + for (i = 0; i < len; i++) + sprintf(hex + 3 * i, "%02x:", bin[i]); + + hex[len * 3 - 1] = '\0'; + return hex; +} + +static int run_test(const test_case_t * const tc) +{ + uint8_t K[TC_BUFSIZE], Q[TC_BUFSIZE], C[TC_BUFSIZE], q[TC_BUFSIZE], c[TC_BUFSIZE]; + size_t K_len, Q_len, C_len, q_len = sizeof(q), c_len = sizeof(c); + char h1[TC_BUFSIZE * 3], h2[TC_BUFSIZE * 3]; + hal_error_t err; + int ok = 1; + + assert(tc != NULL); + + if (!parse_hex(tc->K, K, &K_len, sizeof(K))) + return printf("couldn't parse KEK %s\n", tc->K), 0; + + if (!parse_hex(tc->Q, Q, &Q_len, sizeof(Q))) + return printf("couldn't parse plaintext %s\n", tc->Q), 0; + + if (!parse_hex(tc->C, C, &C_len, sizeof(C))) + return printf("couldn't parse ciphertext %s\n", tc->C), 0; + + if ((err = hal_aes_keywrap(K, K_len, Q, Q_len, c, &c_len)) != HAL_OK) + ok = printf("couldn't wrap %s: %s\n", tc->Q, hal_error_string(err)), 0; + + if ((err = hal_aes_keyunwrap(K, K_len, C, C_len, q, &q_len)) != HAL_OK) + ok = printf("couldn't unwrap %s: %s\n", tc->C, hal_error_string(err)), 0; + + if (C_len != c_len || memcmp(C, c, C_len) != 0) + ok = printf("ciphertext mismatch:\n Want: %s\n Got: %s\n", + format_hex(C, C_len, h1, sizeof(h1)), + format_hex(c, c_len, h2, sizeof(h2))), 0; + + if (Q_len != q_len || memcmp(Q, q, Q_len) != 0) + ok = printf("plaintext mismatch:\n Want: %s\n Got: %s\n", + format_hex(Q, Q_len, h1, sizeof(h1)), + format_hex(q, q_len, h2, sizeof(h2))), 0; + + return ok; +} + +int main (int argc, char *argv[]) +{ + int i, ok = 1; + + for (i = 0; i < sizeof(test_case)/sizeof(*test_case); i++) { + printf("Running test case #%d...", i); + if (run_test(&test_case[i])) + printf("OK\n"); + else + ok = 0; + } + + return !ok; +} + +/* + * "Any programmer who fails to comply with the standard naming, formatting, + * or commenting conventions should be shot. If it so happens that it is + * inconvenient to shoot him, then he is to be politely requested to recode + * his program in adherence to the above standard." + * -- Michael Spier, Digital Equipment Corporation + * + * Local variables: + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.3