summaryrefslogtreecommitdiff
path: root/include/u2f_impl.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/u2f_impl.h')
-rw-r--r--include/u2f_impl.h296
1 files changed, 205 insertions, 91 deletions
diff --git a/include/u2f_impl.h b/include/u2f_impl.h
index 75e50cc6c7..fa59424595 100644
--- a/include/u2f_impl.h
+++ b/include/u2f_impl.h
@@ -9,121 +9,246 @@
#define __CROS_EC_U2F_IMPL_H
#include "common.h"
-
#include "dcrypto.h"
-#include "tpm_vendor_cmds.h"
-#include "u2f.h"
+/* ---- platform cryptography hooks ---- */
-/* ---- Physical presence ---- */
+#define U2F_MAX_KH_SIZE 128 /* Max size of key handle */
-enum touch_state {
- POP_TOUCH_NO = 0, /* waiting for a user touch */
- POP_TOUCH_YES = 1, /* touch recorded and latched */
+/* ---- non-volatile U2F state, shared with common code ---- */
+struct u2f_state {
+ /* G2F key gen seed. */
+ uint32_t salt[8];
+ /* HMAC key for U2F key handle authentication. */
+ uint32_t hmac_key[SHA256_DIGEST_SIZE / sizeof(uint32_t)];
+ /* Stored DRBG entropy. */
+ uint32_t drbg_entropy[16];
+ size_t drbg_entropy_size;
};
-/*
- * Check whether the user presence event was latched.
- *
- * @param consume reset the latched touch event and the presence LED.
- * @return POP_TOUCH_NO or POP_TOUCH_YES.
+/* Forward declarations to reduce dependencies. */
+/* EC (uncompressed) point */
+#define U2F_EC_KEY_SIZE P256_NBYTES /* EC key size in bytes */
+#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) /* Size of EC point */
+
+#define U2F_POINT_UNCOMPRESSED 0x04 /* Uncompressed point format */
+
+struct u2f_ec_point {
+ uint8_t pointFormat; /* Point type */
+ uint8_t x[U2F_EC_KEY_SIZE]; /* X-value */
+ uint8_t y[U2F_EC_KEY_SIZE]; /* Y-value */
+};
+
+BUILD_ASSERT(sizeof(struct u2f_ec_point) == U2F_EC_POINT_SIZE);
+
+struct u2f_signature {
+ uint8_t sig_r[U2F_EC_KEY_SIZE]; /* Signature */
+ uint8_t sig_s[U2F_EC_KEY_SIZE]; /* Signature */
+};
+
+/* Origin seed is a random nonce generated during key handle creation. */
+#define U2F_ORIGIN_SEED_SIZE 32
+#define U2F_AUTHORIZATION_SALT_SIZE 16
+
+#define U2F_V0_KH_SIZE 64
+
+/* Key handle version = 0, only bound to device. */
+struct u2f_key_handle_v0 {
+ uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
+ uint8_t hmac[SHA256_DIGEST_SIZE];
+};
+
+BUILD_ASSERT(sizeof(struct u2f_key_handle_v0) <= U2F_MAX_KH_SIZE);
+BUILD_ASSERT(sizeof(struct u2f_key_handle_v0) == U2F_V0_KH_SIZE);
+
+/**
+ * Key handle version = 1 for WebAuthn, bound to device and user.
*/
-enum touch_state pop_check_presence(int consume);
+#define U2F_V1_KH_SIZE 113
-/* ---- non-volatile U2F state ---- */
+/* Header is composed of version || origin_seed || kh_hmac */
+#define U2F_V1_KH_HEADER_SIZE (U2F_ORIGIN_SEED_SIZE + SHA256_DIGEST_SIZE + 1)
-struct u2f_state {
- uint32_t salt[8];
- uint32_t salt_kek[8];
- uint32_t salt_kh[8];
+struct u2f_key_handle_v1 {
+ uint8_t version;
+ uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
+ uint8_t kh_hmac[SHA256_DIGEST_SIZE];
+ /* Optionally checked in u2f_sign. */
+ uint8_t authorization_salt[U2F_AUTHORIZATION_SALT_SIZE];
+ uint8_t authorization_hmac[SHA256_DIGEST_SIZE];
+};
+
+BUILD_ASSERT(sizeof(struct u2f_key_handle_v1) <= U2F_MAX_KH_SIZE);
+BUILD_ASSERT(sizeof(struct u2f_key_handle_v1) == U2F_V1_KH_SIZE);
+
+union u2f_key_handle_variant {
+ struct u2f_key_handle_v0 v0;
+ struct u2f_key_handle_v1 v1;
};
+BUILD_ASSERT(sizeof(union u2f_key_handle_variant) <= U2F_MAX_KH_SIZE);
+
/**
- * Get the current u2f state from the board.
+ * Create or update DRBG entropy in U2F state. Used when changing ownership
+ * to cryptographically discard previously generated keys.
+ *
+ * @param state u2f state to update
+ *
+ * @return EC_SUCCESS if successful
*/
-struct u2f_state *get_state(void);
+enum ec_error_list u2f_generate_drbg_entropy(struct u2f_state *state);
-/* ---- platform cryptography hooks ---- */
+/**
+ * Create or update HMAC key in U2F state. Used when changing ownership to
+ * cryptographically discard previously generated keys.
+ *
+ * @param state u2f state to update
+ *
+ * @return EC_SUCCESS if successful
+ */
+enum ec_error_list u2f_generate_hmac_key(struct u2f_state *state);
/**
- * Pack the specified origin, user secret and origin-specific seed
- * into a key handle.
+ * Create or update G2F secret in U2F state.
+ *
+ * @param state u2f state to update
*
+ * @return EC_SUCCESS if successful
+ */
+enum ec_error_list u2f_generate_g2f_secret(struct u2f_state *state);
+
+/**
+ * Create a randomized key handle for specified origin, user secret.
+ * Generate associated signing key.
+ *
+ * @param state initialized u2f state
* @param origin pointer to origin id
* @param user pointer to user secret
- * @param seed pointer to origin-specific random seed
- * @param key_handle buffer to hold the output key handle
+ * @param authTimeSecretHash authentication time secret
+ * @param kh output key handle header
+ * @param kh_version - key handle version to generate
+ * @param pubKey - generated public key
*
- * @return EC_SUCCESS if a valid keypair was created.
+ * @return EC_SUCCESS if successful
*/
-int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user,
- const uint8_t *seed,
- struct u2f_key_handle *key_handle);
+enum ec_error_list u2f_generate(const struct u2f_state *state,
+ const uint8_t *user, const uint8_t *origin,
+ const uint8_t *authTimeSecretHash,
+ union u2f_key_handle_variant *kh,
+ uint8_t kh_version,
+ struct u2f_ec_point *pubKey);
/**
- * Pack the specified origin, user secret, origin-specific seed and version
- * byte into a key handle.
+ * Create a randomized key handle for specified origin, user secret.
+ * Generate associated signing key.
*
+ * @param state initialized u2f state
+ * @param kh output key handle header
+ * @param kh_version - key handle version to generate
* @param origin pointer to origin id
* @param user pointer to user secret
- * @param seed pointer to origin-specific random seed
- * @param version the version byte to pack; should be greater than 0.
- * @param key_handle_header buffer to hold the output key handle header
+ * @param authTimeSecretHash pointer to user's authentication secret.
+ * can be set to NULL if authorization_hmac check is not needed.
+ * @param r - generated part of signature
+ * @param s - generated part of signature
*
- * @return EC_SUCCESS if a valid keypair was created.
+ * @return EC_SUCCESS if a valid key pair was created
+ * EC_ACCESS_DENIED if key handle can't authenticated
*/
-int u2f_origin_user_versioned_keyhandle(
- const uint8_t *origin, const uint8_t *user, const uint8_t *seed,
- uint8_t version,
- struct u2f_versioned_key_handle_header *key_handle_header);
+enum ec_error_list u2f_sign(const struct u2f_state *state,
+ const union u2f_key_handle_variant *kh,
+ uint8_t kh_version, const uint8_t *user,
+ const uint8_t *origin,
+ const uint8_t *authTimeSecretHash,
+ const uint8_t *hash, struct u2f_signature *sig);
/**
- * Generate an origin and user-specific ECDSA keypair from the specified
- * key handle.
+ * Verify that key handle matches provided origin, user and user's
+ * authentication secret and was created on this device (signed with
+ * U2F state HMAC key).
*
- * If pk_x and pk_y are NULL, public key generation will be skipped.
+ * @param state initialized u2f state
+ * @param kh input key handle
+ * @param kh_version - key handle version to verify
+ * @param user pointer to user secret
+ * @param origin pointer to origin id
+ * @param authTimeSecretHash pointer to user's authentication secret.
+ * can be set to NULL if authorization_hmac check is not needed.
*
- * @param key_handle pointer to the key handle
- * @param key_handle_size size of the key handle in bytes
- * @param d pointer to ECDSA private key
- * @param pk_x pointer to public key point
- * @param pk_y pointer to public key point
+ * @return EC_SUCCESS if handle can be authenticated
+ */
+enum ec_error_list u2f_authorize_keyhandle(const struct u2f_state *state,
+ const union u2f_key_handle_variant *kh,
+ uint8_t kh_version, const uint8_t *user,
+ const uint8_t *origin,
+ const uint8_t *authTimeSecretHash);
+
+/**
+ * Gets the x509 certificate for the attestation key pair returned
+ * by g2f_individual_keypair().
*
- * @return EC_SUCCESS if a valid keypair was created.
+ * @param state U2F state parameters
+ * @param serial Device serial number
+ * @param buf pointer to a buffer that must be at least
+ *
+ * G2F_ATTESTATION_CERT_MAX_LEN bytes.
+ * @return size of certificate written to buf, 0 on error.
*/
-int u2f_origin_user_keypair(const uint8_t *key_handle, size_t key_handle_size,
- p256_int *d, p256_int *pk_x, p256_int *pk_y);
+size_t g2f_attestation_cert_serial(const struct u2f_state *state,
+ const uint8_t *serial, uint8_t *buf);
/**
- * Derive an hmac from the given salt, key handle and hash. The salt is to make
- * sure the hmac is different for different key handles of one user. The key
- * handle header is encoded into the authorization hmac to protect against
- * swapping auth time secret.
+ * Verify that provided key handle and public key match.
+ * @param state U2F state parameters
+ * @param key_handle key handle
+ * @param kh_version key handle version (0 - legacy, 1 - versioned)
+ * @param user pointer to user secret
+ * @param origin pointer to origin id
+ * @param authTimeSecretHash pointer to user's authentication secret.
+ * can be set to NULL if authorization_hmac check is not needed.
+ * @param public_key pointer to public key point (big endian)
+ * @param data data to sign
+ * @param data_size data size in bytes
+ *
+ * @param r part of generated signature
+ * @param s part of generated signature
+ *
+ * @return EC_SUCCESS if public key matches key handle,
+ * (r,s) set to valid signature
+ * EC_ACCESS_DENIED if key handle can't authenticated
*/
-int u2f_authorization_hmac(const uint8_t *authorization_salt,
- const struct u2f_versioned_key_handle_header *header,
- const uint8_t *auth_time_secret_hash, uint8_t *hmac);
+enum ec_error_list u2f_attest(const struct u2f_state *state,
+ const union u2f_key_handle_variant *kh,
+ uint8_t kh_version, const uint8_t *user,
+ const uint8_t *origin,
+ const uint8_t *authTimeSecretHash,
+ const struct u2f_ec_point *public_key,
+ const uint8_t *data, size_t data_size,
+ struct u2f_signature *sig);
-/***
- * Generate a hardware derived 256b private key.
+
+/**
+ *
+ * Board U2F key management part implemented.
*
- * @param kek ptr to store the generated key.
- * @param key_len size of the storage buffer. Should be 32 bytes.
- * @return EC_SUCCESS if a valid key was created.
*/
-int u2f_gen_kek(const uint8_t *origin, uint8_t *kek, size_t key_len);
/**
- * Generate a hardware derived ECDSA keypair for individual attestation.
+ * Get the current u2f state from the board.
*
- * @param seed ptr to store 32-byte seed to regenerate this key on this chip
- * @param d pointer to ECDSA private key
- * @param pk_x pointer to public key point
- * @param pk_y pointer to public key point
+ * @return pointer to static state if successful, NULL otherwise
+ */
+struct u2f_state *u2f_get_state(void);
+
+/**
+ * Try to load U2F keys or create if failed.
*
- * @return EC_SUCCESS if a valid keypair was created.
+ * @param state - buffer for state to load/create
+ * @param force_create - if true, always create all keys
+ *
+ * @return true if state is properly initialized and will persist in flash.
*/
-int g2f_individual_keypair(p256_int *d, p256_int *pk_x, p256_int *pk_y);
+bool u2f_load_or_create_state(struct u2f_state *state, bool force_create);
/***
* Generates and persists to nvram a new seed that will be used to
@@ -133,33 +258,22 @@ int g2f_individual_keypair(p256_int *d, p256_int *pk_x, p256_int *pk_y);
* @return EC_SUCCESS if seed was successfully created
* (and persisted if requested).
*/
-int u2f_gen_kek_seed(int commit);
-
-/* Maximum size in bytes of G2F attestation certificate. */
-#define G2F_ATTESTATION_CERT_MAX_LEN 315
+enum ec_error_list u2f_gen_kek_seed(int commit);
/**
- * Gets the x509 certificate for the attestation keypair returned
- * by g2f_individual_keypair().
+ * Zeroize U2F keys. Can be used to switch to FIPS-compliant path by
+ * destroying old keys.
*
- * @param buf pointer to a buffer that must be at least
- * G2F_ATTESTATION_CERT_MAX_LEN bytes.
- * @return size of certificate written to buf, 0 on error.
+ * @return true if state is properly initialized and will persist in flash.
*/
-int g2f_attestation_cert(uint8_t *buf);
+enum ec_error_list u2f_zeroize_keys(void);
/**
- * U2F_GENERATE command handler. Generates a key handle according to input
- * parameters.
- */
-enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, void *buf,
- size_t input_size, size_t *response_size);
-
-/**
- * U2F_SIGN command handler. Verifies a key handle is owned and signs data with
- * it.
+ * Update keys to a newer (FIPS-compliant) version if needed. Do nothing if
+ * keys are already updated.
+ *
+ * @return EC_SUCCESS or error code.
*/
-enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf,
- size_t input_size, size_t *response_size);
+enum ec_error_list u2f_update_keys(void);
#endif /* __CROS_EC_U2F_IMPL_H */