diff options
Diffstat (limited to 'projects/cli-test')
26 files changed, 2134 insertions, 378 deletions
diff --git a/projects/cli-test/Makefile b/projects/cli-test/Makefile index acf2720..5bb3fb1 100644 --- a/projects/cli-test/Makefile +++ b/projects/cli-test/Makefile @@ -1,11 +1,28 @@ -TEST = cli-test +PROJ = cli-test -OBJS = crc32.o test_sdram.o mgmt-cli.o mgmt-dfu.c mgmt-fpga.c mgmt-misc.c mgmt-show.c mgmt-test.c +# objs in addition to $(PROJ).o +OBJS = \ + mgmt-cli.o \ + mgmt-dfu.o \ + mgmt-fpga.o \ + mgmt-keystore.o \ + mgmt-masterkey.o \ + mgmt-misc.o \ + mgmt-show.o -CFLAGS += -I$(LIBCLI_DIR) -LIBS += $(LIBCLI_DIR)/libcli.a +CFLAGS += -I$(LIBCLI_SRC) -I$(LIBHAL_SRC) +CFLAGS += -I$(LIBTFM_BLD) +CFLAGS += -Wno-missing-field-initializers -all: $(TEST:=.elf) +ifdef DO_TIMING +CFLAGS += -DDO_TIMING +OBJS += mgmt-timing.o $(TOPLEVEL)/stm-dwt.o +LDFLAGS += -lm +endif + +LIBS += $(LIBCLI_BLD)/libcli.a $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a + +all: $(PROJ:=.elf) %.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS) $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c index ed6aac3..c50338b 100644 --- a/projects/cli-test/cli-test.c +++ b/projects/cli-test/cli-test.c @@ -33,6 +33,7 @@ */ #include "stm-init.h" #include "stm-led.h" +#include "stm-uart.h" #include "mgmt-cli.h" #include "mgmt-dfu.h" @@ -40,72 +41,78 @@ #include "mgmt-misc.h" #include "mgmt-show.h" #include "mgmt-test.h" +#include "mgmt-keystore.h" #include <string.h> +#include <strings.h> /* MGMT UART interrupt receive buffer (data will be put in a larger ring buffer) */ volatile uint8_t uart_rx; - -int check_auth(const char *username, const char *password) -{ - if (strcasecmp(username, "ct") != 0) - return CLI_ERROR; - if (strcasecmp(password, "ct") != 0) - return CLI_ERROR; - return CLI_OK; -} - -typedef void (*pFunction)(void); - -/* This is it's own function to make it more convenient to set a breakpoint at it in gdb */ -void do_early_dfu_jump(void) -{ - pFunction loaded_app = (pFunction) *dfu_code_ptr; - /* Set the stack pointer to the correct one for the firmware */ - __set_MSP(*dfu_msp_ptr); - /* Set the Vector Table Offset Register */ - SCB->VTOR = (uint32_t) dfu_firmware; - loaded_app(); - while (1); -} +/* Sleep for specified number of seconds -- used after bad PIN. */ +void hal_sleep(const unsigned seconds) { HAL_Delay(seconds * 1000); } int main() { - static struct cli_def cli; + stm_init(); + led_on(LED_GREEN); - /* Check if we've just rebooted in order to jump to the firmware. */ - if (*dfu_control == HARDWARE_EARLY_DFU_JUMP) { - *dfu_control = 0; - do_early_dfu_jump(); + /* For the hsm, the keystores are initialized in hal_rpc_server_init(), + * which is...less than optimal, but this is not the time or place to fix + * it, especially in light of all the terrible things I'm doing in this + * version of cli-test. + */ + extern void *hal_ks_token, *hal_ks_volatile; + extern int hal_ks_init(void *, int); + if (hal_ks_init(hal_ks_volatile, 1) != 0 || hal_ks_init(hal_ks_token, 1) != 0) + Error_Handler(); + + while (1) { + cli_main(); + /* embedded_cli_loop returns when the user enters 'quit' or 'exit' */ } - stm_init(); + /* NOT REACHED */ + Error_Handler(); +} - led_on(LED_RED); - mgmt_cli_init(&cli); - cli_set_auth_callback(&cli, check_auth); +/* end of variables declared with __attribute__((section(".sdram1"))) */ +extern uint8_t _esdram1 __asm ("_esdram1"); +/* end of SDRAM1 section */ +extern uint8_t __end_sdram1 __asm ("__end_sdram1"); +static uint8_t *sdram_heap = &_esdram1; - configure_cli_show(&cli); - configure_cli_fpga(&cli); - configure_cli_test(&cli); - configure_cli_misc(&cli); - configure_cli_dfu(&cli); +/* Allocate memory from SDRAM1. */ +static uint8_t *sdram_malloc(size_t size) +{ + uint8_t *p = sdram_heap; - led_off(LED_RED); - led_on(LED_GREEN); +#define pad(n) (((n) + 3) & ~3) + size = pad(size); - embedded_cli_loop(&cli); + if (p + size + sizeof(uint32_t) > &__end_sdram1) + return NULL; - /* embedded_cli_loop returns when the user enters 'quit' or 'exit' */ + *(uint32_t *)p = (uint32_t)size; + p += sizeof(uint32_t); - cli_print(&cli, "Rebooting in 3 seconds"); - HAL_Delay(3000); - HAL_NVIC_SystemReset(); + sdram_heap += size + sizeof(uint32_t); + return p; +} - /* NOT REACHED */ - Error_Handler(); +/* Implement static memory allocation for libhal over sdram_malloc(). + * Used in hal_ks_init. + */ +void *hal_allocate_static_memory(const size_t size) +{ + return sdram_malloc(size); +} + +int hal_free_static_memory(const void * const ptr) +{ + return 0; } + diff --git a/projects/cli-test/crc32.c b/projects/cli-test/crc32.c deleted file mode 100644 index 4d1a0bc..0000000 --- a/projects/cli-test/crc32.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Reference code from RFC1952. Not meant to be used outside test code. */ - -#include "stm32f4xx_hal.h" - - -/* Table of CRCs of all 8-bit messages. */ -unsigned long crc_table[256]; - -/* Flag: has the table been computed? Initially false. */ -int crc_table_computed = 0; - -/* Make the table for a fast CRC. */ -void make_crc_table(void) -{ - unsigned long c; - - int n, k; - for (n = 0; n < 256; n++) { - c = (unsigned long) n; - for (k = 0; k < 8; k++) { - if (c & 1) { - c = 0xedb88320L ^ (c >> 1); - } else { - c = c >> 1; - } - } - crc_table[n] = c; - } - crc_table_computed = 1; -} - -/* - Update a running crc with the bytes buf[0..len-1] and return - the updated crc. The crc should be initialized to zero. Pre- and - post-conditioning (one's complement) is performed within this - function so it shouldn't be done by the caller. Usage example: - - unsigned long crc = 0L; - - while (read_buffer(buffer, length) != EOF) { - crc = update_crc(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ -uint32_t update_crc(uint32_t crc, uint8_t *buf, int len) -{ - unsigned long c = crc ^ 0xffffffffL; - int n; - - if (!crc_table_computed) - make_crc_table(); - for (n = 0; n < len; n++) { - c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); - } - return c ^ 0xffffffffL; -} - -/* Return the CRC of the bytes buf[0..len-1]. */ -unsigned long crc(unsigned char *buf, int len) -{ - return update_crc(0L, buf, len); -} diff --git a/projects/cli-test/filetransfer b/projects/cli-test/filetransfer index f704e31..6e58781 100755 --- a/projects/cli-test/filetransfer +++ b/projects/cli-test/filetransfer @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright (c) 2016, NORDUnet A/S All rights reserved. # @@ -37,7 +37,7 @@ import struct import serial import argparse -from binascii import crc32 +from binascii import crc32, hexlify CHUNK_SIZE = 256 DFU_CHUNK_SIZE = 256 @@ -79,19 +79,19 @@ def parse_args(): def _write(dst, data): dst.write(data) if len(data) == 4: - print("Wrote 0x{!s}".format(data.encode('hex'))) + print(("Wrote 0x{!s}".format(hexlify(data).decode("ascii")))) else: - print("Wrote {!r}".format(data)) + print(("Wrote {!r}".format(data))) def _read(dst): - res = '' + res = b'' while True: x = dst.read(1) if not x: break res += x - print ("Read {!r}".format(res)) + print(("Read {!r}".format(res))) return res @@ -142,19 +142,19 @@ def send_file(filename, args, dst): if not data: break dst.write(data) - print("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter, int(size / chunk_size))) + print(("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter, int(size / chunk_size)))) # read ACK (a counter of number of 4k chunks received) while True: ack_bytes = dst.read(4) if len(ack_bytes) == 4: break - print('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes)) + print(('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes))) dst.write('\r') # eventually get back to the CLI prompt ack = struct.unpack('<I', ack_bytes)[0] if ack != counter + 1: - print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter)) + print(('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter))) flush = dst.read(100) - print('FLUSH data: {!r}'.format(flush)) + print(('FLUSH data: {!r}'.format(flush))) return False counter += 1 diff --git a/projects/cli-test/mgmt-cli.c b/projects/cli-test/mgmt-cli.c index 3b4ffe9..960d691 100644 --- a/projects/cli-test/mgmt-cli.c +++ b/projects/cli-test/mgmt-cli.c @@ -3,7 +3,9 @@ * --------- * Management CLI code. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -31,140 +33,166 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <string.h> + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK #include "stm-init.h" #include "stm-uart.h" #include "stm-led.h" + #include "mgmt-cli.h" +#include "mgmt-fpga.h" +#include "mgmt-misc.h" +#include "mgmt-show.h" +#include "mgmt-test.h" +#include "mgmt-keystore.h" +#include "mgmt-masterkey.h" +#ifdef DO_TIMING +#include "mgmt-timing.h" +#endif + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + +#ifndef CLI_UART_RECVBUF_SIZE +#define CLI_UART_RECVBUF_SIZE 256 +#endif + +typedef struct { + unsigned ridx; + unsigned widx; + mgmt_cli_dma_state_t rx_state; + uint8_t buf[CLI_UART_RECVBUF_SIZE]; +} ringbuf_t; -#include <string.h> +inline void ringbuf_init(ringbuf_t *rb) +{ + memset(rb, 0, sizeof(*rb)); +} -extern uint8_t uart_rx; +/* return number of characters read */ +inline int ringbuf_read_char(ringbuf_t *rb, uint8_t *c) +{ + if (rb->ridx != rb->widx) { + *c = rb->buf[rb->ridx]; + if (++rb->ridx >= sizeof(rb->buf)) + rb->ridx = 0; + return 1; + } + return 0; +} -struct uart_ringbuf_t { - uint32_t enabled, ridx; - enum mgmt_cli_dma_state rx_state; - uint8_t buf[CLI_UART_RECVBUF_SIZE]; -}; +inline void ringbuf_write_char(ringbuf_t *rb, uint8_t c) +{ + rb->buf[rb->widx] = c; + if (++rb->widx >= sizeof(rb->buf)) + rb->widx = 0; +} + +static ringbuf_t uart_ringbuf; -volatile struct uart_ringbuf_t uart_ringbuf = {1, 0, DMA_RX_STOP, {0}}; +/* current character received from UART */ +static uint8_t uart_rx; -#define RINGBUF_RIDX(rb) (rb.ridx & CLI_UART_RECVBUF_MASK) -#define RINGBUF_WIDX(rb) (sizeof(rb.buf) - __HAL_DMA_GET_COUNTER(huart_mgmt.hdmarx)) -#define RINGBUF_COUNT(rb) ((unsigned)(RINGBUF_WIDX(rb) - RINGBUF_RIDX(rb))) -#define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.buf[RINGBUF_RIDX(rb)] = '.'; rb.ridx++;} +/* Callback for HAL_UART_Receive_DMA(). + */ +void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart) +{ + huart = huart; -void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) + ringbuf_write_char(&uart_ringbuf, uart_rx); +} + +static void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) { - char crlf[] = "\r\n"; - uart_send_string2(STM_UART_MGMT, buf); - uart_send_string2(STM_UART_MGMT, crlf); + uart_send_string(buf); + uart_send_string("\r\n"); } -int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) +static ssize_t uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) { - uint32_t timeout = 0xffffff; - while (count && timeout) { - if (RINGBUF_COUNT(uart_ringbuf)) { - RINGBUF_READ(uart_ringbuf, *(uint8_t *) buf); - buf++; - count--; + for (size_t i = 0; i < count; ++i) { + while (ringbuf_read_char(&uart_ringbuf, (uint8_t *)(buf + i)) == 0) { } - timeout--; } - if (! timeout) return 0; - - return 1; + return (ssize_t)count; } -int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count) +static ssize_t uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count) { - uart_send_bytes(STM_UART_MGMT, (uint8_t *) buf, count); - return (int) count; + uart_send_bytes((uint8_t *) buf, count); + return (ssize_t)count; } -int control_mgmt_uart_dma_rx(enum mgmt_cli_dma_state state) +int control_mgmt_uart_dma_rx(mgmt_cli_dma_state_t state) { if (state == DMA_RX_START) { if (uart_ringbuf.rx_state != DMA_RX_START) { - memset((void *) uart_ringbuf.buf, 0, sizeof(uart_ringbuf.buf)); - - /* Start receiving data from the UART using DMA */ - HAL_UART_Receive_DMA(&huart_mgmt, (uint8_t *) uart_ringbuf.buf, sizeof(uart_ringbuf.buf)); - uart_ringbuf.ridx = 0; + ringbuf_init(&uart_ringbuf); + HAL_UART_Receive_DMA(&huart_mgmt, &uart_rx, 1); uart_ringbuf.rx_state = DMA_RX_START; } return 1; } else if (state == DMA_RX_STOP) { - if (HAL_UART_DMAStop(&huart_mgmt) != HAL_OK) return 0; + if (HAL_UART_DMAStop(&huart_mgmt) != CMSIS_HAL_OK) return 0; uart_ringbuf.rx_state = DMA_RX_STOP; return 1; } return 0; } -int embedded_cli_loop(struct cli_def *cli) +static struct cli_def *mgmt_cli_init(void) { - unsigned char c; - int n = 0; - static struct cli_loop_ctx ctx; - - memset(&ctx, 0, sizeof(ctx)); - ctx.insertmode = 1; + struct cli_def *cli; + cli = cli_init(); + cli_read_callback(cli, uart_cli_read); + cli_write_callback(cli, uart_cli_write); + cli_print_callback(cli, uart_cli_print); + cli_set_banner(cli, "Cryptech Alpha test CLI"); + cli_set_hostname(cli, "cryptech"); + return cli; +} - cli->state = CLI_STATE_LOGIN; +hal_user_t user; - /* start off in unprivileged mode */ - cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED); - cli_set_configmode(cli, MODE_EXEC, NULL); +static int check_auth(const char *username, const char *password) +{ + if (strcmp(username, "ct") != 0) + return CLI_ERROR; + if (strcmp(password, "ct") != 0) + return CLI_ERROR; + return CLI_OK; +} - cli_error(cli, "%s", cli->banner); +int cli_main(void) +{ + struct cli_def *cli; + cli = mgmt_cli_init(); + cli_set_auth_callback(cli, check_auth); + + configure_cli_show(cli); + configure_cli_fpga(cli); + configure_cli_misc(cli); + configure_cli_keystore(cli); + configure_cli_masterkey(cli); +#ifdef DO_TIMING + configure_cli_timing(cli); +#endif while (1) { - cli_loop_start_new_command(cli, &ctx); - - control_mgmt_uart_dma_rx(DMA_RX_START); - - while (1) { - cli_loop_show_prompt(cli, &ctx); - - n = cli_loop_read_next_char(cli, &ctx, &c); - - /* - cli_print(cli, "Next char: '%c'/%i, ringbuf ridx %i, widx %i", - c, (int) c, - uart_ringbuf.ridx, - RINGBUF_WIDX(uart_ringbuf) - */ - if (n == CLI_LOOP_CTRL_BREAK) - break; - if (n == CLI_LOOP_CTRL_CONTINUE) - continue; - - n = cli_loop_process_char(cli, &ctx, c); - if (n == CLI_LOOP_CTRL_BREAK) - break; - if (n == CLI_LOOP_CTRL_CONTINUE) - continue; - } - - if (ctx.l < 0) break; + control_mgmt_uart_dma_rx(DMA_RX_START); - /* cli_print(cli, "Process command: '%s'", ctx.cmd); */ - n = cli_loop_process_cmd(cli, &ctx); - if (n == CLI_LOOP_CTRL_BREAK) - break; + cli_loop(cli, 0); + /* cli_loop returns when the user enters 'quit' or 'exit' */ + cli_print(cli, "\nLogging out...\n"); + user = HAL_USER_NONE; } - return CLI_OK; + /*NOTREACHED*/ + return -1; } -void mgmt_cli_init(struct cli_def *cli) -{ - cli_init(cli); - cli_read_callback(cli, uart_cli_read); - cli_write_callback(cli, uart_cli_write); - cli_print_callback(cli, uart_cli_print); - cli_set_banner(cli, "Cryptech Alpha"); - cli_set_hostname(cli, "cryptech"); - cli_telnet_protocol(cli, 0); -} diff --git a/projects/cli-test/mgmt-cli.h b/projects/cli-test/mgmt-cli.h index 16c9fbd98..0b9c40c 100644 --- a/projects/cli-test/mgmt-cli.h +++ b/projects/cli-test/mgmt-cli.h @@ -35,52 +35,15 @@ #ifndef __STM32_MGMT_CLI_H #define __STM32_MGMT_CLI_H -#include "stm-init.h" #include <libcli.h> - -/* A bunch of defines to make it easier to add/maintain the CLI commands. - * - */ -#define _cli_cmd_struct(name, fullname, func, help) \ - static struct cli_command cmd_##fullname##_s = \ - {(char *) #name, func, 0, help, \ - PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL} - -/* ROOT is a top-level label with no command */ -#define cli_command_root(name) \ - _cli_cmd_struct(name, name, NULL, NULL); \ - cli_register_command2(cli, &cmd_##name##_s, NULL) - -/* BRANCH is a label with a parent, but no command */ -#define cli_command_branch(parent, name) \ - _cli_cmd_struct(name, parent##_##name, NULL, NULL); \ - cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s) - -/* NODE is a label with a parent and with a command associated with it */ -#define cli_command_node(parent, name, help) \ - _cli_cmd_struct(name, parent##_##name, cmd_##parent##_##name, (char *) help); \ - cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s) - -/* ROOT NODE is a label without a parent, but with a command associated with it */ -#define cli_command_root_node(name, help) \ - _cli_cmd_struct(name, name, cmd_##name, (char *) help); \ - cli_register_command2(cli, &cmd_##name##_s, NULL) - - -#define CLI_UART_RECVBUF_SIZE 256 /* This must be a power of 2 */ -#define CLI_UART_RECVBUF_MASK (CLI_UART_RECVBUF_SIZE - 1) - -enum mgmt_cli_dma_state { +typedef enum { DMA_RX_STOP, DMA_RX_START, -}; +} mgmt_cli_dma_state_t; + +extern int control_mgmt_uart_dma_rx(mgmt_cli_dma_state_t state); -extern void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf); -extern int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count); -extern int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count); -extern int embedded_cli_loop(struct cli_def *cli); -extern void mgmt_cli_init(struct cli_def *cli); -extern int control_mgmt_uart_dma_rx(enum mgmt_cli_dma_state state); +extern int cli_main(void); #endif /* __STM32_MGMT_CLI_H */ diff --git a/projects/cli-test/mgmt-dfu.c b/projects/cli-test/mgmt-dfu.c index 27fd722..c7273f4 100644 --- a/projects/cli-test/mgmt-dfu.c +++ b/projects/cli-test/mgmt-dfu.c @@ -40,7 +40,10 @@ #include <string.h> -extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len); +#define DFU_FIRMWARE_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_START) +#define DFU_FIRMWARE_END_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_END) +#define DFU_UPLOAD_CHUNK_SIZE 256 +#define HARDWARE_EARLY_DFU_JUMP 0xBADABADA /* Linker symbols are strange in C. Make regular pointers for sanity. */ __IO uint32_t *dfu_control = &CRYPTECH_DFU_CONTROL; @@ -53,25 +56,29 @@ __IO uint32_t *dfu_msp_ptr = &CRYPTECH_FIRMWARE_START; */ __IO uint32_t *dfu_code_ptr = &CRYPTECH_FIRMWARE_START + 1; - - -int cmd_dfu_dump(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_dfu_dump(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + cli_print(cli, "First 256 bytes from DFU application address %p:\r\n", dfu_firmware); - uart_send_hexdump(STM_UART_MGMT, (uint8_t *) dfu_firmware, 0, 0xff); - uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\n"); + uart_send_hexdump((uint8_t *) dfu_firmware, 0, 0xff); + cli_print(cli, "\n"); return CLI_OK; } -int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[], int argc) { int status; - cli_print(cli, "Erasing flash sectors %i to %i (address %p to %p) - expect the CLI to crash now", - stm_flash_sector_num((uint32_t) dfu_firmware), - stm_flash_sector_num((uint32_t) dfu_firmware_end), + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Erasing flash address %p to %p - expect the CLI to crash now", dfu_firmware, dfu_firmware_end); @@ -82,9 +89,14 @@ int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[], int ar return CLI_OK; } -int cmd_dfu_jump(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_dfu_jump(struct cli_def *cli, const char *command, char *argv[], int argc) { uint32_t i; + + command = command; + argv = argv; + argc = argc; + /* Load first byte from the DFU_FIRMWARE_PTR to verify it contains an IVT before * jumping there. */ @@ -112,9 +124,11 @@ int cmd_dfu_jump(struct cli_def *cli, const char *command, char *argv[], int arg void configure_cli_dfu(struct cli_def *cli) { - cli_command_root(dfu); + struct cli_command *c; + + c = cli_register_command(cli, NULL, "dfu", NULL, 0, 0, NULL); - cli_command_node(dfu, dump, "Show the first 256 bytes of the loaded firmware"); - cli_command_node(dfu, jump, "Jump to the loaded firmware"); - cli_command_node(dfu, erase, "Erase the firmware memory (will crash the CLI)"); + cli_register_command(cli, c, "dump", cmd_dfu_dump, 0, 0, "Show the first 256 bytes of the loaded firmware"); + cli_register_command(cli, c, "jump", cmd_dfu_jump, 0, 0, "Jump to the loaded firmware"); + cli_register_command(cli, c, "erase", cmd_dfu_erase, 0, 0, "Erase the firmware memory (will crash the CLI)"); } diff --git a/projects/cli-test/mgmt-dfu.h b/projects/cli-test/mgmt-dfu.h index ac6589c..6128b35 100644 --- a/projects/cli-test/mgmt-dfu.h +++ b/projects/cli-test/mgmt-dfu.h @@ -35,7 +35,6 @@ #ifndef __STM32_CLI_MGMT_DFU_H #define __STM32_CLI_MGMT_DFU_H -#include "stm-init.h" #include <libcli.h> /* symbols defined in the linker script (STM32F429BI.ld) */ @@ -43,17 +42,6 @@ extern uint32_t CRYPTECH_FIRMWARE_START; extern uint32_t CRYPTECH_FIRMWARE_END; extern uint32_t CRYPTECH_DFU_CONTROL; -#define DFU_FIRMWARE_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_START) -#define DFU_FIRMWARE_END_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_END) -#define DFU_UPLOAD_CHUNK_SIZE 256 -#define HARDWARE_EARLY_DFU_JUMP 0xBADABADA - -extern __IO uint32_t *dfu_control; -extern __IO uint32_t *dfu_firmware; -extern __IO uint32_t *dfu_msp_ptr; -extern __IO uint32_t *dfu_code_ptr; - - extern void configure_cli_dfu(struct cli_def *cli); #endif /* __STM32_CLI_MGMT_DFU_H */ diff --git a/projects/cli-test/mgmt-fpga.c b/projects/cli-test/mgmt-fpga.c index 8c1b2a8..b913316 100644 --- a/projects/cli-test/mgmt-fpga.c +++ b/projects/cli-test/mgmt-fpga.c @@ -3,7 +3,7 @@ * ----------- * CLI code to manage the FPGA configuration etc. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -43,25 +43,43 @@ #include <string.h> -volatile uint32_t dfu_offset = 0; +static volatile uint32_t dfu_offset = 0; -int _flash_write_callback(uint8_t *buf, size_t len) { - int res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE) == 1; + +static HAL_StatusTypeDef _flash_write_callback(uint8_t *buf, size_t len) +{ + HAL_StatusTypeDef res; + + if ((dfu_offset % FPGACFG_SECTOR_SIZE) == 0) + /* first page in sector, need to erase sector */ + if ((res = fpgacfg_erase_sector(dfu_offset / FPGACFG_SECTOR_SIZE)) != HAL_OK) + return res; + + /* fpgacfg_write_data (a thin wrapper around n25q128_write_data) + * requires the offset and length to be page-aligned. The last chunk + * will be short, so we pad it out to the full chunk size. + */ + len = len; + res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE); dfu_offset += BITSTREAM_UPLOAD_CHUNK_SIZE; return res; } -int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc) { uint8_t buf[BITSTREAM_UPLOAD_CHUNK_SIZE]; + command = command; + argv = argv; + argc = argc; + dfu_offset = 0; fpgacfg_access_control(ALLOW_ARM); cli_print(cli, "Checking if FPGA config memory is accessible"); - if (fpgacfg_check_id() != 1) { + if (fpgacfg_check_id() != HAL_OK) { cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed."); return CLI_ERROR; } @@ -74,12 +92,16 @@ int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *ar return CLI_OK; } -int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + fpgacfg_access_control(ALLOW_ARM); cli_print(cli, "Checking if FPGA config memory is accessible"); - if (fpgacfg_check_id() != 1) { + if (fpgacfg_check_id() != HAL_OK) { cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed."); return CLI_ERROR; } @@ -90,7 +112,7 @@ int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *arg * * This command could be made to accept an argument indicating the whole memory should be erased. */ - if (! fpgacfg_erase_sectors(1)) { + if (fpgacfg_erase_sector(0) != HAL_OK) { cli_print(cli, "Erasing first sector in FPGA config memory failed"); return CLI_ERROR; } @@ -101,8 +123,12 @@ int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *arg return CLI_OK; } -int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + fpgacfg_access_control(ALLOW_FPGA); fpgacfg_reset_fpga(RESET_FULL); cli_print(cli, "FPGA has been reset"); @@ -110,8 +136,12 @@ int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int a return CLI_OK; } -int cmd_fpga_reset_registers(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_reset_registers(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + fpgacfg_access_control(ALLOW_FPGA); fpgacfg_reset_fpga(RESET_REGISTERS); cli_print(cli, "FPGA registers have been reset"); @@ -121,16 +151,19 @@ int cmd_fpga_reset_registers(struct cli_def *cli, const char *command, char *arg void configure_cli_fpga(struct cli_def *cli) { - /* fpga */ - cli_command_root(fpga); + struct cli_command *c = cli_register_command(cli, NULL, "fpga", NULL, 0, 0, NULL); + /* fpga reset */ - cli_command_node(fpga, reset, "Reset FPGA (config reset)"); + struct cli_command *c_reset = cli_register_command(cli, c, "reset", cmd_fpga_reset, 0, 0, "Reset FPGA (config reset)"); + /* fpga reset registers */ - cli_command_node(fpga_reset, registers, "Reset FPGA registers (soft reset)"); + cli_register_command(cli, c_reset, "registers", cmd_fpga_reset_registers, 0, 0, "Reset FPGA registers (soft reset)"); + + struct cli_command *c_bitstream = cli_register_command(cli, c, "bitstream", NULL, 0, 0, NULL); - cli_command_branch(fpga, bitstream); /* fpga bitstream upload */ - cli_command_node(fpga_bitstream, upload, "Upload new FPGA bitstream"); + cli_register_command(cli, c_bitstream, "upload", cmd_fpga_bitstream_upload, 0, 0, "Upload new FPGA bitstream"); + /* fpga bitstream erase */ - cli_command_node(fpga_bitstream, erase, "Erase FPGA config memory"); + cli_register_command(cli, c_bitstream, "erase", cmd_fpga_bitstream_erase, 0, 0, "Erase FPGA config memory"); } diff --git a/projects/cli-test/mgmt-fpga.h b/projects/cli-test/mgmt-fpga.h index ce185de..9d0aedc 100644 --- a/projects/cli-test/mgmt-fpga.h +++ b/projects/cli-test/mgmt-fpga.h @@ -35,7 +35,6 @@ #ifndef __STM32_CLI_MGMT_FPGA_H #define __STM32_CLI_MGMT_FPGA_H -#include "stm-init.h" #include <libcli.h> diff --git a/projects/cli-test/mgmt-keystore.c b/projects/cli-test/mgmt-keystore.c new file mode 100644 index 0000000..6d0d38d --- /dev/null +++ b/projects/cli-test/mgmt-keystore.c @@ -0,0 +1,412 @@ +/* + * mgmt-keystore.c + * --------------- + * CLI 'keystore' commands. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ + +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-keystore.h" +#include "stm-fpgacfg.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-show.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#warning Really should not be including hal_internal.h here, fix API instead of bypassing it +#include "hal_internal.h" +#undef HAL_OK + +#include <stdlib.h> +#include <string.h> + + +static int cmd_keystore_set_pin(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_user_t user; + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 2) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set pin <user|so|wheel> <pin>"); + return CLI_ERROR; + } + + if (!strcmp(argv[0], "user")) + user = HAL_USER_NORMAL; + else if (!strcmp(argv[0], "so")) + user = HAL_USER_SO; + else if (!strcmp(argv[0], "wheel")) + user = HAL_USER_WHEEL; + else { + cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]); + return CLI_ERROR; + } + + status = hal_rpc_set_pin(client, user, argv[1], strlen(argv[1])); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting PIN: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_clear_pin(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_user_t user; + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore clear pin <user|so|wheel>"); + return CLI_ERROR; + } + + if (!strcmp(argv[0], "user")) + user = HAL_USER_NORMAL; + else if (!strcmp(argv[0], "so")) + user = HAL_USER_SO; + else if (!strcmp(argv[0], "wheel")) + user = HAL_USER_WHEEL; + else { + cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]); + return CLI_ERROR; + } + + status = hal_rpc_set_pin(client, user, "", 0); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting PIN: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_set_pin_iterations(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set pin iterations <number>"); + return CLI_ERROR; + } + + status = hal_set_pin_default_iterations(client, strtoul(argv[0], NULL, 0)); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting iterations: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +/* + * This is badly broken under either old or new keystore API: + * + * + DER is a binary format, it's not safe to read it this way, + * and strlen() will not do what anybody wants; + * + * + As written, this stores an EC public key on no known curve, + * ie, useless nonsense. + * + * The usual text format for DER objects is Base64, often with + * so-called "PEM" header and footer lines. Key type, curve, etcetera + * would be extra command line parameters. + */ +#if 0 +static int cmd_keystore_set_key(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + int hint = 0; + + command = command; + + if (argc != 2) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set key <name> <der>"); + return CLI_ERROR; + } + + if ((status = hal_ks_store(HAL_KEY_TYPE_EC_PUBLIC, + HAL_CURVE_NONE, + 0, + (uint8_t *) argv[0], strlen(argv[0]), + (uint8_t *) argv[1], strlen(argv[1]), + &hint)) != LIBHAL_OK) { + + cli_print(cli, "Failed storing key: %s", hal_error_string(status)); + return CLI_ERROR; + } + + cli_print(cli, "Stored key %i", hint); + + return CLI_OK; +} +#endif /* 0 */ + +static int cmd_keystore_delete_key(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + const hal_client_handle_t client = { HAL_HANDLE_NONE }; + const hal_session_handle_t session = { HAL_HANDLE_NONE }; + hal_pkey_handle_t pkey = { HAL_HANDLE_NONE }; + hal_error_t status; + hal_uuid_t name; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore delete key <name>"); + return CLI_ERROR; + } + + if ((status = hal_uuid_parse(&name, argv[0])) != LIBHAL_OK) { + cli_print(cli, "Couldn't parse key name: %s", hal_error_string(status)); + return CLI_ERROR; + } + + if ((status = hal_rpc_pkey_open(client, session, &pkey, &name)) != LIBHAL_OK || + (status = hal_rpc_pkey_delete(pkey)) != LIBHAL_OK) { + cli_print(cli, "Failed deleting key: %s", hal_error_string(status)); + return CLI_ERROR; + } + + cli_print(cli, "Deleted key %s", argv[0]); + + return CLI_OK; +} + +static int cmd_keystore_show_data(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + uint8_t buf[KEYSTORE_PAGE_SIZE]; + uint32_t i; + + command = command; + argv = argv; + argc = argc; + + if (keystore_check_id() != CMSIS_HAL_OK) { + cli_print(cli, "ERROR: The keystore memory is not accessible."); + } + + memset(buf, 0, sizeof(buf)); + if ((i = keystore_read_data(0, buf, sizeof(buf))) != CMSIS_HAL_OK) { + cli_print(cli, "Failed reading first page from keystore memory: %li", i); + return CLI_ERROR; + } + + cli_print(cli, "First page from keystore memory:\r\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + + return CLI_OK; +} + +static int show_keys(struct cli_def *cli, const char *title) +{ + const hal_client_handle_t client = { -1 }; + const hal_session_handle_t session = { HAL_HANDLE_NONE }; + char key_name[HAL_UUID_TEXT_SIZE]; + hal_uuid_t previous_uuid = {{0}}; + hal_pkey_handle_t pkey; + hal_curve_name_t curve; + hal_key_flags_t flags; + unsigned n, state = 0; + hal_key_type_t type; + hal_error_t status; + hal_uuid_t uuids[50]; + int done = 0; + + cli_print(cli, title); + + while (!done) { + + if ((status = hal_rpc_pkey_match(client, session, HAL_KEY_TYPE_NONE, HAL_CURVE_NONE, + 0, 0, NULL, 0, &state, uuids, &n, + sizeof(uuids)/sizeof(*uuids), + &previous_uuid)) != LIBHAL_OK) { + cli_print(cli, "Could not fetch UUID list: %s", hal_error_string(status)); + return 0; + } + + done = n < sizeof(uuids)/sizeof(*uuids); + + if (!done) + previous_uuid = uuids[sizeof(uuids)/sizeof(*uuids) - 1]; + + for (unsigned i = 0; i < n; i++) { + + if ((status = hal_uuid_format(&uuids[i], key_name, sizeof(key_name))) != LIBHAL_OK) { + cli_print(cli, "Could not convert key name: %s", + hal_error_string(status)); + return 0; + } + + if ((status = hal_rpc_pkey_open(client, session, &pkey, &uuids[i])) != LIBHAL_OK) { + cli_print(cli, "Could not open key %s: %s", + key_name, hal_error_string(status)); + return 0; + } + + if ((status = hal_rpc_pkey_get_key_type(pkey, &type)) != LIBHAL_OK || + (status = hal_rpc_pkey_get_key_curve(pkey, &curve)) != LIBHAL_OK || + (status = hal_rpc_pkey_get_key_flags(pkey, &flags)) != LIBHAL_OK) + cli_print(cli, "Could not fetch metadata for key %s: %s", + key_name, hal_error_string(status)); + + if (status == LIBHAL_OK) + status = hal_rpc_pkey_close(pkey); + else + (void) hal_rpc_pkey_close(pkey); + + if (status != LIBHAL_OK) + return 0; + + const char *type_name = "unknown"; + switch (type) { + case HAL_KEY_TYPE_NONE: type_name = "none"; break; + case HAL_KEY_TYPE_RSA_PRIVATE: type_name = "RSA private"; break; + case HAL_KEY_TYPE_RSA_PUBLIC: type_name = "RSA public"; break; + case HAL_KEY_TYPE_EC_PRIVATE: type_name = "EC private"; break; + case HAL_KEY_TYPE_EC_PUBLIC: type_name = "EC public"; break; + } + + const char *curve_name = "unknown"; + switch (curve) { + case HAL_CURVE_NONE: curve_name = "none"; break; + case HAL_CURVE_P256: curve_name = "P-256"; break; + case HAL_CURVE_P384: curve_name = "P-384"; break; + case HAL_CURVE_P521: curve_name = "P-521"; break; + } + + cli_print(cli, "Key %2i, name %s, type %s, curve %s, flags 0x%lx", + i, key_name, type_name, curve_name, (unsigned long) flags); + } + } + + return 1; +} + +static int cmd_keystore_show_keys(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + if (show_keys(cli, "Keystore:")) + return CLI_OK; + else + return CLI_ERROR; +} + +static int cmd_keystore_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + int status; + + command = command; + + if (argc != 1 || strcmp(argv[0], "YesIAmSure") != 0) { + cli_print(cli, "Syntax: keystore erase YesIAmSure"); + return CLI_ERROR; + } + + cli_print(cli, "OK, erasing keystore, this might take a while..."); + if ((status = keystore_erase_bulk()) != CMSIS_HAL_OK) { + cli_print(cli, "Failed erasing token keystore: %i", status); + return CLI_ERROR; + } + + if ((err = hal_ks_init(hal_ks_token, 0)) != LIBHAL_OK) { + cli_print(cli, "Failed to reinitialize token keystore: %s", hal_error_string(err)); + return CLI_ERROR; + } + + if ((err = hal_ks_init(hal_ks_volatile, 0)) != LIBHAL_OK) { + cli_print(cli, "Failed to reinitialize memory keystore: %s", hal_error_string(err)); + return CLI_ERROR; + } + + cli_print(cli, "Keystore erased"); + return CLI_OK; +} + +void configure_cli_keystore(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "keystore", NULL, 0, 0, NULL); + + struct cli_command *c_set = cli_register_command(cli, c, "set", NULL, 0, 0, NULL); + struct cli_command *c_clear = cli_register_command(cli, c, "clear", NULL, 0, 0, NULL); + struct cli_command *c_delete = cli_register_command(cli, c, "delete", NULL, 0, 0, NULL); + struct cli_command *c_show = cli_register_command(cli, c, "show", NULL, 0, 0, NULL); + + /* keystore erase */ + cli_register_command(cli, c, "erase", cmd_keystore_erase, 0, 0, "Erase the whole keystore"); + + /* keystore set pin */ + struct cli_command *c_set_pin = cli_register_command(cli, c_set, "pin", cmd_keystore_set_pin, 0, 0, "Set either 'wheel', 'user' or 'so' PIN"); + + /* keystore set pin iterations */ + cli_register_command(cli, c_set_pin, "iterations", cmd_keystore_set_pin_iterations, 0, 0, "Set PBKDF2 iterations for PINs"); + + /* keystore clear pin */ + cli_register_command(cli, c_clear, "pin", cmd_keystore_clear_pin, 0, 0, "Clear either 'wheel', 'user' or 'so' PIN"); + +#if 0 + /* keystore set key */ + cli_register_command(cli, c_set, "key", cmd_keystore_set_key, 0, 0, "Set a key"); +#endif + + /* keystore delete key */ + cli_register_command(cli, c_delete, "key", cmd_keystore_delete_key, 0, 0, "Delete a key"); + + /* keystore show data */ + cli_register_command(cli, c_show, "data", cmd_keystore_show_data, 0, 0, "Dump the first page from the keystore memory"); + + /* keystore show keys */ + cli_register_command(cli, c_show, "keys", cmd_keystore_show_keys, 0, 0, "Show what keys are in the keystore"); + +} diff --git a/projects/cli-test/mgmt-keystore.h b/projects/cli-test/mgmt-keystore.h new file mode 100644 index 0000000..9e14ac6 --- /dev/null +++ b/projects/cli-test/mgmt-keystore.h @@ -0,0 +1,42 @@ +/* + * mgmt-keystore.h + * ---------- + * Management CLI 'keystore' functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_KEYSTORE_H +#define __STM32_CLI_MGMT_KEYSTORE_H + +#include <libcli.h> + +extern void configure_cli_keystore(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_KEYSTORE_H */ diff --git a/projects/cli-test/mgmt-keywrap.c b/projects/cli-test/mgmt-keywrap.c new file mode 100644 index 0000000..7d3e219 --- /dev/null +++ b/projects/cli-test/mgmt-keywrap.c @@ -0,0 +1,316 @@ +/* + * mgmt-keywrap.h + * ----------- + * Management CLI functions related to AES keywrap + * + * Copyright (c) 2018, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-keywrap.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK + +#include <string.h> + +/* test vectors and test code are from test-aes-key-wrap.c */ + +/* + * Test cases from RFC 5649 all use a 192-bit key, which our AES + * implementation doesn't support, so had to write our own. + */ + +static const uint8_t Q[] = { /* Plaintext, 81 bytes */ + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x20, 0x20, 0x4d, 0x79, 0x20, 0x6e, + 0x61, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x49, 0x6e, 0x69, 0x67, 0x6f, + 0x20, 0x4d, 0x6f, 0x6e, 0x74, 0x6f, 0x79, 0x61, 0x2e, 0x20, 0x20, 0x59, + 0x6f, 0x75, 0x20, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x20, 0x6d, 0x79, 0x20, + 0x41, 0x45, 0x53, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x72, 0x2e, 0x20, 0x20, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, + 0x65, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x65, 0x2e +}; + +static const uint8_t K_128[] = { /* 128-bit KEK, 16 bytes */ + 0xbc, 0x2a, 0xd8, 0x90, 0xd8, 0x91, 0x10, 0x65, 0xf0, 0x42, 0x10, 0x1b, + 0x4a, 0x6b, 0xaf, 0x99 +}; + +static const uint8_t K_256[] = { /* 256-bit KEK, 32 bytes */ + 0xe3, 0x97, 0x52, 0x81, 0x2b, 0x7e, 0xc2, 0xa4, 0x6a, 0xac, 0x50, 0x18, + 0x0d, 0x10, 0xc6, 0x85, 0x2c, 0xcf, 0x86, 0x0a, 0xa9, 0x4f, 0x69, 0xab, + 0x16, 0xa6, 0x4f, 0x3e, 0x96, 0xa0, 0xbd, 0x9e +}; + +static const uint8_t C_128[] = { /* Plaintext wrapped by 128-bit KEK, 96 bytes */ + 0xb0, 0x10, 0x91, 0x7b, 0xe7, 0x67, 0x9c, 0x10, 0x16, 0x64, 0xe7, 0x73, + 0xd2, 0x68, 0xba, 0xed, 0x8c, 0x50, 0x49, 0x80, 0x16, 0x2f, 0x4e, 0x97, + 0xe8, 0x45, 0x5c, 0x2f, 0x2b, 0x7a, 0x88, 0x0e, 0xd8, 0xef, 0xaa, 0x40, + 0xb0, 0x2e, 0xb4, 0x50, 0xe7, 0x60, 0xf7, 0xbb, 0xed, 0x56, 0x79, 0x16, + 0x65, 0xb7, 0x13, 0x9b, 0x4c, 0x66, 0x86, 0x5f, 0x4d, 0x53, 0x2d, 0xcd, + 0x83, 0x41, 0x01, 0x35, 0x0d, 0x06, 0x39, 0x4e, 0x9e, 0xfe, 0x68, 0xc5, + 0x2f, 0x37, 0x33, 0x99, 0xbb, 0x88, 0xf7, 0x76, 0x1e, 0x82, 0x48, 0xd6, + 0xa2, 0xf3, 0x9b, 0x92, 0x01, 0x65, 0xcb, 0x48, 0x36, 0xf5, 0x42, 0xd3 +}; + +static const uint8_t C_256[] = { /* Plaintext wrapped by 256-bit KEK, 96 bytes */ + 0x08, 0x00, 0xbc, 0x1b, 0x35, 0xe4, 0x2a, 0x69, 0x3f, 0x43, 0x07, 0x54, + 0x31, 0xba, 0xb6, 0x89, 0x7c, 0x64, 0x9f, 0x03, 0x84, 0xc4, 0x4a, 0x71, + 0xdb, 0xcb, 0xae, 0x55, 0x30, 0xdf, 0xb0, 0x2b, 0xc3, 0x91, 0x5d, 0x07, + 0xa9, 0x24, 0xdb, 0xe7, 0xbe, 0x4d, 0x0d, 0x62, 0xd4, 0xf8, 0xb1, 0x94, + 0xf1, 0xb9, 0x22, 0xb5, 0x94, 0xab, 0x7e, 0x0b, 0x15, 0x6a, 0xd9, 0x5f, + 0x6c, 0x20, 0xb7, 0x7e, 0x13, 0x19, 0xfa, 0xc4, 0x70, 0xec, 0x0d, 0xbd, + 0xf7, 0x01, 0xc6, 0xb3, 0x9a, 0x19, 0xaf, 0xf2, 0x47, 0x68, 0xea, 0x7e, + 0x97, 0x7e, 0x52, 0x2e, 0xd4, 0x03, 0x31, 0xcb, 0x22, 0xb6, 0xfe, 0xf5 +}; + +static int run_test(struct cli_def *cli, + const uint8_t * const K, const size_t K_len, + const uint8_t * const C, const size_t C_len) +{ +#define TC_BUFSIZE 96 /* sizeof(C) */ + const size_t Q_len = sizeof(Q); + uint8_t q[TC_BUFSIZE], c[TC_BUFSIZE]; + size_t q_len = sizeof(q), c_len = sizeof(c); + hal_error_t err; + int ok1 = 1, ok2 = 1; + + /* + * Wrap and compare results. + */ + + cli_print(cli, "Wrapping with %lu-bit KEK...", (unsigned long) K_len * 8); + if ((err = hal_aes_keywrap(NULL, K, K_len, Q, Q_len, c, &c_len)) != LIBHAL_OK) { + cli_print(cli, "Couldn't wrap with %lu-bit KEK: %s", + (unsigned long) K_len * 8, hal_error_string(err)); + ok1 = 0; + } + else if (C_len != c_len || memcmp(C, c, C_len) != 0) { + cli_print(cli, "Ciphertext mismatch:\n Want: "); + uart_send_hexdump(C, 0, C_len - 1); + cli_print(cli, "\n Got: "); + uart_send_hexdump(c, 0, c_len - 1); + cli_print(cli, ""); + ok1 = 0; + } + else { + cli_print(cli, "OK"); + } + + /* + * Unwrap and compare results. + */ + + cli_print(cli, "Unwrapping with %lu-bit KEK...", (unsigned long) K_len * 8); + if ((err = hal_aes_keyunwrap(NULL, K, K_len, C, C_len, q, &q_len)) != LIBHAL_OK) { + cli_print(cli, "Couldn't unwrap with %lu-bit KEK: %s", + (unsigned long) K_len * 8, hal_error_string(err)); + ok2 = 0; + } + else if (Q_len != q_len || memcmp(Q, q, Q_len) != 0) { + cli_print(cli, "Plaintext mismatch:\n Want: "); + uart_send_hexdump(Q, 0, Q_len - 1); + cli_print(cli, "\n Got: "); + uart_send_hexdump(q, 0, q_len - 1); + cli_print(cli, ""); + ok2 = 0; + } + else { + cli_print(cli, "OK"); + } + + return ok1 && ok2; +} + +static int cmd_keywrap_test(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + + if (argc == 0) { + cli_print(cli, "1. Test vectors with software keywrap"); + hal_aes_use_keywrap_core(0); + run_test(cli, K_128, sizeof(K_128), C_128, sizeof(C_128)); + run_test(cli, K_256, sizeof(K_256), C_256, sizeof(C_256)); + + cli_print(cli, "\n2. Test vectors with keywrap core"); + if (hal_aes_use_keywrap_core(1) == 0) { + cli_print(cli, "keywrap core not found, skipping"); + } + else { + hal_aes_use_keywrap_core(1); + run_test(cli, K_128, sizeof(K_128), C_128, sizeof(C_128)); + run_test(cli, K_256, sizeof(K_256), C_256, sizeof(C_256)); + } + + cli_print(cli, "\nFor more tests: keywrap test <keysize> <iterations>"); + return CLI_OK; + } + + hal_error_t err; + + if (argc != 2) { + usage: + cli_print(cli, "Syntax: keywrap test <keysize> <iterations>"); + return CLI_ERROR; + } + + const int keysize = atoi(argv[0]); + const int iterations = atoi(argv[1]); + if (keysize <= 0 || iterations <= 0) + goto usage; + + uint8_t Q[keysize + 8]; size_t Q_len; + uint8_t C[keysize + 8]; size_t C_len; + memset(C, 0, sizeof(C)); + if ((err = hal_get_random(NULL, Q, keysize)) != LIBHAL_OK) { + cli_print(cli, "hal_get_random: %s", hal_error_string(err)); + return CLI_ERROR; + } + + cli_print(cli, "1. sanity test"); + C_len = sizeof(C); + if ((err = hal_aes_keywrap(NULL, K_256, sizeof(K_256), Q, keysize, C, &C_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + + for (int i = 0; i <= 1; ++i) { + if (!hal_aes_use_keywrap_core(i) && i) { + cli_print(cli, "keywrap core not found, skipping"); + continue; + } + uint8_t q[keysize + 8]; + size_t q_len = sizeof(q); + if ((err = hal_aes_keyunwrap(NULL, K_256, sizeof(K_256), C, C_len, q, &q_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keyunwrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + if (q_len != (size_t)keysize) { + cli_print(cli, "unwrap size mismatch: expected %d, got %d", (int)keysize, (int)q_len); + return CLI_ERROR; + } + if (memcmp(Q, q, q_len) != 0) { + cli_print(cli, "unwrap mismatch:\n Want: "); + uart_send_hexdump(Q, 0, Q_len - 1); + cli_print(cli, "\n Got: "); + uart_send_hexdump(q, 0, q_len - 1); + cli_print(cli, ""); + return CLI_ERROR; + } + cli_print(cli, "with %s: OK", i ? "keywrap core" : "software keywrap"); + } + + cli_print(cli, "\n2. wrap timing with software keywrap"); + + hal_aes_use_keywrap_core(0); + uint32_t start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + C_len = sizeof(C); + if ((err = hal_aes_keywrap(NULL, K_256, sizeof(K_256), Q, keysize, C, &C_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + uint32_t elapsed = HAL_GetTick() - start; + uint32_t per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + + cli_print(cli, "\n3. wrap timing with keywrap core"); + + if (hal_aes_use_keywrap_core(1) == 0) { + cli_print(cli, "keywrap core not found, skipping"); + } + else { + start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + C_len = sizeof(C); + if ((err = hal_aes_keywrap(NULL, K_256, sizeof(K_256), Q, keysize, C, &C_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + elapsed = HAL_GetTick() - start; + per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + } + + cli_print(cli, "\n4. unwrap timing with software keywrap"); + + hal_aes_use_keywrap_core(0); + start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + Q_len = sizeof(Q); + if ((err = hal_aes_keyunwrap(NULL, K_256, sizeof(K_256), C, C_len, Q, &Q_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keyunwrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + elapsed = HAL_GetTick() - start; + per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + + cli_print(cli, "\n5. unwrap timing with keywrap core"); + + if (hal_aes_use_keywrap_core(1) == 0) { + cli_print(cli, "keywrap core not found, skipping"); + } + else { + start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + Q_len = sizeof(Q); + if ((err = hal_aes_keyunwrap(NULL, K_256, sizeof(K_256), C, C_len, Q, &Q_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + elapsed = HAL_GetTick() - start; + per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + } + + return CLI_OK; +} + +void configure_cli_keywrap(struct cli_def *cli) +{ + struct cli_command *c_keywrap = cli_register_command(cli, NULL, "keywrap", NULL, 0, 0, NULL); + + /* keywrap test */ + cli_register_command(cli, c_keywrap, "test", cmd_keywrap_test, 0, 0, "Test the keywrap core"); +} diff --git a/projects/cli-test/mgmt-keywrap.h b/projects/cli-test/mgmt-keywrap.h new file mode 100644 index 0000000..a18aded --- /dev/null +++ b/projects/cli-test/mgmt-keywrap.h @@ -0,0 +1,42 @@ +/* + * mgmt-keywrap.h + * ----------- + * Management CLI functions related to AES keywrap + * + * Copyright (c) 2018, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_KEYWRAP_H +#define __STM32_CLI_MGMT_KEYWRAP_H + +#include <libcli.h> + +extern void configure_cli_keywrap(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_KEYWRAP_H */ diff --git a/projects/cli-test/mgmt-masterkey.c b/projects/cli-test/mgmt-masterkey.c new file mode 100644 index 0000000..811e15b --- /dev/null +++ b/projects/cli-test/mgmt-masterkey.c @@ -0,0 +1,225 @@ +/* + * mgmt-masterkey.c + * ---------------- + * Masterkey CLI functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-masterkey.h" + +#undef HAL_OK +#define LIBHAL_OK HAL_OK +#include <hal.h> +#warning Refactor so we do not need to include hal_internal here +#include <hal_internal.h> +#undef HAL_OK + +#include <stdlib.h> + +static char * _status2str(const hal_error_t status) +{ + switch (status) { + case LIBHAL_OK: + return (char *) "Set"; + case HAL_ERROR_MASTERKEY_NOT_SET: + return (char *) "Not set"; + default: + return (char *) "Unknown"; + } +} + +static int _parse_hex_groups(uint8_t *buf, size_t len, char *argv[], int argc) +{ + int i; + uint32_t *dst = (uint32_t *) buf; + uint32_t *end = (uint32_t *) buf + len - 1; + char *err_ptr = NULL; + + if (! argc) return 0; + + for (i = 0; i < argc; i++) { + if (dst >= end) return -1; + *dst++ = strtoul(argv[i], &err_ptr, 16); + if (*err_ptr) return -2; + } + + return 1; +} + +static int cmd_masterkey_status(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + uint8_t buf[KEK_LENGTH] = {0}; + + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Status of master key:\n"); + + status = hal_mkm_volatile_read(NULL, 0); + cli_print(cli, " volatile: %s / %s", _status2str(status), hal_error_string(status)); + + status = hal_mkm_flash_read(NULL, 0); + cli_print(cli, " flash: %s / %s", _status2str(status), hal_error_string(status)); + + /* XXX Temporary gaping security hole while developing the master key functionality. + * REMOVE READ-OUT OF MASTER KEY. + */ + + status = hal_mkm_volatile_read(&buf[0], sizeof(buf)); + if (status == LIBHAL_OK || status == HAL_ERROR_MASTERKEY_NOT_SET) { + cli_print(cli, "\nVolatile read-out:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + } else { + cli_print(cli, "Failed reading from volatile memory: %s", hal_error_string(status)); + } + + status = hal_mkm_flash_read(&buf[0], sizeof(buf)); + if (status == LIBHAL_OK || status == HAL_ERROR_MASTERKEY_NOT_SET) { + cli_print(cli, "\nFlash read-out:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + } else { + cli_print(cli, "Failed reading from flash: %s", hal_error_string(status)); + } + + return CLI_OK; +} + +static int cmd_masterkey_set(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + uint8_t buf[KEK_LENGTH] = {0}; + hal_error_t err; + int i; + + command = command; + + if ((i = _parse_hex_groups(&buf[0], sizeof(buf), argv, argc)) != 1) { + cli_print(cli, "Failed parsing master key (%i)", i); + return CLI_OK; + } + + cli_print(cli, "Parsed key:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + + if ((err = hal_mkm_volatile_write(buf, sizeof(buf))) == LIBHAL_OK) { + cli_print(cli, "Master key set in volatile memory"); + } else { + cli_print(cli, "Failed writing key to volatile memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + + command = command; + argv = argv; + argc = argc; + + if ((err = hal_mkm_volatile_erase(KEK_LENGTH)) == LIBHAL_OK) { + cli_print(cli, "Erased master key from volatile memory"); + } else { + cli_print(cli, "Failed erasing master key from volatile memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_unsecure_set(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + uint8_t buf[KEK_LENGTH] = {0}; + hal_error_t err; + int i; + + command = command; + + if ((i = _parse_hex_groups(&buf[0], sizeof(buf), argv, argc)) != 1) { + cli_print(cli, "Failed parsing master key (%i)", i); + return CLI_OK; + } + + cli_print(cli, "Parsed key:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + + if ((err = hal_mkm_flash_write(buf, sizeof(buf))) == LIBHAL_OK) { + cli_print(cli, "Master key set in unsecure flash memory"); + } else { + cli_print(cli, "Failed writing key to unsecure flash memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_unsecure_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + + command = command; + argv = argv; + argc = argc; + + if ((err = hal_mkm_flash_erase(KEK_LENGTH)) == LIBHAL_OK) { + cli_print(cli, "Erased unsecure master key from flash"); + } else { + cli_print(cli, "Failed erasing unsecure master key from flash: %s", hal_error_string(err)); + } + return CLI_OK; +} + +void configure_cli_masterkey(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "masterkey", NULL, 0, 0, NULL); + + /* masterkey status */ + cli_register_command(cli, c, "status", cmd_masterkey_status, 0, 0, "Show status of master key in RAM/flash"); + + /* masterkey set */ + cli_register_command(cli, c, "set", cmd_masterkey_set, 0, 0, "Set the master key in the volatile Master Key Memory"); + + /* masterkey erase */ + cli_register_command(cli, c, "erase", cmd_masterkey_erase, 0, 0, "Erase the master key from the volatile Master Key Memory"); + + struct cli_command *c_unsecure = cli_register_command(cli, c, "unsecure", NULL, 0, 0, NULL); + + /* masterkey unsecure set */ + cli_register_command(cli, c_unsecure, "set", cmd_masterkey_unsecure_set, 0, 0, "Set master key in unprotected flash memory (if unsure, DON'T)"); + + /* masterkey unsecure erase */ + cli_register_command(cli, c_unsecure, "erase", cmd_masterkey_unsecure_erase, 0, 0, "Erase master key from unprotected flash memory"); +} diff --git a/projects/cli-test/mgmt-masterkey.h b/projects/cli-test/mgmt-masterkey.h new file mode 100644 index 0000000..67835e9 --- /dev/null +++ b/projects/cli-test/mgmt-masterkey.h @@ -0,0 +1,42 @@ +/* + * mgmt-masterkey.h + * ----------- + * Management CLI masterkeyellaneous functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_MASTERKEY_H +#define __STM32_CLI_MGMT_MASTERKEY_H + +#include <libcli.h> + +extern void configure_cli_masterkey(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_MASTERKEY_H */ diff --git a/projects/cli-test/mgmt-misc.c b/projects/cli-test/mgmt-misc.c index aea790a..ca95c63 100644 --- a/projects/cli-test/mgmt-misc.c +++ b/projects/cli-test/mgmt-misc.c @@ -3,7 +3,9 @@ * ----------- * Miscellaneous CLI functions. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -32,41 +34,44 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define HAL_OK CMSIS_HAL_OK #include "stm-init.h" #include "stm-uart.h" - #include "mgmt-cli.h" #include "mgmt-misc.h" +#undef HAL_OK -#include <string.h> - - -extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len); +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK +#include <string.h> -volatile uint32_t demo_crc = 0; +static volatile hal_crc32_t demo_crc; -int _count_bytes_callback(uint8_t *buf, size_t len) { - demo_crc = update_crc(demo_crc, buf, len); - return 1; +static HAL_StatusTypeDef _count_bytes_callback(uint8_t *buf, size_t len) { + demo_crc = hal_crc32_update(demo_crc, buf, len); + return CMSIS_HAL_OK; } int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback) { - uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0; + hal_crc32_t crc = 0, my_crc = hal_crc32_init(); + uint32_t filesize = 0, counter = 0; size_t n = len; if (! control_mgmt_uart_dma_rx(DMA_RX_STOP)) { cli_print(cli, "Failed stopping DMA"); - return CLI_OK; + goto fail; } cli_print(cli, "OK, write size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", (uint32_t) n); - if (uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000) != HAL_OK) { + if (uart_receive_bytes((void *) &filesize, sizeof(filesize), 1000) != CMSIS_HAL_OK) { cli_print(cli, "Receive timed out"); - return CLI_ERROR; + goto fail; } cli_print(cli, "Send %li bytes of data", filesize); @@ -79,27 +84,28 @@ int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_cal if (filesize < n) n = filesize; - if (uart_receive_bytes(STM_UART_MGMT, (void *) buf, n, 1000) != HAL_OK) { + if (uart_receive_bytes((void *) buf, n, 1000) != CMSIS_HAL_OK) { cli_print(cli, "Receive timed out"); - return CLI_ERROR; + goto fail; } filesize -= n; - my_crc = update_crc(my_crc, buf, n); + my_crc = hal_crc32_update(my_crc, buf, n); /* After reception of a chunk but before ACKing we have "all" the time in the world to * calculate CRC and invoke the data_callback. */ - if (data_callback != NULL && ! data_callback(buf, (size_t) n)) { + if (data_callback != NULL && data_callback(buf, n) != CMSIS_HAL_OK) { cli_print(cli, "Data processing failed"); - return CLI_OK; + goto fail; } counter++; - uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4); + uart_send_bytes((void *) &counter, 4); } + my_crc = hal_crc32_finalize(my_crc); cli_print(cli, "Send CRC-32"); - uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000); + uart_receive_bytes((void *) &crc, sizeof(crc), 1000); cli_print(cli, "CRC-32 0x%x, calculated CRC 0x%x", (unsigned int) crc, (unsigned int) my_crc); if (crc == my_crc) { cli_print(cli, "CRC checksum MATCHED"); @@ -107,31 +113,129 @@ int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_cal cli_print(cli, "CRC checksum did NOT match"); } + fail: + control_mgmt_uart_dma_rx(DMA_RX_START); return CLI_OK; } -int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc) { uint8_t buf[FILETRANSFER_UPLOAD_CHUNK_SIZE]; - demo_crc = 0; + command = command; + argv = argv; + argc = argc; + + demo_crc = hal_crc32_init(); cli_receive_data(cli, &buf[0], sizeof(buf), _count_bytes_callback); + demo_crc = hal_crc32_finalize(demo_crc); cli_print(cli, "Demo CRC is: %li/0x%x", demo_crc, (unsigned int) demo_crc); return CLI_OK; } -int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + cli_print(cli, "\n\n\nRebooting\n\n\n"); HAL_NVIC_SystemReset(); - while (1) {}; + + /*NOTREACHED*/ + return CLI_OK; +} + +static int cmd_rsa_blinding(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off|clear>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + hal_rsa_set_blinding(1); + else if (strcmp(argv[0], "off") == 0) + hal_rsa_set_blinding(0); + else if (strcmp(argv[0], "clear") == 0) + hal_rsa_clear_blinding_cache(); + else { + cli_print(cli, "Argument must be 'on', 'off', or 'clear' - not '%s'", argv[0]); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_rsa_crt(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int onoff; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + onoff = 1; + else if (strcmp(argv[0], "off") == 0) + onoff = 0; + else { + cli_print(cli, "Argument must be 'on' or 'off' - not '%s'", argv[0]); + return CLI_ERROR; + } + + hal_rsa_set_crt(onoff); + + return CLI_OK; +} + +static int cmd_rsa_modexpng(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int onoff; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + onoff = 1; + else if (strcmp(argv[0], "off") == 0) + onoff = 0; + else { + cli_print(cli, "Argument must be 'on' or 'off' - not '%s'", argv[0]); + return CLI_ERROR; + } + + hal_error_t err; + if ((err = hal_modexp_use_modexpng(onoff)) == LIBHAL_OK) + return CLI_OK; + + cli_print(cli, hal_error_string(err)); + return CLI_ERROR; } void configure_cli_misc(struct cli_def *cli) { /* filetransfer */ - cli_command_root_node(filetransfer, "Test file transfering"); + cli_register_command(cli, NULL, "filetransfer", cmd_filetransfer, 0, 0, "Test file transfering"); + + struct cli_command *c_rsa = cli_register_command(cli, NULL, "rsa", NULL, 0, 0, NULL); + + /* rsa blinding */ + cli_register_command(cli, c_rsa, "blinding", cmd_rsa_blinding, 0, 0, "Set use of RSA blinding"); + + /* rsa crt */ + cli_register_command(cli, c_rsa, "crt", cmd_rsa_crt, 0, 0, "Set use of RSA CRT"); + + /* rsa modexpng */ + cli_register_command(cli, c_rsa, "modexpng", cmd_rsa_modexpng, 0, 0, "Set use of ModExpNG"); + /* reboot */ - cli_command_root_node(reboot, "Reboot the STM32"); + cli_register_command(cli, NULL, "reboot", cmd_reboot, 0, 0, "Reboot the STM32"); } diff --git a/projects/cli-test/mgmt-misc.h b/projects/cli-test/mgmt-misc.h index b7eb4f4..c0581c9 100644 --- a/projects/cli-test/mgmt-misc.h +++ b/projects/cli-test/mgmt-misc.h @@ -35,15 +35,14 @@ #ifndef __STM32_CLI_MGMT_MISC_H #define __STM32_CLI_MGMT_MISC_H -#include "stm-init.h" #include <libcli.h> - #define FILETRANSFER_UPLOAD_CHUNK_SIZE 256 -typedef int (*cli_data_callback)(uint8_t *, size_t); +typedef HAL_StatusTypeDef (*cli_data_callback)(uint8_t *, size_t); -extern void configure_cli_misc(struct cli_def *cli); extern int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback); +extern void configure_cli_misc(struct cli_def *cli); + #endif /* __STM32_CLI_MGMT_MISC_H */ diff --git a/projects/cli-test/mgmt-show.c b/projects/cli-test/mgmt-show.c index 3ae196e..4338dcd 100644 --- a/projects/cli-test/mgmt-show.c +++ b/projects/cli-test/mgmt-show.c @@ -32,6 +32,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK #include "stm-init.h" #include "stm-keystore.h" #include "stm-fpgacfg.h" @@ -40,13 +42,24 @@ #include "mgmt-cli.h" #include "mgmt-show.h" -#include <string.h> +#undef HAL_OK +#define LIBHAL_OK HAL_OK +#include "hal.h" + +#define HAL_STATIC_PKEY_STATE_BLOCKS 6 +#include "hal_internal.h" +#undef HAL_OK +#include <string.h> -int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], int argc) { volatile uint32_t hclk; + command = command; + argv = argv; + argc = argc; + hclk = HAL_RCC_GetHCLKFreq(); cli_print(cli, "HSE_VALUE: %li", HSE_VALUE); cli_print(cli, "HCLK: %li (%i MHz)", hclk, (int) hclk / 1000 / 1000); @@ -54,36 +67,71 @@ int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], in return CLI_OK; } -int cmd_show_fpga_status(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_fpga_status(struct cli_def *cli, const char *command, char *argv[], int argc) { - cli_print(cli, "FPGA has %sloaded a bitstream", fpgacfg_check_done() ? "":"NOT "); + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "FPGA has %sloaded a bitstream", (fpgacfg_check_done() == CMSIS_HAL_OK) ? "":"NOT "); return CLI_OK; } -int cmd_show_keystore_status(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_fpga_cores(struct cli_def *cli, const char *command, char *argv[], int argc) { - cli_print(cli, "Keystore memory is %sonline", (keystore_check_id() != 1) ? "NOT ":""); + hal_core_t *core; + const hal_core_info_t *info; + + command = command; + argv = argv; + argc = argc; + + if (fpgacfg_check_done() != CMSIS_HAL_OK) { + cli_print(cli, "FPGA has not loaded a bitstream"); + return CLI_OK; + } + + for (core = hal_core_iterate(NULL); core != NULL; core = hal_core_iterate(core)) { + info = hal_core_info(core); + cli_print(cli, "%04x: %8.8s %4.4s", + (unsigned int)info->base, info->name, info->version); + } + return CLI_OK; } -int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_keystore_status(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Keystore memory is %sonline", (keystore_check_id() == CMSIS_HAL_OK) ? "":"NOT "); + return CLI_OK; +} + +static int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[], int argc) { uint8_t buf[KEYSTORE_PAGE_SIZE]; uint32_t i; - if (keystore_check_id() != 1) { + command = command; + argv = argv; + argc = argc; + + if (keystore_check_id() != CMSIS_HAL_OK) { cli_print(cli, "ERROR: The keystore memory is not accessible."); } memset(buf, 0, sizeof(buf)); - if ((i = keystore_read_data(0, buf, sizeof(buf))) != 1) { + if ((i = keystore_read_data(0, buf, sizeof(buf))) != CMSIS_HAL_OK) { cli_print(cli, "Failed reading first page from keystore memory: %li", i); return CLI_ERROR; } cli_print(cli, "First page from keystore memory:\r\n"); - uart_send_hexdump(STM_UART_MGMT, buf, 0, sizeof(buf) - 1); - uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); for (i = 0; i < 8; i++) { if (buf[i] == 0xff) break; /* never written */ @@ -97,14 +145,14 @@ int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[ if (buf[i] == 0xff) { cli_print(cli, "Tombstoning byte %li", i); buf[i] = 0x55; - if ((i = keystore_write_data(0, buf, sizeof(buf))) != 1) { + if ((i = keystore_write_data(0, buf, sizeof(buf))) != CMSIS_HAL_OK) { cli_print(cli, "Failed writing data at offset 0: %li", i); return CLI_ERROR; } } } else { cli_print(cli, "Erasing first sector since all the first 8 bytes are tombstones"); - if ((i = keystore_erase_sectors(1)) != 1) { + if ((i = keystore_erase_sector(0)) != CMSIS_HAL_OK) { cli_print(cli, "Failed erasing the first sector: %li", i); return CLI_ERROR; } @@ -116,18 +164,24 @@ int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[ void configure_cli_show(struct cli_def *cli) { - /* show */ - cli_command_root(show); + struct cli_command *c = cli_register_command(cli, NULL, "show", NULL, 0, 0, NULL); /* show cpuspeed */ - cli_command_node(show, cpuspeed, "Show the speed at which the CPU currently operates"); + cli_register_command(cli, c, "cpuspeed", cmd_show_cpuspeed, 0, 0, "Show the speed at which the CPU currently operates"); + + struct cli_command *c_fpga = cli_register_command(cli, c, "fpga", NULL, 0, 0, NULL); - cli_command_branch(show, fpga); /* show fpga status*/ - cli_command_node(show_fpga, status, "Show status about the FPGA"); + cli_register_command(cli, c_fpga, "status", cmd_show_fpga_status, 0, 0, "Show status about the FPGA"); + + /* show fpga cores*/ + cli_register_command(cli, c_fpga, "cores", cmd_show_fpga_cores, 0, 0, "Show the currently available FPGA cores"); + + struct cli_command *c_keystore = cli_register_command(cli, c, "keystore", NULL, 0, 0, NULL); - cli_command_branch(show, keystore); /* show keystore status*/ - cli_command_node(show_keystore, status, "Show status of the keystore memory"); - cli_command_node(show_keystore, data, "Show the first page of the keystore memory"); + cli_register_command(cli, c_keystore, "status", cmd_show_keystore_status, 0, 0, "Show status of the keystore memory"); + + /* show keystore data */ + cli_register_command(cli, c_keystore, "data", cmd_show_keystore_data, 0, 0, "Show the first page of the keystore memory"); } diff --git a/projects/cli-test/mgmt-show.h b/projects/cli-test/mgmt-show.h index 0d7ba3a..7b80a30 100644 --- a/projects/cli-test/mgmt-show.h +++ b/projects/cli-test/mgmt-show.h @@ -1,5 +1,5 @@ /* - * mgmt-misc.h + * mgmt-show.h * ----------- * Management CLI 'show' functions. * @@ -35,7 +35,6 @@ #ifndef __STM32_CLI_MGMT_SHOW_H #define __STM32_CLI_MGMT_SHOW_H -#include "stm-init.h" #include <libcli.h> extern void configure_cli_show(struct cli_def *cli); diff --git a/projects/cli-test/mgmt-test.c b/projects/cli-test/mgmt-test.c index c1f255e..9b9972d 100644 --- a/projects/cli-test/mgmt-test.c +++ b/projects/cli-test/mgmt-test.c @@ -35,34 +35,31 @@ #include "stm-init.h" #include "stm-led.h" #include "stm-sdram.h" +#include "stm-fmc.h" +#include "stm-fpgacfg.h" #include "mgmt-cli.h" #include "mgmt-test.h" #include "test_sdram.h" +#include "test_mkmif.h" +#include "test-fmc.h" #include <stdlib.h> - -int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int argc) { // run external memory initialization sequence - HAL_StatusTypeDef status; int ok, num_cycles = 1, i, test_completed; + command = command; + if (argc == 1) { num_cycles = strtol(argv[0], NULL, 0); if (num_cycles > 100) num_cycles = 100; if (num_cycles < 1) num_cycles = 1; } - cli_print(cli, "Initializing SDRAM"); - status = sdram_init(); - if (status != HAL_OK) { - cli_print(cli, "Failed initializing SDRAM: %i", (int) status); - return CLI_OK; - } - for (i = 1; i <= num_cycles; i++) { cli_print(cli, "Starting SDRAM test (%i/%i)", i, num_cycles); test_completed = 0; @@ -107,11 +104,83 @@ int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int a return CLI_OK; } +static int cmd_test_fmc(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int i, num_cycles = 1, num_rounds = 100000; + + command = command; + + if (argc >= 1) { + num_cycles = strtol(argv[0], NULL, 0); + if (num_cycles > 100000) num_cycles = 100000; + if (num_cycles < 1) num_cycles = 1; + } + + if (argc == 2) { + num_rounds = strtol(argv[1], NULL, 0); + if (num_rounds > 1000000) num_rounds = 1000000; + if (num_rounds < 1) num_rounds = 1; + } + + cli_print(cli, "Checking if FPGA has loaded it's bitstream"); + // Blink blue LED until the FPGA reports it has loaded it's bitstream + led_on(LED_BLUE); + while (! fpgacfg_check_done()) { + for (i = 0; i < 4; i++) { + HAL_Delay(500); + led_toggle(LED_BLUE); + } + } + + // turn on green led, turn off other leds + led_on(LED_GREEN); + led_off(LED_YELLOW); + led_off(LED_RED); + led_off(LED_BLUE); + + // vars + volatile int data_test_ok = 0, addr_test_ok = 0, successful_runs = 0, failed_runs = 0, sleep = 0; + + for (i = 1; i <= num_cycles; i++) { + cli_print(cli, "Starting FMC test (%i/%i)", i, num_cycles); + + // test data bus + data_test_ok = test_fpga_data_bus(cli, num_rounds); + // test address bus + addr_test_ok = test_fpga_address_bus(cli, num_rounds); + + cli_print(cli, "Data: %i, addr %i", data_test_ok, addr_test_ok); + + if (data_test_ok == num_rounds && + addr_test_ok == num_rounds) { + // toggle yellow led to indicate, that we are alive + led_toggle(LED_YELLOW); + + successful_runs++; + sleep = 0; + } else { + led_on(LED_RED); + failed_runs++; + sleep = 2000; + } + + cli_print(cli, "Success %i, failed %i runs\r\n", successful_runs, failed_runs); + HAL_Delay(sleep); + } + + return CLI_OK; +} + void configure_cli_test(struct cli_def *cli) { - /* test */ - cli_command_root(test); + struct cli_command *c = cli_register_command(cli, NULL, "test", NULL, 0, 0, NULL); /* test sdram */ - cli_command_node(test, sdram, "Run SDRAM tests"); + cli_register_command(cli, c, "sdram", cmd_test_sdram, 0, 0, "Run SDRAM tests"); + + /* test mkmif */ + cli_register_command(cli, c, "mkmif", cmd_test_mkmif, 0, 0, "Run Master Key Memory Interface tests"); + + /* test fmc */ + cli_register_command(cli, c, "fmc", cmd_test_fmc, 0, 0, "Run FMC bus tests"); } diff --git a/projects/cli-test/test-fmc.c b/projects/cli-test/test-fmc.c new file mode 100644 index 0000000..d9b0c9b --- /dev/null +++ b/projects/cli-test/test-fmc.c @@ -0,0 +1,217 @@ +/* + * test-fmc.c + * ----------- + * FPGA communication bus (FMC) tests. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + This requires a special bitstream with a special test register. + See core/platform/novena/fmc/rtl/novena_fmc_top.v, sections marked + `ifdef test: + //---------------------------------------------------------------- + // Dummy Register + // + // General-purpose register to test FMC interface using STM32 + // demo program instead of core selector logic. + // + // This register is a bit tricky, but it allows testing of both + // data and address buses. Reading from FPGA will always return + // value, which is currently stored in the test register, + // regardless of read transaction address. Writing to FPGA has + // two variants: a) writing to address 0 will store output data + // data value in the test register, b) writing to any non-zero + // address will store _address_ of write transaction in the test + // register. + // + // To test data bus, write some different patterns to address 0, + // then readback from any address and compare. + // + // To test address bus, write anything to some different non-zero + // addresses, then readback from any address and compare returned + // value with previously written address. + // + //---------------------------------------------------------------- + */ + +#include "stm-init.h" +#include "stm-fmc.h" +#include "stm-uart.h" + +#include "test-fmc.h" + +static RNG_HandleTypeDef rng_inst; + +/* These are some interesting-to-look-at-in-the-debugger values that are declared + * volatile so that the compiler wouldn't optimize/obscure them. + */ +volatile uint32_t data_diff = 0; +volatile uint32_t addr_diff = 0; + + +static int _write_then_read(struct cli_def *cli, uint32_t addr, uint32_t write_buf, uint32_t *read_buf) +{ + int ok; + + fmc_write_32(addr, write_buf); + fmc_read_32(0, read_buf); + + return 1; +} + +int test_fpga_data_bus(struct cli_def *cli, uint32_t test_rounds) +{ + int i, c; + uint32_t rnd, buf; + HAL_StatusTypeDef hal_result; + + /* initialize stm32 rng */ + rng_inst.Instance = RNG; + HAL_RNG_Init(&rng_inst); + + /* run some rounds of data bus test */ + for (c = 0; c < (int)test_rounds; c++) { + data_diff = 0; + /* try to generate "random" number */ + hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd); + if (hal_result != HAL_OK) { + cli_print(cli, "STM32 RNG failed"); + break; + } + + /* write value to fpga at address 0 and then read it back from the test register */ + if (! _write_then_read(cli, 0, rnd, &buf)) break; + + /* compare (abort testing in case of error) */ + data_diff = buf ^ rnd; + if (data_diff) { + cli_print(cli, "Data bus FAIL: expected %lx got %lx", rnd, buf); + uart_send_string((char *) "Binary diff: "); + uart_send_binary(data_diff, 32); + uart_send_string("\r\n"); + + break; + } + } + + if (! data_diff) { + cli_print(cli, "Sample of data bus test data: expected 0x%lx got 0x%lx", rnd, buf); + } else { + uint32_t data; + cli_print(cli, "\nFMC data bus per-bit analysis:"); + for (i = 0; i < 31; i++) { + data = 1 << i; + + if (! _write_then_read(cli, 0, data, &buf)) break; + + if (data == buf) { + cli_print(cli, "Data 0x%08lx (FMC_D%02i) - OK", data, i + 1); + } else { + cli_print(cli, "Data 0x%08lx (FMC_D%02i) - FAIL (read 0x%08lx)", data, i + 1, buf); + } + } + } + + + /* return number of successful tests */ + return c; +} + +int test_fpga_address_bus(struct cli_def *cli, uint32_t test_rounds) +{ + int i, c; + uint32_t addr, buf, dummy = 1; + HAL_StatusTypeDef hal_result; + + /* initialize stm32 rng */ + rng_inst.Instance = RNG; + HAL_RNG_Init(&rng_inst); + + /* run some rounds of address bus test */ + for (c = 0; c < (int)test_rounds; c++) { + addr_diff = 0; + /* try to generate "random" number */ + hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &addr); + if (hal_result != HAL_OK) break; + + /* there are 26 physicaly connected address lines on the alpha, + but "only" 24 usable for now (the top two ones are used by FMC + to choose bank, and we only have one bank set up currently) + */ + addr &= 0x3fffffc; + + /* don't test zero addresses (fpga will store data, not address) */ + if (addr == 0) continue; + + /* write dummy value to fpga at some non-zero address and then read from the + test register to see what address the FPGA thought we wrote to + */ + if (! _write_then_read(cli, addr, dummy, &buf)) break; + + /* fpga receives address of 32-bit word, while we need + byte address here to compare + */ + buf <<= 2; + + /* compare (abort testing in case of error) */ + addr_diff = buf ^ addr; + if (addr_diff) { + cli_print(cli, "Address bus FAIL: expected 0x%lx got 0x%lx", addr, buf); + uart_send_string((char *) "Binary diff: "); + uart_send_binary(addr_diff, 32); + uart_send_string("\r\n"); + + break; + } + } + + if (! addr_diff) { + cli_print(cli, "Sample of address bus test data: expected 0x%lx got 0x%lx", addr, buf); + } else { + cli_print(cli, "\nFMC address bus per-bit analysis:"); + for (i = 0; i < 23; i++) { + uint32_t shifted_addr; + addr = 1 << i; + + shifted_addr = addr << 2; + + if (! _write_then_read(cli, shifted_addr, dummy, &buf)) break; + + if (addr == buf) { + cli_print(cli, "Address 0x%08lx (FMC_A%02i) - OK", addr, i + 1); + } else { + cli_print(cli, "Address 0x%08lx (FMC_A%02i) - FAIL (read 0x%08lx)", addr, i + 1, buf); + } + } + } + + /* return number of successful tests */ + return c; +} diff --git a/projects/cli-test/test-fmc.h b/projects/cli-test/test-fmc.h new file mode 100644 index 0000000..c49da48 --- /dev/null +++ b/projects/cli-test/test-fmc.h @@ -0,0 +1,43 @@ +/* + * test-fmc.h + * ------------ + * Prototypes and defines for testing the FMC bus comms with the FPGA. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __STM32_CLI_TEST_FMC_H +#define __STM32_CLI_TEST_FMC_H + +#include "mgmt-cli.h" + +extern int test_fpga_data_bus(struct cli_def *cli, uint32_t test_rounds); +extern int test_fpga_address_bus(struct cli_def *cli, uint32_t test_rounds); + + +#endif /* __STM32_CLI_TEST_FMC_H */ diff --git a/projects/cli-test/test-mkmif.c b/projects/cli-test/test-mkmif.c new file mode 100644 index 0000000..cd71040 --- /dev/null +++ b/projects/cli-test/test-mkmif.c @@ -0,0 +1,166 @@ +/* + * Test Joachim's MKMIF core. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include <sys/time.h> + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "mgmt-cli.h" + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + + +#define SCLK_DIV 0x20 + +typedef union { + uint8_t byte[4]; + uint32_t word; +} byteword_t; + +static hal_error_t sclk_test(struct cli_def *cli, hal_core_t *core, const uint32_t divisor) +{ + uint32_t readback; + hal_error_t err; + + cli_print(cli, "Trying to adjust the clockspeed (divisor %x).", (unsigned int) divisor); + + if ((err = hal_mkmif_set_clockspeed(core, divisor)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_set_clockspeed: %s", hal_error_string(err)); + return err; + } + if ((err = hal_mkmif_get_clockspeed(core, &readback)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_get_clockspeed: %s", hal_error_string(err)); + return err; + } + if (readback != divisor) { + cli_print(cli, "expected %x, got %x", (unsigned int)divisor, (unsigned int)readback); + return HAL_ERROR_IO_UNEXPECTED; + } + return LIBHAL_OK; +} + +static hal_error_t init_test(struct cli_def *cli, hal_core_t *core) +{ + hal_error_t err; + + cli_print(cli, "Trying to init to the memory in continuous mode."); + + if ((err = hal_mkmif_init(core)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_init: %s", hal_error_string(err)); + return err; + } + + return LIBHAL_OK; +} + +static hal_error_t write_test(struct cli_def *cli, hal_core_t *core) +{ + uint32_t write_data; + uint32_t write_address; + int i; + hal_error_t err; + + for (write_data = 0x01020304, write_address = 0, i = 0; + i < 0x10; + write_data += 0x01010101, write_address += 4, ++i) { + + cli_print(cli, "Trying to write 0x%08x to memory address 0x%08x.", + (unsigned int)write_data, (unsigned int)write_address); + + if ((err = hal_mkmif_write_word(core, write_address, write_data)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_write: %s", hal_error_string(err)); + return err; + } + } + + return LIBHAL_OK; +} + +static hal_error_t read_test(struct cli_def *cli, hal_core_t *core) +{ + uint32_t read_data; + uint32_t read_address; + int i; + hal_error_t err; + + for (read_address = 0, i = 0; + i < 0x10; + read_address += 4, ++i) { + + cli_print(cli, "Trying to read from memory address 0x%08x.", (unsigned int)read_address); + + if ((err = hal_mkmif_read_word(core, read_address, &read_data)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_read: %s", hal_error_string(err)); + return err; + } + cli_print(cli, "Data read: 0x%08x", (unsigned int)read_data); + } + + return LIBHAL_OK; +} + +static hal_error_t write_read_test(struct cli_def *cli, hal_core_t *core) +{ + uint32_t data; + uint32_t readback; + hal_error_t err; + + cli_print(cli, "Trying to write 0xdeadbeef to the memory and then read back."); + + data = 0xdeadbeef; + + if ((err = hal_mkmif_write_word(core, 0x00000000, data)) != LIBHAL_OK) { + cli_print(cli, "write error: %s", hal_error_string(err)); + return err; + } + + if ((err = hal_mkmif_read_word(core, 0x00000000, &readback)) != LIBHAL_OK) { + cli_print(cli, "read error: %s", hal_error_string(err)); + return err; + } + + if (readback != data) { + cli_print(cli, "read %08x, expected %08x", (unsigned int)readback, (unsigned int)data); + return HAL_ERROR_IO_UNEXPECTED; + } + + return LIBHAL_OK; +} + +int cmd_test_mkmif(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_core_t *core = hal_core_find(MKMIF_NAME, NULL); + hal_error_t res; + + command = command; + argv = argv; + argc = argc; + + if (core == NULL) { + cli_print(cli, "MKMIF core not present, not testing."); + return HAL_ERROR_CORE_NOT_FOUND; + } + + res = + sclk_test(cli, core, SCLK_DIV) || + init_test(cli, core) || + write_read_test(cli, core) || + write_test(cli, core) || + read_test(cli, core); + + if (res != LIBHAL_OK) { + cli_print(cli, "\nTest FAILED"); + } + + return CLI_OK; +} diff --git a/projects/cli-test/test_mkmif.h b/projects/cli-test/test_mkmif.h new file mode 100644 index 0000000..d5f2f75 --- /dev/null +++ b/projects/cli-test/test_mkmif.h @@ -0,0 +1,40 @@ +/* + * test_mkmif.h + * ------------ + * Prototypes and defines for testing the master key memory interface. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __STM32_CLI_TEST_MKMIF_H +#define __STM32_CLI_TEST_MKMIF_H + +extern int cmd_test_mkmif(struct cli_def *cli, const char *command, char *argv[], int argc); + + +#endif /* __STM32_CLI_TEST_MKMIF_H */ diff --git a/projects/cli-test/test_sdram.c b/projects/cli-test/test_sdram.c index e720667..4961b94 100644 --- a/projects/cli-test/test_sdram.c +++ b/projects/cli-test/test_sdram.c @@ -31,7 +31,6 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "stm32f4xx_hal.h"
#include "stm-led.h"
#include "stm-sdram.h"
#include "test_sdram.h"
|