aboutsummaryrefslogtreecommitdiff
path: root/projects
diff options
context:
space:
mode:
Diffstat (limited to 'projects')
-rw-r--r--projects/board-test/Makefile5
-rw-r--r--projects/board-test/fmc-perf.c39
-rw-r--r--projects/board-test/fmc-probe.c25
-rw-r--r--projects/board-test/fmc-test.c83
-rw-r--r--projects/board-test/keystore-perf.c197
-rw-r--r--projects/board-test/led-test.c1
-rw-r--r--projects/board-test/rtc-test.c75
-rw-r--r--projects/board-test/short-test.c1
-rw-r--r--projects/board-test/spiflash-perf.c249
-rw-r--r--projects/board-test/uart-test.c1
-rw-r--r--projects/bootloader/Makefile18
-rw-r--r--projects/bootloader/bootloader.c77
-rw-r--r--projects/bootloader/crc32.c62
-rw-r--r--projects/bootloader/dfu.c128
-rw-r--r--projects/bootloader/log.c68
-rw-r--r--projects/bootloader/startup_stm32f429xx.S564
-rw-r--r--projects/bootloader/stm-init.c7
-rw-r--r--projects/cli-test/Makefile27
-rw-r--r--projects/cli-test/cli-test.c99
-rw-r--r--projects/cli-test/crc32.c62
-rwxr-xr-xprojects/cli-test/filetransfer20
-rw-r--r--projects/cli-test/mgmt-cli.c220
-rw-r--r--projects/cli-test/mgmt-cli.h47
-rw-r--r--projects/cli-test/mgmt-dfu.c44
-rw-r--r--projects/cli-test/mgmt-dfu.h12
-rw-r--r--projects/cli-test/mgmt-fpga.c69
-rw-r--r--projects/cli-test/mgmt-fpga.h1
-rw-r--r--projects/cli-test/mgmt-keystore.c412
-rw-r--r--projects/cli-test/mgmt-keystore.h42
-rw-r--r--projects/cli-test/mgmt-keywrap.c316
-rw-r--r--projects/cli-test/mgmt-keywrap.h42
-rw-r--r--projects/cli-test/mgmt-masterkey.c225
-rw-r--r--projects/cli-test/mgmt-masterkey.h42
-rw-r--r--projects/cli-test/mgmt-misc.c164
-rw-r--r--projects/cli-test/mgmt-misc.h7
-rw-r--r--projects/cli-test/mgmt-show.c96
-rw-r--r--projects/cli-test/mgmt-show.h3
-rw-r--r--projects/cli-test/mgmt-test.c95
-rw-r--r--projects/cli-test/test-fmc.c217
-rw-r--r--projects/cli-test/test-fmc.h43
-rw-r--r--projects/cli-test/test-mkmif.c166
-rw-r--r--projects/cli-test/test_mkmif.h40
-rw-r--r--projects/cli-test/test_sdram.c1
-rw-r--r--projects/hsm/Makefile50
-rwxr-xr-xprojects/hsm/cryptech_miniterm45
-rwxr-xr-xprojects/hsm/cryptech_probe158
-rwxr-xr-xprojects/hsm/cryptech_upload385
-rw-r--r--projects/hsm/hsm.c522
-rw-r--r--projects/hsm/log.c68
-rw-r--r--projects/hsm/main.c226
-rw-r--r--projects/hsm/mgmt-bootloader.c89
-rw-r--r--projects/hsm/mgmt-bootloader.h51
-rw-r--r--projects/hsm/mgmt-cli.c220
-rw-r--r--projects/hsm/mgmt-cli.h49
-rw-r--r--projects/hsm/mgmt-firmware.c75
-rw-r--r--projects/hsm/mgmt-firmware.h42
-rw-r--r--projects/hsm/mgmt-fpga.c194
-rw-r--r--projects/hsm/mgmt-fpga.h49
-rw-r--r--projects/hsm/mgmt-keystore.c408
-rw-r--r--projects/hsm/mgmt-keystore.h42
-rw-r--r--projects/hsm/mgmt-masterkey.c244
-rw-r--r--projects/hsm/mgmt-masterkey.h42
-rw-r--r--projects/hsm/mgmt-misc.c259
-rw-r--r--projects/hsm/mgmt-misc.h47
-rw-r--r--projects/hsm/mgmt-task.c136
-rw-r--r--projects/hsm/mgmt-task.h42
-rw-r--r--projects/libhal-test/Makefile11
-rw-r--r--projects/libhal-test/gettimeofday.c2
-rw-r--r--projects/libhal-test/main.c12
-rw-r--r--projects/libhal-test/printf.c6
-rw-r--r--projects/rtos-test/Makefile18
-rw-r--r--projects/rtos-test/mutex-test.c40
-rw-r--r--projects/rtos-test/semaphore-test.c34
-rw-r--r--projects/rtos-test/thread-test.c24
74 files changed, 6710 insertions, 992 deletions
diff --git a/projects/board-test/Makefile b/projects/board-test/Makefile
index 9b1812f..45e75fc 100644
--- a/projects/board-test/Makefile
+++ b/projects/board-test/Makefile
@@ -1,4 +1,7 @@
-TEST = led-test short-test uart-test fmc-test fmc-perf fmc-probe rtc-test
+TEST = led-test short-test uart-test fmc-test fmc-perf fmc-probe
+ifeq (${BOARD},TARGET_CRYPTECH_ALPHA)
+TEST += rtc-test spiflash-perf keystore-perf
+endif
all: $(TEST:=.elf)
diff --git a/projects/board-test/fmc-perf.c b/projects/board-test/fmc-perf.c
index 0c753a7..5af0946 100644
--- a/projects/board-test/fmc-perf.c
+++ b/projects/board-test/fmc-perf.c
@@ -1,7 +1,6 @@
/*
* Test read/write performance of the fmc bus
*/
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-fmc.h"
@@ -32,14 +31,8 @@ static void sanity(void)
uint32_t rnd, data;
rnd = random();
- if (fmc_write_32(0, &rnd) != 0) {
- uart_send_string("fmc_write_32 failed\r\n");
- Error_Handler();
- }
- if (fmc_read_32(0, &data) != 0) {
- uart_send_string("fmc_read_32 failed\r\n");
- Error_Handler();
- }
+ fmc_write_32(0, rnd);
+ fmc_read_32(0, &data);
if (data != rnd) {
uart_send_string("Data bus fail: expected ");
uart_send_hex(rnd, 8);
@@ -57,11 +50,11 @@ static void _time_check(char *label, const uint32_t t0)
uint32_t t = HAL_GetTick() - t0;
uart_send_string(label);
- uart_send_integer(t / 1000, 0);
+ uart_send_integer(t / 1000, 1);
uart_send_char('.');
uart_send_integer(t % 1000, 3);
uart_send_string(" seconds, ");
- uart_send_integer(((1000 * TEST_NUM_ROUNDS) / t), 0);
+ uart_send_integer(((1000 * TEST_NUM_ROUNDS) / t), 1);
uart_send_string("/sec\r\n");
}
@@ -77,10 +70,7 @@ static void test_read(void)
uint32_t i, data;
for (i = 0; i < TEST_NUM_ROUNDS; ++i) {
- if (fmc_read_32(0, &data) != 0) {
- uart_send_string("fmc_read_32 failed\r\n");
- Error_Handler();
- }
+ fmc_read_32(0, &data);
}
}
@@ -89,33 +79,16 @@ static void test_write(void)
uint32_t i;
for (i = 0; i < TEST_NUM_ROUNDS; ++i) {
- if (fmc_write_32(0, &i) != 0) {
- uart_send_string("fmc_write_32 failed\r\n");
- Error_Handler();
- }
+ fmc_write_32(0, i);
}
}
int main(void)
{
stm_init();
-
- uart_send_string("Keep calm for Novena boot...\r\n");
-
- // Blink blue LED for six seconds to not upset the Novena at boot.
- led_on(LED_BLUE);
- for (int i = 0; i < 12; i++) {
- HAL_Delay(500);
- led_toggle(LED_BLUE);
- }
- led_off(LED_BLUE);
-
// initialize rng
MX_RNG_Init();
- // prepare fmc interface
- fmc_init();
-
sanity();
time_check("read ", test_read());
diff --git a/projects/board-test/fmc-probe.c b/projects/board-test/fmc-probe.c
index 55d3521..38897ab 100644
--- a/projects/board-test/fmc-probe.c
+++ b/projects/board-test/fmc-probe.c
@@ -2,7 +2,6 @@
* in other cases, it will be the core name and version strings.
*/
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-fmc.h"
@@ -22,37 +21,15 @@ static uint32_t read0(uint32_t addr)
{
uint32_t data;
- if (fmc_read_32(addr, &data) != 0) {
- uart_send_string("fmc_read_32 failed\r\n");
- Error_Handler();
- }
+ fmc_read_32(addr, &data);
return data;
}
int main(void)
{
- int i;
-
stm_init();
-
- uart_send_string("Keep calm for Novena boot...\r\n");
-
- // Blink blue LED for six seconds to not upset the Novena at boot.
- led_on(LED_BLUE);
- for (i = 0; i < 12; i++) {
- HAL_Delay(500);
- led_toggle(LED_BLUE);
- }
-
- // prepare fmc interface
- fmc_init();
-
- // turn on green led, turn off other leds
led_on(LED_GREEN);
- led_off(LED_YELLOW);
- led_off(LED_RED);
- led_off(LED_BLUE);
for (uint32_t addr = 0; addr < 0x00080000; addr += 4) {
uint32_t data = read0(addr);
diff --git a/projects/board-test/fmc-test.c b/projects/board-test/fmc-test.c
index bc5a768..bd30dd5 100644
--- a/projects/board-test/fmc-test.c
+++ b/projects/board-test/fmc-test.c
@@ -4,8 +4,7 @@
/*
This requires a special bitstream with a special test register.
- See core/platform/novena/fmc/rtl/novena_fmc_top.v, sections marked
- `ifdef test:
+ See core/platform/alpha/rtl/alpha_fmc_test.v:
//----------------------------------------------------------------
// Dummy Register
//
@@ -34,11 +33,11 @@
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-fmc.h"
#include "stm-uart.h"
+#include "stm-fpgacfg.h"
//------------------------------------------------------------------------------
// Defines
@@ -76,6 +75,7 @@ int test_fpga_address_bus(void);
// Defines
//------------------------------------------------------------------------------
#define TEST_NUM_ROUNDS 100000
+#define VERBOSE 0
//------------------------------------------------------------------------------
@@ -88,7 +88,7 @@ int main(void)
uart_send_string("Keep calm for FPGA bitstream loading...\r\n");
- // Blink blue LED until the FPGA reports it has loaded it's bitstream
+ // Blink blue LED until the FPGA reports it has loaded its bitstream
led_on(LED_BLUE);
while (! fpgacfg_check_done()) {
for (i = 0; i < 4; i++) {
@@ -100,9 +100,6 @@ int main(void)
// initialize rng
MX_RNG_Init();
- // prepare fmc interface
- fmc_init();
-
// turn on green led, turn off other leds
led_on(LED_GREEN);
led_off(LED_YELLOW);
@@ -120,11 +117,15 @@ int main(void)
// test address bus
addr_test_ok = test_fpga_address_bus();
- uart_send_string("Data: ");
- uart_send_integer(data_test_ok, 6);
- uart_send_string(", addr: ");
- uart_send_integer(addr_test_ok, 6);
- uart_send_string("\r\n");
+ if (VERBOSE ||
+ (data_test_ok != TEST_NUM_ROUNDS ||
+ addr_test_ok != TEST_NUM_ROUNDS)) {
+ uart_send_string("Data: ");
+ uart_send_integer(data_test_ok, 6);
+ uart_send_string(", addr: ");
+ uart_send_integer(addr_test_ok, 6);
+ uart_send_string("\r\n");
+ }
if (data_test_ok == TEST_NUM_ROUNDS &&
addr_test_ok == TEST_NUM_ROUNDS) {
@@ -140,11 +141,12 @@ int main(void)
}
uart_send_string("Success ");
- uart_send_integer(successful_runs, 0);
+ uart_send_integer(successful_runs, 1);
uart_send_string(", fail ");
- uart_send_integer(failed_runs, 0);
- uart_send_string("\r\n\r\n");
-
+ uart_send_integer(failed_runs, 1);
+ uart_send_string("\r\n");
+ if (VERBOSE)
+ uart_send_string("\r\n");
HAL_Delay(sleep);
}
@@ -156,7 +158,7 @@ int main(void)
int test_fpga_data_bus(void)
//------------------------------------------------------------------------------
{
- int c, ok;
+ int c;
uint32_t rnd, buf;
HAL_StatusTypeDef hal_result;
@@ -169,12 +171,10 @@ int test_fpga_data_bus(void)
if (hal_result != HAL_OK) break;
// write value to fpga at address 0
- ok = fmc_write_32(0, &rnd);
- if (ok != 0) break;
+ fmc_write_32(0, rnd);
// read value from fpga
- ok = fmc_read_32(0, &buf);
- if (ok != 0) break;
+ fmc_read_32(0, &buf);
// compare (abort testing in case of error)
if (buf != rnd)
@@ -197,13 +197,16 @@ int test_fpga_data_bus(void)
data_diff = buf;
data_diff ^= rnd;
- uart_send_string("Sample of data bus test data: expected ");
- uart_send_binary(rnd, 32);
- uart_send_string(", got ");
- uart_send_binary(buf, 32);
- uart_send_string(", diff ");
- uart_send_binary(data_diff, 32);
- uart_send_string("\r\n");
+ if (VERBOSE || data_diff) {
+ uart_send_string("Sample of data bus test data: expected ");
+ uart_send_binary(rnd, 32);
+ uart_send_string(", got ");
+ uart_send_binary(buf, 32);
+ uart_send_string(", diff ");
+ uart_send_binary(data_diff, 32);
+ uart_send_string("\r\n");
+ }
+
// return number of successful tests
return c;
}
@@ -213,7 +216,7 @@ int test_fpga_data_bus(void)
int test_fpga_address_bus(void)
//------------------------------------------------------------------------------
{
- int c, ok;
+ int c;
uint32_t rnd, buf;
HAL_StatusTypeDef hal_result;
@@ -234,12 +237,10 @@ int test_fpga_address_bus(void)
if (rnd == 0) continue;
// write dummy value to fpga at some non-zero address
- ok = fmc_write_32(rnd, &buf);
- if (ok != 0) break;
+ fmc_write_32(rnd, buf);
// read value from fpga
- ok = fmc_read_32(0, &buf);
- if (ok != 0) break;
+ fmc_read_32(0, &buf);
// fpga receives address of 32-bit word, while we need
// byte address here to compare
@@ -266,13 +267,15 @@ int test_fpga_address_bus(void)
addr_diff = buf;
addr_diff ^= rnd;
- uart_send_string("Sample of addr bus test data: expected ");
- uart_send_binary(rnd, 32);
- uart_send_string(", got ");
- uart_send_binary(buf, 32);
- uart_send_string(", diff ");
- uart_send_binary(addr_diff, 32);
- uart_send_string("\r\n");
+ if (VERBOSE || addr_diff) {
+ uart_send_string("Sample of addr bus test data: expected ");
+ uart_send_binary(rnd, 32);
+ uart_send_string(", got ");
+ uart_send_binary(buf, 32);
+ uart_send_string(", diff ");
+ uart_send_binary(addr_diff, 32);
+ uart_send_string("\r\n");
+ }
return c;
}
diff --git a/projects/board-test/keystore-perf.c b/projects/board-test/keystore-perf.c
new file mode 100644
index 0000000..c2aa4fb
--- /dev/null
+++ b/projects/board-test/keystore-perf.c
@@ -0,0 +1,197 @@
+/*
+ * Test read/write/erase performance of the flash keystore.
+ */
+
+#include "string.h"
+
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-uart.h"
+#include "stm-keystore.h"
+
+/*
+ * 1. Read the entire flash by subsectors, ignoring data.
+ */
+static void test_read_data(void)
+{
+ uint8_t read_buf[KEYSTORE_SUBSECTOR_SIZE];
+ uint32_t i;
+ HAL_StatusTypeDef err;
+
+ for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) {
+ err = keystore_read_data(i * KEYSTORE_SUBSECTOR_SIZE, read_buf, KEYSTORE_SUBSECTOR_SIZE);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: keystore_read_data returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * Read the flash data and verify it against a known pattern.
+ */
+static void _read_verify(uint8_t *vrfy_buf)
+{
+ uint8_t read_buf[KEYSTORE_SUBSECTOR_SIZE];
+ uint32_t i;
+ HAL_StatusTypeDef err;
+
+ for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) {
+ err = keystore_read_data(i * KEYSTORE_SUBSECTOR_SIZE, read_buf, KEYSTORE_SUBSECTOR_SIZE);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: keystore_read_data returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ if (memcmp(read_buf, vrfy_buf, KEYSTORE_SUBSECTOR_SIZE) != 0) {
+ uart_send_string("ERROR: verify failed in subsector ");
+ uart_send_integer(i, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 2a. Erase the entire flash by sectors.
+ */
+static void test_erase_sector(void)
+{
+ uint32_t i;
+ HAL_StatusTypeDef err;
+
+ for (i = 0; i < KEYSTORE_NUM_SECTORS; ++i) {
+ err = keystore_erase_sector(i);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: keystore_erase_sector returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 2b. Erase the entire flash by subsectors.
+ */
+static void test_erase_subsector(void)
+{
+ uint32_t i;
+ HAL_StatusTypeDef err;
+
+ for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) {
+ err = keystore_erase_subsector(i);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: keystore_erase_subsector returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 2c. Read the entire flash, verify erasure.
+ */
+static void test_verify_erase(void)
+{
+ uint8_t vrfy_buf[KEYSTORE_SUBSECTOR_SIZE];
+ uint32_t i;
+
+ for (i = 0; i < sizeof(vrfy_buf); ++i)
+ vrfy_buf[i] = 0xFF;
+
+ _read_verify(vrfy_buf);
+}
+
+/*
+ * 3a. Write the entire flash with a pattern.
+ */
+static void test_write_data(void)
+{
+ uint8_t write_buf[KEYSTORE_SUBSECTOR_SIZE];
+ uint32_t i;
+ HAL_StatusTypeDef err;
+
+ for (i = 0; i < sizeof(write_buf); ++i)
+ write_buf[i] = i & 0xFF;
+
+ for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) {
+ err = keystore_write_data(i * KEYSTORE_SUBSECTOR_SIZE, write_buf, KEYSTORE_SUBSECTOR_SIZE);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: keystore_write_data returned ");
+ uart_send_integer(err, 1);
+ uart_send_string(" for subsector ");
+ uart_send_integer(i, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 3b. Read the entire flash, verify data.
+ */
+static void test_verify_write(void)
+{
+ uint8_t vrfy_buf[KEYSTORE_SUBSECTOR_SIZE];
+ uint32_t i;
+
+ for (i = 0; i < sizeof(vrfy_buf); ++i)
+ vrfy_buf[i] = i & 0xFF;
+
+ _read_verify(vrfy_buf);
+}
+
+static void _time_check(char *label, const uint32_t t0, uint32_t n_rounds)
+{
+ uint32_t t = HAL_GetTick() - t0;
+
+ uart_send_string(label);
+ uart_send_integer(t / 1000, 1);
+ uart_send_char('.');
+ uart_send_integer(t % 1000, 3);
+ uart_send_string(" sec");
+ if (n_rounds > 1) {
+ uart_send_string(" for ");
+ uart_send_integer(n_rounds, 1);
+ uart_send_string(" rounds, ");
+ uart_send_integer(t / n_rounds, 1);
+ uart_send_char('.');
+ uart_send_integer(((t % n_rounds) * 100) / n_rounds, 2);
+ uart_send_string(" ms each");
+ }
+ uart_send_string("\r\n");
+}
+
+#define time_check(_label_, _expr_, _n_) \
+ do { \
+ uint32_t _t = HAL_GetTick(); \
+ (_expr_); \
+ _time_check(_label_, _t, _n_); \
+ } while (0)
+
+int main(void)
+{
+ stm_init();
+
+ if (keystore_check_id() != HAL_OK) {
+ uart_send_string("ERROR: keystore_check_id failed\r\n");
+ return 0;
+ }
+
+ uart_send_string("Starting...\r\n");
+
+ time_check("read data ", test_read_data(), KEYSTORE_NUM_SUBSECTORS);
+ time_check("erase subsector ", test_erase_subsector(), KEYSTORE_NUM_SUBSECTORS);
+ time_check("erase sector ", test_erase_sector(), KEYSTORE_NUM_SECTORS);
+ time_check("verify erase ", test_verify_erase(), KEYSTORE_NUM_SUBSECTORS);
+ time_check("write data ", test_write_data(), KEYSTORE_NUM_SUBSECTORS);
+ time_check("verify write ", test_verify_write(), KEYSTORE_NUM_SUBSECTORS);
+
+ uart_send_string("Done.\r\n\r\n");
+ return 0;
+}
diff --git a/projects/board-test/led-test.c b/projects/board-test/led-test.c
index 7e72788..2ec7c9d 100644
--- a/projects/board-test/led-test.c
+++ b/projects/board-test/led-test.c
@@ -1,7 +1,6 @@
/*
* Blink the four LEDs on the rev01 board in a pattern.
*/
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
diff --git a/projects/board-test/rtc-test.c b/projects/board-test/rtc-test.c
index b8a7511..bbb297a 100644
--- a/projects/board-test/rtc-test.c
+++ b/projects/board-test/rtc-test.c
@@ -8,7 +8,6 @@
*/
#include <string.h>
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-uart.h"
@@ -23,18 +22,18 @@ uint32_t i;
uint32_t device_ready(uint16_t i2c_addr)
{
- uart_send_string2(STM_UART_MGMT, "Checking readiness of 0x");
- uart_send_number2(STM_UART_MGMT, i2c_addr, 4, 16);
- uart_send_string2(STM_UART_MGMT, "...");
+ uart_send_string("Checking readiness of 0x");
+ uart_send_hex(i2c_addr, 4);
+ uart_send_string("...");
if (rtc_device_ready(i2c_addr) == HAL_OK) {
- uart_send_string2(STM_UART_MGMT, "OK\r\n");
+ uart_send_string("OK\r\n");
return 1;
}
- uart_send_string2(STM_UART_MGMT, "Not ready (0x");
- uart_send_number2(STM_UART_MGMT, i, 4, 16);
- uart_send_string2(STM_UART_MGMT, ")\r\n");
+ uart_send_string("Not ready (0x");
+ uart_send_hex(i, 4);
+ uart_send_string(")\r\n");
return 0;
}
@@ -44,34 +43,34 @@ void send_byte(const uint16_t i2c_addr, const uint8_t value)
{
uint8_t ch = value;
- uart_send_string2(STM_UART_MGMT, "Sending ");
- uart_send_number2(STM_UART_MGMT, ch, 2, 16);
- uart_send_string2(STM_UART_MGMT, " to 0x");
- uart_send_number2(STM_UART_MGMT, i2c_addr, 4, 16);
- uart_send_string2(STM_UART_MGMT, "...");
+ uart_send_string("Sending ");
+ uart_send_hex(ch, 2);
+ uart_send_string(" to 0x");
+ uart_send_hex(i2c_addr, 4);
+ uart_send_string("...");
if (rtc_send_byte(i2c_addr, ch, 1000) != HAL_OK) {
- uart_send_string2(STM_UART_MGMT, "Timeout\r\n");
+ uart_send_string("Timeout\r\n");
Error_Handler();
}
- uart_send_string2(STM_UART_MGMT, "OK\r\n");
+ uart_send_string("OK\r\n");
}
void read_bytes (uint8_t *buf, const uint16_t i2c_addr, const uint8_t len)
{
- uart_send_string2(STM_UART_MGMT, "Reading ");
- uart_send_number2(STM_UART_MGMT, len, 3, 10);
- uart_send_string2(STM_UART_MGMT, " bytes from 0x");
- uart_send_number2(STM_UART_MGMT, i2c_addr, 4, 16);
- uart_send_string2(STM_UART_MGMT, "...");
+ uart_send_string("Reading ");
+ uart_send_integer(len, 1);
+ uart_send_string(" bytes from 0x");
+ uart_send_hex(i2c_addr, 4);
+ uart_send_string("...");
if (rtc_read_bytes(i2c_addr, buf, len, 1000) != HAL_OK) {
- uart_send_string2(STM_UART_MGMT, "Timeout\r\n");
+ uart_send_string("Timeout\r\n");
Error_Handler();
}
- uart_send_string2(STM_UART_MGMT, "OK\r\n");
+ uart_send_string("OK\r\n");
}
void request_data(uint8_t *buf, const uint16_t i2c_addr, const uint8_t offset, const uint8_t bytes)
@@ -85,8 +84,8 @@ void print_time()
request_data(buf, RTC_RTC_ADDR, RTC_TIME_OFFSET, RTC_TIME_BYTES);
for (i = 0; i < RTC_TIME_BYTES; i++) {
- uart_send_number2(STM_UART_MGMT, buf[i], 2, 16);
- uart_send_string2(STM_UART_MGMT, " ");
+ uart_send_hex(buf[i], 2);
+ uart_send_string(" ");
}
}
@@ -94,37 +93,37 @@ void dump_sram()
{
request_data(buf, RTC_RTC_ADDR, 0x0, RTC_SRAM_TOTAL_BYTES);
- uart_send_string2(STM_UART_MGMT, "SRAM contents:\r\n");
- uart_send_hexdump(STM_UART_MGMT, buf, 0, RTC_SRAM_TOTAL_BYTES);
+ uart_send_string("SRAM contents:\r\n");
+ uart_send_hexdump(buf, 0, RTC_SRAM_TOTAL_BYTES);
- uart_send_string2(STM_UART_MGMT, "\r\n");
+ uart_send_string("\r\n");
}
void dump_eeprom()
{
request_data(buf, RTC_EEPROM_ADDR, 0x0, RTC_EEPROM_TOTAL_BYTES);
- uart_send_string2(STM_UART_MGMT, "EEPROM contents:\r\n");
- uart_send_hexdump(STM_UART_MGMT, buf, 0, RTC_EEPROM_TOTAL_BYTES);
- uart_send_string2(STM_UART_MGMT, "\r\n");
+ uart_send_string("EEPROM contents:\r\n");
+ uart_send_hexdump(buf, 0, RTC_EEPROM_TOTAL_BYTES);
+ uart_send_string("\r\n");
request_data(buf, RTC_EEPROM_ADDR, RTC_EEPROM_EUI48_OFFSET, RTC_EEPROM_EUI48_BYTES);
- uart_send_string2(STM_UART_MGMT, "EEPROM EUI-48:\r\n");
- uart_send_hexdump(STM_UART_MGMT, buf, RTC_EEPROM_EUI48_OFFSET, RTC_EEPROM_EUI48_BYTES);
+ uart_send_string("EEPROM EUI-48:\r\n");
+ uart_send_hexdump(buf, RTC_EEPROM_EUI48_OFFSET, RTC_EEPROM_EUI48_BYTES);
- uart_send_string2(STM_UART_MGMT, "\r\n");
+ uart_send_string("\r\n");
}
void enable_oscillator()
{
- uart_send_string2(STM_UART_MGMT, "Enabling oscillator...\r\n");
+ uart_send_string("Enabling oscillator...\r\n");
if (rtc_enable_oscillator() != HAL_OK) {
- uart_send_string2(STM_UART_MGMT, "Timeout\r\n");
+ uart_send_string("Timeout\r\n");
Error_Handler();
}
- uart_send_string2(STM_UART_MGMT, "OK\r\n");
+ uart_send_string("OK\r\n");
}
@@ -132,7 +131,7 @@ int
main()
{
stm_init();
- uart_send_string2(STM_UART_MGMT, "\r\n\r\n*** Init done\r\n");
+ uart_send_string("\r\n\r\n*** Init done\r\n");
dump_sram();
dump_eeprom();
@@ -148,7 +147,7 @@ main()
print_time(buf);
- uart_send_string2(STM_UART_MGMT, "\r\n\r\n");
+ uart_send_string("\r\n\r\n");
HAL_GPIO_TogglePin(LED_PORT, LED_GREEN);
DELAY();
diff --git a/projects/board-test/short-test.c b/projects/board-test/short-test.c
index 27b8e7a..db0251b 100644
--- a/projects/board-test/short-test.c
+++ b/projects/board-test/short-test.c
@@ -5,7 +5,6 @@
* Toggles the BLUE LED slowly and the RED LED for every
* character sent.
*/
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-uart.h"
diff --git a/projects/board-test/spiflash-perf.c b/projects/board-test/spiflash-perf.c
new file mode 100644
index 0000000..36c6131
--- /dev/null
+++ b/projects/board-test/spiflash-perf.c
@@ -0,0 +1,249 @@
+/*
+ * Test read/write/erase performance of the N25Q128 SPI flash chip.
+ */
+
+#include "string.h"
+
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-uart.h"
+#include "stm-keystore.h"
+#include "spiflash_n25q128.h"
+
+/*
+ * Use the keystore memory for testing, because it's less involved than
+ * using the FPGA configuration memory, and less work to restore it to a
+ * useful configuration.
+ *
+ * However, rather than using the stm-keystore abstractions, this version
+ * goes straight to the low-level API.
+ */
+
+extern struct spiflash_ctx keystore_ctx;
+static struct spiflash_ctx *ctx = &keystore_ctx;
+
+/*
+ * 1a. Read the entire flash by pages, ignoring data.
+ */
+static void test_read_page(void)
+{
+ uint8_t read_buf[N25Q128_PAGE_SIZE];
+ uint32_t i;
+ int err;
+
+ for (i = 0; i < N25Q128_NUM_PAGES; ++i) {
+ err = n25q128_read_page(ctx, i, read_buf);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_read_page returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 1b. Read the entire flash by subsectors, ignoring data.
+ */
+static void test_read_subsector(void)
+{
+ uint8_t read_buf[N25Q128_SUBSECTOR_SIZE];
+ uint32_t i;
+ int err;
+
+ for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) {
+ err = n25q128_read_subsector(ctx, i, read_buf);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_read_subsector returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * Read the flash data and verify it against a known pattern.
+ * It turns out that verification doesn't slow us down in any measurable
+ * way, because memcmp on 256 bytes is pretty inconsequential.
+ */
+static void _read_verify(uint8_t *vrfy_buf)
+{
+ uint8_t read_buf[N25Q128_PAGE_SIZE];
+ uint32_t i;
+ int err;
+
+ for (i = 0; i < N25Q128_NUM_PAGES; ++i) {
+ err = n25q128_read_page(ctx, i, read_buf);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_read_page returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ if (memcmp(read_buf, vrfy_buf, N25Q128_PAGE_SIZE) != 0) {
+ uart_send_string("ERROR: verify failed in page ");
+ uart_send_integer(i, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 2a. Erase the entire flash by sectors.
+ */
+static void test_erase_sector(void)
+{
+ uint32_t i;
+ int err;
+
+ for (i = 0; i < N25Q128_NUM_SECTORS; ++i) {
+ err = n25q128_erase_sector(ctx, i);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_erase_sector returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 2b. Erase the entire flash by subsectors.
+ */
+static void test_erase_subsector(void)
+{
+ uint32_t i;
+ int err;
+
+ for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) {
+ err = n25q128_erase_subsector(ctx, i);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_erase_subsector returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 2c. Erase the entire flash in bulk.
+ */
+static void test_erase_bulk(void)
+{
+ int err;
+
+ err = n25q128_erase_bulk(ctx);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_erase_bulk returned ");
+ uart_send_integer(err, 1);
+ uart_send_string("\r\n");
+ }
+}
+
+/*
+ * 2d. Read the entire flash, verify erasure.
+ */
+static void test_verify_erase(void)
+{
+ uint8_t vrfy_buf[N25Q128_PAGE_SIZE];
+ uint32_t i;
+
+ for (i = 0; i < sizeof(vrfy_buf); ++i)
+ vrfy_buf[i] = 0xFF;
+
+ _read_verify(vrfy_buf);
+}
+
+/*
+ * 3a. Write the entire flash with a pattern.
+ */
+static void test_write_page(void)
+{
+ uint8_t write_buf[N25Q128_PAGE_SIZE];
+ uint32_t i;
+ int err;
+
+ for (i = 0; i < sizeof(write_buf); ++i)
+ write_buf[i] = i & 0xFF;
+
+ for (i = 0; i < N25Q128_NUM_PAGES; ++i) {
+ err = n25q128_write_page(ctx, i, write_buf);
+ if (err != HAL_OK) {
+ uart_send_string("ERROR: n25q128_write_page returned ");
+ uart_send_integer(err, 1);
+ uart_send_string(" for page ");
+ uart_send_integer(i, 1);
+ uart_send_string("\r\n");
+ break;
+ }
+ }
+}
+
+/*
+ * 3b. Read the entire flash, verify data.
+ */
+static void test_verify_write(void)
+{
+ uint8_t vrfy_buf[N25Q128_PAGE_SIZE];
+ uint32_t i;
+
+ for (i = 0; i < sizeof(vrfy_buf); ++i)
+ vrfy_buf[i] = i & 0xFF;
+
+ _read_verify(vrfy_buf);
+}
+
+static void _time_check(char *label, const uint32_t t0, uint32_t n_rounds)
+{
+ uint32_t t = HAL_GetTick() - t0;
+
+ uart_send_string(label);
+ uart_send_integer(t / 1000, 1);
+ uart_send_char('.');
+ uart_send_integer(t % 1000, 3);
+ uart_send_string(" sec");
+ if (n_rounds > 1) {
+ uart_send_string(" for ");
+ uart_send_integer(n_rounds, 1);
+ uart_send_string(" rounds, ");
+ uart_send_integer(t / n_rounds, 1);
+ uart_send_char('.');
+ uart_send_integer(((t % n_rounds) * 100) / n_rounds, 2);
+ uart_send_string(" ms each");
+ }
+ uart_send_string("\r\n");
+}
+
+#define time_check(_label_, _expr_, _n_) \
+ do { \
+ uint32_t _t = HAL_GetTick(); \
+ (_expr_); \
+ _time_check(_label_, _t, _n_); \
+ } while (0)
+
+int main(void)
+{
+ stm_init();
+
+ if (n25q128_check_id(ctx) != HAL_OK) {
+ uart_send_string("ERROR: n25q128_check_id failed\r\n");
+ return 0;
+ }
+
+ uart_send_string("Starting...\r\n");
+
+ time_check("read page ", test_read_page(), N25Q128_NUM_PAGES);
+ time_check("read subsector ", test_read_subsector(), N25Q128_NUM_SUBSECTORS);
+ time_check("erase subsector ", test_erase_subsector(), N25Q128_NUM_SUBSECTORS);
+ time_check("erase sector ", test_erase_sector(), N25Q128_NUM_SECTORS);
+ time_check("erase bulk ", test_erase_bulk(), 1);
+ time_check("verify erase ", test_verify_erase(), N25Q128_NUM_PAGES);
+ time_check("write page ", test_write_page(), N25Q128_NUM_PAGES);
+ time_check("verify write ", test_verify_write(), N25Q128_NUM_PAGES);
+
+ uart_send_string("Done.\r\n\r\n");
+ return 0;
+}
diff --git a/projects/board-test/uart-test.c b/projects/board-test/uart-test.c
index be06863..9a56dee 100644
--- a/projects/board-test/uart-test.c
+++ b/projects/board-test/uart-test.c
@@ -6,7 +6,6 @@
* Toggles the BLUE LED slowly and the GREEN LED for every
* character sent.
*/
-#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-uart.h"
diff --git a/projects/bootloader/Makefile b/projects/bootloader/Makefile
index 4eef758..6c1012f 100644
--- a/projects/bootloader/Makefile
+++ b/projects/bootloader/Makefile
@@ -1,6 +1,22 @@
PROG = bootloader
-OBJS = crc32.o dfu.o
+OBJS = dfu.o log.o
+
+BOARD_OBJS = \
+ ./stm-init.o \
+ $(TOPLEVEL)/stm-fmc.o \
+ $(TOPLEVEL)/stm-uart.o \
+ $(TOPLEVEL)/spiflash_n25q128.o \
+ $(TOPLEVEL)/stm-keystore.o \
+ $(TOPLEVEL)/stm-flash.o \
+ $(TOPLEVEL)/syscalls.o \
+ $(BOARD_DIR)/system_stm32f4xx.o \
+ $(BOARD_DIR)/stm32f4xx_hal_msp.o \
+ ./startup_stm32f429xx.o \
+ $(BOARD_DIR)/stm32f4xx_it.o
+
+CFLAGS += -I$(LIBHAL_SRC)
+LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a
all: $(PROG:=.elf)
diff --git a/projects/bootloader/bootloader.c b/projects/bootloader/bootloader.c
index ab3c1d9..6413597 100644
--- a/projects/bootloader/bootloader.c
+++ b/projects/bootloader/bootloader.c
@@ -5,6 +5,8 @@
* or jump to previously installed firmware.
*
* Copyright (c) 2016, 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
@@ -16,9 +18,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,11 +34,30 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
+/* Ignore "deprecated" warnings in ARM-supplied CMSIS code:
+ *
+ * libraries/mbed/targets/cmsis/core_cm4.h:85:28: warning: listing the stack pointer register 'sp' in a clobber list is deprecated
+ * libraries/mbed/targets/cmsis/core_cm4.h:85:28: note: the value of the stack pointer after an 'asm' statement must be the same as it was before the statement
+ *
+ * This comes from our use of __set_MSP to set the stack pointer when
+ * switching tasks. If GCC ever decides to actually forbid this, then
+ * we'll have to figure out something else, possibly a native assembly
+ * function.
+ */
+#pragma GCC diagnostic ignored "-Wdeprecated"
+
#include "stm-init.h"
#include "stm-led.h"
#include "stm-uart.h"
+#include "stm-fmc.h"
#include "dfu.h"
+/* stub these out to avoid linker error */
+void fpgacfg_init(void) { }
+void sdram_init(void) { }
+void *hal_allocate_static_memory(const size_t size) { return 0; }
+
/* Linker symbols are strange in C. Make regular pointers for sanity. */
__IO uint32_t *dfu_control = &CRYPTECH_DFU_CONTROL;
__IO uint32_t *dfu_firmware = &CRYPTECH_FIRMWARE_START;
@@ -49,16 +70,20 @@ __IO uint32_t *dfu_code_ptr = &CRYPTECH_FIRMWARE_START + 1;
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)
+/* called from Reset_Handler */
+void check_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);
+ /* Check if we've just rebooted in order to jump to the firmware. */
+ if (*dfu_control == HARDWARE_EARLY_DFU_JUMP) {
+ *dfu_control = 0;
+ 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);
+ }
}
int should_dfu()
@@ -66,35 +91,31 @@ int should_dfu()
int i;
uint8_t rx = 0;
- /* While blinking the blue LED for one second, see if we receive a CR on the MGMT UART.
+ /* While blinking the blue LED for 5 seconds, see if we receive a CR on the MGMT UART.
* We've discussed also requiring one or both of the FPGA config jumpers installed
* before allowing DFU of the STM32 - that check could be done here.
*/
led_on(LED_BLUE);
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < 50; i++) {
HAL_Delay(100);
led_toggle(LED_BLUE);
- if (uart_recv_char2(STM_UART_MGMT, &rx, 0) == HAL_OK) {
+ if (uart_recv_char(&rx, 0) == HAL_OK) {
if (rx == 13) return 1;
}
}
return 0;
}
-int
-main()
+/* Sleep for specified number of seconds -- used after bad PIN. */
+void hal_sleep(const unsigned seconds) { HAL_Delay(seconds * 1000); }
+
+int main(void)
{
int status;
- /* 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();
- }
-
stm_init();
- uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\nThis is the bootloader speaking...");
+ uart_send_string("\r\n\r\nThis is the bootloader speaking...");
if (should_dfu()) {
led_off(LED_BLUE);
@@ -104,9 +125,9 @@ main()
*/
led_off(LED_BLUE);
led_on(LED_RED);
- uart_send_string2(STM_UART_MGMT, (char *) "dfu_receive_firmware failed: ");
- uart_send_number2(STM_UART_MGMT, status, 3, 16);
- uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\nRebooting in three seconds\r\n");
+ uart_send_string("dfu_receive_firmware failed: ");
+ uart_send_hex(status, 2);
+ uart_send_string("\r\n\r\nRebooting in three seconds\r\n");
HAL_Delay(3000);
HAL_NVIC_SystemReset();
while (1) {};
@@ -118,7 +139,7 @@ main()
*/
*dfu_control = HARDWARE_EARLY_DFU_JUMP;
- uart_send_string2(STM_UART_MGMT, (char *) "loading firmware\r\n\r\n");
+ uart_send_string("loading firmware\r\n\r\n");
/* De-initialize hardware by rebooting */
HAL_NVIC_SystemReset();
diff --git a/projects/bootloader/crc32.c b/projects/bootloader/crc32.c
deleted file mode 100644
index 4d1a0bc..0000000
--- a/projects/bootloader/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/bootloader/dfu.c b/projects/bootloader/dfu.c
index 231e388..83aef20 100644
--- a/projects/bootloader/dfu.c
+++ b/projects/bootloader/dfu.c
@@ -31,43 +31,132 @@
* 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 "dfu.h"
#include "stm-led.h"
#include "stm-uart.h"
#include "stm-flash.h"
+#undef HAL_OK
+
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#include "hal_internal.h"
+#undef HAL_OK
#include <string.h>
-extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len);
+static int getline(char *buf, int len)
+{
+ int i;
+ uint8_t c;
+
+ for (i = 0; i < len; ++i) {
+ if (uart_recv_char(&c, HAL_MAX_DELAY) != CMSIS_HAL_OK)
+ return -1;
+ if (c == '\r') {
+ buf[i] = '\0';
+ break;
+ }
+ buf[i] = c;
+ }
+ return i;
+}
+static void uart_flush(void)
+{
+ uint8_t c;
+ while (uart_recv_char(&c, 0) == CMSIS_HAL_OK) { ; }
+}
+
+static int do_login(void)
+{
+ char username[8];
+ char pin[hal_rpc_max_pin_length];
+ hal_client_handle_t client = { -1 };
+ hal_user_t user;
+ int n;
+
+ uart_flush();
+ uart_send_string("\r\nUsername: ");
+ if (getline(username, sizeof(username)) <= 0)
+ return -1;
+ if (strcmp(username, "wheel") == 0)
+ user = HAL_USER_WHEEL;
+ else if (strcmp(username, "so") == 0)
+ user = HAL_USER_SO;
+ else if (strcmp(username, "user") == 0)
+ user = HAL_USER_NORMAL;
+ else
+ user = HAL_USER_NONE;
+
+ uart_flush();
+ uart_send_string("\r\nPassword: ");
+ if ((n = getline(pin, sizeof(pin))) <= 0)
+ return -1;
+
+ uart_flush();
+
+ hal_ks_init_read_only_pins_only();
+
+ if (hal_rpc_login(client, user, pin, n) != LIBHAL_OK) {
+ uart_send_string("\r\nAccess denied\r\n");
+ return -1;
+ }
+ return 0;
+}
int dfu_receive_firmware(void)
{
- uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0;
uint32_t offset = DFU_FIRMWARE_ADDR, n = DFU_UPLOAD_CHUNK_SIZE;
- uint32_t buf[DFU_UPLOAD_CHUNK_SIZE / 4];
+ hal_crc32_t crc = 0, my_crc = hal_crc32_init();
+ uint32_t filesize = 0, counter = 0;
+ uint8_t buf[DFU_UPLOAD_CHUNK_SIZE];
+
+ if (do_login() != 0)
+ return -1;
+
+ /* Fake the CLI */
+ uart_send_string("\r\ncryptech> ");
+ char cmd[64];
+ if (getline(cmd, sizeof(cmd)) <= 0)
+ return -1;
+ if (strcmp(cmd, "firmware upload") != 0) {
+ uart_send_string("\r\nInvalid command \"");
+ uart_send_string(cmd);
+ uart_send_string("\"\r\n");
+ return -1;
+ }
- uart_send_string2(STM_UART_MGMT, (char *) "\r\nOK, bootloader waiting for new firmware\r\n");
+ uart_send_string("OK, write size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)\r\n");
/* Read file size (4 bytes) */
- uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
+ uart_receive_bytes((void *) &filesize, sizeof(filesize), 10000);
if (filesize < 512 || filesize > DFU_FIRMWARE_END_ADDR - DFU_FIRMWARE_ADDR) {
+ uart_send_string("Invalid filesize ");
+ uart_send_integer(filesize, 1);
+ uart_send_string("\r\n");
return -1;
}
HAL_FLASH_Unlock();
+ uart_send_string("Send ");
+ uart_send_integer(filesize, 1);
+ uart_send_string(" bytes of data\r\n");
+
while (filesize) {
/* By initializing buf to the same value that erased flash has (0xff), we don't
* have to try and be smart when writing the last page of data to the memory.
*/
- memset(buf, 0xffffffff, sizeof(buf));
+ memset(buf, 0xff, sizeof(buf));
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, 10000) != CMSIS_HAL_OK) {
return -2;
}
filesize -= n;
@@ -75,23 +164,34 @@ int dfu_receive_firmware(void)
/* After reception of a chunk but before ACKing we have "all" the time in the world to
* calculate CRC and write it to flash.
*/
- my_crc = update_crc(my_crc, (uint8_t *) buf, n);
- stm_flash_write32(offset, buf, sizeof(buf) / 4);
+ my_crc = hal_crc32_update(my_crc, buf, n);
+ stm_flash_write32(offset, (uint32_t *)buf, sizeof(buf)/4);
offset += DFU_UPLOAD_CHUNK_SIZE;
/* ACK this chunk by sending the current chunk counter (4 bytes) */
counter++;
- uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
+ uart_send_bytes((void *) &counter, 4);
led_toggle(LED_BLUE);
}
+ my_crc = hal_crc32_finalize(my_crc);
+
HAL_FLASH_Lock();
- /* The sending side will now send it's calculated CRC-32 */
- uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000);
+ uart_send_string("Send CRC-32\r\n");
+
+ /* The sending side will now send its calculated CRC-32 */
+ uart_receive_bytes((void *) &crc, sizeof(crc), 10000);
+
+ uart_send_string("CRC-32 0x");
+ uart_send_hex(crc, 1);
+ uart_send_string(", calculated CRC 0x");
+ uart_send_hex(my_crc, 1);
if (crc == my_crc) {
- uart_send_string2(STM_UART_MGMT, (char *) "\r\nSuccess\r\n");
- return 0;
+ uart_send_string("CRC checksum MATCHED\r\n");
+ return 0;
+ } else {
+ uart_send_string("CRC checksum did NOT match\r\n");
}
led_on(LED_RED);
diff --git a/projects/bootloader/log.c b/projects/bootloader/log.c
new file mode 100644
index 0000000..fbc0e73
--- /dev/null
+++ b/projects/bootloader/log.c
@@ -0,0 +1,68 @@
+/*
+ * log.c
+ * -----
+ * Implement libhal logging API on Alpha.
+ *
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define HAL_OK CMSIS_HAL_OK
+#include "stm-uart.h"
+#undef HAL_OK
+
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#include "hal_internal.h"
+#undef HAL_OK
+
+static hal_log_level_t current_log_level;
+
+void hal_log_set_level(const hal_log_level_t level)
+{
+ current_log_level = level;
+}
+
+void hal_log(const hal_log_level_t level, const char *format, ...)
+{
+ if (level < current_log_level)
+ return;
+
+ char buffer[2048];
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ uart_send_string(buffer);
+ uart_send_string("\r\n");
+}
diff --git a/projects/bootloader/startup_stm32f429xx.S b/projects/bootloader/startup_stm32f429xx.S
new file mode 100644
index 0000000..fc8bf34
--- /dev/null
+++ b/projects/bootloader/startup_stm32f429xx.S
@@ -0,0 +1,564 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32f429xx.s
+ * @author MCD Application Team
+ * @version V2.4.1
+ * @date 09-October-2015
+ * @brief STM32F429xx Devices vector table for GCC based toolchains.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M4 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of STMicroelectronics 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.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m4
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
+
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr sp, =_estack /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2], #4
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+ /* Check if we've just rebooted in order to jump to the firmware. */
+ bl check_early_dfu_jump
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+ bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ * @param None
+ * @retval None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M3. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+*******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+
+ /* External Interrupts */
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_IRQHandler /* PVD through EXTI Line detection */
+ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
+ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_IRQHandler /* EXTI Line0 */
+ .word EXTI1_IRQHandler /* EXTI Line1 */
+ .word EXTI2_IRQHandler /* EXTI Line2 */
+ .word EXTI3_IRQHandler /* EXTI Line3 */
+ .word EXTI4_IRQHandler /* EXTI Line4 */
+ .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
+ .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
+ .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
+ .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
+ .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
+ .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
+ .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
+ .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
+ .word CAN1_TX_IRQHandler /* CAN1 TX */
+ .word CAN1_RX0_IRQHandler /* CAN1 RX0 */
+ .word CAN1_RX1_IRQHandler /* CAN1 RX1 */
+ .word CAN1_SCE_IRQHandler /* CAN1 SCE */
+ .word EXTI9_5_IRQHandler /* External Line[9:5]s */
+ .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
+ .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
+ .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM4_IRQHandler /* TIM4 */
+ .word I2C1_EV_IRQHandler /* I2C1 Event */
+ .word I2C1_ER_IRQHandler /* I2C1 Error */
+ .word I2C2_EV_IRQHandler /* I2C2 Event */
+ .word I2C2_ER_IRQHandler /* I2C2 Error */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_IRQHandler /* USART3 */
+ .word EXTI15_10_IRQHandler /* External Line[15:10]s */
+ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
+ .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
+ .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
+ .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
+ .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
+ .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
+ .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
+ .word FMC_IRQHandler /* FMC */
+ .word SDIO_IRQHandler /* SDIO */
+ .word TIM5_IRQHandler /* TIM5 */
+ .word SPI3_IRQHandler /* SPI3 */
+ .word UART4_IRQHandler /* UART4 */
+ .word UART5_IRQHandler /* UART5 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
+ .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
+ .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
+ .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
+ .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
+ .word ETH_IRQHandler /* Ethernet */
+ .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
+ .word CAN2_TX_IRQHandler /* CAN2 TX */
+ .word CAN2_RX0_IRQHandler /* CAN2 RX0 */
+ .word CAN2_RX1_IRQHandler /* CAN2 RX1 */
+ .word CAN2_SCE_IRQHandler /* CAN2 SCE */
+ .word OTG_FS_IRQHandler /* USB OTG FS */
+ .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
+ .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
+ .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
+ .word USART6_IRQHandler /* USART6 */
+ .word I2C3_EV_IRQHandler /* I2C3 event */
+ .word I2C3_ER_IRQHandler /* I2C3 error */
+ .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
+ .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
+ .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
+ .word OTG_HS_IRQHandler /* USB OTG HS */
+ .word DCMI_IRQHandler /* DCMI */
+ .word 0 /* Reserved */
+ .word HASH_RNG_IRQHandler /* Hash and Rng */
+ .word FPU_IRQHandler /* FPU */
+ .word UART7_IRQHandler /* UART7 */
+ .word UART8_IRQHandler /* UART8 */
+ .word SPI4_IRQHandler /* SPI4 */
+ .word SPI5_IRQHandler /* SPI5 */
+ .word SPI6_IRQHandler /* SPI6 */
+ .word SAI1_IRQHandler /* SAI1 */
+ .word LTDC_IRQHandler /* LTDC_IRQHandler */
+ .word LTDC_ER_IRQHandler /* LTDC_ER_IRQHandler */
+ .word DMA2D_IRQHandler /* DMA2D */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_IRQHandler
+ .thumb_set PVD_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream0_IRQHandler
+ .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream1_IRQHandler
+ .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream2_IRQHandler
+ .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream3_IRQHandler
+ .thumb_set DMA1_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream4_IRQHandler
+ .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream5_IRQHandler
+ .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream6_IRQHandler
+ .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
+
+ .weak ADC_IRQHandler
+ .thumb_set ADC_IRQHandler,Default_Handler
+
+ .weak CAN1_TX_IRQHandler
+ .thumb_set CAN1_TX_IRQHandler,Default_Handler
+
+ .weak CAN1_RX0_IRQHandler
+ .thumb_set CAN1_RX0_IRQHandler,Default_Handler
+
+ .weak CAN1_RX1_IRQHandler
+ .thumb_set CAN1_RX1_IRQHandler,Default_Handler
+
+ .weak CAN1_SCE_IRQHandler
+ .thumb_set CAN1_SCE_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_TIM9_IRQHandler
+ .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_TIM10_IRQHandler
+ .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_TIM11_IRQHandler
+ .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak OTG_FS_WKUP_IRQHandler
+ .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_TIM12_IRQHandler
+ .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_TIM13_IRQHandler
+ .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_TIM14_IRQHandler
+ .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream7_IRQHandler
+ .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
+
+ .weak FMC_IRQHandler
+ .thumb_set FMC_IRQHandler,Default_Handler
+
+ .weak SDIO_IRQHandler
+ .thumb_set SDIO_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream0_IRQHandler
+ .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream1_IRQHandler
+ .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream2_IRQHandler
+ .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream3_IRQHandler
+ .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream4_IRQHandler
+ .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
+
+ .weak ETH_IRQHandler
+ .thumb_set ETH_IRQHandler,Default_Handler
+
+ .weak ETH_WKUP_IRQHandler
+ .thumb_set ETH_WKUP_IRQHandler,Default_Handler
+
+ .weak CAN2_TX_IRQHandler
+ .thumb_set CAN2_TX_IRQHandler,Default_Handler
+
+ .weak CAN2_RX0_IRQHandler
+ .thumb_set CAN2_RX0_IRQHandler,Default_Handler
+
+ .weak CAN2_RX1_IRQHandler
+ .thumb_set CAN2_RX1_IRQHandler,Default_Handler
+
+ .weak CAN2_SCE_IRQHandler
+ .thumb_set CAN2_SCE_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream5_IRQHandler
+ .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream6_IRQHandler
+ .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream7_IRQHandler
+ .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
+
+ .weak USART6_IRQHandler
+ .thumb_set USART6_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_OUT_IRQHandler
+ .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_IN_IRQHandler
+ .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_HS_WKUP_IRQHandler
+ .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_HS_IRQHandler
+ .thumb_set OTG_HS_IRQHandler,Default_Handler
+
+ .weak DCMI_IRQHandler
+ .thumb_set DCMI_IRQHandler,Default_Handler
+
+ .weak HASH_RNG_IRQHandler
+ .thumb_set HASH_RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+
+ .weak UART7_IRQHandler
+ .thumb_set UART7_IRQHandler,Default_Handler
+
+ .weak UART8_IRQHandler
+ .thumb_set UART8_IRQHandler,Default_Handler
+
+ .weak SPI4_IRQHandler
+ .thumb_set SPI4_IRQHandler,Default_Handler
+
+ .weak SPI5_IRQHandler
+ .thumb_set SPI5_IRQHandler,Default_Handler
+
+ .weak SPI6_IRQHandler
+ .thumb_set SPI6_IRQHandler,Default_Handler
+
+ .weak SAI1_IRQHandler
+ .thumb_set SAI1_IRQHandler,Default_Handler
+
+ .weak LTDC_IRQHandler
+ .thumb_set LTDC_IRQHandler,Default_Handler
+
+ .weak LTDC_ER_IRQHandler
+ .thumb_set LTDC_ER_IRQHandler,Default_Handler
+
+ .weak DMA2D_IRQHandler
+ .thumb_set DMA2D_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/projects/bootloader/stm-init.c b/projects/bootloader/stm-init.c
new file mode 100644
index 0000000..b331b8a
--- /dev/null
+++ b/projects/bootloader/stm-init.c
@@ -0,0 +1,7 @@
+/* Disable modules that the bootloader doesn't need. */
+
+#include "stm32f4xx_hal.h"
+
+#undef HAL_I2C_MODULE_ENABLED
+
+#include "../../stm-init.c"
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"
diff --git a/projects/hsm/Makefile b/projects/hsm/Makefile
index f5546d8..7fd3ad6 100644
--- a/projects/hsm/Makefile
+++ b/projects/hsm/Makefile
@@ -1,19 +1,53 @@
PROJ = hsm
-SRCS = main.c
+# objs in addition to $(PROJ).o
+OBJS = mgmt-cli.o \
+ mgmt-firmware.o \
+ mgmt-bootloader.o \
+ mgmt-fpga.o \
+ mgmt-keystore.o \
+ mgmt-masterkey.o \
+ mgmt-misc.o \
+ mgmt-task.o \
+ log.o \
+ $(TOPLEVEL)/task.o
-OBJS = $(SRCS:.c=.o)
+CFLAGS += -DNUM_RPC_TASK=8
-CFLAGS += -I $(LIBHAL_DIR)
+CFLAGS += -I$(LIBHAL_SRC)
+CFLAGS += -I$(LIBCLI_SRC)
+CFLAGS += -I$(LIBTFM_BLD)
+CFLAGS += -Wno-missing-field-initializers
-LIBS += $(LIBHAL_DIR)/libhal.a $(LIBTFM_DIR)/libtfm.a
+LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a
+LIBS += $(LIBCLI_BLD)/libcli.a
+
+LDFLAGS += -mcpu=cortex-m4 -mthumb -mlittle-endian -mthumb-interwork
+LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+LDFLAGS += -Wl,--gc-sections
+
+ifdef DO_PROFILING
+LDFLAGS += --specs=rdimon.specs -lc -lrdimon
+endif
+
+ifdef DO_TASK_METRICS
+CFLAGS += -DDO_TASK_METRICS
+endif
+
+ifdef DO_TIMING
+CFLAGS += -DDO_TIMING
+CFLAGS += -I../cli-test
+CFLAGS += -DCLI_STACK_SIZE=65536
+OBJS += ../cli-test/mgmt-timing.o $(TOPLEVEL)/stm-dwt.o
+LDFLAGS += -lm
+endif
all: $(PROJ:=.elf)
-$(PROJ).elf: $(OBJS) $(BOARD_OBJS) $(LIBS)
- $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$(PROJ).map
- $(OBJCOPY) -O binary $(PROJ).elf $(PROJ).bin
- $(SIZE) $(PROJ).elf
+%.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS)
+ $(CC) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map $(LDFLAGS)
+ $(OBJCOPY) -O binary $*.elf $*.bin
+ $(SIZE) $*.elf
clean:
rm -f *.o
diff --git a/projects/hsm/cryptech_miniterm b/projects/hsm/cryptech_miniterm
new file mode 100755
index 0000000..b646811
--- /dev/null
+++ b/projects/hsm/cryptech_miniterm
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+"""
+Utility to run PySerial's "miniterm" with default settings suitable
+for talking to the Cryptech Alpha's console port.
+"""
+
+import serial.tools.miniterm
+import sys
+import os
+
+default_port = os.getenv("CRYPTECH_CTY_CLIENT_SERIAL_DEVICE")
+default_baud = os.getenv("CRYPTECH_CTY_CLIENT_SERIAL_SPEED", 921600)
+
+sys.exit(serial.tools.miniterm.main(default_port = default_port,
+ default_baudrate = int(default_baud)))
+
diff --git a/projects/hsm/cryptech_probe b/projects/hsm/cryptech_probe
new file mode 100755
index 0000000..356931a
--- /dev/null
+++ b/projects/hsm/cryptech_probe
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+"""
+Utility to probe USB serial port(s) trying to figure out which one(s)
+we have plugged in today. stdout is environment variable settings,
+suitable for use in bash with "eval `cryptech_probe`"; all other output
+goes to stderr.
+"""
+
+import sys
+import time
+import argparse
+import serial.tools.list_ports_posix
+
+if sys.version_info.major == 2:
+ def colon_hex(raw):
+ return ":".join("{:02x}".format(ord(b)) for b in raw)
+else:
+ def colon_hex(raw):
+ return ":".join("{:02x}".format(b) for b in raw)
+
+class positive_integer(int):
+ def __init__(self, value):
+ if self <= 0:
+ raise ValueError
+
+parser = argparse.ArgumentParser(formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument("-v", "--verbose", action = "store_true", help = "produce human-readable output")
+parser.add_argument("-d", "--debug", action = "store_true", help = "blather about what we're doing")
+parser.add_argument("--no-cleanup", action = "store_true", help = "don't send cleanup sequences after probing")
+parser.add_argument("--read-buffer-size", type = positive_integer, help = "size of read buffer", default = 1024)
+args = parser.parse_args()
+
+SLIP_END = b"\300" # Indicates end of SLIP packet
+SLIP_ESC = b"\333" # Indicates byte stuffing
+SLIP_ESC_END = b"\334" # ESC ESC_END means END data byte
+SLIP_ESC_ESC = b"\335" # ESC ESC_ESC means ESC data byte
+
+Control_U = b"\025" # Console: clear line
+Control_M = b"\015" # Console: end of line
+
+RPC_query = b"\0" * 8 # client_handle = 0, function code = RPC_FUNC_GET_VERSION
+RPC_reply = b"\0" * 12 # opcode = RPC_FUNC_GET_VERSION, client_handle = 0, valret = HAL_OK
+
+# This is the query string we send to each USB port we find. It's
+# intended to be relatively harmless, at least for either of the HSM
+# ports: the final Control-U should prevent the console from trying to
+# interpret the RPC command, and the SLIP_END markers should cause
+# the RPC server to treat the ASCII control characters as noise.
+#
+# Yes, this is a total kludge. Useful identifiers for the USB ports
+# are are on the wish list for a future revision of the hardware, but
+# for the moment, we do what we can with what we have.
+
+probe_string = SLIP_END + Control_U + SLIP_END + RPC_query + SLIP_END + Control_U + Control_M
+
+ports = [port for port, desc, hwid in serial.tools.list_ports_posix.comports()
+ if "VID:PID=0403:6014" in hwid]
+
+if not ports:
+ sys.exit("Couldn't find any likely USB ports")
+
+if args.debug:
+ sys.stderr.write("Candidate USB ports: {}\n".format(", ".join(ports)))
+
+env = {}
+
+for port in ports:
+
+ while True:
+ try:
+ tty = serial.Serial(port, 921600, timeout=0.1)
+ break
+ except serial.SerialException:
+ time.sleep(0.2)
+
+ # Not sure we really need to dribble the probe string out this slowly anymore,
+ # but once upon a time we did this for a reason and it's not like this program
+ # is a performance bottleneck, so stick with the safe version.
+
+ for i in range(len(probe_string)):
+ tty.write(probe_string[i:i+1])
+ time.sleep(0.1)
+
+ response = tty.read(args.read_buffer_size)
+ if args.debug:
+ sys.stderr.write("Received from {}: {!r} ({})\n".format(port, response, colon_hex(response)))
+
+ # Check whether we got a known console prompt.
+
+ is_cty = any(prompt in response for prompt in (b"Username:", b"Password:", b"cryptech>"))
+
+ # Check whether we got something that looks like the response to an RPC version query.
+ # We skip over the version value itself, as it might change, but we check that it's
+ # terminated properly. This is fragile, and will need to handle SLIP decoding if
+ # we ever bump one of the version fields up into the range where the SLIP control
+ # characters live, but it will do for the moment.
+
+ try:
+ is_hsm = response[response.index(SLIP_END + RPC_reply) + len(SLIP_END + RPC_reply) + 4] == SLIP_END[0]
+ except ValueError:
+ is_hsm = False
+ except IndexError:
+ is_hsm = False
+
+ if is_cty and args.verbose:
+ sys.stderr.write("{} looks like the Cryptech HSM console port\n".format(port))
+
+ if is_hsm and args.verbose:
+ sys.stderr.write("{} looks like the Cryptech HSM RPC port\n".format(port))
+
+ if is_cty:
+ env.update(CRYPTECH_CTY_CLIENT_SERIAL_DEVICE = port)
+
+ if is_hsm:
+ env.update(CRYPTECH_RPC_CLIENT_SERIAL_DEVICE = port)
+
+ if (is_cty or is_hsm) and not args.no_cleanup:
+ if is_cty:
+ tty.write(Control_U)
+ if is_hsm:
+ tty.write(SLIP_END)
+ while tty.read(args.read_buffer_size):
+ pass
+
+ tty.close()
+
+if env:
+ sys.stdout.write("export {}\n".format(
+ " ".join("{}='{}'".format(var, env[var]) for var in sorted(env))))
diff --git a/projects/hsm/cryptech_upload b/projects/hsm/cryptech_upload
new file mode 100755
index 0000000..b40427d
--- /dev/null
+++ b/projects/hsm/cryptech_upload
@@ -0,0 +1,385 @@
+#!/usr/bin/env python3
+#
+# 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
+# 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.
+
+"""
+Utility to upload a new firmware image or FPGA bitstream.
+"""
+
+import os
+import sys
+import time
+import struct
+import serial
+import socket
+import getpass
+import os.path
+import tarfile
+import argparse
+import platform
+
+from binascii import crc32, hexlify
+
+FIRMWARE_CHUNK_SIZE = 4096
+FPGA_CHUNK_SIZE = 4096
+
+
+def parse_args():
+ """
+ Parse the command line arguments
+ """
+
+ share_directory = "/usr/share" if platform.system() == "Linux" else "/usr/local/share"
+
+ default_tarball = os.path.join(share_directory, "cryptech-alpha-firmware.tar.gz")
+
+ if not os.path.exists(default_tarball):
+ default_tarball = None
+
+ parser = argparse.ArgumentParser(description = __doc__,
+ formatter_class = argparse.ArgumentDefaultsHelpFormatter,
+ )
+
+ parser.add_argument("-d", "--device",
+ default = os.getenv("CRYPTECH_CTY_CLIENT_SERIAL_DEVICE", "/dev/ttyUSB0"),
+ help = "Name of management port USB serial device",
+ )
+
+ parser.add_argument("--socket",
+ default = os.getenv("CRYPTECH_CTY_CLIENT_SOCKET_NAME",
+ "/tmp/.cryptech_muxd.cty"),
+ help = "Name of cryptech_muxd management port socket",
+ )
+
+ parser.add_argument("--firmware-tarball",
+ type = argparse.FileType("rb"),
+ default = default_tarball,
+ help = "Location of firmware tarball",
+ )
+
+ parser.add_argument("--username",
+ choices = ("so", "wheel"),
+ default = "so",
+ help = "Username to use when logging into the HSM",
+ )
+
+ parser.add_argument("--pin",
+ help = "PIN to use when logging into the HSM",
+ )
+
+ parser.add_argument("--separate-pins",
+ action = "store_true",
+ help = "Prompt separately for each PIN required during firmware upload")
+
+ actions = parser.add_mutually_exclusive_group(required = True)
+ actions.add_argument("--fpga",
+ action = "store_true",
+ help = "Upload FPGA bitstream",
+ )
+ actions.add_argument("--firmware", "--hsm",
+ action = "store_true",
+ help = "Upload HSM firmware image",
+ )
+ actions.add_argument("--bootloader",
+ action = "store_true",
+ help = "Upload bootloader image (dangerous!)",
+ )
+
+ parser.add_argument("--simon-says-whack-my-bootloader",
+ action = "store_true",
+ help = "Confirm that you really want to risk bricking the HSM",
+ )
+
+ parser.add_argument("-i", "--explicit-image",
+ type = argparse.FileType("rb"),
+ help = "Explicit source image file for upload, overrides firmware tarball")
+
+ parser.add_argument("--debug",
+ action = "store_true",
+ help = "Enable debugging of upload protocol",
+ )
+
+ parser.add_argument("-q", "--quiet",
+ action = "store_true",
+ help = "Only report errors",
+ )
+
+ return parser.parse_args()
+
+
+class ManagementPortAbstract(object):
+ """
+ Abstract class encapsulating actions on the HSM management port.
+ """
+
+ def __init__(self, args):
+ self.args = args
+
+ def write(self, data):
+ numeric = isinstance(data, int)
+ if numeric:
+ data = struct.pack("<I", data)
+ self.send(data)
+ if self.args.debug:
+ if numeric:
+ print("Wrote 0x{}".format(hexlify(data).decode("ascii")))
+ else:
+ print("Wrote {!r}".format(data))
+
+ def read(self):
+ res = b""
+ x = self.recv()
+ while not x:
+ x = self.recv()
+ while x:
+ res += x
+ x = self.recv()
+ if self.args.debug:
+ print("Read {!r}".format(res))
+ return res
+
+ def execute(self, cmd):
+ self.write(b"\r")
+ prompt = self.read()
+ #if prompt.endswith("This is the bootloader speaking..."):
+ # prompt = self.read()
+ if prompt.endswith(b"Username: "):
+ self.write(self.args.username.encode("ascii") + b"\r")
+ prompt = self.read()
+ if prompt.endswith(b"Password: "):
+ if not self.args.pin or self.args.separate_pins:
+ self.args.pin = getpass.getpass("{} PIN: ".format(self.args.username))
+ self.write(self.args.pin.encode("ascii") + b"\r")
+ prompt = self.read()
+ if not prompt.endswith((b"> ", b"# ")):
+ print("Device does not seem to be ready for a file transfer (got {!r})".format(prompt))
+ return prompt
+ self.write(cmd + b"\r")
+ response = self.read()
+ return response
+
+
+class ManagementPortSerial(ManagementPortAbstract):
+ """
+ Implmentation of HSM management port abstraction over a direct
+ serial connection.
+ """
+
+ def __init__(self, args, timeout = 1):
+ super(ManagementPortSerial, self).__init__(args)
+ self.serial = serial.Serial(args.device, 921600, timeout = timeout)
+
+ def send(self, data):
+ self.serial.write(data)
+ self.serial.flush()
+
+ def recv(self):
+ return self.serial.read(1)
+
+ def set_timeout(self, timeout):
+ self.serial.timeout = timeout
+
+ def close(self):
+ self.serial.close()
+
+class ManagementPortSocket(ManagementPortAbstract):
+ """
+ Implmentation of HSM management port abstraction over a PF_UNIX
+ socket connection to the cryptech_muxd management socket.
+ """
+
+ def __init__(self, args, timeout = 1):
+ super(ManagementPortSocket, self).__init__(args)
+ self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.socket.connect(args.socket)
+ self.socket.settimeout(timeout)
+
+ def send(self, data):
+ self.socket.sendall(data)
+
+ def recv(self):
+ try:
+ return self.socket.recv(1)
+ except socket.timeout:
+ return b""
+
+ def set_timeout(self, timeout):
+ self.socket.settimeout(timeout)
+
+ def close(self):
+ self.socket.close()
+
+
+def send_file(src, size, args, dst):
+ """
+ Upload an image from some file-like source to the management port.
+ Details depend on what kind of image it is.
+ """
+
+ if args.fpga:
+ chunk_size = FPGA_CHUNK_SIZE
+ response = dst.execute(b"fpga bitstream upload")
+ elif args.firmware:
+ chunk_size = FIRMWARE_CHUNK_SIZE
+ response = dst.execute(b"firmware upload")
+ if b"Rebooting" in response:
+ response = dst.execute(b"firmware upload")
+ elif args.bootloader:
+ chunk_size = FIRMWARE_CHUNK_SIZE
+ response = dst.execute(b"bootloader upload")
+ if b"Access denied" in response:
+ print("Access denied")
+ return False
+ if not b"OK" in response:
+ print("Device did not accept the upload command (got {!r})".format(response))
+ return False
+
+ dst.set_timeout(0.001)
+ crc = 0
+ counter = 0
+ # 1. Write size of file (4 bytes)
+ dst.write(struct.pack("<I", size))
+ response = dst.read()
+ if not response.startswith(b"Send "):
+ print(response)
+ return False
+
+ # 2. Write file contents while calculating CRC-32
+ chunks = int((size + chunk_size - 1) / chunk_size)
+ for counter in range(chunks):
+ data = src.read(chunk_size)
+ dst.write(data)
+ if not args.quiet:
+ print("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter + 1, chunks))
+ # read ACK (a counter of number of 4k chunks received)
+ ack_bytes = b""
+ while len(ack_bytes) < 4:
+ ack_bytes += dst.read()
+ ack = struct.unpack("<I", ack_bytes[:4])[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))
+ return False
+ counter += 1
+
+ crc = crc32(data, crc) & 0xffffffff
+
+ # 3. Write CRC-32 (4 bytes)
+ dst.write(struct.pack("<I", crc))
+ response = dst.read()
+ if not args.quiet:
+ print(response)
+
+ src.close()
+
+ if args.fpga:
+ # tell the fpga to read its new configuration
+ dst.execute(b"fpga reset")
+ # log out of the CLI
+ # (firmware/bootloader upgrades reboot, don't need an exit)
+ dst.execute(b"exit")
+
+ return True
+
+
+dire_bootloader_warning = '''
+ WARNING
+
+Updating the bootloader risks bricking your HSM! If something goes
+badly wrong here, or you upload a bad bootloader image, you will not
+be able to recover without an ST-LINK programmer.
+
+In most cases a normal "--firmware" upgrade should be all that is
+necessary to bring your HSM up to date, there is seldom any real need
+to update the bootloader.
+
+Do not proceed with this unless you REALLY know what you are doing.
+
+If you got here by accident, ^C now, without answering the PIN prompt.
+'''
+
+
+def main():
+ global args
+ args = parse_args()
+
+
+ if args.bootloader:
+ if not args.simon_says_whack_my_bootloader:
+ sys.exit("You didn't say \"Simon says\"")
+ print(dire_bootloader_warning)
+ args.pin = None
+
+ if args.explicit_image is None and args.firmware_tarball is None:
+ sys.exit("No source file specified for upload and firmware tarball not found")
+
+ if args.explicit_image:
+ src = args.explicit_image # file-like object, thanks to argparse
+ size = os.fstat(src.fileno()).st_size
+ if size == 0: # Flashing from stdin won't work, sorry
+ sys.exit("Can't flash from a pipe or zero-length file")
+ if not args.quiet:
+ print("Uploading from explicitly-specified file {}".format(args.explicit_image.name))
+
+ else:
+ tar = tarfile.open(fileobj = args.firmware_tarball)
+ if not args.quiet:
+ print("Firmware tarball {} content:".format(args.firmware_tarball.name))
+ tar.list(True)
+ if args.fpga:
+ name = "alpha_fmc.bit"
+ elif args.firmware:
+ name = "hsm.bin"
+ elif args.bootloader:
+ name = "bootloader.bin"
+ else:
+ # Somebody updated other part of this script without updating this part :(
+ sys.exit("Don't know which component to select from firmware tarball, sorry")
+ try:
+ size = tar.getmember(name).size
+ except KeyError:
+ sys.exit("Expected component {} missing from firmware tarball {}".format(name, args.firmware_tarball.name))
+ src = tar.extractfile(name)
+ if not args.quiet:
+ print("Uploading {} from {}".format(name, args.firmware_tarball.name))
+
+ if not args.quiet:
+ print("Initializing management port and synchronizing with HSM, this may take a few seconds")
+ try:
+ dst = ManagementPortSocket(args, timeout = 1)
+ except socket.error as e:
+ dst = ManagementPortSerial(args, timeout = 1)
+ send_file(src, size, args, dst)
+ dst.close()
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
diff --git a/projects/hsm/hsm.c b/projects/hsm/hsm.c
new file mode 100644
index 0000000..52157c9
--- /dev/null
+++ b/projects/hsm/hsm.c
@@ -0,0 +1,522 @@
+/*
+ * hsm.c
+ * ----------------
+ * Main module for the HSM project.
+ *
+ * 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
+ * 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 is the main RPC server module. At the moment, it has a single
+ * worker thread to handle RPC requests, while the main thread handles CLI
+ * activity. The design allows for multiple worker threads to handle
+ * concurrent RPC requests from multiple clients (muxed through a daemon
+ * on the host).
+ */
+
+#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-led.h"
+#include "stm-fmc.h"
+#include "stm-uart.h"
+#include "stm-sdram.h"
+#include "task.h"
+
+#include "mgmt-cli.h"
+
+#undef HAL_OK
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#include "hal_internal.h"
+#include "slip_internal.h"
+#include "xdr_internal.h"
+#undef HAL_OK
+
+#ifndef NUM_RPC_TASK
+#define NUM_RPC_TASK 1
+#elif NUM_RPC_TASK < 1 || NUM_RPC_TASK > 10
+#error invalid NUM_RPC_TASK
+#endif
+
+#ifndef TASK_STACK_SIZE
+/* Define an absurdly large task stack, because some pkey operation use a
+ * lot of stack variables. This has to go in SDRAM, because it exceeds the
+ * total RAM on the ARM.
+ */
+#define TASK_STACK_SIZE 200*1024
+#endif
+
+/* Stack for the busy task. This doesn't need to be very big.
+ */
+#ifndef BUSY_STACK_SIZE
+#define BUSY_STACK_SIZE 1*1024
+#endif
+static uint8_t busy_stack[BUSY_STACK_SIZE];
+
+/* Stack for the CLI task. This needs to be big enough to accept a
+ * 4096-byte block of an FPGA or bootloader image upload.
+ */
+#ifndef CLI_STACK_SIZE
+#define CLI_STACK_SIZE 16*1024
+#endif
+
+/* RPC buffers. For each active request, there will be two - input and output.
+ */
+typedef struct rpc_buffer_s {
+ size_t len;
+ uint8_t buf[HAL_RPC_MAX_PKT_SIZE];
+ struct rpc_buffer_s *next; /* for ibuf queue linking */
+} rpc_buffer_t;
+
+/* RPC input (requst) buffers */
+static rpc_buffer_t *ibufs;
+
+/* ibuf queue structure */
+typedef struct {
+ rpc_buffer_t *head, *tail;
+ size_t len, max; /* for reporting */
+} ibufq_t;
+
+/* ibuf queues. These correspond roughly to task states - 'waiting' is for
+ * unallocated ibufs, while 'ready' is for requests that are ready to be
+ * processed.
+ */
+static ibufq_t ibuf_waiting, ibuf_ready;
+
+/* Get an ibuf from a queue. */
+static rpc_buffer_t *ibuf_get(ibufq_t *q)
+{
+ hal_critical_section_start();
+ rpc_buffer_t *ibuf = q->head;
+ if (ibuf) {
+ q->head = ibuf->next;
+ if (q->head == NULL)
+ q->tail = NULL;
+ ibuf->next = NULL;
+ --q->len;
+ }
+ hal_critical_section_end();
+ return ibuf;
+}
+
+/* Put an ibuf on a queue. */
+static void ibuf_put(ibufq_t *q, rpc_buffer_t *ibuf)
+{
+ hal_critical_section_start();
+ if (q->tail)
+ q->tail->next = ibuf;
+ else
+ q->head = ibuf;
+ q->tail = ibuf;
+ ibuf->next = NULL;
+ if (++q->len > q->max)
+ q->max = q->len;
+ hal_critical_section_end();
+}
+
+/* Get the current length of the 'ready' queue, for reporting in the CLI. */
+size_t request_queue_len(void)
+{
+ size_t n;
+
+ hal_critical_section_start();
+ n = ibuf_ready.len;
+ hal_critical_section_end();
+
+ return n;
+}
+
+/* Get the maximum length of the 'ready' queue, for reporting in the CLI. */
+size_t request_queue_max(void)
+{
+ size_t n;
+
+ hal_critical_section_start();
+ n = ibuf_ready.max;
+ hal_critical_section_end();
+
+ return n;
+}
+
+static void dispatch_task(void);
+static void busy_task(void);
+static tcb_t *busy_tcb;
+
+/* Select an available dispatch task. For simplicity, this doesn't try to
+ * allocate tasks in a round-robin fashion, so the lowest-numbered task
+ * will see the most action. OTOH, this lets us gauge the level of system
+ * activity in the CLI's 'task show' command.
+ */
+static tcb_t *task_next_waiting(void)
+{
+ for (tcb_t *t = task_iterate(NULL); t; t = task_iterate(t)) {
+ if (task_get_func(t) == dispatch_task &&
+ task_get_state(t) == TASK_WAITING)
+ return t;
+ }
+ return NULL;
+}
+
+static uint8_t *sdram_malloc(size_t size);
+
+/* Callback for HAL_UART_Receive_DMA().
+ */
+static void RxCallback(uint8_t c)
+{
+ int complete;
+ static rpc_buffer_t *ibuf = NULL;
+
+ /* If we couldn't previously get an ibuf, a task may have freed one up
+ * in the meantime. Otherwise, allocate one from SDRAM. In normal
+ * operation, the number of ibufs will expand to the number of remote
+ * clients (which we don't know and can't predict). It would take an
+ * active attempt to DOS the system to exhaust SDRAM, and there are
+ * easier ways to attack the device (don't release hash or pkey handles).
+ */
+ if (ibuf == NULL) {
+ ibuf = ibuf_get(&ibuf_waiting);
+ if (ibuf == NULL) {
+ ibuf = (rpc_buffer_t *)sdram_malloc(sizeof(rpc_buffer_t));
+ if (ibuf == NULL)
+ Error_Handler();
+ }
+ ibuf->len = 0;
+ }
+
+ /* Process this character into the ibuf. */
+ if (hal_slip_process_char(c, ibuf->buf, &ibuf->len, sizeof(ibuf->buf), &complete) != LIBHAL_OK)
+ Error_Handler();
+
+ if (complete) {
+ /* Add the ibuf to the request queue, and try to get another ibuf.
+ */
+ ibuf_put(&ibuf_ready, ibuf);
+ ibuf = ibuf_get(&ibuf_waiting);
+ if (ibuf != NULL)
+ ibuf->len = 0;
+ /* else all ibufs are busy, try again next time */
+
+ /* Wake a dispatch task to deal with this request, or wake the
+ * busy task to re-try scheduling a dispatch task.
+ */
+ tcb_t *t = task_next_waiting();
+ if (t)
+ task_wake(t);
+ else
+ task_wake(busy_tcb);
+ }
+}
+
+/* A ring buffer for the UART DMA receiver. In theory, it should get at most
+ * 92 characters per 1ms tick, but we're going to up-size it for safety.
+ */
+#ifndef RPC_UART_RECVBUF_SIZE
+#define RPC_UART_RECVBUF_SIZE 1024 /* must be a power of 2 */
+#endif
+#define RPC_UART_RECVBUF_MASK (RPC_UART_RECVBUF_SIZE - 1)
+
+typedef struct {
+ uint32_t ridx;
+ uint8_t buf[RPC_UART_RECVBUF_SIZE];
+} uart_ringbuf_t;
+
+volatile uart_ringbuf_t uart_ringbuf = {0, {0}};
+
+#define RINGBUF_RIDX(rb) (rb.ridx & RPC_UART_RECVBUF_MASK)
+#define RINGBUF_WIDX(rb) (sizeof(rb.buf) - __HAL_DMA_GET_COUNTER(huart_user.hdmarx))
+#define RINGBUF_COUNT(rb) ((RINGBUF_WIDX(rb) - RINGBUF_RIDX(rb)) & RPC_UART_RECVBUF_MASK)
+#define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.ridx++;}
+
+size_t uart_rx_max = 0;
+
+void HAL_SYSTICK_Callback(void)
+{
+#ifdef DO_PROFILING
+ extern void profil_callback(void);
+ profil_callback();
+#endif
+
+ size_t count = RINGBUF_COUNT(uart_ringbuf);
+ if (uart_rx_max < count) uart_rx_max = count;
+
+ while (RINGBUF_COUNT(uart_ringbuf)) {
+ uint8_t c;
+ RINGBUF_READ(uart_ringbuf, c);
+ RxCallback(c);
+ }
+}
+
+/* Send one character over the UART. This is called from
+ * hal_slip_send_char().
+ */
+hal_error_t hal_serial_send_char(uint8_t c)
+{
+ return (uart_send_char2(STM_UART_USER, c) == 0) ? LIBHAL_OK : HAL_ERROR_RPC_TRANSPORT;
+}
+
+/* Task entry point for the RPC request handler.
+ */
+static void dispatch_task(void)
+{
+ rpc_buffer_t obuf_s, *obuf = &obuf_s;
+
+ while (1) {
+ /* Wait for a complete RPC request */
+ task_sleep();
+
+ rpc_buffer_t *ibuf = ibuf_get(&ibuf_ready);
+ if (ibuf == NULL)
+ /* probably an error, but go back to sleep */
+ continue;
+
+ memset(obuf, 0, sizeof(*obuf));
+ obuf->len = sizeof(obuf->buf);
+
+ /* Process the request */
+ hal_error_t ret = hal_rpc_server_dispatch(ibuf->buf, ibuf->len, obuf->buf, &obuf->len);
+ ibuf_put(&ibuf_waiting, ibuf);
+ if (ret == LIBHAL_OK) {
+ /* Send the response */
+ if (hal_rpc_sendto(obuf->buf, obuf->len, NULL) != LIBHAL_OK)
+ Error_Handler();
+ }
+ /* Else hal_rpc_server_dispatch failed with an XDR error, which
+ * probably means the request packet was garbage. In any case, we
+ * have nothing to transmit.
+ */
+ }
+}
+
+/* Task entry point for the task-rescheduling task.
+ */
+static void busy_task(void)
+{
+ while (1) {
+ /* Wake as many tasks as we have requests.
+ */
+ size_t n;
+ for (n = request_queue_len(); n > 0; --n) {
+ tcb_t *t;
+ if ((t = task_next_waiting()) != NULL)
+ task_wake(t);
+ else
+ break;
+ }
+ if (n == 0)
+ /* flushed the queue, our work here is done */
+ task_sleep();
+ else
+ /* more work to do, try again after some tasks have run */
+ task_yield();
+ }
+}
+
+#include "stm-fpgacfg.h"
+
+static void hashsig_restart_task(void)
+{
+ /* wait for the fpga to configure itself on cold-boot */
+ while (fpgacfg_check_done() != CMSIS_HAL_OK)
+ task_yield();
+
+ /* reinitialize the hashsig key structures after a device restart */
+ hal_hashsig_ks_init();
+
+ /* done, convert this task to an RPC handler */
+ task_mod((char *)task_get_cookie(NULL), dispatch_task, NULL);
+}
+
+/* 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;
+
+/* Allocate memory from SDRAM1. */
+static uint8_t *sdram_malloc(size_t size)
+{
+ uint8_t *p = sdram_heap;
+
+#define pad(n) (((n) + 3) & ~3)
+ size = pad(size);
+
+ if (p + size + sizeof(uint32_t) > &__end_sdram1)
+ return NULL;
+
+ *(uint32_t *)p = (uint32_t)size;
+ p += sizeof(uint32_t);
+
+ sdram_heap += size + sizeof(uint32_t);
+ return p;
+}
+
+/* A very limited form of free(), which only frees memory if it's at the
+ * top of the heap.
+ */
+static hal_error_t sdram_free(uint8_t *ptr)
+{
+ uint8_t *p = ptr - sizeof(uint32_t);
+ uint32_t size = *(uint32_t *)p;
+ if (ptr + size == sdram_heap) {
+ sdram_heap = p;
+ return LIBHAL_OK;
+ }
+ else
+ return HAL_ERROR_FORBIDDEN;
+}
+
+hal_error_t sdram_stats(size_t *used, size_t *available)
+{
+ if (used == NULL || available == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *used = sdram_heap - &_esdram1;
+ *available = &__end_sdram1 - sdram_heap;
+
+ return LIBHAL_OK;
+}
+
+/* Implement static memory allocation for libhal over sdram_malloc().
+ */
+void *hal_allocate_static_memory(const size_t size)
+{
+ return sdram_malloc(size);
+}
+
+hal_error_t hal_free_static_memory(const void * const ptr)
+{
+ return sdram_free((uint8_t *)ptr);
+}
+
+/* Critical section start/end - temporarily disable interrupts.
+ */
+void hal_critical_section_start(void)
+{
+ __disable_irq();
+}
+
+void hal_critical_section_end(void)
+{
+ __enable_irq();
+}
+
+/* A genericized public interface to task_yield(), for calling from
+ * libhal.
+ */
+void hal_task_yield(void)
+{
+ task_yield();
+}
+
+void hal_task_yield_maybe(void)
+{
+ task_yield_maybe();
+}
+
+/* A mutex to arbitrate concurrent access to the keystore.
+ */
+task_mutex_t ks_mutex = { 0 };
+void hal_ks_lock(void) { task_mutex_lock(&ks_mutex); }
+void hal_ks_unlock(void) { task_mutex_unlock(&ks_mutex); }
+
+/* A mutex to arbitrary concurrent access to the RSA blinding factors cache.
+ */
+task_mutex_t rsa_bf_mutex = { 0 };
+void hal_rsa_bf_lock(void) { task_mutex_lock(&rsa_bf_mutex); }
+void hal_rsa_bf_unlock(void) { task_mutex_unlock(&rsa_bf_mutex); }
+
+/* Sleep for specified number of seconds.
+ */
+void hal_sleep(const unsigned seconds) { task_delay(seconds * 1000); }
+
+/* The main task. This does all the setup, and the worker tasks handle
+ * the rest.
+ */
+int main(void)
+{
+ stm_init();
+ led_on(LED_GREEN);
+
+ if (hal_rpc_server_init() != LIBHAL_OK)
+ Error_Handler();
+
+ /* Initialize the ibuf queues. */
+ ibufs = (rpc_buffer_t *)sdram_malloc(NUM_RPC_TASK * sizeof(rpc_buffer_t));
+ if (ibufs == NULL)
+ Error_Handler();
+ memset(ibufs, 0, NUM_RPC_TASK * sizeof(rpc_buffer_t));
+ memset(&ibuf_waiting, 0, sizeof(ibuf_waiting));
+ memset(&ibuf_ready, 0, sizeof(ibuf_ready));
+ for (size_t i = 0; i < NUM_RPC_TASK; ++i)
+ ibuf_put(&ibuf_waiting, &ibufs[i]);
+
+ /* Create the rpc dispatch worker tasks. */
+ static char label[NUM_RPC_TASK][sizeof("dispatch0")];
+ for (int i = 0; i < NUM_RPC_TASK; ++i) {
+ sprintf(label[i], "dispatch%d", i);
+ void *stack = (void *)sdram_malloc(TASK_STACK_SIZE);
+ if (stack == NULL)
+ Error_Handler();
+ if (i == NUM_RPC_TASK - 1) {
+ if (task_add("hashsig_restart", hashsig_restart_task, label[i], stack, TASK_STACK_SIZE) == NULL)
+ Error_Handler();
+ }
+ else {
+ if (task_add(label[i], dispatch_task, NULL, stack, TASK_STACK_SIZE) == NULL)
+ Error_Handler();
+ }
+ }
+
+ /* Create the busy task. */
+ busy_tcb = task_add("busy", busy_task, NULL, busy_stack, sizeof(busy_stack));
+ if (busy_tcb == NULL)
+ Error_Handler();
+
+ /* Start the UART receiver. */
+ if (HAL_UART_Receive_DMA(&huart_user, (uint8_t *) uart_ringbuf.buf, sizeof(uart_ringbuf.buf)) != CMSIS_HAL_OK)
+ Error_Handler();
+
+ /* Launch other tasks (csprng warm-up task?)
+ * Wait for FPGA_DONE interrupt.
+ */
+
+ /* Create the CLI task. */
+ void *cli_stack = (void *)sdram_malloc(CLI_STACK_SIZE);
+ if (task_add("cli", (funcp_t)cli_main, NULL, cli_stack, CLI_STACK_SIZE) == NULL)
+ Error_Handler();
+
+ /* Start the tasker */
+ task_yield();
+
+ /*NOTREACHED*/
+ return 0;
+}
diff --git a/projects/hsm/log.c b/projects/hsm/log.c
new file mode 100644
index 0000000..fbc0e73
--- /dev/null
+++ b/projects/hsm/log.c
@@ -0,0 +1,68 @@
+/*
+ * log.c
+ * -----
+ * Implement libhal logging API on Alpha.
+ *
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define HAL_OK CMSIS_HAL_OK
+#include "stm-uart.h"
+#undef HAL_OK
+
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#include "hal_internal.h"
+#undef HAL_OK
+
+static hal_log_level_t current_log_level;
+
+void hal_log_set_level(const hal_log_level_t level)
+{
+ current_log_level = level;
+}
+
+void hal_log(const hal_log_level_t level, const char *format, ...)
+{
+ if (level < current_log_level)
+ return;
+
+ char buffer[2048];
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ uart_send_string(buffer);
+ uart_send_string("\r\n");
+}
diff --git a/projects/hsm/main.c b/projects/hsm/main.c
deleted file mode 100644
index 79c567b..0000000
--- a/projects/hsm/main.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * rpc_server.c
- * ------------
- * Remote procedure call server-side private API implementation.
- *
- * 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 is the main RPC server moddule. It creates a new thread to deal
- * with each request, to prevent a long-running request (e.g. RSA keygen)
- * from blocking independent requests from other clients. This has a
- * number of consequences. We can't do a blocking receive in the main
- * thread, because that prevents the dispatch thread from transmitting the
- * response (because they both want to lock the UART - see
- * stm32f4xx_hal_uart.c). So we have to do a non-blocking receive with a
- * callback routine. But we can't create a thread from the callback
- * routine, because it's in the context of an ISR, so we raise a semaphore
- * for the main thread to create the dispatch thread.
- */
-
-#include <string.h>
-
-#include "cmsis_os.h"
-
-#include "stm-init.h"
-#include "stm-led.h"
-#include "stm-fmc.h"
-#include "stm-uart.h"
-
-/* stm32f4xx_hal_def.h and hal.h both define HAL_OK as an enum value */
-#define HAL_OK HAL_OKAY
-
-#include "hal.h"
-#include "hal_internal.h"
-#include "slip_internal.h"
-#include "xdr_internal.h"
-
-/* RPC buffers. For each active RPC, there will be two - input and output.
- */
-
-#ifndef NUM_RPC_BUFFER
-/* An arbitrary number, but we don't expect to have more than 8 concurrent
- * RPC requests.
- */
-#define NUM_RPC_BUFFER 16
-#endif
-
-#ifndef MAX_PKT_SIZE
-/* Another arbitrary number, more or less driven by the 4096-bit RSA
- * keygen test.
- */
-#define MAX_PKT_SIZE 4096
-#endif
-
-/* The thread entry point takes a single void* argument, so we bundle the
- * packet buffer and length arguments together.
- */
-typedef struct {
- size_t len;
- uint8_t buf[MAX_PKT_SIZE];
-} rpc_buffer_t;
-
-osPoolDef(rpc_buffer_pool, NUM_RPC_BUFFER, rpc_buffer_t);
-osPoolId rpc_buffer_pool;
-
-static rpc_buffer_t *rpc_buffer_alloc(void)
-{
- return (rpc_buffer_t *)osPoolCAlloc(rpc_buffer_pool);
-}
-
-/* A mutex to arbitrate concurrent UART transmits, from RPC responses.
- */
-osMutexId uart_mutex;
-osMutexDef(uart_mutex);
-
-/* Thread entry point for the RPC request handler.
- */
-static void dispatch_thread(void const *args)
-{
- rpc_buffer_t *ibuf = (rpc_buffer_t *)args;
- rpc_buffer_t *obuf = rpc_buffer_alloc();
- if (obuf == NULL) {
- uint8_t buf[8];
- uint8_t * bufptr = &buf[4];
- const uint8_t * const limit = buf + sizeof(buf);
- memcpy(buf, ibuf->buf, 4);
- hal_xdr_encode_int(&bufptr, limit, HAL_ERROR_ALLOCATION_FAILURE);
- osMutexWait(uart_mutex, osWaitForever);
- hal_rpc_sendto(ibuf->buf, sizeof(buf), NULL);
- osMutexRelease(uart_mutex);
- osPoolFree(rpc_buffer_pool, ibuf);
- Error_Handler();
- }
- /* copy client ID from request to response */
- memcpy(obuf->buf, ibuf->buf, 4);
- obuf->len = sizeof(obuf->buf) - 4;
- hal_rpc_server_dispatch(ibuf->buf + 4, ibuf->len - 4, obuf->buf + 4, &obuf->len);
- osPoolFree(rpc_buffer_pool, ibuf);
- osMutexWait(uart_mutex, osWaitForever);
- hal_error_t ret = hal_rpc_sendto(obuf->buf, obuf->len + 4, NULL);
- osMutexRelease(uart_mutex);
- osPoolFree(rpc_buffer_pool, obuf);
- if (ret != HAL_OK)
- Error_Handler();
-}
-osThreadDef(dispatch_thread, osPriorityNormal, DEFAULT_STACK_SIZE);
-
-/* Semaphore to inform the main thread that there's a new RPC request.
- */
-osSemaphoreId rpc_sem;
-osSemaphoreDef(rpc_sem);
-
-static uint8_t c; /* current character received from UART */
-static rpc_buffer_t *ibuf; /* current RPC input buffer */
-
-/* Callback for HAL_UART_Receive_IT().
- */
-void HAL_UART2_RxCpltCallback(UART_HandleTypeDef *huart)
-{
- int complete;
- hal_slip_recv_char(ibuf->buf, &ibuf->len, sizeof(ibuf->buf), &complete);
- if (complete)
- osSemaphoreRelease(rpc_sem);
-
- HAL_UART_Receive_IT(huart, &c, 1);
-}
-
-hal_error_t hal_serial_send_char(uint8_t c)
-{
- return (uart_send_char(c) == 0) ? HAL_OK : HAL_ERROR_RPC_TRANSPORT;
-}
-
-hal_error_t hal_serial_recv_char(uint8_t *cp)
-{
- /* return the character from HAL_UART_Receive_IT */
- *cp = c;
- return HAL_OK;
-}
-
-/* The main thread. After the system setup, it waits for the RPC-request
- * semaphore from HAL_UART_RxCpltCallback, and spawns a dispatch thread.
- */
-int main()
-{
- stm_init();
-
-#ifdef TARGET_CRYPTECH_DEV_BRIDGE
- /* Wait six seconds to not upset the Novena at boot. */
- led_on(LED_BLUE);
- for (int i = 0; i < 12; i++) {
- osDelay(500);
- led_toggle(LED_BLUE);
- }
- led_off(LED_BLUE);
-#endif
- led_on(LED_GREEN);
- /* Prepare FMC interface. */
- fmc_init();
-
- /* Haaaack. probe_cores() calls malloc(), which works from the main
- * thread, but not from a spawned thread. It would be better to
- * rewrite it to use static memory, but for now, just force it to
- * probe early.
- */
- hal_core_iterate(NULL);
-
- rpc_buffer_pool = osPoolCreate(osPool(rpc_buffer_pool));
- uart_mutex = osMutexCreate(osMutex(uart_mutex));
- rpc_sem = osSemaphoreCreate(osSemaphore(rpc_sem), 0);
-
-#ifdef TARGET_CRYPTECH_ALPHA
- /* Launch other threads:
- * - admin thread on USART1
- * - csprng warm-up thread?
- */
-#endif
-
- if (hal_rpc_server_init() != HAL_OK)
- Error_Handler();
-
- ibuf = rpc_buffer_alloc();
- if (ibuf == NULL)
- /* Something is badly wrong. */
- Error_Handler();
-
- /* Start the non-blocking receive */
- HAL_UART_Receive_IT(&huart_user, &c, 1);
-
- while (1) {
- osSemaphoreWait(rpc_sem, osWaitForever);
- if (osThreadCreate(osThread(dispatch_thread), (void *)ibuf) == NULL)
- Error_Handler();
- while ((ibuf = rpc_buffer_alloc()) == NULL);
- /* XXX There's a potential race condition, where another request
- * could write into the old ibuf, or into the null pointer if
- * we're out of ibufs.
- */
- }
-}
diff --git a/projects/hsm/mgmt-bootloader.c b/projects/hsm/mgmt-bootloader.c
new file mode 100644
index 0000000..1d8b8ad
--- /dev/null
+++ b/projects/hsm/mgmt-bootloader.c
@@ -0,0 +1,89 @@
+/*
+ * mgmt-bootloader.c
+ * -----------------
+ * CLI code for updating the bootloader.
+ *
+ * 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 "stm-flash.h"
+#include "mgmt-cli.h"
+#include "mgmt-misc.h"
+#include "mgmt-bootloader.h"
+
+#undef HAL_OK
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#undef HAL_OK
+
+extern hal_user_t user;
+
+static uint32_t dfu_offset;
+
+static HAL_StatusTypeDef _flash_write_callback(uint8_t *buf, size_t len)
+{
+ HAL_StatusTypeDef status = stm_flash_write32(dfu_offset, (uint32_t *)buf, len/4);
+ dfu_offset += DFU_UPLOAD_CHUNK_SIZE;
+ return status;
+}
+
+static int cmd_bootloader_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ if (user < HAL_USER_SO) {
+ cli_print(cli, "Permission denied.");
+ return CLI_ERROR;
+ }
+
+ uint8_t buf[DFU_UPLOAD_CHUNK_SIZE];
+ dfu_offset = DFU_BOOTLOADER_ADDR;
+
+ int ret = cli_receive_data(cli, buf, sizeof(buf), _flash_write_callback);
+ if (ret == CLI_OK) {
+ cli_print(cli, "\nRebooting\n");
+ HAL_NVIC_SystemReset();
+ }
+ return ret;
+}
+
+void configure_cli_bootloader(struct cli_def *cli)
+{
+ struct cli_command *c;
+
+ c = cli_register_command(cli, NULL, "bootloader", NULL, 0, 0, NULL);
+
+ cli_register_command(cli, c, "upload", cmd_bootloader_upload, 0, 0, "Upload new bootloader image");
+}
diff --git a/projects/hsm/mgmt-bootloader.h b/projects/hsm/mgmt-bootloader.h
new file mode 100644
index 0000000..31dbefc
--- /dev/null
+++ b/projects/hsm/mgmt-bootloader.h
@@ -0,0 +1,51 @@
+/*
+ * mgmt-bootloader.h
+ * ---------------
+ * Management CLI bootloader upgrade code.
+ *
+ * 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_BOOTLOADER_H
+#define __STM32_CLI_MGMT_BOOTLOADER_H
+
+#include <libcli.h>
+
+/* symbols defined in the linker script (STM32F429BI_bootloader.ld) */
+extern uint32_t CRYPTECH_BOOTLOADER_START;
+extern uint32_t CRYPTECH_BOOTLOADER_END;
+extern uint32_t CRYPTECH_DFU_CONTROL;
+
+#define DFU_BOOTLOADER_ADDR ((uint32_t) &CRYPTECH_BOOTLOADER_START)
+#define DFU_BOOTLOADER_END_ADDR ((uint32_t) &CRYPTECH_BOOTLOADER_END)
+#define DFU_UPLOAD_CHUNK_SIZE 4096
+
+extern void configure_cli_bootloader(struct cli_def *cli);
+
+#endif /* __STM32_CLI_MGMT_BOOTLOADER_H */
diff --git a/projects/hsm/mgmt-cli.c b/projects/hsm/mgmt-cli.c
new file mode 100644
index 0000000..fd5c90a
--- /dev/null
+++ b/projects/hsm/mgmt-cli.c
@@ -0,0 +1,220 @@
+/*
+ * mgmt-cli.c
+ * ---------
+ * Management CLI code.
+ *
+ * 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
+ * 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 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
+ * 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.
+ */
+
+#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 "task.h"
+
+#include "mgmt-cli.h"
+#include "mgmt-firmware.h"
+#include "mgmt-bootloader.h"
+#include "mgmt-fpga.h"
+#include "mgmt-misc.h"
+#include "mgmt-keystore.h"
+#include "mgmt-masterkey.h"
+#include "mgmt-task.h"
+#ifdef DO_TIMING
+#include "mgmt-timing.h"
+#endif
+
+#undef HAL_OK
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#warning Refactor so we do not need to include hal_internal.h here
+#include "hal_internal.h"
+#undef HAL_OK
+
+static tcb_t *cli_task;
+
+#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;
+
+inline void ringbuf_init(ringbuf_t *rb)
+{
+ memset(rb, 0, sizeof(*rb));
+}
+
+/* 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;
+}
+
+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;
+
+/* current character received from UART */
+static uint8_t uart_rx;
+
+/* Callback for HAL_UART_Receive_DMA().
+ */
+void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+ huart = huart;
+
+ ringbuf_write_char(&uart_ringbuf, uart_rx);
+ task_wake(cli_task);
+}
+
+static void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf)
+{
+ char crlf[] = "\r\n";
+ uart_send_string(buf);
+ uart_send_string(crlf);
+}
+
+static ssize_t uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count)
+{
+ for (size_t i = 0; i < count; ++i) {
+ while (ringbuf_read_char(&uart_ringbuf, (uint8_t *)(buf + i)) == 0)
+ task_sleep();
+ }
+ return (ssize_t)count;
+}
+
+static ssize_t uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count)
+{
+ uart_send_bytes((uint8_t *) buf, count);
+ return (ssize_t)count;
+}
+
+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) {
+ 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) != CMSIS_HAL_OK) return 0;
+ uart_ringbuf.rx_state = DMA_RX_STOP;
+ return 1;
+ }
+ return 0;
+}
+
+hal_user_t user;
+
+static int check_auth(const char *username, const char *password)
+{
+ hal_client_handle_t client = { -1 };
+
+ /* PIN-based login */
+ if (strcmp(username, "wheel") == 0)
+ user = HAL_USER_WHEEL;
+ else if (strcmp(username, "so") == 0)
+ user = HAL_USER_SO;
+ else if (strcmp(username, "user") == 0)
+ user = HAL_USER_NORMAL;
+ else
+ user = HAL_USER_NONE;
+
+ if (hal_rpc_login(client, user, password, strlen(password)) == LIBHAL_OK)
+ return CLI_OK;
+
+ user = HAL_USER_NONE;
+ return CLI_ERROR;
+}
+
+int cli_main(void)
+{
+ cli_task = task_get_tcb();
+
+ struct cli_def *cli;
+ cli = cli_init();
+ if (cli == NULL)
+ Error_Handler();
+
+ 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_set_auth_callback(cli, check_auth);
+
+ /* we don't have any privileged commands at the moment */
+ cli_unregister_command(cli, "enable");
+
+ configure_cli_fpga(cli);
+ configure_cli_keystore(cli);
+ configure_cli_masterkey(cli);
+ configure_cli_firmware(cli);
+ configure_cli_bootloader(cli);
+ configure_cli_misc(cli);
+ configure_cli_task(cli);
+#ifdef DO_TIMING
+ configure_cli_timing(cli);
+#endif
+
+ while (1) {
+ control_mgmt_uart_dma_rx(DMA_RX_START);
+
+ cli_loop(cli, 0);
+ /* cli_loop returns when the user enters 'quit' or 'exit' */
+ cli_print(cli, "\nLogging out...\n");
+ user = HAL_USER_NONE;
+ }
+
+ /*NOTREACHED*/
+ return -1;
+}
diff --git a/projects/hsm/mgmt-cli.h b/projects/hsm/mgmt-cli.h
new file mode 100644
index 0000000..0b9c40c
--- /dev/null
+++ b/projects/hsm/mgmt-cli.h
@@ -0,0 +1,49 @@
+/*
+ * mgmt-cli.h
+ * ---------
+ * Management CLI code.
+ *
+ * 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_MGMT_CLI_H
+#define __STM32_MGMT_CLI_H
+
+#include <libcli.h>
+
+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 int cli_main(void);
+
+#endif /* __STM32_MGMT_CLI_H */
diff --git a/projects/hsm/mgmt-firmware.c b/projects/hsm/mgmt-firmware.c
new file mode 100644
index 0000000..b6b3321
--- /dev/null
+++ b/projects/hsm/mgmt-firmware.c
@@ -0,0 +1,75 @@
+/*
+ * mgmt-firmware.c
+ * ---------------
+ * CLI code for managing the loaded firmware.
+ *
+ * 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"
+
+#undef HAL_OK
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#undef HAL_OK
+
+extern hal_user_t user;
+
+static int cmd_firmware_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ if (user < HAL_USER_SO) {
+ cli_print(cli, "Permission denied.");
+ return CLI_ERROR;
+ }
+
+ /* reboot and let the bootloader handle the upload */
+ cli_print(cli, "\n\n\nRebooting\n\n\n");
+ HAL_NVIC_SystemReset();
+
+ /*NOTREACHED*/
+ return CLI_OK;
+}
+
+void configure_cli_firmware(struct cli_def *cli)
+{
+ struct cli_command *c;
+
+ c = cli_register_command(cli, NULL, "firmware", NULL, 0, 0, NULL);
+
+ cli_register_command(cli, c, "upload", cmd_firmware_upload, 0, 0, "Upload new firmware image");
+}
diff --git a/projects/hsm/mgmt-firmware.h b/projects/hsm/mgmt-firmware.h
new file mode 100644
index 0000000..af7c67c
--- /dev/null
+++ b/projects/hsm/mgmt-firmware.h
@@ -0,0 +1,42 @@
+/*
+ * mgmt-firmware.h
+ * ---------------
+ * Management CLI Device Firmware Upgrade code.
+ *
+ * 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_FIRMWARE_H
+#define __STM32_CLI_MGMT_FIRMWARE_H
+
+#include <libcli.h>
+
+extern void configure_cli_firmware(struct cli_def *cli);
+
+#endif /* __STM32_CLI_MGMT_FIRMWARE_H */
diff --git a/projects/hsm/mgmt-fpga.c b/projects/hsm/mgmt-fpga.c
new file mode 100644
index 0000000..af7ba11
--- /dev/null
+++ b/projects/hsm/mgmt-fpga.c
@@ -0,0 +1,194 @@
+/*
+ * mgmt-fpga.c
+ * -----------
+ * CLI code to manage the FPGA configuration etc.
+ *
+ * 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
+ * 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 "stm-fpgacfg.h"
+
+#include "mgmt-cli.h"
+#include "mgmt-fpga.h"
+#include "mgmt-misc.h"
+
+#undef HAL_OK
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#undef HAL_OK
+
+#include <string.h>
+
+
+extern hal_user_t user;
+
+static volatile uint32_t dfu_offset = 0;
+
+
+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)) != CMSIS_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;
+}
+
+static int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ if (user < HAL_USER_SO) {
+ cli_print(cli, "Permission denied.");
+ return CLI_ERROR;
+ }
+
+ uint8_t buf[BITSTREAM_UPLOAD_CHUNK_SIZE];
+
+ dfu_offset = 0;
+
+ fpgacfg_access_control(ALLOW_ARM);
+
+ cli_print(cli, "Checking if FPGA config memory is accessible");
+ if (fpgacfg_check_id() != CMSIS_HAL_OK) {
+ cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed.");
+ return CLI_ERROR;
+ }
+
+ cli_receive_data(cli, &buf[0], sizeof(buf), _flash_write_callback);
+
+ fpgacfg_access_control(ALLOW_FPGA);
+
+ cli_print(cli, "DFU offset now: %li (%li chunks)", dfu_offset, dfu_offset / BITSTREAM_UPLOAD_CHUNK_SIZE);
+ return CLI_OK;
+}
+
+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() != CMSIS_HAL_OK) {
+ cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed.");
+ return CLI_ERROR;
+ }
+
+ /* Erasing the whole config memory takes a while, we just need to erase the first sector.
+ * The bitstream has an EOF marker, so even if the next bitstream uploaded is shorter than
+ * the current one there should be no problem.
+ *
+ * This command could be made to accept an argument indicating the whole memory should be erased.
+ */
+ if (fpgacfg_erase_sector(0) != CMSIS_HAL_OK) {
+ cli_print(cli, "Erasing first sector in FPGA config memory failed");
+ return CLI_ERROR;
+ }
+
+ cli_print(cli, "Erased FPGA config memory");
+ fpgacfg_access_control(ALLOW_FPGA);
+
+ return CLI_OK;
+}
+
+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);
+ hal_core_reset_table();
+ cli_print(cli, "FPGA has been reset");
+
+ return CLI_OK;
+}
+
+static int cmd_fpga_show_cores(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ 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;
+}
+
+void configure_cli_fpga(struct cli_def *cli)
+{
+ struct cli_command *c = cli_register_command(cli, NULL, "fpga", NULL, 0, 0, NULL);
+
+ struct cli_command *c_show = cli_register_command(cli, c, "show", NULL, 0, 0, NULL);
+ struct cli_command *c_bitstream = cli_register_command(cli, c, "bitstream", NULL, 0, 0, NULL);
+
+ /* fpga show cores */
+ cli_register_command(cli, c_show, "cores", cmd_fpga_show_cores, 0, 0, "Show FPGA core names and versions");
+
+ /* fpga reset */
+ cli_register_command(cli, c, "reset", cmd_fpga_reset, 0, 0, "Reset FPGA (config reset)");
+
+ /* fpga bitstream upload */
+ cli_register_command(cli, c_bitstream, "upload", cmd_fpga_bitstream_upload, 0, 0, "Upload new FPGA bitstream");
+
+ /* fpga bitstream erase */
+ cli_register_command(cli, c_bitstream, "erase", cmd_fpga_bitstream_erase, 0, 0, "Erase FPGA config memory");
+}
diff --git a/projects/hsm/mgmt-fpga.h b/projects/hsm/mgmt-fpga.h
new file mode 100644
index 0000000..9d0aedc
--- /dev/null
+++ b/projects/hsm/mgmt-fpga.h
@@ -0,0 +1,49 @@
+/*
+ * mgmt-fpga.h
+ * -----------
+ * Management FPGA related code.
+ *
+ * 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_FPGA_H
+#define __STM32_CLI_MGMT_FPGA_H
+
+#include <libcli.h>
+
+
+/* The chunk size have to be a multiple of the SPI flash page size (256 bytes),
+ and it has to match the chunk size in the program sending the bitstream over the UART.
+*/
+#define BITSTREAM_UPLOAD_CHUNK_SIZE 4096
+
+
+extern void configure_cli_fpga(struct cli_def *cli);
+
+#endif /* __STM32_CLI_MGMT_FPGA_H */
diff --git a/projects/hsm/mgmt-keystore.c b/projects/hsm/mgmt-keystore.c
new file mode 100644
index 0000000..9eb42da
--- /dev/null
+++ b/projects/hsm/mgmt-keystore.c
@@ -0,0 +1,408 @@
+/*
+ * mgmt-keystore.c
+ * ---------------
+ * CLI 'keystore' commands.
+ *
+ * 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
+ * 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"
+
+#undef HAL_OK
+#define LIBHAL_OK HAL_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>
+#include <strings.h>
+#include <ctype.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") == 0)
+ user = HAL_USER_NORMAL;
+ else if (strcmp(argv[0], "so") == 0)
+ user = HAL_USER_SO;
+ else if (strcmp(argv[0], "wheel") == 0)
+ 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;
+ }
+
+ user = HAL_USER_NONE;
+ if (strcmp(argv[0], "user") == 0)
+ user = HAL_USER_NORMAL;
+ else if (strcmp(argv[0], "so") == 0)
+ user = HAL_USER_SO;
+ else if (strcmp(argv[0], "wheel") == 0)
+ user = HAL_USER_WHEEL;
+ else {
+ cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]);
+ return CLI_ERROR;
+ }
+
+ if ((status = hal_rpc_set_pin(client, user, "", 0)) != LIBHAL_OK) {
+ cli_print(cli, "Failed clearing 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;
+}
+
+static int cmd_keystore_delete_key(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ const hal_client_handle_t client = { -1 };
+ 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) {
+ cli_print(cli, "Couldn't find key: %s", hal_error_string(status));
+ return CLI_ERROR;
+ }
+
+ if ((status = hal_rpc_pkey_delete(pkey)) != LIBHAL_OK) {
+ cli_print(cli, "Failed deleting key: %s", hal_error_string(status));
+ (void) hal_rpc_pkey_close(pkey);
+ return CLI_ERROR;
+ }
+
+ cli_print(cli, "Deleted key %s", argv[0]);
+
+ return CLI_OK;
+}
+
+#include "ks.h"
+
+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_uuid_t uuids[50];
+ hal_key_type_t type;
+ hal_error_t status;
+ int count = 0;
+ int done = 0;
+
+ cli_print(cli, title);
+
+ size_t avail;
+ if ((status = hal_ks_available(hal_ks_token, &avail)) == HAL_OK)
+ cli_print(cli, "Token keystore: %d available", avail);
+ else
+ cli_print(cli, "Error reading token keystore: %s", hal_error_string(status));
+ if ((status = hal_ks_available(hal_ks_volatile, &avail)) == HAL_OK)
+ cli_print(cli, "Volatile keystore: %d available", avail);
+ else
+ cli_print(cli, "Error reading volatile keystore: %s", hal_error_string(status));
+
+ 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 CLI_ERROR;
+ }
+
+ 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, skipping: %s",
+ hal_error_string(status));
+ continue;
+ }
+
+ if ((status = hal_rpc_pkey_open(client, session, &pkey, &uuids[i])) != LIBHAL_OK) {
+ cli_print(cli, "Could not open key %s, skipping: %s",
+ key_name, hal_error_string(status));
+ continue;
+ }
+
+ 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, skipping: %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)
+ continue;
+
+ 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;
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE: type_name = "hashsig private"; break;
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC: type_name = "hashsig public"; break;
+ case HAL_KEY_TYPE_HASHSIG_LMS: type_name = "hashsig lms"; break;
+ case HAL_KEY_TYPE_HASHSIG_LMOTS: type_name = "hashsig lmots"; 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",
+ count++, key_name, type_name, curve_name, (unsigned long) flags);
+ }
+ }
+
+ return CLI_OK;
+}
+
+static int show_pin(struct cli_def *cli, char *label, hal_user_t user)
+{
+ const hal_ks_pin_t *p;
+
+ if (hal_get_pin(user, &p) != HAL_OK)
+ return CLI_ERROR;
+
+ /*
+ * I'm not sure iterations is the most interesting thing to show, but
+ * it's what we had before.
+ */
+
+ cli_print(cli, "%s iterations: 0x%lx", label, p->iterations);
+ return CLI_OK;
+}
+
+static int cmd_keystore_show_keys(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ int err = 0;
+
+ err |= show_keys(cli, "Keystore:");
+
+ cli_print(cli, "\nPins:");
+ err |= show_pin(cli, "Wheel", HAL_USER_WHEEL);
+ err |= show_pin(cli, "SO ", HAL_USER_SO);
+ err |= show_pin(cli, "User ", HAL_USER_NORMAL);
+
+ return err ? CLI_ERROR : CLI_OK;
+}
+
+static int cmd_keystore_erase(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ hal_error_t err;
+ HAL_StatusTypeDef status;
+ int preserve_PINs = 0;
+
+ command = command;
+
+ if (argc < 1 || argc > 2 || strcmp(argv[0], "YesIAmSure") != 0) {
+ usage:
+ cli_print(cli, "Syntax: keystore erase YesIAmSure [preservePINs]");
+ return CLI_ERROR;
+ }
+ if (argc == 2) {
+ if (strcasecmp(argv[1], "preservePINs") != 0)
+ goto usage;
+ else
+ preserve_PINs = 1;
+ }
+
+ hal_user_t users[3] = { HAL_USER_NORMAL, HAL_USER_SO, HAL_USER_WHEEL };
+ hal_ks_pin_t pins[3];
+ if (preserve_PINs) {
+ for (size_t i = 0; i < 3; ++i) {
+ const hal_ks_pin_t *pin;
+ if (hal_get_pin(users[i], &pin) != HAL_OK) {
+ cli_print(cli, "Failed to get the PINs");
+ return CLI_ERROR;
+ }
+ memcpy(&pins[i], pin, sizeof(*pin));
+ }
+ }
+
+ cli_print(cli, "OK, erasing keystore, this will take about 45 seconds...");
+ 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;
+ }
+
+ if (preserve_PINs) {
+ for (size_t i = 0; i < 3; ++i) {
+ if (hal_set_pin(users[i], &pins[i]) != HAL_OK) {
+ cli_print(cli, "Failed to restore the PINs");
+ 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_show = cli_register_command(cli, c, "show", 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);
+
+ /* keystore show keys */
+ cli_register_command(cli, c_show, "keys", cmd_keystore_show_keys, 0, 0, "Show what PINs and keys are in the 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");
+
+ /* keystore delete key */
+ cli_register_command(cli, c_delete, "key", cmd_keystore_delete_key, 0, 0, "Delete a key");
+
+ /* keystore erase */
+ cli_register_command(cli, c, "erase", cmd_keystore_erase, 0, 0, "Erase the whole keystore");
+}
diff --git a/projects/hsm/mgmt-keystore.h b/projects/hsm/mgmt-keystore.h
new file mode 100644
index 0000000..9e14ac6
--- /dev/null
+++ b/projects/hsm/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/hsm/mgmt-masterkey.c b/projects/hsm/mgmt-masterkey.c
new file mode 100644
index 0000000..97e62a0
--- /dev/null
+++ b/projects/hsm/mgmt-masterkey.c
@@ -0,0 +1,244 @@
+/*
+ * 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.h 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 cmd_masterkey_status(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ hal_error_t status;
+
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ cli_print(cli, "Status of master key:\n");
+
+ status = hal_keywrap_mkm_status(NULL);
+ 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));
+
+ return CLI_OK;
+}
+
+static int str_to_hex_digit(char c)
+{
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ c = c - 'A' + 10;
+ else
+ return -1;
+
+ return c;
+}
+
+static inline char hex_to_str_digit(const uint8_t c)
+{
+ return (c < 10) ? ((char)c + '0') : ((char)c + 'A' - 10);
+}
+
+static char *hexdump_kek(const uint8_t * const kek)
+{
+ /* This is only for dumping masterkey values, so has no length checks.
+ * Do not use it for anything else.
+ *
+ * For convenience of possibly hand-copying and hand-retyping, the key
+ * is divided into 8 4-byte (8-character) groups.
+ */
+
+ static char buf[2 * KEK_LENGTH + 8];
+ char *dst = buf;
+
+ for (size_t i = 0; i < KEK_LENGTH; ++i) {
+ uint8_t b = kek[i];
+ *dst++ = hex_to_str_digit(b >> 4);
+ *dst++ = hex_to_str_digit(b & 0xf);
+ if ((i & 3) == 3)
+ *dst++ = ' ';
+ }
+ buf[sizeof(buf) - 1] = '\0';
+
+ return buf;
+}
+
+static int _masterkey_set(struct cli_def *cli, char *argv[], int argc,
+ char *label, hal_error_t (*writer)(const uint8_t * const, const size_t))
+{
+ uint8_t buf[KEK_LENGTH] = {0};
+ hal_error_t err;
+
+ if (argc == 0) {
+ /* fill master key with yummy randomness */
+ if ((err = hal_get_random(NULL, buf, sizeof(buf))) != LIBHAL_OK) {
+ cli_print(cli, "Error getting random key: %s", hal_error_string(err));
+ return CLI_ERROR;
+ }
+ cli_print(cli, "Random key:\n%s", hexdump_kek(buf));
+ }
+
+ else {
+ /* input is 32 hex bytes, arranged however the user wants */
+ size_t len = 0;
+ for (int i = 0; i < argc; ++i) {
+ for (char *cp = argv[i]; *cp != '\0'; ) {
+ int c;
+ if ((c = str_to_hex_digit(*cp++)) < 0)
+ goto errout;
+ buf[len] = c << 4;
+ if ((c = str_to_hex_digit(*cp++)) < 0)
+ goto errout;
+ buf[len] |= c & 0xf;
+ if (++len > KEK_LENGTH)
+ goto errout;
+ }
+ }
+ if (len < KEK_LENGTH) {
+ errout:
+ cli_print(cli, "Failed parsing master key, expected exactly %d hex bytes", KEK_LENGTH);
+ return CLI_ERROR;
+ }
+
+ cli_print(cli, "Parsed key:\n%s", hexdump_kek(buf));
+ }
+
+ if ((err = writer(buf, sizeof(buf))) == LIBHAL_OK) {
+ cli_print(cli, "Master key set in %s memory", label);
+ } else {
+ cli_print(cli, "Failed writing key to %s memory: %s", label, hal_error_string(err));
+ }
+ return CLI_OK;
+}
+
+static hal_error_t _mkm_volatile_write(const uint8_t *kek, const size_t kek_len)
+{
+ return hal_keywrap_mkm_write(NULL, kek, kek_len);
+}
+
+static int cmd_masterkey_set(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+
+ return _masterkey_set(cli, argv, argc, "volatile", _mkm_volatile_write);
+}
+
+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_keywrap_mkm_erase(NULL, 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)
+{
+ command = command;
+
+ return _masterkey_set(cli, argv, argc, "flash", hal_mkm_flash_write);
+}
+
+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/hsm/mgmt-masterkey.h b/projects/hsm/mgmt-masterkey.h
new file mode 100644
index 0000000..67835e9
--- /dev/null
+++ b/projects/hsm/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/hsm/mgmt-misc.c b/projects/hsm/mgmt-misc.c
new file mode 100644
index 0000000..377af73
--- /dev/null
+++ b/projects/hsm/mgmt-misc.c
@@ -0,0 +1,259 @@
+/*
+ * mgmt-misc.c
+ * -----------
+ * Miscellaneous CLI functions.
+ *
+ * Copyright (c) 2016-2018, 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
+ * 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 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
+ * 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-misc.h"
+#undef HAL_OK
+
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#include "hal_internal.h"
+#undef HAL_OK
+
+#include <string.h>
+
+
+int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback)
+{
+ 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");
+ goto okay;
+ }
+
+ cli_print(cli, "OK, write size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", (uint32_t) n);
+
+ if (uart_receive_bytes((void *) &filesize, sizeof(filesize), 2000) != CMSIS_HAL_OK) {
+ cli_print(cli, "Receive timed out");
+ goto fail;
+ }
+
+ cli_print(cli, "Send %li bytes of data", filesize);
+
+ while (filesize) {
+ /* By initializing buf to the same value that erased flash has (0xff), we don't
+ * have to try and be smart when writing the last page of data to a flash memory.
+ */
+ memset(buf, 0xff, len);
+
+ if (filesize < n) n = filesize;
+
+ if (uart_receive_bytes((void *) buf, n, 2000) != CMSIS_HAL_OK) {
+ cli_print(cli, "Receive timed out");
+ goto fail;
+ }
+ filesize -= 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, n) != CMSIS_HAL_OK) {
+ cli_print(cli, "Data processing failed");
+ goto okay;
+ }
+
+ counter++;
+ uart_send_bytes((void *) &counter, 4);
+ }
+
+ my_crc = hal_crc32_finalize(my_crc);
+ cli_print(cli, "Send CRC-32");
+ uart_receive_bytes((void *) &crc, sizeof(crc), 2000);
+ 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");
+ } else {
+ cli_print(cli, "CRC checksum did NOT match");
+ }
+
+ okay:
+ control_mgmt_uart_dma_rx(DMA_RX_START);
+ return CLI_OK;
+
+ fail:
+ control_mgmt_uart_dma_rx(DMA_RX_START);
+ return CLI_ERROR;
+}
+
+#ifdef DO_PROFILING
+static int cmd_profile_start(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli = cli;
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ extern uint32_t CRYPTECH_FIRMWARE_START;
+ extern char __etext; /* end of text/code symbol, defined by linker */
+ extern void monstartup (size_t lowpc, size_t highpc);
+ monstartup((size_t)&CRYPTECH_FIRMWARE_START, (size_t)&__etext);
+ return CLI_OK;
+}
+
+static int cmd_profile_stop(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli = cli;
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ extern void _mcleanup(void);
+ _mcleanup();
+ return CLI_OK;
+}
+
+#endif
+
+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();
+
+ /*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)
+{
+#ifdef DO_PROFILING
+ struct cli_command *c_profile = cli_register_command(cli, NULL, "profile", NULL, 0, 0, NULL);
+
+ /* profile start */
+ cli_register_command(cli, c_profile, "start", cmd_profile_start, 0, 0, "Start collecting profiling data");
+
+ /* profile stop */
+ cli_register_command(cli, c_profile, "stop", cmd_profile_stop, 0, 0, "Stop collecting profiling data");
+#endif
+
+ 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_register_command(cli, NULL, "reboot", cmd_reboot, 0, 0, "Reboot the STM32");
+}
+
diff --git a/projects/hsm/mgmt-misc.h b/projects/hsm/mgmt-misc.h
new file mode 100644
index 0000000..ef63a9e
--- /dev/null
+++ b/projects/hsm/mgmt-misc.h
@@ -0,0 +1,47 @@
+/*
+ * mgmt-misc.h
+ * -----------
+ * Management CLI miscellaneous 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_MISC_H
+#define __STM32_CLI_MGMT_MISC_H
+
+#include <libcli.h>
+
+/* Write a chunk of received data to flash. */
+typedef HAL_StatusTypeDef (*cli_data_callback)(uint8_t *, size_t);
+
+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/hsm/mgmt-task.c b/projects/hsm/mgmt-task.c
new file mode 100644
index 0000000..180c6d9
--- /dev/null
+++ b/projects/hsm/mgmt-task.c
@@ -0,0 +1,136 @@
+/*
+ * mgmt-task.c
+ * -----------
+ * CLI 'task' functions.
+ *
+ * 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
+ * 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.
+ */
+
+/*
+ * Show the active tasks. This is mostly for debugging, and looks deeply
+ * into OS-level structures, but sometimes you just need to know...
+ */
+
+#include "mgmt-cli.h"
+#include "mgmt-task.h"
+#include "task.h"
+
+static char *task_state[] = {
+ "INIT",
+ "WAITING",
+ "READY"
+};
+
+extern size_t request_queue_len(void);
+extern size_t request_queue_max(void);
+
+static int cmd_task_show(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ cli_print(cli, "name state stack high water");
+ cli_print(cli, "-------- -------- ----------------");
+
+ for (tcb_t *t = task_iterate(NULL); t != NULL; t = task_iterate(t)) {
+ cli_print(cli, "%-15s %-15s %d",
+ task_get_name(t),
+ task_state[task_get_state(t)],
+ task_get_stack_highwater(t));
+ }
+
+ cli_print(cli, " ");
+ cli_print(cli, "RPC request queue current length: %u", request_queue_len());
+ cli_print(cli, "RPC request queue maximum length: %u", request_queue_max());
+
+ extern size_t uart_rx_max;
+ cli_print(cli, " ");
+ cli_print(cli, "UART receive queue maximum length: %u", uart_rx_max);
+
+ size_t used, available;
+ extern void sdram_stats(size_t *used, size_t *available);
+ sdram_stats(&used, &available);
+ cli_print(cli, " ");
+ cli_print(cli, "SDRAM used: %u, available: %u", used, available);
+
+ return CLI_OK;
+}
+
+#ifdef DO_TASK_METRICS
+static int cmd_task_show_metrics(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ struct task_metrics tm;
+
+ task_get_metrics(&tm);
+
+ cli_print(cli, "avg time between yields: %ld.%06ld sec", tm.avg.tv_sec, tm.avg.tv_usec);
+ cli_print(cli, "max time between yields: %ld.%06ld sec", tm.max.tv_sec, tm.max.tv_usec);
+
+ return CLI_OK;
+}
+
+static int cmd_task_reset_metrics(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ cli = cli;
+ command = command;
+ argv = argv;
+ argc = argc;
+
+ task_reset_metrics();
+
+ return CLI_OK;
+}
+#endif
+
+void configure_cli_task(struct cli_def *cli)
+{
+ struct cli_command *c = cli_register_command(cli, NULL, "task", NULL, 0, 0, NULL);
+
+ /* task show */
+#ifdef DO_TASK_METRICS
+ struct cli_command *c_show =
+#endif
+ cli_register_command(cli, c, "show", cmd_task_show, 0, 0, "Show the active tasks");
+
+#ifdef DO_TASK_METRICS
+ /* task show metrics */
+ cli_register_command(cli, c_show, "metrics", cmd_task_show_metrics, 0, 0, "Show task metrics");
+
+ /* task reset */
+ struct cli_command *c_reset = cli_register_command(cli, c, "reset", NULL, 0, 0, NULL);
+
+ /* task reset metrics */
+ cli_register_command(cli, c_reset, "metrics", cmd_task_reset_metrics, 0, 0, "Reset task metrics");
+#endif
+}
diff --git a/projects/hsm/mgmt-task.h b/projects/hsm/mgmt-task.h
new file mode 100644
index 0000000..f903962
--- /dev/null
+++ b/projects/hsm/mgmt-task.h
@@ -0,0 +1,42 @@
+/*
+ * mgmt-task.h
+ * -----------
+ * Management CLI 'task' functions.
+ *
+ * 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
+ * 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_TASK_H
+#define __STM32_CLI_MGMT_TASK_H
+
+#include <libcli.h>
+
+extern void configure_cli_task(struct cli_def *cli);
+
+#endif /* __STM32_CLI_MGMT_TASK_H */
diff --git a/projects/libhal-test/Makefile b/projects/libhal-test/Makefile
index f58f480..c5dbc84 100644
--- a/projects/libhal-test/Makefile
+++ b/projects/libhal-test/Makefile
@@ -1,12 +1,12 @@
-TEST = cores test-bus test-trng test-hash test-aes-key-wrap test-pbkdf2 test-ecdsa test-rsa test-mkmif
+TEST = cores test-bus test-trng test-hash test-aes-key-wrap test-pbkdf2 test-ecdsa test-rsa
-CFLAGS += -I $(LIBHAL_DIR)
+CFLAGS += -I $(LIBHAL_SRC)
LIBC_OBJS = printf.o gettimeofday.o
-LIBS += $(LIBHAL_DIR)/libhal.a $(LIBTFM_DIR)/libtfm.a
+LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a
all: $(TEST:=.elf)
-vpath %.c $(LIBHAL_DIR)/tests $(LIBHAL_DIR)/utils
+vpath %.c $(LIBHAL_SRC)/tests $(LIBHAL_SRC)/utils
# .mo extension for files with main() that need to be wrapped as __main()
%.mo: %.c
@@ -17,9 +17,6 @@ vpath %.c $(LIBHAL_DIR)/tests $(LIBHAL_DIR)/utils
$(OBJCOPY) -O binary $*.elf $*.bin
$(SIZE) $*.elf
-# don't automatically delete objects, to avoid a lot of unnecessary rebuilding
-.SECONDARY: $(BOARD_OBJS) $(LIBC_OBJS)
-
clean:
rm -f *.o *.mo
rm -f *.elf
diff --git a/projects/libhal-test/gettimeofday.c b/projects/libhal-test/gettimeofday.c
index b13485d..f7a87f1 100644
--- a/projects/libhal-test/gettimeofday.c
+++ b/projects/libhal-test/gettimeofday.c
@@ -56,6 +56,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
{
uint32_t tick = HAL_GetTick(); /* uptime in ms */
+ tz = tz;
+
tv->tv_sec = tick / 1000;
tv->tv_usec = (tick % 1000) * 1000;
diff --git a/projects/libhal-test/main.c b/projects/libhal-test/main.c
index a40871b..c0d9330 100644
--- a/projects/libhal-test/main.c
+++ b/projects/libhal-test/main.c
@@ -43,18 +43,8 @@ extern void __main(void);
int main(void)
{
stm_init();
-
-#ifdef TARGET_CRYPTECH_DEV_BRIDGE
- // Blink blue LED for six seconds to not upset the Novena at boot.
- led_on(LED_BLUE);
- for (int i = 0; i < 12; i++) {
- HAL_Delay(500);
- led_toggle(LED_BLUE);
- }
- led_off(LED_BLUE);
-#endif
+ HAL_Delay(500);
led_on(LED_GREEN);
- fmc_init();
__main();
diff --git a/projects/libhal-test/printf.c b/projects/libhal-test/printf.c
index 5a15d12..85af09b 100644
--- a/projects/libhal-test/printf.c
+++ b/projects/libhal-test/printf.c
@@ -244,7 +244,7 @@ OK, I found my mistake. The math here is _always_ unsigned */
if (precision != 0)
{
width = max(width, precision);
- if (precision > strlen(where))
+ if (precision > strlen((const char *)where))
flags |= PR_LZ;
precision = 0;
}
@@ -295,7 +295,7 @@ EMIT2: if((flags & PR_LJ) == 0)
count++;
}
/* emit string/char/converted number */
- for(int i = (flags & PR_WS) ? 1 : 0;
+ for(unsigned i = (flags & PR_WS) ? 1 : 0;
i < length; ++i)
{
fn(*where++, &ptr);
@@ -362,6 +362,8 @@ You must write your own putchar()
*****************************************************************************/
int vprintf_help(unsigned c, void **ptr)
{
+ ptr = ptr;
+
putchar(c);
return 0 ;
}
diff --git a/projects/rtos-test/Makefile b/projects/rtos-test/Makefile
deleted file mode 100644
index dd2cab5..0000000
--- a/projects/rtos-test/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-TEST = thread-test semaphore-test mutex-test
-
-all: $(TEST:=.elf)
-
-%.elf: %.o $(BOARD_OBJS) $(LIBS)
- $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map
- $(OBJCOPY) -O ihex $*.elf $*.hex
- $(OBJCOPY) -O binary $*.elf $*.bin
- $(OBJDUMP) -St $*.elf >$*.lst
- $(SIZE) $*.elf
-
-clean:
- rm -f *.o
- rm -f *.elf
- rm -f *.hex
- rm -f *.bin
- rm -f *.map
- rm -f *.lst
diff --git a/projects/rtos-test/mutex-test.c b/projects/rtos-test/mutex-test.c
deleted file mode 100644
index 402f9ba..0000000
--- a/projects/rtos-test/mutex-test.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "cmsis_os.h"
-
-#include "stm-init.h"
-#include "stm-uart.h"
-
-osMutexId stdio_mutex;
-osMutexDef(stdio_mutex);
-
-void notify(const char* name, int state) {
- osMutexWait(stdio_mutex, osWaitForever);
- //printf("%s: %d\n\r", name, state);
- uart_send_string(name);
- uart_send_string(": ");
- uart_send_integer(state, 1);
- uart_send_string("\r\n");
- osMutexRelease(stdio_mutex);
-}
-
-void test_thread(void const *args) {
- while (1) {
- notify((const char*)args, 0); osDelay(1000);
- notify((const char*)args, 1); osDelay(1000);
- }
-}
-
-void t2(void const *argument) {test_thread("Th 2");}
-osThreadDef(t2, osPriorityNormal, DEFAULT_STACK_SIZE);
-
-void t3(void const *argument) {test_thread("Th 3");}
-osThreadDef(t3, osPriorityNormal, DEFAULT_STACK_SIZE);
-
-int main() {
- stm_init();
- stdio_mutex = osMutexCreate(osMutex(stdio_mutex));
-
- osThreadCreate(osThread(t2), NULL);
- osThreadCreate(osThread(t3), NULL);
-
- test_thread((void *)"Th 1");
-}
diff --git a/projects/rtos-test/semaphore-test.c b/projects/rtos-test/semaphore-test.c
deleted file mode 100644
index 3a3b5de..0000000
--- a/projects/rtos-test/semaphore-test.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "cmsis_os.h"
-
-#include "stm-init.h"
-#include "stm-uart.h"
-
-osSemaphoreId two_slots;
-osSemaphoreDef(two_slots);
-
-void test_thread(void const *name) {
- while (1) {
- osSemaphoreWait(two_slots, osWaitForever);
- //printf("%s\n\r", (const char*)name);
- uart_send_string((const char*)name);
- uart_send_string("\r\n");
- osDelay(1000);
- osSemaphoreRelease(two_slots);
- }
-}
-
-void t2(void const *argument) {test_thread("Th 2");}
-osThreadDef(t2, osPriorityNormal, DEFAULT_STACK_SIZE);
-
-void t3(void const *argument) {test_thread("Th 3");}
-osThreadDef(t3, osPriorityNormal, DEFAULT_STACK_SIZE);
-
-int main (void) {
- stm_init();
- two_slots = osSemaphoreCreate(osSemaphore(two_slots), 2);
-
- osThreadCreate(osThread(t2), NULL);
- osThreadCreate(osThread(t3), NULL);
-
- test_thread((void *)"Th 1");
-}
diff --git a/projects/rtos-test/thread-test.c b/projects/rtos-test/thread-test.c
deleted file mode 100644
index 8b31a26..0000000
--- a/projects/rtos-test/thread-test.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "cmsis_os.h"
-
-#include "stm-init.h"
-#include "stm-led.h"
-
-void led2_thread(void const *args)
-{
- while (1) {
- led_toggle(LED_BLUE);
- osDelay(1000);
- }
-}
-osThreadDef(led2_thread, osPriorityNormal, DEFAULT_STACK_SIZE);
-
-int main()
-{
- stm_init();
- osThreadCreate(osThread(led2_thread), NULL);
-
- while (1) {
- led_toggle(LED_GREEN);
- osDelay(500);
- }
-}