A U2F device should generate a newECC key pair foreach service it registers with. When authenticating, the device should use thepreviously generated private key for that service. This is trivial, but getsmore complex as we add more requirements:
Initial requirements
Without any additional requirements, all we need is a key-value store on thedevice.
example.org => [Private key for example.org]acme.com => [Private key for acme.com]
Multiple keys per service
We want to allow devices to store multiple credentials per service. For example,a user might have more than one Gmail account.To solve this, we associate each credential with a key handle instead of witha service. During registration, the device sends a key handle which is kept bythe service. When authenticating, the service sends the key handle back to thedevice.
KeyHandle[0x21AE9B] => [Private key 1 for example.org]KeyHandle[0xFBD308] => [Private key 2 for example.org]KeyHandle[0x18C77B] => [Private key 1 for acme.com]
Limited storage on device
The implementation described above works just fine, but it comes with alimitation. Each credential consists of a private key along with metadataassociated with that credential, which all require storage space. This puts anupper limit to the number of credentials that can fit on any one device. Toavoid this limitation, YubiKeys use the following approach:
Note | Updated Feb 2020 to reflect current YubiKeys. The following applies to anyYubiKey or Security Key by Yubico with a firmware version of 4.4 or greater (this includes any YubiKey FIPS device). |
During credential registration, a new key pair is randomly generated by theYubiKey, unique to the new credential. The private key, along with somemetadata about the credential, is encrypted usingauthenticatedencryption with a master key. This master key is unique per YubiKey, generatedby the device itself upon first startup, and never leaves the YubiKey in anyform. For FIDO2 capable YubiKeys, this master key is re-generated if FIDO2RESET is invoked, thereby invalidating any previously created credentials.
The encryption used for each credential isAES-256 inCCM mode, which allows us tocryptographically tie things like the AppID to the private key, ensuring thatthe credential can only ever be used with the correct RP. The encrypted (andauthenticated) data then forms the 64-byte key handle, which is sent to theserver as part of the registration flow, to be stored by the RP for later.
For authentication, the RP returns the key handle to the YubiKey. Here it isdecrypted to re-form the private key which is needed to sign the challenge tocomplete the authentication. Due to the authenticated encryption used, we knowthat the private data has not been altered in any way, and can verify that thecredential is being used with the correct AppID.
By using this approach, the YubiKey does not need to store any per-credentialdata, and can thus register and use any number of credentials. This is true forboth U2F and for WebAuthn "non-resident keys". For WebAuthnresident keys,internal storage must still be used.