diff options
Diffstat (limited to 'include/u2f_impl.h')
-rw-r--r-- | include/u2f_impl.h | 296 |
1 files changed, 91 insertions, 205 deletions
diff --git a/include/u2f_impl.h b/include/u2f_impl.h index fa59424595..75e50cc6c7 100644 --- a/include/u2f_impl.h +++ b/include/u2f_impl.h @@ -9,246 +9,121 @@ #define __CROS_EC_U2F_IMPL_H #include "common.h" -#include "dcrypto.h" - -/* ---- platform cryptography hooks ---- */ - -#define U2F_MAX_KH_SIZE 128 /* Max size of key handle */ - -/* ---- 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; -}; - -/* 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 */ -}; +#include "dcrypto.h" -/* Origin seed is a random nonce generated during key handle creation. */ -#define U2F_ORIGIN_SEED_SIZE 32 -#define U2F_AUTHORIZATION_SALT_SIZE 16 +#include "tpm_vendor_cmds.h" +#include "u2f.h" -#define U2F_V0_KH_SIZE 64 +/* ---- Physical presence ---- */ -/* 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]; +enum touch_state { + POP_TOUCH_NO = 0, /* waiting for a user touch */ + POP_TOUCH_YES = 1, /* touch recorded and latched */ }; -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. +/* + * 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. */ -#define U2F_V1_KH_SIZE 113 +enum touch_state pop_check_presence(int consume); -/* Header is composed of version || origin_seed || kh_hmac */ -#define U2F_V1_KH_HEADER_SIZE (U2F_ORIGIN_SEED_SIZE + SHA256_DIGEST_SIZE + 1) +/* ---- non-volatile U2F state ---- */ -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; +struct u2f_state { + uint32_t salt[8]; + uint32_t salt_kek[8]; + uint32_t salt_kh[8]; }; -BUILD_ASSERT(sizeof(union u2f_key_handle_variant) <= U2F_MAX_KH_SIZE); - /** - * 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 - */ -enum ec_error_list u2f_generate_drbg_entropy(struct u2f_state *state); - -/** - * 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 + * Get the current u2f state from the board. */ -enum ec_error_list u2f_generate_hmac_key(struct u2f_state *state); +struct u2f_state *get_state(void); -/** - * 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); +/* ---- platform cryptography hooks ---- */ /** - * Create a randomized key handle for specified origin, user secret. - * Generate associated signing key. + * Pack the specified origin, user secret and origin-specific seed + * into a key handle. * - * @param state initialized u2f state * @param origin pointer to origin id * @param user pointer to user secret - * @param authTimeSecretHash authentication time secret - * @param kh output key handle header - * @param kh_version - key handle version to generate - * @param pubKey - generated public key + * @param seed pointer to origin-specific random seed + * @param key_handle buffer to hold the output key handle * - * @return EC_SUCCESS if successful + * @return EC_SUCCESS if a valid keypair was created. */ -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); +int u2f_origin_user_keyhandle(const uint8_t *origin, const uint8_t *user, + const uint8_t *seed, + struct u2f_key_handle *key_handle); /** - * Create a randomized key handle for specified origin, user secret. - * Generate associated signing key. + * Pack the specified origin, user secret, origin-specific seed and version + * byte into a key handle. * - * @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 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 + * @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 * - * @return EC_SUCCESS if a valid key pair was created - * EC_ACCESS_DENIED if key handle can't authenticated + * @return EC_SUCCESS if a valid keypair was created. */ -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); +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); /** - * 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). - * - * @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. + * Generate an origin and user-specific ECDSA keypair from the specified + * key handle. * - * @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(). - * - * @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. - */ -size_t g2f_attestation_cert_serial(const struct u2f_state *state, - const uint8_t *serial, uint8_t *buf); - -/** - * 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 + * If pk_x and pk_y are NULL, public key generation will be skipped. * - * @param r part of generated signature - * @param s part of generated signature + * @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 public key matches key handle, - * (r,s) set to valid signature - * EC_ACCESS_DENIED if key handle can't authenticated + * @return EC_SUCCESS if a valid keypair was created. */ -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); - +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); /** - * - * Board U2F key management part implemented. - * + * 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. */ +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); -/** - * Get the current u2f state from the board. +/*** + * Generate a hardware derived 256b private key. * - * @return pointer to static state if successful, NULL otherwise + * @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. */ -struct u2f_state *u2f_get_state(void); +int u2f_gen_kek(const uint8_t *origin, uint8_t *kek, size_t key_len); /** - * Try to load U2F keys or create if failed. + * Generate a hardware derived ECDSA keypair for individual attestation. * - * @param state - buffer for state to load/create - * @param force_create - if true, always create all keys + * @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 true if state is properly initialized and will persist in flash. + * @return EC_SUCCESS if a valid keypair was created. */ -bool u2f_load_or_create_state(struct u2f_state *state, bool force_create); +int g2f_individual_keypair(p256_int *d, p256_int *pk_x, p256_int *pk_y); /*** * Generates and persists to nvram a new seed that will be used to @@ -258,22 +133,33 @@ bool u2f_load_or_create_state(struct u2f_state *state, bool force_create); * @return EC_SUCCESS if seed was successfully created * (and persisted if requested). */ -enum ec_error_list u2f_gen_kek_seed(int commit); +int u2f_gen_kek_seed(int commit); + +/* Maximum size in bytes of G2F attestation certificate. */ +#define G2F_ATTESTATION_CERT_MAX_LEN 315 /** - * Zeroize U2F keys. Can be used to switch to FIPS-compliant path by - * destroying old keys. + * Gets the x509 certificate for the attestation keypair returned + * by g2f_individual_keypair(). * - * @return true if state is properly initialized and will persist in flash. + * @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. */ -enum ec_error_list u2f_zeroize_keys(void); +int g2f_attestation_cert(uint8_t *buf); /** - * Update keys to a newer (FIPS-compliant) version if needed. Do nothing if - * keys are already updated. - * - * @return EC_SUCCESS or error code. + * 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. */ -enum ec_error_list u2f_update_keys(void); +enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, void *buf, + size_t input_size, size_t *response_size); #endif /* __CROS_EC_U2F_IMPL_H */ |