Files
OpenCellular/common/rma_auth.c
Randall Spangler 282765fdd4 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
2017-06-30 16:02:50 -07:00

124 lines
3.2 KiB
C

/* 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;
}