Mapping out the U2F Attestation Format

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 Wednesday, 14 December 2016 18:54:52 UTC