summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Collard <louiscollard@chromium.org>2019-08-12 15:54:40 +0800
committerCommit Bot <commit-bot@chromium.org>2019-08-23 09:09:16 +0000
commit84ba4bb756187dac279c70fe6915e3437199d040 (patch)
tree0a8533067c025cc679897c09878e4046501f98b1
parentbfdf551cf25c51f0781d1e8e5aeb395c5213ba7c (diff)
downloadchrome-ec-84ba4bb756187dac279c70fe6915e3437199d040.tar.gz
cr50: Delete legacy U2F implementation
This implementation has been replaced, and is no longer needed. Removing it frees 2376 bytes in flash. BRANCH=none BUG=b:138578925 TEST=test_that ... firmware_IntegratedU2F Signed-off-by: Louis Collard <louiscollard@chromium.org> Change-Id: Id5b2009bb1b56ae25de9173acb5d5e67eaf1caa3 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1748847 Reviewed-by: Andrey Pronin <apronin@chromium.org>
-rw-r--r--board/cr50/u2f.c56
-rw-r--r--common/u2f.c312
-rw-r--r--include/u2f.h46
-rw-r--r--include/u2f_impl.h19
4 files changed, 1 insertions, 432 deletions
diff --git a/board/cr50/u2f.c b/board/cr50/u2f.c
index 9ac009c7d1..038a990b43 100644
--- a/board/cr50/u2f.c
+++ b/board/cr50/u2f.c
@@ -173,21 +173,6 @@ int use_g2f(void)
return use_u2f() && u2f_mode == MODE_U2F_EXTENDED;
}
-unsigned u2f_custom_dispatch(uint8_t ins, struct apdu apdu,
- uint8_t *buf, unsigned *ret_len)
-{
- if (ins == U2F_VENDOR_MODE) {
- if (apdu.p1) { /* Set mode */
- u2f_mode = apdu.p2;
- }
- /* return the current mode */
- buf[0] = use_u2f() ? u2f_mode : 0;
- *ret_len = 1;
- return U2F_SW_NO_ERROR;
- }
- return U2F_SW_INS_NOT_SUPPORTED;
-}
-
static enum vendor_cmd_rc set_u2f_mode(enum vendor_cmd_cc code, void *buf,
size_t input_size, size_t *response_size)
{
@@ -222,23 +207,6 @@ static int _derive_key(enum dcrypto_appid appid, const uint32_t input[8],
return result;
}
-int u2f_origin_keypair(uint8_t *seed, p256_int *d,
- p256_int *pk_x, p256_int *pk_y)
-{
- uint32_t tmp[P256_NDIGITS];
-
- do {
- if (!DCRYPTO_ladder_random(seed))
- return EC_ERROR_UNKNOWN;
- memcpy(tmp, seed, sizeof(tmp));
- if (!_derive_key(U2F_ORIGIN, tmp, tmp))
- return EC_ERROR_UNKNOWN;
- } while (
- !DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, (const uint8_t *)tmp));
-
- return EC_SUCCESS;
-}
-
int u2f_origin_key(const uint8_t *seed, p256_int *d)
{
uint32_t tmp[P256_NDIGITS];
@@ -341,27 +309,3 @@ int u2f_gen_kek_seed(int commit)
return EC_SUCCESS;
}
-
-/* ---- Send/receive U2F APDU over TPM vendor commands ---- */
-
-static enum vendor_cmd_rc vc_u2f_apdu(enum vendor_cmd_cc code, void *body,
- size_t cmd_size, size_t *response_size)
-{
- unsigned retlen;
-
- if (!use_u2f()) { /* the feature is disabled */
- uint8_t *cmd = body;
- /* process it only if the host tries to enable the feature */
- if (cmd_size < 2 || cmd[1] != U2F_VENDOR_MODE) {
- *response_size = 0;
- return VENDOR_RC_NO_SUCH_COMMAND;
- }
- }
-
- /* Process U2F APDU */
- retlen = u2f_apdu_rcv(body, cmd_size, *response_size);
-
- *response_size = retlen;
- return VENDOR_RC_SUCCESS;
-}
-DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_APDU, vc_u2f_apdu);
diff --git a/common/u2f.c b/common/u2f.c
index c5114431fd..b79a998e62 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -10,7 +10,6 @@
#include "cryptoc/sha256.h"
#include "dcrypto.h"
#include "extension.h"
-#include "nvcounter.h"
#include "system.h"
#include "u2f_impl.h"
#include "u2f.h"
@@ -24,17 +23,6 @@
#define AES_BLOCK_LEN 16
#define KH_LEN 64
-/* Interleave bytes of two 32 byte arrays */
-static void interleave32(const uint8_t *a, const uint8_t *b, uint8_t *out)
-{
- size_t i;
-
- for (i = 0; i < 32; ++i) {
- out[2 * i + 0] = a[i];
- out[2 * i + 1] = b[i];
- }
-}
-
/* De-interleave 64 bytes into two 32 arrays. */
static void deinterleave64(const uint8_t *in, uint8_t *a, uint8_t *b)
{
@@ -67,12 +55,6 @@ static int wrap_kh(const uint8_t *origin, const uint8_t *in,
return EC_SUCCESS;
}
-static int anonymous_cert(const p256_int *d, const p256_int *pk_x,
- const p256_int *pk_y, uint8_t *cert, const int n)
-{
- return DCRYPTO_x509_gen_u2f_cert(d, pk_x, pk_y, NULL, cert, n);
-}
-
static int individual_cert(const p256_int *d, const p256_int *pk_x,
const p256_int *pk_y, uint8_t *cert, const int n)
{
@@ -100,300 +82,6 @@ int g2f_attestation_cert(uint8_t *buf)
buf, G2F_ATTESTATION_CERT_MAX_LEN);
}
-static unsigned u2f_version(struct apdu apdu, void *buf, unsigned *ret_len,
- unsigned max_len)
-{
- static const char version[] = "U2F_V2";
-
- if (apdu.len || max_len < sizeof(version) - 1)
- return U2F_SW_WRONG_LENGTH;
-
- memcpy(buf, version, sizeof(version) - 1 /* not ending zero */);
- *ret_len = sizeof(version) - 1;
-
- return U2F_SW_NO_ERROR;
-}
-
-/* U2F REGISTER command */
-static unsigned u2f_register(struct apdu apdu, void *buf,
- unsigned *ret_len, unsigned max_len)
-{
- const U2F_REGISTER_REQ *req = (const U2F_REGISTER_REQ *)apdu.data;
- U2F_REGISTER_RESP *resp;
- int l, m_off; /* msg length and interior offset */
-
- p256_int r, s; /* ecdsa signature */
- struct drbg_ctx ctx;
- /* Origin keypair */
- uint8_t od_seed[SHA256_DIGEST_SIZE];
- p256_int od, opk_x, opk_y;
- /* KDF, Key handle */
- HASH_CTX sha;
- uint8_t kh[U2F_APPID_SIZE + sizeof(p256_int)];
- uint8_t tmp[U2F_APPID_SIZE + sizeof(p256_int)];
- /* sha256({RFU, app ID, nonce, keyhandle, public key}) */
- p256_int h;
- const uint8_t rfu = U2F_REGISTER_HASH_ID;
- const uint8_t pk_start = U2F_POINT_UNCOMPRESSED;
- p256_int att_d;
- int cert_len;
- const int cert_max_len = max_len - sizeof(kh)
- - offsetof(U2F_REGISTER_RESP, keyHandleCertSig);
-
- if (apdu.len != sizeof(U2F_REGISTER_REQ)) {
- CPRINTF("#ERR REGISTER wrong length");
- return U2F_SW_WRONG_LENGTH;
- }
-
- /* Check user presence, w/ optional consume */
- if (pop_check_presence(apdu.p1 & G2F_CONSUME) != POP_TOUCH_YES &&
- (apdu.p1 & U2F_AUTH_FLAG_TUP) != 0) {
- return U2F_SW_CONDITIONS_NOT_SATISFIED;
- }
-
- /* Generate origin-specific keypair */
- if (u2f_origin_keypair(od_seed, &od, &opk_x, &opk_y) !=
- EC_SUCCESS) {
- CPRINTF("#ERR Origin-specific keypair generation failed");
- return U2F_SW_WTF + 1;
- }
-
- /* Generate key handle */
- /* Interleave origin ID, origin priv key, wrap and export. */
- interleave32(req->appId, od_seed, tmp);
- if (wrap_kh(req->appId, tmp, kh, ENCRYPT_MODE) != EC_SUCCESS)
- return U2F_SW_WTF + 2;
-
- /* Response message hash for signing */
- DCRYPTO_SHA256_init(&sha, 0);
- HASH_update(&sha, &rfu, sizeof(rfu));
- HASH_update(&sha, req->appId, U2F_APPID_SIZE);
- HASH_update(&sha, req->chal, U2F_CHAL_SIZE);
- HASH_update(&sha, kh, sizeof(kh));
- HASH_update(&sha, &pk_start, sizeof(pk_start));
-
- /*
- * From this point: the request 'req' content is invalid as it is
- * overridden by the response we are building in the same buffer.
- */
- resp = buf;
-
- /* Insert origin-specific public keys into the response */
- p256_to_bin(&opk_x, resp->pubKey.x); /* endianness */
- p256_to_bin(&opk_y, resp->pubKey.y); /* endianness */
- HASH_update(&sha, resp->pubKey.x, sizeof(p256_int));
- HASH_update(&sha, resp->pubKey.y, sizeof(p256_int));
- p256_from_bin(HASH_final(&sha), &h);
-
- /* Construct remainder of the response */
- resp->registerId = U2F_REGISTER_ID;
- l = sizeof(resp->registerId);
- resp->pubKey.pointFormat = U2F_POINT_UNCOMPRESSED;
- l += sizeof(resp->pubKey);
- resp->keyHandleLen = sizeof(kh);
- l += sizeof(resp->keyHandleLen);
- memcpy(resp->keyHandleCertSig, kh, sizeof(kh));
- l += sizeof(kh);
- m_off = sizeof(kh);
-
- if (use_g2f() && apdu.p1 & G2F_ATTEST) {
- /* Use a hw-derived keypair for Individual attestation */
- if (g2f_individual_keypair(&att_d, &opk_x, &opk_y)) {
- CPRINTF("#ERR Attestation key generation failed");
- return U2F_SW_WTF + 3;
- }
- cert_len = individual_cert(&att_d, &opk_x, &opk_y,
- resp->keyHandleCertSig + m_off, cert_max_len);
- } else {
- /* Anon attestation keypair; use origin key to self-sign */
- cert_len = anonymous_cert(&od, &opk_x, &opk_y,
- resp->keyHandleCertSig + m_off, cert_max_len);
- att_d = od;
- }
- if (cert_len == 0)
- return U2F_SW_WTF + 4;
-
- l += cert_len;
- m_off += cert_len;
-
- /* Sign over the response w/ the attestation key */
- hmac_drbg_init_rfc6979(&ctx, &att_d, &h);
- if (!dcrypto_p256_ecdsa_sign(&ctx, &att_d, &h, &r, &s)) {
- p256_clear(&att_d);
- p256_clear(&od);
- CPRINTF("#ERR signing error");
- return U2F_SW_WTF + 5;
- }
- p256_clear(&att_d);
- p256_clear(&od);
-
- /* Signature -> ASN.1 DER encoded bytes */
- l += DCRYPTO_asn1_sigp(resp->keyHandleCertSig + m_off, &r, &s);
-
- *ret_len = l;
-
- return U2F_SW_NO_ERROR; /* APDU success */
-}
-
-static unsigned u2f_authenticate(struct apdu apdu, void *buf,
- unsigned *ret_len, unsigned max_len)
-{
- const U2F_AUTHENTICATE_REQ *req = (const void *)apdu.data;
- U2F_AUTHENTICATE_RESP *resp;
- uint8_t unwrapped_kh[KH_LEN];
- uint8_t od_seed[SHA256_DIGEST_SIZE];
- struct drbg_ctx ctx;
-
- p256_int origin_d;
- uint8_t origin[U2F_APPID_SIZE];
-
- HASH_CTX sha;
- p256_int h, r, s;
- unsigned sig_len;
-
- uint8_t flags;
- uint8_t ctr[U2F_CTR_SIZE];
- uint32_t count = 0;
-
- if (apdu.len != U2F_APPID_SIZE + U2F_CHAL_SIZE + 1 + KH_LEN) {
- CPRINTF("#ERR AUTHENTICATE wrong length %d", apdu.len);
- return U2F_SW_WRONG_LENGTH;
- }
-
- /* Unwrap key handle */
- if (wrap_kh(req->appId, req->keyHandle, unwrapped_kh, DECRYPT_MODE))
- return U2F_SW_WTF + 1;
- deinterleave64(unwrapped_kh, origin, od_seed);
-
- /* Check whether appId (i.e. origin) matches.
- * Constant time.
- */
- p256_from_bin(origin, &r);
- p256_from_bin(req->appId, &s);
- if (p256_cmp(&r, &s) != 0)
- return U2F_SW_WRONG_DATA;
-
- /* Origin check only? */
- if (apdu.p1 == U2F_AUTH_CHECK_ONLY)
- return U2F_SW_CONDITIONS_NOT_SATISFIED;
-
- /* Sense user presence, with optional consume */
- flags = pop_check_presence(apdu.p1 & G2F_CONSUME) == POP_TOUCH_YES;
-
- /* Mandatory user presence? */
- if ((apdu.p1 & U2F_AUTH_ENFORCE) != 0 && flags == 0)
- return U2F_SW_CONDITIONS_NOT_SATISFIED;
-
- /* Increment-only counter in flash. OK to share between origins. */
- count = nvcounter_incr();
- ctr[0] = (count >> 24) & 0xFF;
- ctr[1] = (count >> 16) & 0xFF;
- ctr[2] = (count >> 8) & 0xFF;
- ctr[3] = count & 0xFF;
-
- /* Message signature */
- DCRYPTO_SHA256_init(&sha, 0);
- HASH_update(&sha, req->appId, U2F_APPID_SIZE);
- HASH_update(&sha, &flags, sizeof(uint8_t));
- HASH_update(&sha, ctr, U2F_CTR_SIZE);
- HASH_update(&sha, req->chal, U2F_CHAL_SIZE);
- p256_from_bin(HASH_final(&sha), &h);
-
- if (u2f_origin_key(od_seed, &origin_d))
- return U2F_SW_WTF + 2;
-
- hmac_drbg_init_rfc6979(&ctx, &origin_d, &h);
- if (!dcrypto_p256_ecdsa_sign(&ctx, &origin_d, &h, &r, &s)) {
- p256_clear(&origin_d);
- return U2F_SW_WTF + 3;
- }
- p256_clear(&origin_d);
-
- /*
- * From this point: the request 'req' content is invalid as it is
- * overridden by the response we are building in the same buffer.
- * The response is smaller than the request, so we have the space.
- */
- resp = buf;
- resp->flags = flags;
- memcpy(resp->ctr, ctr, U2F_CTR_SIZE);
-
- sig_len = DCRYPTO_asn1_sigp(resp->sig, &r, &s);
-
- *ret_len = sizeof(resp->flags) + U2F_CTR_SIZE + sig_len;
- return U2F_SW_NO_ERROR;
-}
-
-unsigned u2f_apdu_rcv(uint8_t *buf, unsigned in_len, unsigned max_len)
-{
- unsigned ret_len = 0;
- uint16_t sw = U2F_SW_CLA_NOT_SUPPORTED;
- /*
- * APDU structure:
- * [CLA INS P1 P2 [LC1 [LC2 LC3 <request-data>]]]
- */
- uint8_t cla = buf[0];
- uint8_t ins = buf[1];
- struct apdu apdu = {
- .p1 = buf[2],
- .p2 = buf[3],
- .len = 0,
- .data = buf + 5
- };
-
- /* ISO7618 LC decoding */
- if (in_len >= 5)
- apdu.len = buf[4];
-
- if (apdu.len == 0 && in_len >= 7) {
- apdu.len = (buf[5] << 8) | buf[6];
- apdu.data += 2;
- }
-
- CPRINTF("%T/%d U2F APDU ", apdu.len);
- /* Is the APDU well-formed including its payload ? */
- if (in_len < 4 || (apdu.len > in_len - (apdu.data - buf))) {
- sw = U2F_SW_WRONG_LENGTH;
- goto ret_status;
- }
-
- if (cla == 0x00) { /* Always 0x00 */
- sw = U2F_SW_INS_NOT_SUPPORTED;
- max_len -= 2; /* reserve space for the status */
-
- switch (ins) {
- case (U2F_REGISTER):
- CPRINTF("REGISTER");
- sw = u2f_register(apdu, buf, &ret_len, max_len);
- break;
-
- case (U2F_AUTHENTICATE):
- CPRINTF("AUTHENTICATE");
- sw = u2f_authenticate(apdu, buf, &ret_len, max_len);
- break;
-
- case (U2F_VERSION):
- CPRINTF("VERSION");
- sw = u2f_version(apdu, buf, &ret_len, max_len);
- break;
- }
-
- /* Not a U2F INS. Try internal extensions next. */
- if (sw == U2F_SW_INS_NOT_SUPPORTED && u2f_custom_dispatch &&
- (use_g2f() || ins == U2F_VENDOR_MODE))
- sw = u2f_custom_dispatch(ins, apdu, buf, &ret_len);
- }
-
-ret_status:
- /* append SW status word */
- buf[ret_len++] = sw >> 8;
- buf[ret_len++] = sw;
-
- CPRINTF(" resp %04x len %d\n", sw, ret_len);
-
- return ret_len;
-}
-
/* U2F GENERATE command */
static enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code,
void *buf,
diff --git a/include/u2f.h b/include/u2f.h
index 1a445f8f4a..0f54dfc990 100644
--- a/include/u2f.h
+++ b/include/u2f.h
@@ -44,56 +44,12 @@ typedef struct {
uint8_t y[U2F_EC_KEY_SIZE]; // Y-value
} U2F_EC_POINT;
-// U2F native commands
-
-#define U2F_REGISTER 0x01 // Registration command
-#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command
-#define U2F_VERSION 0x03 // Read version string command
-
-#define U2F_VENDOR_FIRST 0x40 // First vendor defined command
-#define U2F_VENDOR_LAST 0xbf // Last vendor defined command
-
-// U2F_CMD_REGISTER command defines
-
-#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier
-#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier
-
-typedef struct {
- uint8_t chal[U2F_CHAL_SIZE]; // Challenge
- uint8_t appId[U2F_APPID_SIZE]; // Application id
-} U2F_REGISTER_REQ;
-
-typedef struct {
- uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2)
- U2F_EC_POINT pubKey; // Generated public key
- uint8_t keyHandleLen; // Length of key handle
- uint8_t keyHandleCertSig[
- U2F_MAX_KH_SIZE + // Key handle
- U2F_MAX_ATT_CERT_SIZE + // Attestation certificate
- U2F_MAX_EC_SIG_SIZE]; // Registration signature
-} U2F_REGISTER_RESP;
-
-// U2F_CMD_AUTHENTICATE command defines
-
-// Authentication control byte
+// Request Flags.
#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign
#define U2F_AUTH_CHECK_ONLY 0x07 // Check only
#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set
-typedef struct {
- uint8_t chal[U2F_CHAL_SIZE]; // Challenge
- uint8_t appId[U2F_APPID_SIZE]; // Application id
- uint8_t keyHandleLen; // Length of key handle
- uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle
-} U2F_AUTHENTICATE_REQ;
-
-typedef struct {
- uint8_t flags; // U2F_AUTH_FLAG_ values
- uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian)
- uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature
-} U2F_AUTHENTICATE_RESP;
-
// TODO(louiscollard): Add Descriptions.
typedef struct {
diff --git a/include/u2f_impl.h b/include/u2f_impl.h
index 41d4bf97bc..ec1fb3c16a 100644
--- a/include/u2f_impl.h
+++ b/include/u2f_impl.h
@@ -11,21 +11,6 @@
#include "common.h"
#include "cryptoc/p256.h"
-/* APDU fields to pass around */
-struct apdu {
- uint8_t p1;
- uint8_t p2;
- uint16_t len;
- const uint8_t *data;
-};
-
-/*
- * Parses an APDU-framed message according to the u2f protocol.
- *
- * @return 0 on failure, output buffer's byte count on success.
- */
-unsigned u2f_apdu_rcv(uint8_t *buffer, unsigned in_len, unsigned max_len);
-
/* ---- Physical presence ---- */
enum touch_state {
@@ -149,8 +134,4 @@ int g2f_attestation_cert(uint8_t *buf);
/* Use non-standard extensions to the U2F protocol */
int use_g2f(void);
-/* call extensions for unsupported U2F INS */
-unsigned u2f_custom_dispatch(uint8_t ins, struct apdu apdu, uint8_t *buf,
- unsigned *ret_len) __attribute__((weak));
-
#endif /* __CROS_EC_U2F_IMPL_H */