summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2017-06-27 17:58:45 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-10-06 00:21:29 -0700
commit02045eb040227250689caec9b9401c2cd3861363 (patch)
treef09e73f9794a6e581c3ae3ff2e5c344dd2dd0b63
parent366c36c8f1655c57f4c05d000cb4c000020d10db (diff)
downloadchrome-ec-02045eb040227250689caec9b9401c2cd3861363.tar.gz
mn50: add data signing capability
Add a PERSO_AUTH appid to sign data passed through the AUTH mn50. Add a signer command to start and generate signatures. Clean UART init to avoid spurious nonprinting characters that will contaminate the siugnature. BUG=b:36910757 BRANCH=None TEST=generates signature for uart and spi Signed-off-by: Nick Sanders <nsanders@chromium.org> Change-Id: I5fc3c4ee34898421060b57b774a09734f6a1bae5 Reviewed-on: https://chromium-review.googlesource.com/670984 Reviewed-by: Marius Schilder <mschilder@chromium.org>
-rw-r--r--board/mn50/board.c70
-rw-r--r--board/mn50/board.h1
-rw-r--r--board/mn50/build.mk1
-rw-r--r--board/mn50/ec.tasklist2
-rw-r--r--board/mn50/signing.c201
-rw-r--r--board/mn50/signing.h73
-rw-r--r--board/mn50/usb_spi.c7
-rw-r--r--chip/g/dcrypto/app_key.c10
-rw-r--r--chip/g/dcrypto/dcrypto.h1
-rw-r--r--chip/g/usart.c48
-rw-r--r--chip/g/usb_spi.c13
-rw-r--r--chip/g/usb_spi.h2
-rw-r--r--include/config.h8
13 files changed, 431 insertions, 6 deletions
diff --git a/board/mn50/board.c b/board/mn50/board.c
index 15371075d3..302a7d5296 100644
--- a/board/mn50/board.c
+++ b/board/mn50/board.c
@@ -23,6 +23,7 @@
#include "nvmem_vars.h"
#include "registers.h"
#include "signed_header.h"
+#include "signing.h"
#include "spi.h"
#include "system.h"
#include "task.h"
@@ -137,9 +138,7 @@ static void board_init(void)
/* Enable USB / CCD */
usb_release();
usb_console_enable(1, 0);
- usb_spi_enable(&ccd_usb_spi, 1);
ccd_phy_init();
- uartn_enable(UART_AP);
/* Calibrate INA0 (VBUS) with 1mA/LSB scale */
i2cm_init();
@@ -258,6 +257,9 @@ void enable_socket(void)
/* UART */
GWRITE(PINMUX, DIOA7_SEL, GC_PINMUX_UART1_TX_SEL);
+ GWRITE(PINMUX, DIOA3_SEL, GC_PINMUX_UART1_RX_SEL);
+ GWRITE_FIELD(PINMUX, DIOA3_CTL, PU, 1);
+ uartn_enable(UART_AP);
/* Chip select. */
GWRITE_FIELD(PINMUX, DIOA5_CTL, PU, 1);
@@ -281,7 +283,10 @@ void disable_socket(void)
GWRITE(PINMUX, DIOA5_SEL, GC_PINMUX_GPIO0_GPIO10_SEL);
/* UART */
+ uartn_disable(UART_AP);
GWRITE(PINMUX, DIOA7_SEL, 0);
+ GWRITE(PINMUX, DIOA3_SEL, 0);
+ GWRITE_FIELD(PINMUX, DIOA3_CTL, PU, 0);
/* GPIOs as inputs. */
gpio_set_flags(GPIO_DUT_BOOT_CFG, GPIO_INPUT);
@@ -319,6 +324,67 @@ DECLARE_SAFE_CONSOLE_COMMAND(socket, command_socket,
"[enable|disable]",
"Activate and deactivate socket");
+#ifdef CONFIG_STREAM_SIGNATURE
+/*
+ * This command allows signing the contents of a data stream that passes
+ * through mn50/scribe. This allows critical segments of SPI readouts,
+ * including the haven personalization data to be verified on the server
+ * side as coming from a registered scribe board. (go/haven-registration)
+ *
+ * The actual interface enables capturing data (start command) on a stream
+ * (either SPI or UART), until stopped (sign command), at which point a
+ * signature is printed to the console. An "append" command is available
+ * to manually insert characters for testing, and should be disabled
+ * before release.
+ */
+static int command_signer(int argc, char **argv)
+{
+ static int initted; /* = 0; */
+ char *data;
+
+ if (!initted) {
+ init_signing();
+ initted = 1;
+ }
+
+ if (argc > 2) {
+ enum stream_id id;
+
+ if (!strcasecmp("spi", argv[1]))
+ id = stream_spi;
+ else if (!strcasecmp("uart", argv[1]))
+ id = stream_uart;
+ else
+ return EC_ERROR_PARAM1;
+
+ if (!strcasecmp("sign", argv[2])) {
+ if (argc == 3)
+ return sig_sign(id);
+ else
+ return EC_ERROR_PARAM3;
+ } else if (!strcasecmp("start", argv[2])) {
+ if (argc == 3)
+ return sig_start(id);
+ else
+ return EC_ERROR_PARAM3;
+ } else if (!strcasecmp("append", argv[2])) {
+ if (argc == 4) {
+ data = argv[3];
+ return sig_append(id, data, strlen(data));
+ } else
+ return EC_ERROR_PARAM3;
+ } else
+ return EC_ERROR_PARAM2;
+ } else
+ return EC_ERROR_PARAM1;
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(signer, command_signer,
+ "[spi|uart] [start|append|sign] data",
+ "Sign data");
+#endif
+
void post_reboot_request(void)
{
/* This will never return. */
diff --git a/board/mn50/board.h b/board/mn50/board.h
index 5b9c9c43af..fd63a10ff9 100644
--- a/board/mn50/board.h
+++ b/board/mn50/board.h
@@ -80,6 +80,7 @@
#define CONFIG_STREAM_USART
#define CONFIG_STREAM_USB
#define CONFIG_STREAM_USART1
+#define CONFIG_STREAM_SIGNATURE
#define CONFIG_USB_PID 0x502a
#define CONFIG_USB_SELF_POWERED
diff --git a/board/mn50/build.mk b/board/mn50/build.mk
index 2f52cfa576..ca5cc90a74 100644
--- a/board/mn50/build.mk
+++ b/board/mn50/build.mk
@@ -27,6 +27,7 @@ dirs-y += chip/$(CHIP)/dcrypto
# Objects that we need to build
board-y = board.o
+board-${CONFIG_STREAM_SIGNATURE} += signing.o
board-${CONFIG_USB_SPI} += usb_spi.o
INCLUDE_ROOT := $(abspath ./include)
diff --git a/board/mn50/ec.tasklist b/board/mn50/ec.tasklist
index ac18090c67..d831b1a1ad 100644
--- a/board/mn50/ec.tasklist
+++ b/board/mn50/ec.tasklist
@@ -18,4 +18,4 @@
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, CONFIG_STACK_SIZE) \
- TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)
+ TASK_ALWAYS(CONSOLE, console_task, NULL, 8192)
diff --git a/board/mn50/signing.c b/board/mn50/signing.c
new file mode 100644
index 0000000000..ca61f59a9d
--- /dev/null
+++ b/board/mn50/signing.c
@@ -0,0 +1,201 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "common.h"
+#include "console.h"
+#include "dcrypto/dcrypto.h"
+#include "signing.h"
+#include "task.h"
+
+#include "cryptoc/sha.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+#define fail() cprints(CC_SYSTEM, "FAIL: %s:%d", __FILE__, __LINE__)
+
+static p256_int x, y, d;
+
+static HASH_CTX sig_sha[stream_count];
+
+enum signer_states {
+ state_notready = 0,
+ state_ready,
+ state_started,
+};
+
+/* Current state of each signer stream. */
+static int signer_state[stream_count];
+
+/* Bytes ingested into the hash so far. */
+static int signer_bytes[stream_count];
+
+/* Human readable name of each stream. */
+static const char *signer_name[stream_count] = {
+ "spi", "uart"
+};
+
+void init_signing(void)
+{
+ /* Add this enum to dcrypto.h */
+ enum dcrypto_appid appid = PERSO_AUTH;
+ struct APPKEY_CTX ctx;
+ uint32_t key_bytes[8];
+ const uint32_t PERSO_SALT[8] = {0xd00d1e, 0xba0, 0xc0ffee};
+
+ /*
+ * Initialize signing key
+ */
+ if (!DCRYPTO_appkey_init(appid, &ctx))
+ fail();
+ if (!DCRYPTO_appkey_derive(appid, PERSO_SALT, key_bytes))
+ fail();
+ if (!DCRYPTO_p256_key_from_bytes(&x, &y, &d,
+ (const uint8_t *)key_bytes))
+ fail();
+
+ /* (x,y) = pubkey, d = privkey */
+ signer_state[stream_uart] = state_ready;
+ signer_state[stream_spi] = state_ready;
+}
+
+/*
+ * Start collecting data into a hash to be signed.
+ * stream_id can be either stream_uart or stream_spi.
+ */
+int sig_start(enum stream_id id)
+{
+ if ((id < 0) || (id >= stream_count))
+ return EC_ERROR_PARAM1;
+
+ if (signer_state[id] != state_ready) {
+ CPRINTS("Signer %d not ready", id);
+ return EC_ERROR_INVAL;
+ }
+
+ /* Zero the hash. */
+ DCRYPTO_SHA256_init(&sig_sha[id], 0);
+ signer_bytes[id] = 0;
+ signer_state[id] = state_started;
+
+ return EC_SUCCESS;
+}
+
+/*
+ * Append data into this stream's hash for future signing.
+ * This function is called inline with data receive, from the UART rx code
+ * or the SPI rx code.
+ *
+ * This can be called any time, but only hashes data when the stream
+ * capture is started.
+ */
+int sig_append(enum stream_id id, const uint8_t *data, size_t data_len)
+{
+ HASH_CTX *sha = &sig_sha[id];
+ const uint8_t *blob = data;
+ size_t len = data_len;
+
+ if ((id < 0) || (id >= stream_count))
+ return EC_ERROR_PARAM1;
+
+ if (signer_state[id] != state_started)
+ return EC_ERROR_INVAL;
+
+ HASH_update(sha, blob, len);
+ signer_bytes[id] += len;
+
+ return EC_SUCCESS;
+}
+
+/* Close this stream's capture and print out the signature. */
+int sig_sign(enum stream_id id)
+{
+ HASH_CTX *sha = &sig_sha[id];
+ p256_int r, s; /* signature tuple */
+ p256_int digest;
+ struct drbg_ctx drbg;
+
+ if ((id < 0) || (id >= stream_count))
+ return EC_ERROR_PARAM1;
+
+ if (signer_state[id] != state_started) {
+ CPRINTS("Signer %d not starter", id);
+ return EC_ERROR_INVAL;
+ }
+
+ p256_from_bin(HASH_final(sha), &digest);
+ drbg_rand_init(&drbg);
+
+ if (!dcrypto_p256_ecdsa_sign(&drbg, &d, &digest, &r, &s)) {
+ fail();
+ return EC_ERROR_INVAL;
+ }
+
+ /* Check that the signature was correctly computed */
+ if (!dcrypto_p256_ecdsa_verify(&x, &y, &digest, &r, &s)) {
+ fail();
+ return EC_ERROR_INVAL;
+ }
+
+ /* Serialize r, s into output. */
+
+ CPRINTS("Signed %d bytes from %s.", signer_bytes[id], signer_name[id]);
+ CPRINTS("digest:");
+ CPRINTS("%08x %08x %08x %08x",
+ digest.a[0], digest.a[1], digest.a[2], digest.a[3]);
+ CPRINTS("%08x %08x %08x %08x",
+ digest.a[4], digest.a[5], digest.a[6], digest.a[7]);
+ CPRINTS("r:");
+ CPRINTS("%08x %08x %08x %08x", r.a[0], r.a[1], r.a[2], r.a[3]);
+ CPRINTS("%08x %08x %08x %08x", r.a[4], r.a[5], r.a[6], r.a[7]);
+ CPRINTS("s:");
+ CPRINTS("%08x %08x %08x %08x", s.a[0], s.a[1], s.a[2], s.a[3]);
+ CPRINTS("%08x %08x %08x %08x", s.a[4], s.a[5], s.a[6], s.a[7]);
+
+ signer_state[id] = state_ready;
+ return EC_SUCCESS;
+}
+
+
+/*
+ * Intercept UART data between the uart driver and usb bridge.
+ *
+ * This code is called by the ec's queue implementation, and ingests
+ * the UART RX queue, appends the data to the signer, then passes it
+ * on the the USB bridge's TX queue.
+ */
+void signer_written(struct consumer const *consumer, size_t count)
+{
+ struct signer_config const *config =
+ DOWNCAST(consumer, struct signer_config, consumer);
+ struct producer const *producer = &(config->producer);
+ enum stream_id id = config->id;
+
+ /* This queue receives characters from the UART. */
+ struct queue const *sig_in = consumer->queue;
+
+ /*
+ * This enqueues characters into the USB bridge,
+ * once they have been hashed.
+ */
+ struct queue const *sig_out = producer->queue;
+ char c;
+
+ /* Copy UART rx from queue. */
+ while (queue_count(sig_in) && QUEUE_REMOVE_UNITS(sig_in, &c, 1)) {
+ /* Append this data to the hash. */
+ sig_append(id, &c, 1);
+ /* Pass the data to the USB bridge. */
+ QUEUE_ADD_UNITS(sig_out, &c, 1);
+ }
+}
+
+struct producer_ops const signer_producer_ops = {
+ .read = NULL,
+};
+
+struct consumer_ops const signer_consumer_ops = {
+ .written = signer_written,
+ .flush = NULL,
+};
diff --git a/board/mn50/signing.h b/board/mn50/signing.h
new file mode 100644
index 0000000000..397a78441b
--- /dev/null
+++ b/board/mn50/signing.h
@@ -0,0 +1,73 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Add inline signing to verify records pasased through
+ * AUTH haven on Scribe SLT board.
+ */
+
+#ifndef __CROS_EC_SIGNER_H
+#define __CROS_EC_SIGNER_H
+
+#include "queue.h"
+#include "queue_policies.h"
+
+/*
+ * Data signing is supported on the following inputs:
+ * stream_spi: data received on H1's SPI master.
+ * stream_uart: data received on UART1.
+ *
+ * It's possible to hash multiple streams at once.
+ * Currently the hash will print out as console output
+ * in hex format when the stream is stopped.
+ */
+enum stream_id {
+ stream_spi = 0,
+ stream_uart = 1,
+ stream_count = 2,
+};
+
+/* Init the signing state and derive keys. Must be called before sig_start. */
+void init_signing(void);
+
+/* Zero the existing hash and start processing data in the specified stream. */
+int sig_start(enum stream_id id);
+
+/* Append data into the specified stream, if started, otherwise do nothing. */
+int sig_append(enum stream_id id, const uint8_t *data, size_t data_len);
+
+/* Stop a stream and sign the hash. The signature will print to the console. */
+int sig_sign(enum stream_id id);
+
+
+struct signer_config {
+ enum stream_id id;
+
+ struct producer const producer;
+ struct consumer const consumer;
+};
+
+extern struct consumer_ops const signer_consumer_ops;
+extern struct producer_ops const signer_producer_ops;
+
+void signer_written(struct consumer const *consumer, size_t count);
+
+/*
+ * Macro to set up inline signer.
+ * Usage: SIGNER_CONFIG(name, stream_id, tx queue, rx queue)
+ */
+#define SIGNER_CONFIG(NAME, ID, RX_QUEUE, TX_QUEUE) \
+ struct signer_config const NAME = { \
+ .id = ID, \
+ .consumer = { \
+ .queue = &TX_QUEUE, \
+ .ops = &signer_consumer_ops, \
+ }, \
+ .producer = { \
+ .queue = &RX_QUEUE, \
+ .ops = &signer_producer_ops, \
+ }, \
+ }
+#endif
diff --git a/board/mn50/usb_spi.c b/board/mn50/usb_spi.c
index 9dffeeae99..b44a450f91 100644
--- a/board/mn50/usb_spi.c
+++ b/board/mn50/usb_spi.c
@@ -7,6 +7,7 @@
#include "gpio.h"
#include "hooks.h"
#include "registers.h"
+#include "signing.h"
#include "spi.h"
#include "system.h"
#include "timer.h"
@@ -67,6 +68,12 @@ int usb_spi_interface(struct usb_spi_config const *config,
else
disable_socket();
break;
+ case USB_SPI_REQ_SIGNING_START:
+ sig_start(stream_spi);
+ break;
+ case USB_SPI_REQ_SIGNING_SIGN:
+ sig_sign(stream_spi);
+ break;
case USB_SPI_REQ_ENABLE_AP:
case USB_SPI_REQ_ENABLE:
CPRINTS("ERROR: Must specify target");
diff --git a/chip/g/dcrypto/app_key.c b/chip/g/dcrypto/app_key.c
index e2b709f3c0..173bc9d214 100644
--- a/chip/g/dcrypto/app_key.c
+++ b/chip/g/dcrypto/app_key.c
@@ -49,6 +49,16 @@ const struct {
0xcd375bcd, 0x8065e8cc, 0xc892ed69, 0x72436c7d
}
},
+#ifdef CONFIG_STREAM_SIGNATURE
+ {
+ /* This key signs data from H1's configured by mn50/scribe. */
+ "PERSO_AUTH",
+ {
+ 0x2019da34, 0xf1a01a13, 0x0fb9f73f, 0xf2e85f76,
+ 0x5ecb7690, 0x09f732c9, 0xe540bf14, 0xcc46799a
+ }
+ },
+#endif
};
int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx)
diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h
index 5c643382c6..e964288f84 100644
--- a/chip/g/dcrypto/dcrypto.h
+++ b/chip/g/dcrypto/dcrypto.h
@@ -271,6 +271,7 @@ enum dcrypto_appid {
U2F_ATTEST = 2,
U2F_ORIGIN = 3,
U2F_WRAP = 4,
+ PERSO_AUTH = 5,
/* This enum value should not exceed 7. */
};
diff --git a/chip/g/usart.c b/chip/g/usart.c
index 3e5493c579..598b4d4ed9 100644
--- a/chip/g/usart.c
+++ b/chip/g/usart.c
@@ -8,25 +8,63 @@
#include "uartn.h"
#include "usart.h"
#include "usb-stream.h"
+#ifdef CONFIG_STREAM_SIGNATURE
+#include "signing.h"
+#endif
#define USE_UART_INTERRUPTS (!(defined(CONFIG_CUSTOMIZED_RO) && \
defined(SECTION_IS_RO)))
#define QUEUE_SIZE 64
+
#ifdef CONFIG_STREAM_USART1
struct usb_stream_config const ap_usb;
struct usart_config const ap_uart;
-static struct queue const ap_uart_to_usb =
+#ifdef CONFIG_STREAM_SIGNATURE
+/*
+ * This code adds the ability to capture UART data received, and
+ * sign it with H1's key. This allows the log output to be verified
+ * as actual UART output from this board.
+ *
+ * This functionality is enabled by redirecting the UART receive queue
+ * to feed into the signing module rather than the usb tx. After being
+ * added to the running hash, the data is then pushed by the signer
+ * into the usb tx queue.
+ */
+struct signer_config const sig;
+static struct queue const ap_uart_output =
+ QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ap_uart.producer, sig.consumer);
+static struct queue const sig_to_usb =
+ QUEUE_DIRECT(QUEUE_SIZE, uint8_t, sig.producer, ap_usb.consumer);
+
+SIGNER_CONFIG(sig, stream_uart, sig_to_usb, ap_uart_output);
+
+#else /* Not CONFIG_STREAM_SIGNATURE */
+static struct queue const ap_uart_output =
QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ap_uart.producer, ap_usb.consumer);
+#endif
+
static struct queue const ap_usb_to_uart =
QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ap_usb.producer, ap_uart.consumer);
+/*
+ * AP UART data is sent to the ap_uart_output queue, and received from
+ * the ap_usb_to_uart queue. The ap_uart_output queue is received by the
+ * USB bridge, or if a signer is enabled, received by the signer, which then
+ * passes the data to the USB bridge after processing it.
+ */
USART_CONFIG(ap_uart,
UART_AP,
- ap_uart_to_usb,
+ ap_uart_output,
ap_usb_to_uart);
+/*
+ * The UART USB bridge receives character data from the UART's queue,
+ * unless signing is enabled, in which case it receives data from the
+ * signer's queue, after the signer has received it from the UART and
+ * processed it.
+ */
USB_STREAM_CONFIG(ap_usb,
USB_IFACE_AP,
USB_STR_AP_NAME,
@@ -34,8 +72,12 @@ USB_STREAM_CONFIG(ap_usb,
USB_MAX_PACKET_SIZE,
USB_MAX_PACKET_SIZE,
ap_usb_to_uart,
- ap_uart_to_usb)
+#ifdef CONFIG_STREAM_SIGNATURE
+ sig_to_usb)
+#else
+ ap_uart_output)
#endif
+#endif /* CONFIG_STREAM_USART1 */
#ifdef CONFIG_STREAM_USART2
struct usb_stream_config const ec_usb;
diff --git a/chip/g/usb_spi.c b/chip/g/usb_spi.c
index 34e23bc4c5..a5f6ddd175 100644
--- a/chip/g/usb_spi.c
+++ b/chip/g/usb_spi.c
@@ -14,6 +14,10 @@
#include "usb_spi.h"
#include "util.h"
+#ifdef CONFIG_STREAM_SIGNATURE
+#include "signing.h"
+#endif
+
#define CPUTS(outstr) cputs(CC_USB, outstr)
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
@@ -40,6 +44,15 @@ static uint16_t usb_spi_read_packet(struct usb_spi_config const *config)
static void usb_spi_write_packet(struct usb_spi_config const *config,
uint8_t count)
{
+#ifdef CONFIG_STREAM_SIGNATURE
+ /*
+ * This hook allows mn50 to sign SPI data read from newly
+ * manufactured H1 devieces. The data is added to a running
+ * hash until a completion message is received.
+ */
+ sig_append(stream_spi, config->buffer, count);
+#endif
+
QUEUE_ADD_UNITS(config->tx_queue, config->buffer, count);
}
diff --git a/chip/g/usb_spi.h b/chip/g/usb_spi.h
index b852310f1e..72364ab469 100644
--- a/chip/g/usb_spi.h
+++ b/chip/g/usb_spi.h
@@ -70,6 +70,8 @@ enum usb_spi_request {
USB_SPI_REQ_RESET = 0x0005,
USB_SPI_REQ_BOOT_CFG = 0x0006,
USB_SPI_REQ_SOCKET = 0x0007,
+ USB_SPI_REQ_SIGNING_START = 0x0008,
+ USB_SPI_REQ_SIGNING_SIGN = 0x0009,
};
/* USB SPI device bitmasks */
diff --git a/include/config.h b/include/config.h
index 9023a41502..5a5e232458 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2842,6 +2842,14 @@
/* USB Power monitoring interface config */
#undef CONFIG_USB_POWER
+/*****************************************************************************/
+/*
+ * USB stream signing config. This allows data read over UART or SPI
+ * to have a signature generated that can be used to validate the data
+ * offline based on H1's registered key. Used by mn50.
+ */
+#undef CONFIG_STREAM_SIGNATURE
+
/*****************************************************************************/