move fido2-impl.md
This commit is contained in:
parent
1ffe85f083
commit
91066292ae
@ -1,86 +0,0 @@
|
|||||||
This page aims to document the security related aspects of the FIDO2
|
|
||||||
implementation on Solo. This is to make it easier for public review and
|
|
||||||
comments.
|
|
||||||
|
|
||||||
# Key generation
|
|
||||||
|
|
||||||
Solo aims to achieve 256 bit (32 byte) security with its FIDO2 implementation,
|
|
||||||
even in light of physical side channels.
|
|
||||||
|
|
||||||
When Solo is first programmed, it will be "uninitialized," meaning it won't
|
|
||||||
have any secret material, until the first time it boots, then it will leverage
|
|
||||||
the TRNG to generate all necessary material. This only happens once.
|
|
||||||
|
|
||||||
A master secret, `M`, is generated at initialization. This is only used for
|
|
||||||
all key generation and derivation in FIDO2. Solo uses a key wrapping method
|
|
||||||
for FIDO2 operation.
|
|
||||||
|
|
||||||
** NOTE: The masked implementation of AES is planned, but not yet implemented. Currently it is normal AES. **
|
|
||||||
|
|
||||||
## Key wrapping
|
|
||||||
|
|
||||||
When you register a service with a FIDO2 or U2F authenticator, the
|
|
||||||
authenticator must generate a new keypair unique to that service. This keypair
|
|
||||||
could be stored on the authenticator to be used in subsequent authentications,
|
|
||||||
but now a certain amount of memory needs to be allocated for this. On embedded
|
|
||||||
devices, there isn't much memory to spare and users will allows frustratingly
|
|
||||||
hit the limit of this memory.
|
|
||||||
|
|
||||||
The answer to this problem is to do key wrapping. The authenticator just
|
|
||||||
stores `M` and uses `M` and the TRNG to generate new keys and derive previous
|
|
||||||
keys on the fly. A random number, `R`, is generated, and is placed in the
|
|
||||||
FIDO2/U2F `KEYID` parameter. The service stores `KEYID` after registering a
|
|
||||||
key and will issue it back to the authenticator for subsequent authentications.
|
|
||||||
|
|
||||||
In essence, the following happens at registration.
|
|
||||||
|
|
||||||
1. Generate `R`, calculate private key, `K`, using `HMAC(M,R)`
|
|
||||||
2. Derive public key, `P`, from `K`
|
|
||||||
3. Return `P` and `R` to service. (`R` is in `KEYID` parameter)
|
|
||||||
4. Service stores `P` and `R`.
|
|
||||||
|
|
||||||
Now on authenication.
|
|
||||||
|
|
||||||
1. Service issues authentication request with `R` in `KEYID` parameter.
|
|
||||||
2. \* Authenticator generates `K` by calculating `HMAC(M,R)`.
|
|
||||||
3. Proceed normally as if `K` was loaded from storage memory.
|
|
||||||
|
|
||||||
|
|
||||||
<!-- As part of FIDO2/U2F, there is a `KEYID` parameter that is bascially a
|
|
||||||
binary blob that the authenticator returns to the service after registering,
|
|
||||||
and the service must store it and provide it to the authenticator on subsquent
|
|
||||||
authentications.
|
|
||||||
|
|
||||||
64 bytes of secrets will be generated to make master secret parts `M1` and
|
|
||||||
`M2`, 32 bytes each. The master secrets are only used for generating signing
|
|
||||||
keys which are then used for FIDO2/U2F. -->
|
|
||||||
|
|
||||||
## Key derivation
|
|
||||||
|
|
||||||
** Planned, but not yet implemented. **
|
|
||||||
|
|
||||||
Master secret `M` consists of 64 bytes, split into equal parts `M1` and `M2`.
|
|
||||||
In theory, we should only need 32 bytes to achieve 256 security, but we also
|
|
||||||
plan to have side channel security hence the added bytes.
|
|
||||||
|
|
||||||
Our HMAC currently is a two step process. First, just generate a normal
|
|
||||||
`SHA256-HMAC`.
|
|
||||||
|
|
||||||
1. `tmp = SHA256_HMAC(M1, R)`
|
|
||||||
|
|
||||||
We could proceed using `tmp` as our secret key, `K`. But our `SHA256-HMAC`
|
|
||||||
implementation isn't side channel resistant and we won't bother trying to add
|
|
||||||
side channel resistance. So we add an additional stage that is side channel
|
|
||||||
resistant.
|
|
||||||
|
|
||||||
2. `K = aes256_masked(M2, tmp)`
|
|
||||||
|
|
||||||
We add a masked AES encryption to provide side channel resistance. Masked AES
|
|
||||||
is well studied and relatively easy to implement. An adversary may be able to
|
|
||||||
recover `M1` via SCA but not `M2`.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<sup>* There are other details I leave out. There's also an authentication tag
|
|
||||||
in the `KEYID` parameter to ensure this is a key generated by the Solo
|
|
||||||
key.</sup>
|
|
@ -57,6 +57,8 @@ keys which are then used for FIDO2/U2F. -->
|
|||||||
|
|
||||||
## Key derivation
|
## Key derivation
|
||||||
|
|
||||||
|
** Planned, but not yet implemented. **
|
||||||
|
|
||||||
Master secret `M` consists of 64 bytes, split into equal parts `M1` and `M2`.
|
Master secret `M` consists of 64 bytes, split into equal parts `M1` and `M2`.
|
||||||
In theory, we should only need 32 bytes to achieve 256 security, but we also
|
In theory, we should only need 32 bytes to achieve 256 security, but we also
|
||||||
plan to have side channel security hence the added bytes.
|
plan to have side channel security hence the added bytes.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user