blob: a1faf6fc5ed52acbbc1ebc11e4817d85d0ee7b88 [file] [log] [blame] [view] [edit]
# Low-Entropy (LE) Credential Protection
This feature enables us to protect low-entropy credentials, which allows the UI
to offer PIN codes as an authentication mechanism for sign-in.
[TOC]
## Overview
LE secrets that need brute force protection are mapped to high-entropy secrets
that can be obtained via a rate-limited lookup enforced by the security module.
The high-entropy secret is then plugged into the actual authentication mechanism
used to implement sign-in. In other words, the released high-entropy secret is
used as the key to protect a VaultKeyset, which contains further secrets such as
the actual file system encryption key protecting encrypted user data.
The low-entropy credentials and related metadata (including the number of
unsuccessful authentication attempts to this point) are stored in an encrypted
form on disk. This ensures that the security module can enforce retry limits
against a compromised OS or hardware-level attacks while minimizing the storage
footprint in security module flash. The security module manages a number of
credential slots which are referred to by labels.
Cryptohome communicates with the security module to verify that the credential
presented by a user in an authentication attempt is correct. On success, the
security module releases the corresponding high-entropy secret to cryptohome.
Brute forcing is prevented by enforcing a cryptohome-defined delay schedule in
the security module firmware. This only allows a limited number of
authentication attempts for a specified timeframe (the delay schedule can also
set a hard limit on the number of unsuccessful attempts). Each time a correct LE
credential is provided, the number of unsuccessful attempts is reset to 0.
An LE secret which has been locked out (i.e all attempts exhausted) may be reset
by providing a separate high entropy reset credential to the LECredentialManager
class (this reset credential is generated, encrypted to a conventional password
for that user, and supplied when the LE secret is being set up). Presenting the
reset credential to the security module resets the attempts counter for the
credential, thus clearing the lockout and allowing the LE credential to be used
in subsequent authentication attempts.
## Hash tree
A hash tree is used by the security module to ensure integrity and track the
state of all the credentials' metadata. Each credential has its own hash tree
leaf, which is addressed by an integer label corresponding to its position in
the tree.
Using the hash tree we can obtain a root hash of the entire tree, and store that
in the security module. This allows us to capture the entire state of the
on-disk tree, using a single hash.
This hash is then used to verify the integrity of the state passed to the
security module while performing authentication/insert/reset operations. Since
it is stored in the NVRAM of the security module, it can't be manipulated by the
OS or attackers. Hardware attacks are hard since they will require decapping the
chip.
For more information on hash trees, see
https://en.wikipedia.org/wiki/Merkle_tree .
## Relevant classes
A diagram can be used to illustrate the various classes and their relation.
```
LECredentialManager
/ \
/ \
/ \
/ \
SignInHashTree LECredentialBackend
|
|
|
|
PersistentLookupTable
```
### PersistentLookupTable
This class provides a key-value like storage. The key is a uint64_t, and the
value is a binary blob which contains data in a caller-determined format. The
class aims to provide an atomic storage solution for its entries; updates to the
table will either be correctly recorded or will have no effect. So, the table
will always be in a valid state (without partial updates).
It provides an API that allows values to be Stored, Retrieved and Removed, and
is used by the SignInHashTree.
### SignInHashTree
This class stores and manages the various credentials and labels used by the
LECredentialManager on disk. As the implementation of the hash tree concept, it
not only represents the leaf nodes of the hash tree, but also keeps track of all
the inner-nodes' hash values.
Using PersistentLookupTable, it stores an encrypted blob containing the metadata
associated with an LE credential. It also stores alongside it a MAC which has
been calculated on the metadata. The MACs are used during root hash
calculations. Both of these are expected to be provided by the caller.
Logically, the PersistentLookupTable can be thought of as storing all the leaf
nodes of the hash tree.
The hash tree is defined by two parameters:
- The fan-out, i.e the number of children of a node.
- The length (in terms of bits) of a leaf node label.
These two parameters can be used to determine the layout of the hash tree. This
helps to understand:
- How a root hash is calculated.
- What are the hash values that are required, given a particular leaf node, to
recalculate a root hash.
The SignInHashTree also contains a HashCache file. This file stores the inner
node hash values, and helps avoid recalculation of these values with each
authentication attempt. The HashCache file is redundant, and should be
regenerated if there is any discrepancy detected between it and the leaf nodes
and/or the state on security module.
### LECredentialBackend
This is an interface used to communicate with the security module to perform the
LE Credential operations. The LECredentialBackend will expose the following
functionality provided by the security module:
- Validate a credential.
- Enforce the delay schedule provided during credential creation.
- Encrypt and return the credential metadata.
- Store, update and provide an operation log, to be used in case of state
mis-match with on-disk state.
### LECredentialManager
This class uses both the SignInHashTree and LeCredentialBackend to provide an
interface that cryptohome can use to Add, Check, Reset and Remove an LE
Credential.
It provides support for the following operations:
- InsertCredential: Provided an LE Secret, the high-entropy secret it is
guarding, a reset credential which is used to unlock a locked-out LE secret
and a delay schedule, it stores the resulting credential and returns a
uint64_t label which can be used by cryptohome to reference the credential.
- CheckCredential: Attempts authentication of a user. It is provided the label
of the credential to verify, and the user-supplied secret, and on success
returns the corresponding high entropy secret.
- RemoveCredential: Given a label, removes that credential from the hash tree,
and updates the security module's state to reflect that.
- ResetCredential: TODO(https://crbug.com/809723)
## Key derivation
### LE secret
The generation of the LE secret which is stored by the pinweaver manager can
be best illustrated by the following diagram:
Definitions:
- `VKK`: VaultKeyset Key
- `VKK IV`: VKK Initialization Vector
- `VK`: VaultKeyset
```
LE Salt (randomly generated) + User PIN
|
|
|
Scrypt
|
|
\|/
VKK IV + SKeyKDF + LE Secret
VKK Seed (randomly generated high entropy secret)
|
|
(guarded by LE secret)
|
|
\|/
Stored in LECredentialManager
VKK Seed
|
|
HMAC256(SKeyKDF)
|
|
\|/
VKK
VKK IV + VK(Vault Key)
|
|
AES Encryption(VKK)
|
|
\|/
Encrypted VK
```
Per the above scheme, the SerializedVaultKeyset will store the LE Salt, so that
it can be used to regenerate the LE secret used during CheckCredential().
### Reset secret
TODO(https://crbug.com/809723)
## Resynchronization
TODO(https://crbug.com/809710)