summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2017-06-21 13:10:57 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-30 16:02:50 -0700
commit282765fdd409fd16ed1e092e5d7fee8de5af7a5a (patch)
tree6ba38fa099ef790c72d34f1caa458bd731aa39d3 /common
parent4a8b509020ce5104abf9b43335283cb39c7b75b2 (diff)
downloadchrome-ec-282765fdd409fd16ed1e092e5d7fee8de5af7a5a.tar.gz
common: Add RMA reset auth challenge-response crypto
RMA auth uses X25519 to generate a relatively small challenge and response. Currently, nothing calls the rma_auth code. We'll need console and TPM vendor commands to do so. BUG=b:37952913 BRANCH=none TEST=make buildall Change-Id: Iec7f2d0e3dc8243f79b009ead16bb3ba9f1bef9d Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/544184
Diffstat (limited to 'common')
-rw-r--r--common/build.mk1
-rw-r--r--common/rma_auth.c123
2 files changed, 124 insertions, 0 deletions
diff --git a/common/build.mk b/common/build.mk
index d264c6c2e5..9954798988 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -81,6 +81,7 @@ common-$(CONFIG_POWER_BUTTON_X86)+=power_button_x86.o
common-$(CONFIG_PSTORE)+=pstore_commands.o
common-$(CONFIG_PWM)+=pwm.o
common-$(CONFIG_PWM_KBLIGHT)+=pwm_kblight.o
+common-$(CONFIG_RMA_AUTH)+=rma_auth.o
common-$(CONFIG_RSA)+=rsa.o
common-$(CONFIG_ROLLBACK)+=rollback.o
common-$(CONFIG_RWSIG)+=rwsig.o
diff --git a/common/rma_auth.c b/common/rma_auth.c
new file mode 100644
index 0000000000..f178524927
--- /dev/null
+++ b/common/rma_auth.c
@@ -0,0 +1,123 @@
+/* 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.
+ */
+
+/* RMA authorization challenge-response */
+
+#include "common.h"
+#include "base32.h"
+#include "chip/g/board_id.h"
+#include "curve25519.h"
+#include "rma_auth.h"
+#include "sha256.h"
+#include "system.h"
+#include "timer.h"
+#include "util.h"
+
+/* Minimum time since system boot or last challenge before making a new one */
+#define CHALLENGE_INTERVAL (10 * SECOND)
+
+/* Number of tries to properly enter auth code */
+#define MAX_AUTHCODE_TRIES 3
+
+/* Server public key and key ID */
+static const uint8_t server_pub_key[32] = CONFIG_RMA_AUTH_SERVER_PUBLIC_KEY;
+static const uint8_t server_key_id = CONFIG_RMA_AUTH_SERVER_KEY_ID;
+
+static char challenge[RMA_CHALLENGE_BUF_SIZE];
+static char authcode[RMA_AUTHCODE_BUF_SIZE];
+static int tries_left;
+static uint64_t last_challenge_time;
+
+/**
+ * Create a new RMA challenge/response
+ *
+ * @return EC_SUCCESS, EC_ERROR_TIMEOUT if too soon since the last challenge,
+ * or other non-zero error code.
+ */
+int rma_create_challenge(void)
+{
+ uint8_t temp[32]; /* Private key or HMAC */
+ uint8_t secret[32];
+ struct rma_challenge c;
+ struct board_id bid;
+ uint8_t *device_id;
+ uint8_t *cptr = (uint8_t *)&c;
+ uint64_t t;
+
+ /* Clear the current challenge and authcode, if any */
+ memset(challenge, 0, sizeof(challenge));
+ memset(authcode, 0, sizeof(authcode));
+
+ /* Rate limit challenges */
+ t = get_time().val;
+ if (t - last_challenge_time < CHALLENGE_INTERVAL)
+ return EC_ERROR_TIMEOUT;
+ last_challenge_time = t;
+
+ memset(&c, 0, sizeof(c));
+ c.version_key_id = RMA_CHALLENGE_VKID_BYTE(
+ RMA_CHALLENGE_VERSION, server_key_id);
+
+ if (read_board_id(&bid))
+ return EC_ERROR_UNKNOWN;
+ memcpy(c.board_id, &bid.type, sizeof(c.board_id));
+
+ if (system_get_chip_unique_id(&device_id) != sizeof(c.device_id))
+ return EC_ERROR_UNKNOWN;
+ memcpy(c.device_id, device_id, sizeof(c.device_id));
+
+ /* Calculate a new ephemeral key pair */
+ X25519_keypair(c.device_pub_key, temp);
+
+ /* Encode the challenge */
+ if (base32_encode(challenge, sizeof(challenge), cptr, 8 * sizeof(c), 9))
+ return EC_ERROR_UNKNOWN;
+
+ /* Calculate the shared secret */
+ X25519(secret, temp, server_pub_key);
+
+ /*
+ * Auth code is a truncated HMAC of the ephemeral public key, BoardID,
+ * and DeviceID. Those are all in the right order in the challenge
+ * struct, after the version/key id byte.
+ */
+ hmac_SHA256(temp, secret, sizeof(secret), cptr + 1, sizeof(c) - 1);
+ if (base32_encode(authcode, sizeof(authcode), temp,
+ RMA_AUTHCODE_CHARS * 5, 0))
+ return EC_ERROR_UNKNOWN;
+
+ tries_left = MAX_AUTHCODE_TRIES;
+ return EC_SUCCESS;
+}
+
+const char *rma_get_challenge(void)
+{
+ return challenge;
+}
+
+int rma_try_authcode(const char *code)
+{
+ int rv = EC_ERROR_INVAL;
+
+ /* Fail if out of tries */
+ if (!tries_left)
+ return EC_ERROR_ACCESS_DENIED;
+
+ if (safe_memcmp(authcode, code, RMA_AUTHCODE_CHARS)) {
+ /* Mismatch */
+ tries_left--;
+ } else {
+ rv = EC_SUCCESS;
+ tries_left = 0;
+ }
+
+ /* Clear challenge and response if out of tries */
+ if (!tries_left) {
+ memset(challenge, 0, sizeof(challenge));
+ memset(authcode, 0, sizeof(authcode));
+ }
+
+ return rv;
+}