Re: Notes from WebAuthn Review

On 6/3/16, 4:57 PM, "Powers, Adam" <> wrote:
>[...] I've deleted all the issues
>that I consider closed based on your feedback.


>>>> This specification defines an API for web pages to access scoped
>>>> credentials through JavaScript, for the purpose of strongly
>>>> authenticating a user.
>>>> [...] 
>>>> § 1.1. Registration (embedded authenticator mode)
>>> Diagrams? 
>> do you mean diagrams of some person messing with their phone+laptop or
>> do you mean protocol flow diagrams ?
>> if the latter, I'm working on some and will offer them up, tho it will
>> be up to the group whether we bake them directly into the spec...
>> WebAuthn-Figures-00
>I was thinking more of higher-level sequence diagrams to help illustrate
>the use cases. Something along the lines of:
>user+browser+authenticator+relying party. I think the diagram you are
>working on is great and needed, but probably
> more detail than needed for an introduction.
>Happy to put together an example of what I'm thinking if that helps.

go for it.

>>>> [...] 
>>>> interface ScopedCredentialInfo {
>>>> readonly attribute Credential credential;
>>>> readonly attribute any publicKey;
>>>> readonly attribute WebAuthnAttestation <<<<attestation;>>>>
>>>> }; 
>>> If attestation is null, there would
>>> be no clientDataHash. Negative
>>> security ramifications?
>> yes, there would be negative security ramifications if there is no
>> supplied attestation (i.e., attestation == null), and the RP were to to
>> ahead and store the credential and the publicKey for later use.
>> However, per web IDL, the attribute members declared within
>> ScopedCredentialInfo are *not* "nullable", so your concern is being
>> implicitly addressed. And it is also nominally addressed in the
>> registration operation processing rules I believe.
>There is consideration that attestation may be nullable (and the Edge
>implementation currently returns a null attestation), so this was largely
>just thinking ahead. See also:

yes, noted. 

Nominally, I think optional attestation is fine -- it is up to the RP's
risk tolerance whether they accept a unattested registrations. We will
need to carefully examine the ramifications in the security
considerations, tho.

i added the above as a comment to #86.

>>>> On success, the promise will be resolved with a
>>>> ScopedCredentialInfoobject describing the newly created
>>>> credential. 
>>>> This method takes the following parameters:
>>>> [...] 
>>>> When this method is invoked, the user agent MUST execute the
>>>> following algorithm:
>>>> 1. If credentialTimeoutSeconds was specified, check if its value
>>>> lies within a reasonable range as defined by the platform and if
>>>> not, correct it to the closest value lying within that range. Set
>>>> adjustedTimeout to this adjusted value. If
>>>> credentialTimeoutSeconds was not specified then set adjustedTimeout
>>>> to a platform-specific default.
>>>> 2. Let promise be a new Promise. Return promise and start a timer
>>>> for adjustedTimeout seconds. Then asynchronously continue executing
>>>> the following steps. 3. Set callerOrigin to the origin of the
>>>> caller. Derive the RP ID from callerOrigin by computing the "public
>>>> suffix + 1" or "PS+1" (which is also referred to as the "Effective
>>>> Top-Level Domain plus One" or "eTLD+1") part of callerOrigin [PSL].
>>>> Set rpId to the RP ID.
>>>> 4. Initialize issuedRequests to an empty list.
>>>> 5. Process each element of cryptoParameters using the following
>>>> steps, to produce a new sequence normalizedParameters:
>>> Additional description of what
>>> normalization is trying to
>>> accomplish would be helpful
>> see 
>> that said, webcrypto normalization is fairly gnarly, tho I spent some
>> time figuring it out a while back and have info to send to this mailing
>> list about it. 
>Even just quoting WebCrypto 18.4.1 would be helpful in understanding the
>³The AlgorithmIdentifier typedef permits algorithms to either be
>specified as a DOMString or an object. The usage of DOMString is to
>permit authors a short-hand for noting algorithms that have no parameters
>(e.g. SHA-1). The usage
> of object is to allow an Algorithm (or appropriate subclass) to be
>specified, which contains all of > the associated parameters for an
>³Because of this, it's necessary to define the algorithm for converting
>an AlgorithmIdentifier into an appropriate dictionary that is usable with
>this API. This algorithm must be extensible, so as to allow new
>cryptographic algorithms
> to be added, and consistent, so that Web IDL type mapping can occur
>before any control is > returned to the calling script, which would
>potentially allow the mutation of parameters or the script environment.²

I think a link directly to  WebCrypto
will be appropriately sufficient.

>>>> Let current be the currently selected element of cryptoParameters.
>>>> [...] 
>>>> 6. If blacklist is undefined, set it to the empty list.
>>>> 7. If credentialExtensions was specified, process any extensions
>>>> supported by this client platform, to produce the extension data
>>>> that needs to be sent to the authenticator. Call this data
>>>> clientExtensions.
>>>> 8. For each embedded or external authenticator currently available on
>>>> this platform: asynchronously invoke the authenticatorMakeCredential
>>>> operation on that authenticator with callerOrigin, rpId,
>>>> accountInformation, normalizedParameters, blacklist,
>>>> attestationChallenge and clientExtensions as parameters. Add a
>>>> corresponding entry to issuedRequests.
>>>> 9. While issuedRequests is not empty, perform the following actions
>>>> depending upon the adjustedTimeout timer and responses from the
>>>> authenticators:
>>>>* If the adjustedTimeout timer expires, then for each entry in
>>>> issuedRequests invoke the authenticatorCancel operation on that
>>>> authenticator and remove its entry from the list.
>>>>* If any authenticator returns a status indicating that the user
>>>> cancelled the operation, delete that authenticator's entry from
>>>> issuedRequests. <<<< For each remaining entry in issuedRequests
>>>> invoke the authenticatorCancel operation on that authenticator
>>>> and remove its entry from the list. >>>> <=== The intent is that
>>> cancel on one 
>>> results in cancelling all?
>> what you mean "cancel on one" is perhaps mistaken. The intent is that
>> the user has canceled *the entire registration operation*.
>I think we are saying the same thing. Here is my understanding: Assuming
>that a system has recognized three available authenticators, when a
>makeCredential() request is called all three authenticators will display
>a message asking
> a user to approve making a credential. If a user were to select cancel /
>no / decline on one > authenticator, a authenticatorCancel() request
>would be sent to the two other authenticators and the entire registration
>operation would effectively be cancelled.

yes, that is also my understanding

>As a separate question, which occurred to me later, what happens when the
>first authenticator succeeds? If a user selects ok / yes / approve, do
>the other two authenticators still display their confirmation messages
>and allow additional registration responses? Or should the client send
>authenticationCancel() to the two other authenticators after the first
>successful result? I'm assuming it's the latter, but I can imagine
>arguments for the former.

To a fair degree this is all up to "the platform" (OS+UA+authnrs), I
think, although invoking authenticatorCancel on any remaining
issuedRequests entries /could/ be added to the last bullet item of step 9
in.. you suggest, but others should probably weigh-in.

>>>> [ makeCredential() cont'd ]
>>>>* If any authenticator returns an error status, delete the
>>>> corresponding entry from issuedRequests. If any authenticator
>>>> indicates success, create a new ScopedCredentialInfoobject named
>>>> value and populate its fields with the values returned from the
>>>> authenticator. Resolve promise with value and terminate this
>>>> algorithm. 
>>>> 10. Resolve promise with a DOMException whose name is
>>>> "NotFoundError", and terminate this algorithm.
>>>> During the above process, the user agent SHOULD show some UI to the
>>>> user to guide them in the process of selecting and authorizing an
>>>> authenticator.
>>> ...but requests are sent to all
>>> authenticators in #8 above?
>> yes, authenticatorMakeCredential() is invoked asynchronously on each
>> authnr, however this is a protocol spec and we are not specifying
>> particular UI/UX. the parag you are referring to is simply
>> implementation guidance. each user agent will do their best to craft a
>> worthwhile UX (user experience).
>Sorry, my question wasnıt very clear. Hereıs the UX as it seems to be
>described in this section:

The set of steps you are referring to here does not describe any
particular UX, you are inferring it. the steps below are your
interpretation as to how a UX might be manifested (they are not in the

>1. User navigates to a website and selects ³register², which calls the
>makeCredential() API of the user agent
>2. The user agent shows a UI allowing the user to select which
>authenticator should be used
>3. The user agent then calls authenticatorMakeCredential() on all the
>available authenticators, and all of the userıs authenticators display a
>message asking the user to accept / reject
> the registration request
>Why does the user select an authenticator in step #2, only to have all
>the authenticators request registration in step #3? Was step #2 intended
>to be a filter for step #3? If it was, then step #3 should be "calls
> on all the authenticators selected by the user"?

The steps you identify as #2 and #3 are up to the platform (OS+UA+authnrs)
to figure out and manifest a UI/UX that (hopefully) makes sense.  i.e.,
there's room for innovation here ;)

The final line in this section {#makeCredential} is..

"During the above process, the user agent SHOULD show some UI to the user
to guide them in the process of selecting and authorizing an

>>>> [ getAssertion() cont'd ]
>>>> * If whitelist is defined and non-empty, <<<< optionally
>>>> execute a 
>>>> platform-specific procedure to determine which of these
>>>> credentials can possibly be present on this
>>>> authenticator.>>>>
>>> Implies cred id was stored in makeCred?
>>> Maybe some hint in makeCred?
>> yes, the authnr generates and stores a tuple of { private key, cred id,
>> cred type, RP ID } -- this is stated in "The
>> operation" <>, though it
>> could perhaps be stated more rigorously.
>My understanding is that this section is talking about user agent
>behavior, not authenticator behavior.

Well, because we leaving up to "the platforms" how to architect the layers
below this web api, this getAssertion() section is about "the platform's"
behavior, where platform = OS+UA+authnrs. Note that each OS platform may
draw the layer booundaries somewhat differently.

So, I sorta take back what I said above about what the authnr stores and
being more rigorous -- rather, we should say that "the platform" stores
essentially that tuple. at this level of abstraction, what matters for
interoperability is the overall behavior of the web api in terms of data
in and data out per specification, not necessarily who-stores-what in the
layer cake underneath.

That said, there are likely security, privacy, and implementation
considerations we should consider adding to the spec in order to more
fully illustrate the overall context and what some of the tradeoffs are.

>This step seems to imply that upon
>a successful makeCredential() call, the user agent stored some tuple like
>{ authenticator identifier,
> credential id, credential type, RP ID }. Now, in getAssertion() the user
>agent is going to do something like iterate through its list of available
>authenticators and see if it has a matching { credential id, credential
>type } that matches the ids / types in
> the whitelist. If this authenticator doesnıt have any potential
>credential ids that are available in the whitelist, it should be ignored.
>If my understanding is correct, there should be a corresponding step in
>the algorithm of Section 3.1.1, where makeCredential() stores the
>credential id associated with the authenticator.

My understanding of the platform folks' perspective is that the above is
too detailed and they'll take care of architecting these details on their
systems. tho I could be mistaken.

>>>> § 3.3. User Account Information (dictionary Account)
>>>> This dictionary is used by the caller to specify information about
>>>> the user account and WebAuthn Relying Party with which a credential
>>>> is to be associated. It is intended to help the authenticator in
>>>> providing a friendly credential selection interface for the user.
>>>> The rpDisplayName member contains the friendly name of the
>>>> WebAuthn Relying Party, such as "Acme Corporation", "Widgets Inc"
>>>> or "Awesome Site".
>>>> The displayName member contains the friendly name associated with
>>>> the user account by the WebAuthn Relying Party, such as "John P.
>>>> Smith". 
>>>> The name member contains a detailed name for the account, such as
>>>> "".
>>>> The id member contains an identifier for the account, stored for
>>>> the use of the WebAuthn Relying Party. This is not meant to be
>>>> displayed to the user.
>>>> The imageURL member contains a URL that resolves to the user's
>>>> account image. This may be a URL that can be used to retrieve an
>>>> image containing the user's current avatar, or a data URI that
>>>> contains the image data.
>>> Other fields okay?
>> I am unsure what you are asking here.
>Can User Account Information be expanded to include other attributes,
>such as Relying Party Logo URL? Or is it strictly limited to the
>attributes that have been named?

Oh, ok, so my understanding of the way web apis work is that if one adds
extra stuff to an object such as defined by the Account dictionary,
consumers of that object simply ignore it if they do not know about it.
If that's correct, then yes, if a RP's webapp added additional fields to
the Account object that a particular OS+authnr "understands", then great,
they will use 'em. And OS+authnr's that don't understand 'em should simply
ignore those extra fields.

>>>> credential public key, attestation information that can be verified
>>>> by a WebAuthn Relying Party. Typically, this information contains a
>>>> signature by an attesting key over the attested public key and a
>>>> challenge, as well as a certificate or similar information providing
>>>> provenance information for the attesting key, enabling a trust
>>>> decision to be made.
>>>> [...] 
>>>> § 4. WebAuthn Authenticator model
>>>> [...] 
>>>> § 4.1. Authenticator operations
>>>> A client must connect to an authenticator in order to invoke any of
>>>> the operations of that authenticator. This connection defines an
>>>> authenticator session. An authenticator must maintain isolation
>>>> between sessions. It may do this by only allowing one session to
>>>> exist at any particular time, or by providing more complicated
>>>> session management.
>>>> The following operations can be invoked by the client in an
>>>> authenticator session.
>>>> § 4.1.1. The authenticatorMakeCredential operation
>>> Should clientDataHash be passed
>>> in, or is this assuming that the
>>> authn calculates it?
>> The authenticator marshalls the input params of this operation into the
>> clientData structure and computes the clientDataHash.
>> See:
>Per WebAuthn Section 5.2 ³To save bandwidth and processing requirements
>on the authenticator, the client platform hashes the client data and
>sends only the result to the authenticator.²
>I suppose we could interpret 5.1 as sending data down to an
>intermediate-level driver between the browser and the authenticator, and
>that intermediate-level driver could create clientDataJSON and
>clientDataHash and send just the clientDataHash
> to the authenticator.


>But that intermediate-level driver would also need
>tokenBinding information for the clientDataJSON (currently a missing
>argument to authenticatorGetAssertion). It would also be operating
>outside the Secure Context and I have a hard time
> understanding why we would be creating the clientDataJSON and
>clientDataHash outside the Secure Context.
>My guess is that the arguments to authenticatorGetAssertion() should be:
>RP ID, clientDataHash, whitelist, extensions.

again, this is the purview of the platforms to architect, detail-wise.

though, you are finding inconsistencies in the spec that we ought to
polish out. 

>>>> Before making a request to an authenticator, the client platform
>>>> layer SHALL perform the following steps.
>>>> 1. Represent the parameters passed in by the RP in the form of a
>>>> ClientDatastructure.
>>>> 2. Let clientDataJSON be the UTF-8 encoded JSON serialization
>> [RFC7159] 
>>>> of this ClientData dictionary.
>>>> 3. Let clientDataHash be the hash (computed using hashAlg) of
>>>> clientDataJSON, as an array.
>>>> The clientDataHash value is delivered to the authenticator.
>>>> The hash algorithm hashAlg used to compute clientDataHash is
>>>> included in the ClientData object. This way it is available to the
>>>> WebAuthn Relying Party and it is also hashed over when computing
>>>> clientDataHash and hence anchored in the signature itself.
>>>> A raw cryptographic signature must assert the integrity of both
>>>> the client data and the authenticator data. Thus, an authenticator
>>>> SHALL compute a signature over the concatenation of the
>>>> authenticatorData and the clientDataHash.
>>> There's no mention of incrementing
>>> the counter? 
>> that could perhaps be mentioned in the more general
>> authenticatorMakeCredential operation section.
>>> Also, should 
>>> authenticatorMakeCredential mention
>>> storing / retrieving it?
>> counters are already mentioned in the various attestation sections --
>> this not sufficient?
>Searching for ³counter² across the entire document only shows a few
>definitions of counters, not any description of their use. Am I missing

yeah, there could be some further language in the spec (eg Impl guidelines
and sec considerations) regarding the signature counter.

>And what about for assertion signatures ­ every time an authenticator
>asserts it should grab the last counter, bump it, sign it, and store the
>new value, right?

yes -- though this would be, in this spec, impl guidance.

>>>> § 4.3. Credential Attestation Statements
>>> Thinking ahead to future
>>> attestation formats, is there
>>> a requirement that they MUST
>>> sign over clientDataHash?
>> nominally, yes -- clientData comprises the contextual bindings gathered
>> as the challenge+params wends its way from the RP-server-side (RPSS)
>> down to the authenticator. marshaling it into clientDataJSON, hashing
>> it, and signing over it, and then returning the plaintext collected
>> clientDataJSON as well as the signature gives the RPSS assurance that
>> was indeed its challenge+params that the authnr received and that they
>> weren't fiddled with during their travels. this is explained in
>> but perhaps could be
>> expanded upon (contributions welcome :)
>> if you examine all three presently-defined attestation types (packed,
>> TPM, android), you'll see we've carefully spec'd how to incorporate
>> clientData into the inputs to the data the authenticator signs over.
>> to answer your question, yes, perhaps stipulating the importance of any
>> new attestation types including some form of contextaul binding a la
>> clientdata should be added. (contributions welcome :)
>My point was what you said in your last paragraph. Should we clarify the
>requirements of future attestation formats here or maybe that happens in
>the definition of an IANA registry (assuming that attestation formats
>eventually end
> up in a registry)?

I would define in the spec in which attestation is defined, which
presently is the webauthn spec.

The IANA registry will essentially only contain a list of attestation type
identifiers with pointers to the spec where each is defined.

>>>> Surrogate Basic Attestation
>>>> [...] 
>>>> § 4.3.4. Security Considerations
>>>> § Privacy
>>>> Attestation keys may be used to track users or link various online
>>>> identities of the same user together. This may be mitigated in
>>>> ways, including:
>>>> [...] 
>>>> Attestation Certificate and Attestation Certificate CA
>>>> Compromise 
>>>> [...] 
>>>> If attestation certificate validation fails due to a revoked
>>>> intermediate attestation CA certificate, and the WebAuthn Relying
>>>> Party's policy requires rejecting the registration/authentication
>>>> request in these situations, then it is recommended that the
>>>> WebAuthn Relying Party also un-registers (or marks as "surrogate
>>>> attestation" 
>>>> (see §4.3.1 Attestation Models), <<<< policy permitting >>>>) scoped
>>> ??? 
>>>> credentials that were registered post the CA compromise date using
>>>> an attestation certificate chaining up to the same intermediate CA.
>> We may need to get Rolf to explain this since he wrote it. in any case,
>> the "policy permitting" qualifying phrase you highlight should perhaps
>> be "webauthn relying party local policy permitting", meaning that in
>> this situation, if the RP wishes to establish local policy allowing it
>> to not necessarily unregister scoped creds that had been reg'd
>> post-CA-cert-revocation, an option for them is to note that those
>> creds (ie: {public key, <>, cred.type, account,
>>attestation type,
>> ...}) as being of attstn type "surrogate basic" rather than "full
>> The connotation of "surrogate basic" being that there is
>> proof-of-possession of the credential private key at registration time,
>> but there is no proof-of-provenance of the authenticator as a whole as
>> there is with legit full basic attstn (or DAA, or Privacy CA).
>Can we create a new issue flagged as ³needs discussion²?

feel free :)


Received on Tuesday, 7 June 2016 22:18:21 UTC