Re: Mapping out the U2F Attestation Format

Thanks for bringing this up. I may restate certain obvious things, but
I believe the outcome of this is important so I'd just like to be sure
to be aligned on the fundamentals.

I believe the only problem is the MakeCredential call, as the
authenticatorData field and the way the signature is generated is
identical in U2F.

GetAssertion authenticatorData:
- rpidHash (32 bytes)
- flags (1 byte). ED always cleared in U2F
- Counter (4)
- Optional ED (never present in U2F)
- clientDataHash (32 bytes

Hash to be signed is then SHA256(authenticatorData || clientDataHash)


As there is no flags + counter fields in a U2F register (=
MakeCredential) response, it seems to me that the authenticator data
format needs to be different. Having to perform two actions (register
+ authenticate) to get a counter value + signature seems very awkward
and still won’t provide a single signature that can be verified on the
RP side.

U2F authenticatorData:
- HashId (=0) (1 byte)
- rpidHash (32)
- clientDataHash (32)
- attestationCert (n)
- DER-coded public key

Hash to be signed is then SHA256(authenticatorData)

Webauthn authenticatorData
- rpidHash (32 bytes)
- Counter (4)
- aaguid (16)
- credentialId (2 + n)
- CBOR encoded algorithm specifier
- Optional CBOR encoded extensions

Hash to be signed is then SHA256(authenticatorData || clientDataHash)

So for the RP to find out how to construct the hash and verify the
signature, we'll have to have something that specifies the format.

- Have a new key "format": "U2F", which implicitly defines both the
U2F attestation format as well as the authenticator data format
OR
- Define a new CBOR key for authenticatorDataV1

An RP storing the last counter value will have to make up something
for the missing counter field here. I believe this is quite
straight-forward to handle.


Thank you,

Jakob Ehrensvard
CTO
Skype: jehrensvard
US mobile: +1 650-283-1537
SE mobile: +46 (0) 708 24 63 53

http://www.yubico.com

On Wed, Dec 14, 2016 at 10:53 AM, J.C. Jones <jc@mozilla.com> wrote:
> All,
>
> I have a work-in-progress patch in out for initial feedback[1] to enable
> WebAuthn WD-{02/03} support in Firefox, tied to our U2F soft token. I know
> we don't yet have a definition of how the various fields in WebAuthn are
> mapped to the data that comes back from a U2F token, so I just mashed some
> things together to start a conversation.
>
> Note: I've attached this implementation to our U2F soft token, as we're
> still working on USB HID support, but in theory this should work about the
> same.
>
> First thing's first: makeCredential -
>
> After checking isRegistered, we call Register on the RP ID and Client Data
> hashes, and get back the Register Response. The Register Response gets put
> into the WebAuthnAttestation.Attestation field.  Then the Response is pulled
> apart to get the Key Handle buffer for the ScopedCredential.ID field.
>
> Then we call Sign on the RP ID and Client Data hashes - again - using the
> Key Handle from Register, in order to get a Signature Response. That
> Response is concatenated onto the RP ID Hash (RP ID Hash || Signature
> Response), and stored into WebAuthnAttestation.AuthenticatorData, since that
> ... sort of ... looks like the correct format. By which I mean it includes
> the counter, while Register's output does not. This is assuming the counter
> is important to security at this stage of the process, which is not clear to
> me.
>
> You can see this part of the algorithm here [2]. This is obviously pretty
> hacky, as U2F devices used to register here would have to be touched /
> inserted twice.
>
> As for getAssertion -
>
> It's more straightforward; we just call Sign this time. No
> double-test-of-user-presenceing. So we Sign the RP ID and Client Data hashes
> to get a Signature Response. [3] That Response is concatenated onto the RP
> ID Hash (RP ID Hash || Signature Response), and stored into
> WebAuthnAssertion.AuthenticatorData, similar to before. The
> WebAuthnAssertion.SignatureData is set to the Signature Response, and the
> WebAuthnAssertion.ClientData to the serialized Client Data. The
> Credential.ID is copied from the Allow List.
>
> So semi-visually, here's how I mashed things up:
>
> ScopedCredentialInfo
> - Credential
> -- ID: Key Handle buffer extracted from U2F Register() Response
> -- Type: "ScopedCred"
> - WebAuthnAttestation
> -- Format: "u2f"
> -- ClientData: serialized JSON
> -- AuthenticatorData: RP ID Hash || U2F Sign() Response
> -- Attestation: U2F Register() Response
>
> WebAuthnAssertion
> - Credential
> -- ID: ID of Credential from AllowList that succeeded
> -- Type: "ScopedCred"
> - ClientData: serialized JSON
> - AuthenticatorData: RP ID Hash || U2F Sign() Response
> - Signature: U2F Sign() Response
>
> Question 1:
> For Attestation Format=U2F, should AuthenticatorData be omitted, or defined
> to not include a counter?
>
> Question 2:
> For Assertion Format=U2F, should AuthenticatorData be likewise omitted as
> duplicating the Signature field?
>
> Question 3:
> Does the general mapping make sense?
>
>
> [1] https://reviewboard.mozilla.org/r/97088
> [2]
> https://reviewboard-hg.mozilla.org/gecko/rev/04fe96701f18e3261fd1e24d8377b4012f143911#l13.404
> [3]
> https://reviewboard-hg.mozilla.org/gecko/rev/04fe96701f18e3261fd1e24d8377b4012f143911#l13.559
>
> Cheers,
> J.C.

Received on Thursday, 15 December 2016 13:13:56 UTC