- From: Jakob Ehrensvärd <jakob@yubico.com>
- Date: Thu, 15 Dec 2016 05:12:07 -0800
- To: "J.C. Jones" <jc@mozilla.com>
- Cc: W3C WebAuthn WG <public-webauthn@w3.org>
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