From 2d10a10a195b2060a7a68ec75265a70adc26dbc4 Mon Sep 17 00:00:00 2001 From: Mike West Date: Wed, 12 Apr 2017 09:26:28 +0200 Subject: [PATCH 1/9] Introduce authenticator response interfaces. This patch adds an 'AuthenticatorResponse' interface, representing the generic attributes of responses from authenticators. It then redefines 'ScopedCredentialInfo' and 'AuthenticatorAssertion' to derive from this interface, and renames them to 'AuthenticatorAttestionResponse' and 'AuthenticatorAssertionResponse' respectively. These new interfaces are a drop-in replacement for the old interfaces, no normative changes are intended in this patch, other than the renaming. --- index.bs | 172 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 76 deletions(-) diff --git a/index.bs b/index.bs index 7fa6c3473..94001a3c7 100644 --- a/index.bs +++ b/index.bs @@ -235,7 +235,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S verification=]. : Authentication Assertion -:: The cryptographically signed {{AuthenticationAssertion}} object returned by an [=authenticator=] as the result of a +:: The cryptographically signed {{AuthenticatorAssertionResponse}} object returned by an [=authenticator=] as the result of a [=authenticatorGetAssertion=] operation. : Authenticator @@ -377,14 +377,14 @@ The Web Authentication API is defined by the union of the Web IDL fragments pres [SecureContext] interface WebAuthentication { - Promise<ScopedCredentialInfo> makeCredential( + Promise<AuthenticatorAttestationResponse> makeCredential( RelyingPartyUserInfo accountInformation, sequence<ScopedCredentialParameters> cryptoParameters, BufferSource attestationChallenge, optional ScopedCredentialOptions options ); - Promise<AuthenticationAssertion> getAssertion( + Promise<AuthenticatorAssertionResponse> getAssertion( BufferSource assertionChallenge, optional AssertionOptions options ); @@ -399,7 +399,7 @@ This interface has two methods, which are described in the following subsections <div link-for-hint="WebAuthentication/makeCredential(accountInformation, cryptoParameters, attestationChallenge, options)"> With this method, a script can request the User Agent to create a new credential of a given type and persist it to the underlying platform, which may involve data storage managed by the browser or the OS. The user agent will prompt the user to -approve this operation. On success, the promise will be resolved with a {{ScopedCredentialInfo}} object describing the newly +approve this operation. On success, the promise will be resolved with a {{AuthenticatorAttestationResponse}} object describing the newly created credential. <div class="note"> @@ -536,10 +536,10 @@ When this method is invoked, the user agent MUST execute the following algorithm <dt>If any |authenticator| indicates success,</dt> <dd> 1. [=set/Remove=] |authenticator| from |issuedRequests|. - 2. Let |value| be a new {{ScopedCredentialInfo}} object associated with |global| whose fields are: - : {{ScopedCredentialInfo/clientDataJSON}} + 2. Let |value| be a new {{AuthenticatorAttestationResponse}} object associated with |global| whose fields are: + : {{AuthenticatorResponse/clientDataJSON}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of |clientDataJSON|. - : {{ScopedCredentialInfo/attestationObject}} + : {{AuthenticatorAttestationResponse/attestationObject}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the value returned from the successful [=authenticatorMakeCredential=] operation 3. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on @@ -676,20 +676,20 @@ When this method is invoked, the user agent MUST execute the following algorithm <dt>If any |authenticator| indicates success,</dt> <dd> 1. [=set/Remove=] |authenticator| from |issuedRequests|. - 2. Let |value| be a new {{AuthenticationAssertion}} object associated with |global| whose fields are: - : {{AuthenticationAssertion/credential}} + 2. Let |value| be a new {{AuthenticatorAssertionResponse}} object associated with |global| whose fields are: + : {{AuthenticatorAssertionResponse/credential}} :: A new {{ScopedCredential}} object associated with |global| whose fields are: 1. {{ScopedCredential/type}} whose value is the {{ScopedCredentialType}} representing this [=scoped credential=]'s type. 1. {{ScopedCredential/id}} whose value is a new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the credential ID returned from the successful [=authenticatorGetAssertion=] operation. - : {{AuthenticationAssertion/clientDataJSON}} + : {{AuthenticatorResponse/clientDataJSON}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of |clientDataJSON| - : {{AuthenticationAssertion/authenticatorData}} + : {{AuthenticatorAssertionResponse/authenticatorData}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the returned {{authenticatorData}} - : {{AuthenticationAssertion/signature}} + : {{AuthenticatorAssertionResponse/signature}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the returned {{signature}} 3. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on @@ -704,35 +704,85 @@ During the above process, the user agent SHOULD show some UI to the user to guid authorizing an authenticator with which to complete the operation. </div> +## Authenticator Responses (interface <dfn interface>AuthenticatorResponse</dfn>) ## {#iface-authenticatorresponse} -## Information about Scoped Credential (interface <dfn interface>ScopedCredentialInfo</dfn>) ## {#iface-credentialInfo} +[=Authenticators=] respond to relying party requests by returning an object derived from the +{{AuthenticatorResponse}} interface: <pre class="idl"> [SecureContext] - interface ScopedCredentialInfo { - readonly attribute ArrayBuffer clientDataJSON; - readonly attribute ArrayBuffer attestationObject; + interface AuthenticatorResponse { + readonly attribute ArrayBuffer clientDataJSON; }; </pre> +<div dfn-type="attribute" dfn-for="AuthenticatorResponse"> + : <dfn>clientDataJSON</dfn> + :: This attribute contains a [=JSON-serialized client data|JSON serialization=] of the [=client data=] passed to the + authenticator by the client in order to generate this response. +</div> + +### Information about Scoped Credential (interface <dfn interface>AuthenticatorAttestationResponse</dfn>) ### {#iface-authenticatorattestationresponse} -<div dfn-type="attribute" dfn-for="ScopedCredentialInfo"> - This interface represents a newly-created scoped credential. It contains information about the credential that can be used - to locate it later for use, and also contains metadata that can be used by the [=[RP]=] to assess the strength of the - credential during registration. - - The <dfn>clientDataJSON</dfn> attribute contains the [=JSON-serialized client data=] (see [[#cred-attestation]]) passed to - the authenticator by the client in order to generate this credential. The exact JSON serialization must be preserved as the - [=hash of the serialized client data=] has been computed over it. - - The <dfn>attestationObject</dfn> attribute contains an [=attestation object=]. The contents of this object are - determined by the [=attestation statement format=] used by the authenticator. This object is opaque to, and - cryptographically protected against tampering by, the client. It contains the credential's unique identifier, [=credential - public key=], and attestation statement. It also contains any additional information that the [RP]'s server requires to - validate the attestation statement, as well as to decode and validate the bindings of both the client and authenticator - data. For more details, see [[#cred-attestation]]. +The {{AuthenticatorAttestationResponse}} interface represents the [=authenticator=]'s response to a client's request +to create a new [=scoped credential=]. It contains information about the credential that can be used to identify it +for later use, and metadata that can be used by the [=[RP]=] to assess the characteristics of the credential during +registration. + +<pre class="idl"> + [SecureContext] + interface AuthenticatorAttestationResponse : AuthenticatorResponse { + readonly attribute ArrayBuffer attestationObject; + }; +</pre> +<div dfn-type="attribute" dfn-for="AuthenticatorAttestationResponse"> + : {{AuthenticatorResponse/clientDataJSON}} + :: This attribute, inherited from {{AuthenticatorResponse}}, contains the [=JSON-serialized client data=] (see + [[#cred-attestation]]) passed to the authenticator by the client in order to generate this credential. The + exact JSON serialization must be preserved, as the [=hash of the serialized client data=] has been computed + over it. + + : <dfn>attestationObject</dfn> + :: This attribute contains an [=attestation object=]. The contents of the object are determined by the + [=attestation statement format=] used by the authenticator. The object is opaque to, and cryptographically + protected against tampering by, the client. It contains the credential's unique identifier, the [=credential + public key=], and the attestation statement. It also contains any additional information that the [RP]'s + server requires to validate the attestation statement, as well as to decode and validate the bindings of both + the client and authenticator data. For more details, see [[#cred-attestation]] as well as + [Figure 3](#fig-attStructs). </div> +### Web Authentication Assertion (interface <dfn interface>AuthenticatorAssertionResponse</dfn>) ### {#iface-authenticatorassertionresponse} + +The {{AuthenticatorAssertionResponse}} interface represents that [=authenticator=]'s response to a client's request +to generate an [=authentication assertion=]. This response contains a cryptographic signature proving possession of +the [=credential private key=], and optionally evidence of [=user consent=] to a specific transaction. + +<pre class="idl"> + [SecureContext] + interface AuthenticatorAssertionResponse : AuthenticatorResponse { + readonly attribute ScopedCredential credential; + readonly attribute ArrayBuffer authenticatorData; + readonly attribute ArrayBuffer signature; + }; +</pre> +<div dfn-type="attribute" dfn-for="AuthenticatorAssertionResponse"> + : {{AuthenticatorResponse/clientDataJSON}} + :: This attribute, inherited from {{AuthenticatorResponse}}, contains the [=JSON-serialized client data=] (see + [[#sec-client-data]]) passed to the authenticator by the client in order to generate this assertion. The + exact JSON serialization must be preserved, as the [=hash of the serialized client data=] has been computed + over it. + + : <dfn>credential</dfn> + :: This attribute represents the [=scoped credential=] that was used to generate this assertion. + + : <dfn>authenticatorData</dfn> + :: This attribute contains the [=authenticator data=] returned by the authenticator. See [[#sec-authenticator-data]]. + + : <dfn>signature</dfn> + :: This attribute contains the raw signature returned from the authenticator. See [[#op-get-assertion]]. +</div> + ## User Account Information (dictionary <dfn dictionary>RelyingPartyUserInfo</dfn>) ## {#iface-userinfo} <pre class="idl"> @@ -861,35 +911,6 @@ example of the latter, when the user is accessing the [RP] from a given client f use a [=roaming authenticator=] which was originally registered with the [RP] using a different client. -## Web Authentication Assertion (interface <dfn interface>AuthenticationAssertion</dfn>) ## {#iface-assertion} - -<pre class="idl"> - [SecureContext] - interface AuthenticationAssertion { - readonly attribute ScopedCredential credential; - readonly attribute ArrayBuffer clientDataJSON; - readonly attribute ArrayBuffer authenticatorData; - readonly attribute ArrayBuffer signature; - }; -</pre> - -Scoped credentials produce a cryptographic signature that provides proof of possession of a private key as well as evidence of -user consent to a specific transaction. The structure of these signatures is defined as follows. - -<div dfn-type="attribute" dfn-for="AuthenticationAssertion"> - The <dfn>credential</dfn> attribute represents the credential that was used to generate this assertion. - - The <dfn>clientDataJSON</dfn> attribute contains the parameters sent to the authenticator by the client, in serialized form. - See [[#sec-client-data]] for the format of this parameter and how it is generated. - - The <dfn>authenticatorData</dfn> attribute contains the [=authenticator data=] returned by the authenticator. See - [[#sec-authenticator-data]]. - - The <dfn>signature</dfn> attribute contains the raw signature returned from the authenticator. See - [[#op-get-assertion]]. -</div> - - ## Additional options for Assertion Generation (dictionary <dfn dictionary>AssertionOptions</dfn>) ## {#assertion-options} <xmp class="idl"> @@ -976,8 +997,7 @@ following Web IDL. : <dfn dfn>JSON-serialized client data</dfn> :: This is the [=UTF-8 encoding=] of the result of calling the initial value of {{JSON/stringify|JSON.stringify}} on a - {{CollectedClientData}} dictionary. To avoid ambiguity, the {{ScopedCredentialInfo}} and {{AuthenticationAssertion}} structures - contain the actual serializations used by the client to generate them. + {{CollectedClientData}} dictionary. : <dfn dfn>Hash of the serialized client data</dfn> :: This is the hash (computed using {{hashAlg}}) of the [=JSON-serialized client data=], as constructed by the client. @@ -1605,17 +1625,17 @@ should be specified in the attestation certificate itself, so that it can be ver # [RP] Operations # {#rp-operations} Upon successful execution of a {{makeCredential()}} or {{getAssertion()}} call, the [RP]'s script receives a -{{ScopedCredentialInfo}} or {{AuthenticationAssertion}} structure respectively from the client. It must then deliver the -contents of this structure to the [=[RP]=], using methods outside the scope of this specification. This section describes the -operations that the [RP] must perform upon receipt of these structures. +{{AuthenticatorAttestationResponse}} or {{AuthenticatorAssertionResponse}} structure respectively from the client. It must then +deliver the contents of this structure to the [=[RP]=], using methods outside the scope of this specification. This section +describes the operations that the [RP] must perform upon receipt of these structures. ## Registering a new credential ## {#registering-a-new-credential} -When requested to register a new credential, represented by a {{ScopedCredentialInfo}} structure, as part of a registration +When requested to register a new credential, represented by a {{AuthenticatorAttestationResponse}} structure, as part of registration ceremony, a [RP] MUST proceed as follows: -1. Perform JSON deserialization on the {{ScopedCredentialInfo/clientDataJSON}} field of the {{ScopedCredentialInfo}} object to +1. Perform JSON deserialization on the {{AuthenticatorResponse/clientDataJSON}} field of the {{AuthenticatorAttestationResponse}} object to extract the [=client data=] |C| claimed to have been used for the credential's attestation. 2. Verify that the {{CollectedClientData/challenge}} in |C| matches the challenge that was sent to the authenticator in the @@ -1628,10 +1648,10 @@ ceremony, a [RP] MUST proceed as follows: 5. Verify that the {{CollectedClientData/extensions}} in |C| is a proper subset of the extensions requested by the RP. -6. Compute the hash of {{ScopedCredentialInfo/clientDataJSON}} using the algorithm identified by +6. Compute the hash of {{AuthenticatorResponse/clientDataJSON}} using the algorithm identified by <code>|C|.{{CollectedClientData/hashAlg}}</code>. -7. Perform CBOR decoding on the {{ScopedCredentialInfo/attestationObject}} field of the {{ScopedCredentialInfo}} structure to +7. Perform CBOR decoding on the {{AuthenticatorAttestationResponse/attestationObject}} field of the {{AuthenticatorAttestationResponse}} structure to obtain the attestation statement format |fmt|, the [=authenticator data=] |authData|, and the attestation statement |attStmt|. @@ -1683,15 +1703,15 @@ or it MAY decide to accept the registration, e.g. while deleting the older regis ## Verifying an authentication assertion ## {#verifying-assertion} -When requested to authenticate a given {{AuthenticationAssertion}} structure as part of an authentication ceremony, the [RP] -MUST proceed as follows: +When requested to authenticate a given {{AuthenticatorAssertionResponse}} structure as part of an authentication ceremony, the +[RP] MUST proceed as follows: -1. Using the {{ScopedCredential/id}} attribute contained in the {{AuthenticationAssertion/credential}} attribute of the given - {{AuthenticationAssertion}} structure, look up the corresponding credential public key. +1. Using the {{ScopedCredential/id}} attribute contained in the {{AuthenticatorAssertionResponse/credential}} attribute of the given + {{AuthenticatorAssertionResponse}} structure, look up the corresponding credential public key. -2. Let |cData|, |aData| and |sig| denote the {{AuthenticationAssertion/clientDataJSON}}, - {{AuthenticationAssertion/authenticatorData}} and {{AuthenticationAssertion/signature}} attributes of the given - {{AuthenticationAssertion}} structure, respectively. +2. Let |cData|, |aData| and |sig| denote the {{AuthenticatorResponse/clientDataJSON}}, + {{AuthenticatorAssertionResponse/authenticatorData}} and {{AuthenticatorAssertionResponse/signature}} attributes of the given + {{AuthenticatorAssertionResponse}} structure, respectively. 3. Perform JSON deserialization on |cData| to extract the [=client data=] |C| used for the signature. From a9da99223c2da0bb07413af2d07b6aa36236421f Mon Sep 17 00:00:00 2001 From: Mike West <mkwst@google.com> Date: Wed, 12 Apr 2017 11:38:02 +0200 Subject: [PATCH 2/9] Move `getAssertion()`'s `challenge` into `AssertionOptions` Passing a single dictionary parameter into `getAssertion()` provides for greater forward compatibility, as new data can be flexibly added to the method invocation without restructuring the existing structure. It also helps developers understand what they're passing in. This is less important for `getAssertion()` than it is for `makeCredential()`, obviously, but aligning both in a similar structure seems like a good change to make. --- index.bs | 75 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/index.bs b/index.bs index 7fa6c3473..12b86ae03 100644 --- a/index.bs +++ b/index.bs @@ -384,10 +384,7 @@ The Web Authentication API is defined by the union of the Web IDL fragments pres optional ScopedCredentialOptions options ); - Promise<AuthenticationAssertion> getAssertion( - BufferSource assertionChallenge, - optional AssertionOptions options - ); + Promise<AuthenticationAssertion> getAssertion(AssertionOptions options); }; @@ -480,7 +477,7 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=list/Append=] |result| to |clientExtensions|. 1. Let |collectedclientData| be a new {{CollectedClientData}} instance whose fields are: - : {{challenge}} + : {{CollectedClientData/challenge}} :: The [=base64url encoding=] of {{attestationChallenge}} : {{origin}} :: The [=unicode serialization of an origin|unicode serialization=] of |rpId| @@ -557,23 +554,17 @@ authorizing an authenticator. ### Use an existing credential - getAssertion() method ### {#getAssertion} -
+
This method is used to discover and use an existing scoped credential, with the user's consent. The script optionally specifies some criteria to indicate what credentials are acceptable to it. The user agent and/or platform locates credentials matching the specified criteria, and guides the user to pick one that the script should be allowed to use. The user may choose not to provide a credential even if one is present, for example to maintain privacy. -
-This method takes the following parameters: - -
    -- The assertionChallenge parameter contains a challenge that the selected authenticator is expected to sign to - produce the assertion. +
    + This method takes the following parameters: -- The optional options parameter specifies additional options, as described in - [[#assertion-options]]. - -
+ : options + :: This dictionary contains the data necessary to generate an assertion, as described in [[#assertion-options]].
When this method is invoked, the user agent MUST execute the following algorithm: @@ -610,8 +601,8 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=list/Append=] |result| to |clientExtensions|. 1. Let |collectedclientData| be a new {{CollectedClientData}} instance whose fields are: - : {{challenge}} - :: The [=base64url encoding=] of {{assertionChallenge}} + : {{CollectedClientData/challenge}} + :: The [=base64url encoding=] of {{options}}.{{AssertionOptions/challenge}} : {{origin}} :: The [=unicode serialization of an origin|unicode serialization=] of |rpId| : {{hashAlg}} @@ -892,8 +883,12 @@ user consent to a specific transaction. The structure of these signatures is def ## Additional options for Assertion Generation (dictionary AssertionOptions) ## {#assertion-options} +The {{AssertionOptions}} dictionary supplies {{getAssertion()}} with the data it needs to generate an assertion. Its +member {{AssertionOptions/challenge}} must be present, while its other members are optional. + dictionary AssertionOptions { + required BufferSource challenge; unsigned long timeout; USVString rpId; sequence<ScopedCredentialDescriptor> allowList = []; @@ -902,20 +897,28 @@ user consent to a specific transaction. The structure of these signatures is def
- This dictionary is used to supply additional options when generating an assertion. All these parameters are optional. - - - The optional timeout parameter specifies a time, in milliseconds, that the caller is willing to wait for the - call to complete. This is treated as a hint, and may be overridden by the platform. - - - The optional rpId parameter specifies the rpId claimed by the caller. If it is omitted, it will be assumed to - be equal to the [=origin=] specified by the {{WebAuthentication}} object's [=relevant settings object=]. - - - The optional allowList member contains a list of credentials acceptable to the caller, in order of the - caller's preference. - - - The optional extensions parameter contains additional parameters requesting additional processing by the client - and authenticator. For example, if transaction confirmation is sought from the user, then the prompt string would be - included in an extension. + : challenge + :: This member represents a challenge that the selected [=authenticator=] is expected to sign in order to produce an + [=authentication assertion=]. + + : timeout + :: This optional member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. + The value is treated as a hint, and may be overridden by the platform. + + : rpId + :: This optional member specifies the [=relying party identifier=] claimed by the caller. If omitted, its value will + be the [=ASCII serialization of an origin|ASCII serialization=] of the {{WebAuthentication}} object's [=relevant + settings object=]'s [=environment settings object/origin=]. + + : allowList + :: This optional member contains a list of {{ScopedCredentialDescriptor}} object representing [=scoped credentials=] + acceptable to the caller, in decending order of the caller's preference (the first item in the list is the most + preferred credential, and so on down the line). + + : extensions + :: This optional member contains additional parameters requesting additional processing by the client and authenticator. + For example, if transaction confirmation is sought from the user, then the prompt string might be included as an + extension.
@@ -2907,13 +2910,13 @@ then the sample code for performing such an authentication might look like this: if (!webauthnAPI) { /* Platform not capable. Handle error. */ } - var challenge = new TextEncoder().encode("climb a mountain"); var options = { - timeout = 60000, // 1 minute + challenge: new TextEncoder().encode("climb a mountain"), + timeout: 60000, // 1 minute allowList: [{ type: "ScopedCred" }] }; - webauthnAPI.getAssertion(challenge, options) + webauthnAPI.getAssertion(options) .then(function (assertion) { // Send assertion to server for verification }).catch(function (err) { @@ -2931,7 +2934,6 @@ extension for transaction authorization. if (!webauthnAPI) { /* Platform not capable. Handle error. */ } var encoder = new TextEncoder(); - var challenge = encoder.encode("climb a mountain"); var acceptableCredential1 = { type: "ScopedCred", id: encoder.encode("!!!!!!!hi there!!!!!!!\n") @@ -2942,6 +2944,7 @@ extension for transaction authorization. }; var options = { + challenge: encoder.encode("climb a mountain"), timeout: 60000, // 1 minute allowList: [acceptableCredential1, acceptableCredential2]; extensions: { 'webauthn.txauth.simple': From 4fad3e51fbe89eb8fbc3ec12542cbd194339c8c2 Mon Sep 17 00:00:00 2001 From: Mike West Date: Wed, 12 Apr 2017 14:57:24 +0200 Subject: [PATCH 3/9] Convert `makeCredential()`'s parameters into a dictionary. Passing a single dictionary parameter into `makrCredential()` provides for greater forward compatibility, as new data can be flexibly added to the method invocation without restructuring the existing structure. It also helps developers understand what they're passing in, as each parameter will be labeled. This patch restructures the data passed into `makeCredential()` substantially, moving from four parameters to a single dictionary, and merging some existing types into a simpler structure. Most of it is straightforward; the only bit I know will be controversial is dropping `RelyingPartyUserInfo` in favor of two instances of a simpler `ScopedCredentialEntity` object: one for the RP, one for the user. Let's chat about how (un)reasonable this approach might be. --- index.bs | 272 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 137 insertions(+), 135 deletions(-) diff --git a/index.bs b/index.bs index 7fa6c3473..123d91754 100644 --- a/index.bs +++ b/index.bs @@ -377,12 +377,7 @@ The Web Authentication API is defined by the union of the Web IDL fragments pres [SecureContext] interface WebAuthentication { - Promise<ScopedCredentialInfo> makeCredential( - RelyingPartyUserInfo accountInformation, - sequence<ScopedCredentialParameters> cryptoParameters, - BufferSource attestationChallenge, - optional ScopedCredentialOptions options - ); + Promise<ScopedCredentialInfo> makeCredential(MakeCredentialOptions options); Promise<AuthenticationAssertion> getAssertion( BufferSource assertionChallenge, @@ -396,45 +391,24 @@ This interface has two methods, which are described in the following subsections ### Create a new credential - makeCredential() method ### {#makeCredential} -<div link-for-hint="WebAuthentication/makeCredential(accountInformation, cryptoParameters, attestationChallenge, options)"> +<div link-for-hint="WebAuthentication/makeCredential(options)"> With this method, a script can request the User Agent to create a new credential of a given type and persist it to the underlying platform, which may involve data storage managed by the browser or the OS. The user agent will prompt the user to approve this operation. On success, the promise will be resolved with a {{ScopedCredentialInfo}} object describing the newly created credential. -<div class="note"> -This method takes the following parameters: - -<ul dfn-type="argument" dfn-for="WebAuthentication/makeCredential(accountInformation, cryptoParameters, attestationChallenge, options)"> -- The <dfn>accountInformation</dfn> parameter specifies information about the user account for which the credential is being - created. This is meant for later use by the authenticator when it needs to prompt the user to select a credential. An - authenticator is only required to store one credential for any given value of {{accountInformation}}. Specifically, if an - authenticator already has a credential for the specified value of {{RelyingPartyUserInfo/id}} in {{accountInformation}}, and if this - credential is not listed in the {{ScopedCredentialOptions/excludeList}} member of {{options}}, then after successful - execution of this method: - - Any calls to {{getAssertion()}} that do not specify {{AssertionOptions/allowList}} will not result in the older - credential being offered to the user. - - Any calls to {{getAssertion()}} that specify the older credential in the {{AssertionOptions/allowList}} may also not - result in it being offered to the user. - -- The <dfn>cryptoParameters</dfn> parameter supplies information about the desired properties of the credential to be created. - The sequence is ordered from most preferred to least preferred. The platform makes a best effort to create the most - preferred credential that it can. - -- The <dfn>attestationChallenge</dfn> parameter contains a challenge intended to be used for generating the newly created - credential's attestation object. +<div class="note" dfn-type="argument" dfn-for="WebAuthentication/makeCredential(options)"> + This method takes the following parameters: -- The optional <dfn>options</dfn> parameter specifies additional options, as described in - [[#credential-options]]. - -</ul> + : <dfn>options</dfn> + :: This parameter specifies how the credential is to be made, as described in [[#dictionary-makecredentialoptions]]. </div> When this method is invoked, the user agent MUST execute the following algorithm: -1. If the {{ScopedCredentialOptions/timeout}} member of {{options}} is [=present=], check if its value lies within a +1. If the {{MakeCredentialOptions/timeout}} member of {{options}} is [=present=], 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 the {{ScopedCredentialOptions/timeout}} member of {{options}} is [=present|not + |adjustedTimeout| to this adjusted value. If the {{MakeCredentialOptions/timeout}} member of {{options}} is [=present|not present=], then set |adjustedTimeout| to a platform-specific default. 1. Let |global| be this {{WebAuthentication}} object's [=global object|environment settings object's global object=]. @@ -443,19 +417,22 @@ When this method is invoked, the user agent MUST execute the following algorithm |callerOrigin| is an [=opaque origin=], return [=a promise rejected with=] a {{DOMException}} whose name is "{{NotAllowedError}}", and terminate this algorithm. -1. If the {{ScopedCredentialOptions/rpId}} member of {{options}} is [=present|not present=], then set |rpId| to |callerOrigin|. - Otherwise: +1. If the {{ScopedCredentialEntity/id}} member of {{options}}.{{MakeCredentialOptions/rp}} is [=present|not present=], then set + |rpId| to |callerOrigin|. + + Otherwise: 1. Let |effectiveDomain| be the |callerOrigin|'s [=effective domain=]. 1. If |effectiveDomain| is null, then return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}" and terminate this algorithm. - 1. If {{ScopedCredentialOptions/rpId}} [=is not a registrable domain suffix of and is not equal to=] |effectiveDomain|, - return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}", and terminate this algorithm. - 1. Set |rpId| to the {{ScopedCredentialOptions/rpId}}. + 1. If {{options}}.{{MakeCredentialOptions/rp}}.{{ScopedCredentialEntity/id}} [=is not a registrable domain suffix of and is + not equal to=] |effectiveDomain|, return [=a promise rejected with=] a {{DOMException}} whose name is + "{{SecurityError}}", and terminate this algorithm. + 1. Set |rpId| to {{options}}.{{MakeCredentialOptions/rp}}.{{ScopedCredentialEntity/id}}. -1. Let |normalizedParameters| be a new [=list=] whose [=list/items=] are pairs of ScopedCredentialType and a [=dictionary=] type - (as returned by [=normalizing an algorithm=]). +1. Let |normalizedParameters| be a new [=list=] whose [=list/items=] are pairs of {{ScopedCredentialType}} and a [=dictionary=] + type (as returned by [=normalizing an algorithm=]). -1. [=list/For each=] |current| of {{cryptoParameters}}: +1. [=list/For each=] |current| of {{options}}.{{MakeCredentialOptions/parameters}}: 1. If <code>|current|.{{ScopedCredentialParameters/type}}</code> does not contain a {{ScopedCredentialType}} supported by this implementation, then [=continue=]. 1. Let |normalizedAlgorithm| be the result of [=normalizing an algorithm=] [[!WebCryptoAPI]], with |alg| set to @@ -464,14 +441,14 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=list/Append=] the pair of <code>|current|.{{ScopedCredentialParameters/type}}</code> and |normalizedAlgorithm| to |normalizedParameters|. -1. If |normalizedParameters| [=list/is empty=] and {{cryptoParameters}} [=list/is not empty=], cancel the timer - started in step 2, return [=a promise rejected with=] with a {{DOMException}} whose name is "{{NotSupportedError}}", and - terminate this algorithm. +1. If |normalizedParameters| [=list/is empty=] and {{options}}.{{MakeCredentialOptions/parameters}} [=list/is not empty=], + cancel the timer started in step 2, return [=a promise rejected with=] with a {{DOMException}} whose name is + "{{NotSupportedError}}", and terminate this algorithm. 1. Let |clientExtensions| be a new [=list=]. -1. If the {{ScopedCredentialOptions/extensions}} member of {{options}} is [=present=], then [=map/for each=] - |extension| → |argument| of <code>{{options}}.{{ScopedCredentialOptions/extensions}}</code>: +1. If the {{MakeCredentialOptions/extensions}} member of {{options}} is [=present=], then [=map/for each=] + |extension| → |argument| of <code>{{options}}.{{MakeCredentialOptions/extensions}}</code>: 1. If |extension| is not supported by this client platform, then [=continue=]. 1. Otherwise, let |result| be the result of running |extension|'s [=client processing=] algorithm on |argument|. If the @@ -480,8 +457,8 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=list/Append=] |result| to |clientExtensions|. 1. Let |collectedclientData| be a new {{CollectedClientData}} instance whose fields are: - : {{challenge}} - :: The [=base64url encoding=] of {{attestationChallenge}} + : {{CollectedClientData/challenge}} + :: The [=base64url encoding=] of{{options}}.{{MakeCredentialOptions/challenge}} : {{origin}} :: The [=unicode serialization of an origin|unicode serialization=] of |rpId| : {{hashAlg}} @@ -499,17 +476,18 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |issuedRequests| and |currentlyAvailableAuthenticators| be new [=ordered sets=]. 1. For each |authenticator| currently available on this platform, if - <code>{{options}}.{{ScopedCredentialOptions/attachment}}</code> is [=present|not present=] or its value matches + <code>{{options}}.{{MakeCredentialOptions/attachment}}</code> is [=present|not present=] or its value matches |authenticator|'s attachment modality, [=set/append=] |authenticator| to |currentlyAvailableAuthenticators|. 1. [=set/For each=] |authenticator| in |currentlyAvailableAuthenticators|: 1. Let |excludeList| be a new [=list=]. - 1. [=list/For each=] credential |C| in <code>{{options}}.{{ScopedCredentialOptions/excludeList}}</code>: + 1. [=list/For each=] credential |C| in <code>{{options}}.{{MakeCredentialOptions/exclude}}</code>: 1. If <code>|C|.{{transports}}</code> [=list/is not empty=], and |authenticator| is connected over a transport not mentioned in <code>|C|.{{transports}}</code>, the client MAY [=continue=]. 1. Otherwise, [=list/Append=] |C| to |excludeList|. 1. [=In parallel=], invoke the [=authenticatorMakeCredential=] operation on |authenticator| with |rpId|, - |clientDataHash|, {{accountInformation}}, |normalizedParameters|, |excludeList| and |clientExtensions| as parameters. + |clientDataHash|, {{options}}.{{MakeCredentialOptions/rp}}, {{options}}.{{MakeCredentialOptions/user}}, + |normalizedParameters|, |excludeList| and |clientExtensions| as parameters. 1. [=set/Append=] |authenticator| to |issuedRequests|. 1. Let |promise| be [=a new promise=]. Return |promise| and start a timer for |adjustedTimeout| milliseconds. Then execute the @@ -610,7 +588,7 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=list/Append=] |result| to |clientExtensions|. 1. Let |collectedclientData| be a new {{CollectedClientData}} instance whose fields are: - : {{challenge}} + : {{CollectedClientData/challenge}} :: The [=base64url encoding=] of {{assertionChallenge}} : {{origin}} :: The [=unicode serialization of an origin|unicode serialization=] of |rpId| @@ -733,40 +711,6 @@ authorizing an authenticator with which to complete the operation. </div> -## User Account Information (dictionary <dfn dictionary>RelyingPartyUserInfo</dfn>) ## {#iface-userinfo} - -<pre class="idl"> - dictionary RelyingPartyUserInfo { - required DOMString rpDisplayName; - required DOMString displayName; - required DOMString id; - DOMString name; - DOMString imageURL; - }; -</pre> - -<div dfn-type="dict-member" dfn-for="RelyingPartyUserInfo"> - This dictionary is used by the caller to specify information about the user account and [=[RP]=] 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 <dfn>rpDisplayName</dfn> member contains the friendly name of the [RP], such as "Acme Corporation", "Widgets Inc" or - "Awesome Site". - - The <dfn>displayName</dfn> member contains the friendly name associated with the user account by the [RP], such as "John - P. Smith". - - The <dfn>id</dfn> member contains an identifier for the account, specified by the [RP]. This is not meant to be displayed - to the user. It is used by the [RP] to control the number of credentials - an authenticator will never contain more than one - credential for a given [RP] under the same {{RelyingPartyUserInfo/id}}. - - The <dfn>name</dfn> member contains a detailed name for the account, such as "john.p.smith@example.com". - - The <dfn>imageURL</dfn> 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. -</div> - - ## Parameters for Credential Generation (dictionary <dfn dictionary>ScopedCredentialParameters</dfn>) ## {#credential-params} <pre class="idl"> @@ -786,47 +730,6 @@ authorizing an authenticator with which to complete the operation. </div> -## Additional options for Credential Generation (dictionary <dfn dictionary>ScopedCredentialOptions</dfn>) ## {#credential-options} - -<xmp class="idl"> - dictionary ScopedCredentialOptions { - unsigned long timeout; - USVString rpId; - sequence<ScopedCredentialDescriptor> excludeList = []; - Attachment attachment; - AuthenticationExtensions extensions; - }; - - - -
- This dictionary is used to supply additional options when creating a new credential. All these parameters are optional. - - - The timeout parameter specifies a time, in milliseconds, that the caller is willing to wait for the call to - complete. This is treated as a hint, and may be overridden by the platform. - - - The rpId parameter explicitly specifies the RP ID that the credential should be associated with. If it is - omitted, the RP ID will be set to the [=origin=] specified by the {{WebAuthentication}} object's [=relevant settings - object=]. - - - The excludeList parameter is intended for use by [=[RPS]=] that wish to limit the creation of multiple - credentials for the same account on a single authenticator. The platform is requested to return an error if the new - credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter. - - - The extensions parameter contains additional parameters requesting additional processing by the client and - authenticator. For example, the caller may request that only authenticators with certain capabilities be used to create - the credential, or that particular information be returned in the [=attestation object=]. The caller may also specify - an additional message that they would like the authenticator to display to the user. Some extensions are defined in - [[#extensions]]; - consult the IANA "WebAuthn Extension Identifier" registry established by [[!WebAuthn-Registries]] - for an up-to-date list of registered WebAuthn Extensions. - - - The attachment parameter contains authenticator attachment descriptions, which are used as an additional - constraint on which authenticators are eligible to participate in a [[#makeCredential]] or [[#getAssertion]] operation. - See [[#attachment]] for a description of the attachment values and their meanings. - -
- ### Credential Attachment enumeration (enum Attachment) ### {#attachment}
@@ -889,6 +792,102 @@ user consent to a specific transaction. The structure of these signatures is def
     [[#op-get-assertion]].
 
+## Additional options for Attestation (dictionary MakeCredentialOptions) ## {#dictionary-makecredentialoptions} + + + dictionary MakeCredentialOptions { + // Relying Party / User Metadata: + required ScopedCredentialEntity rp; + required ScopedCredentialEntity user; + + // Attestation configuration: + required BufferSource challenge; + required sequence<ScopedCredentialParameters> parameters; + + // Optional constraints: + unsigned long timeout; + sequence<ScopedCredentialDescriptor> exclude; + Attachment attachment; + AuthenticationExtensions extensions; + }; + +
+ : rp + :: This member contains data about the [=relying party=] responsible for the request. + + Its value's {{ScopedCredentialEntity/name}} member is required, and contains the friendly name of the relying party + (e.g. "Acme Corporation", "Widgets, Inc.", or "Awesome Site". + + Its value's {{ScopedCredentialEntity/id}} member specifies the [=relying party identifier=] with which the credential + should be associated. If this identifier is not explicitly set, it will default to the [=ASCII serialization of an + origin|ASCII serialization=] of the {{WebAuthentication}} object's [=relevant settings object=]'s [=environment settings + object/origin=]. + + : user + :: This member contains data about the user account for which the [=relying party=] is requesting attestation. + + Its value's {{ScopedCredentialEntity/name}} member is required, and contains a friendly name for the user account (e.g. + "john.p.smith@example.com", or "John P. Smith"). + + Its value's {{ScopedCredentialEntity/id}} member is required, and contains an identifier for the account, specified by + the [=relying party=]. This is not meant to be displayed to the user, but is used by the relying party to control the + number of credentials - an authenticator will never contain more than one credential for a given relying party under the + same {{ScopedCredentialEntity/id}}. + + : challenge + :: This member contains a channelge intended to be used for generating the newly created credential's [=attestation object=]. + + : parameters + :: This member contains information about the desired properties of the credential to be created. The sequence is ordered + from most preferred to least preferred. The platform makes a best-effort to create the most preferred credential that it + can. + + : timeout + :: This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is + treated as a hint, and may be overridden by the platform. + + : exclude + :: This member is intended for use by [=[RPS]=] that wish to limit the creation of multiple credentials for the same + account on a single authenticator. The platform is requested to return an error if the new credential would be created + on an authenticator that also contains one of the credentials enumerated in this parameter. + + : attachment + :: This member contains authenticator attachment descriptions, which are used as an additional constraint on which + authenticators are eligible to participate in a [[#makeCredential]] or [[#getAssertion]] operation. See [[#attachment]] + for a description of the attachment values and their meanings. + + : extensions + :: This member contains additional parameters requesting additional processing by the client and authenticator. For example, + the caller may request that only authenticators with certain capabilies be used to create the credential, or that + particular information be returned in the [=attestation object=]. Some extensions are defined in [[#extensions]]; + consult the IANA "WebAuthn Extension Identifier" registry established by [[!WebAuthn-Registries]] for an up-to-date list + of registered WebAuthn Extensions. +
+ +### Entity Description ### {#dictionary-scopedcredentialentity} + +The {{ScopedCredentialEntity}} dictionary describes a user account or a [=relying party=] with which a credential is associated. + + + dictionary ScopedCredentialEntity { + DOMString id; + DOMString name; + USVString icon; + }; + +
+ : id + :: A unique identifier for the entity. This will be the [=ASCII serialization of an origin=] for a [=relying party=], + and an arbitrary string specified by the [=relying party=] for user accounts. + + : name + :: A human-friendly identifier for the entity. For example, this could be a company name for a [=relying party=], or a + user's name. This identifier is intended for display. + + : icon + :: A [=URL serializer|serialized=] URL which resolves to an image associated with the entity. For example, this could be + a user's avatar or a [=relying party=]'s logo. +
## Additional options for Assertion Generation (dictionary AssertionOptions) ## {#assertion-options} @@ -1247,7 +1246,8 @@ input parameters: - The caller's RP ID, as determined by the user agent and the client. - The [=hash of the serialized client data=], provided by the client. -- The {{RelyingPartyUserInfo}} information provided by the [RP]. +- The [=relying party=]'s {{ScopedCredentialEntity}}. +- The user account's {{ScopedCredentialEntity}}. - The {{ScopedCredentialType}} and cryptographic parameters requested by the [RP], with the cryptographic algorithms normalized as per the procedure in [[WebCryptoAPI#algorithm-normalization-normalize-an-algorithm]]. - A list of {{ScopedCredential}} objects provided by the [RP] with the intention that, if any of these are known to the @@ -1269,8 +1269,10 @@ When this operation is invoked, the authenticator must perform the following pro parameters supported by this authenticator. - Generate an identifier for this credential, such that this identifier is globally unique with high probability across all credentials with the same type across all authenticators. - - Associate the credential with the specified RP ID and the user's account identifier {{RelyingPartyUserInfo/id}}. - - Delete any older credentials with the same RP ID and {{RelyingPartyUserInfo/id}} that are stored locally in the authenticator. + - Associate the credential with the specified RP ID and the user's account identifier + {{MakeCredentialOptions/user}}.{{ScopedCredentialEntity/id}}. + - Delete any older credentials with the same RP ID and {{MakeCredentialOptions/user}}.{{ScopedCredentialEntity/id}} that + are stored locally in the authenticator. - If any error occurred while creating the new credential object, return an error code equivalent to UnknownError and terminate the operation. - Process all the supported extensions requested by the client, and generate the [=authenticator data=] with @@ -1657,9 +1659,9 @@ ceremony, a [RP] MUST proceed as follows: 13. If the attestation statement |attStmt| verified successfully and is found to be trustworthy, then register the new credential with the account that was denoted in the - {{WebAuthentication/makeCredential(accountInformation, cryptoParameters, attestationChallenge, options)/accountInformation}} - passed to {{makeCredential()}}, by associating it with the credential ID and credential public key contained in |authData|'s - [=attestation data=], as appropriate for the [RP]'s systems. + {{WebAuthentication/makeCredential(options)/options}}.{{MakeCredentialOptions/user}} passed to {{makeCredential()}}, by + associating it with the credential ID and credential public key contained in |authData|'s [=attestation data=], as + appropriate for the [RP]'s systems. 14. If the attestation statement |attStmt| successfully verified but is not trustworthy per step 12 above, the [RP] SHOULD fail the registration ceremony. @@ -2258,7 +2260,7 @@ in the {{getAssertion()}} or {{makeCredential()}} call, while the authentic to the authenticator during the processing of these calls. A [RP] simultaneously requests the use of an extension and sets its client argument by including an entry in the -{{ScopedCredentialOptions/extensions}} option to the {{makeCredential()}} or {{getAssertion()}} call. The entry key MUST be the +{{MakeCredentialOptions/extensions}} option to the {{makeCredential()}} or {{getAssertion()}} call. The entry key MUST be the extension identifier, and the value MUST be the [=client argument=].

From 0039a138e2d27567e7d32f0ddd203748bedb9cbb Mon Sep 17 00:00:00 2001
From: Mike West 
Date: Wed, 12 Apr 2017 18:40:20 +0200
Subject: [PATCH 4/9] fixup drop 'additional'

---
 index.bs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/index.bs b/index.bs
index 12b86ae03..990eb7959 100644
--- a/index.bs
+++ b/index.bs
@@ -881,7 +881,7 @@ user consent to a specific transaction. The structure of these signatures is def
 
-## Additional options for Assertion Generation (dictionary AssertionOptions) ## {#assertion-options} +## Options for Assertion Generation (dictionary AssertionOptions) ## {#assertion-options} The {{AssertionOptions}} dictionary supplies {{getAssertion()}} with the data it needs to generate an assertion. Its member {{AssertionOptions/challenge}} must be present, while its other members are optional. From 6dca154104884ed814f2b0ded74a959bdf28e3ef Mon Sep 17 00:00:00 2001 From: Mike West Date: Wed, 12 Apr 2017 18:42:19 +0200 Subject: [PATCH 5/9] fixup 'additional' --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 123d91754..ca3f342e7 100644 --- a/index.bs +++ b/index.bs @@ -792,7 +792,7 @@ user consent to a specific transaction. The structure of these signatures is def [[#op-get-assertion]]. -## Additional options for Attestation (dictionary MakeCredentialOptions) ## {#dictionary-makecredentialoptions} +## Parameters for Credential Creation (dictionary MakeCredentialOptions) ## {#dictionary-makecredentialoptions} dictionary MakeCredentialOptions { From 3a5fefb7b0603cab4c7a0bdf7476575067561462 Mon Sep 17 00:00:00 2001 From: Mike West <mkwst@google.com> Date: Wed, 12 Apr 2017 19:07:49 +0200 Subject: [PATCH 6/9] fixup AssertionRequest --- index.bs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/index.bs b/index.bs index 990eb7959..b207c6d2b 100644 --- a/index.bs +++ b/index.bs @@ -384,7 +384,7 @@ The Web Authentication API is defined by the union of the Web IDL fragments pres optional ScopedCredentialOptions options ); - Promise<AuthenticationAssertion> getAssertion(AssertionOptions options); + Promise<AuthenticationAssertion> getAssertion(AssertionRequest request); }; @@ -409,9 +409,9 @@ This method takes the following parameters: authenticator already has a credential for the specified value of {{RelyingPartyUserInfo/id}} in {{accountInformation}}, and if this credential is not listed in the {{ScopedCredentialOptions/excludeList}} member of {{options}}, then after successful execution of this method: - - Any calls to {{getAssertion()}} that do not specify {{AssertionOptions/allowList}} will not result in the older + - Any calls to {{getAssertion()}} that do not specify {{AssertionRequest/allowList}} will not result in the older credential being offered to the user. - - Any calls to {{getAssertion()}} that specify the older credential in the {{AssertionOptions/allowList}} may also not + - Any calls to {{getAssertion()}} that specify the older credential in the {{AssertionRequest/allowList}} may also not result in it being offered to the user. - The cryptoParameters parameter supplies information about the desired properties of the credential to be created. @@ -560,18 +560,18 @@ some criteria to indicate what credentials are acceptable to it. The user agent specified criteria, and guides the user to pick one that the script should be allowed to use. The user may choose not to provide a credential even if one is present, for example to maintain privacy. -
+
This method takes the following parameters: : options - :: This dictionary contains the data necessary to generate an assertion, as described in [[#assertion-options]]. + :: This dictionary contains the data necessary to generate an assertion, as described in [[#assertion-request]].
When this method is invoked, the user agent MUST execute the following algorithm: -1. If the {{AssertionOptions/timeout}} member of {{options}} is [=present=], check if its value lies within a reasonable range +1. If the {{AssertionRequest/timeout}} member of {{request}} is [=present=], 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 the {{AssertionOptions/timeout}} member of {{options}} is [=present|not present=], then set + this adjusted value. If the {{AssertionRequest/timeout}} member of {{request}} is [=present|not present=], then set |adjustedTimeout| to a platform-specific default. 1. Let |global| be this {{WebAuthentication}} object's [=global object|environment settings object's global object=]. @@ -580,20 +580,20 @@ When this method is invoked, the user agent MUST execute the following algorithm |callerOrigin| is an [=opaque origin=], return [=a promise rejected with=] a {{DOMException}} whose name is "{{NotAllowedError}}", and terminate this algorithm. -1. If the {{AssertionOptions/rpId}} member of {{options}} is [=present|not present=], then set |rpId| to |callerOrigin|. +1. If the {{AssertionRequest/rpId}} member of {{request}} is [=present|not present=], then set |rpId| to |callerOrigin|. Otherwise: 1. Let |effectiveDomain| be the |callerOrigin|'s [=effective domain=]. 1. If |effectiveDomain| is null, then return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}" and terminate this algorithm. - 1. If {{AssertionOptions/rpId}} [=is not a registrable domain suffix of and is not equal to=] + 1. If {{AssertionRequest/rpId}} [=is not a registrable domain suffix of and is not equal to=] |effectiveDomain|, return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}", and terminate this algorithm. - 1. Set |rpId| to the {{AssertionOptions/rpId}}. + 1. Set |rpId| to the {{AssertionRequest/rpId}}. 1. Let |clientExtensions| be a new [=list=]. -1. If the {{AssertionOptions/extensions}} member of {{options}} is [=present=], then [=map/for each=] - |extension| → |argument| of {{options}}.{{AssertionOptions/extensions}}: +1. If the {{AssertionRequest/extensions}} member of {{request}} is [=present=], then [=map/for each=] + |extension| → |argument| of {{request}}.{{AssertionRequest/extensions}}: 1. If |extension| is not supported by this client platform, then [=continue=]. 1. Otherwise, let |result| be the result of running |extension|'s [=client processing=] algorithm on |argument|. If the algorithm returned an error, [=continue=]. @@ -602,7 +602,7 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |collectedclientData| be a new {{CollectedClientData}} instance whose fields are: : {{CollectedClientData/challenge}} - :: The [=base64url encoding=] of {{options}}.{{AssertionOptions/challenge}} + :: The [=base64url encoding=] of {{request}}.{{AssertionRequest/challenge}} : {{origin}} :: The [=unicode serialization of an origin|unicode serialization=] of |rpId| : {{hashAlg}} @@ -623,11 +623,11 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |credentialList| be a new [=list=]. - 1. If {{options}}.{{AssertionOptions/allowList}} [=list/is not empty=], execute a + 1. If {{request}}.{{AssertionRequest/allowList}} [=list/is not empty=], execute a platform-specific procedure to determine which, if any, credentials in - {{options}}.{{AssertionOptions/allowList}} are present on this |authenticator| by matching with - {{options}}.{{AssertionOptions/allowList}}.{{ScopedCredentialDescriptor/id}} and - {{options}}.{{AssertionOptions/allowList}}.{{ScopedCredentialDescriptor/type}}, and set |credentialList| to + {{request}}.{{AssertionRequest/allowList}} are present on this |authenticator| by matching with + {{request}}.{{AssertionRequest/allowList}}.{{ScopedCredentialDescriptor/id}} and + {{request}}.{{AssertionRequest/allowList}}.{{ScopedCredentialDescriptor/type}}, and set |credentialList| to this filtered list. 1. If |credentialList| [=list/is empty=] then [=continue=]. @@ -881,13 +881,13 @@ user consent to a specific transaction. The structure of these signatures is def
-## Options for Assertion Generation (dictionary AssertionOptions) ## {#assertion-options} +## Options for Assertion Generation (dictionary AssertionRequest) ## {#assertion-request} -The {{AssertionOptions}} dictionary supplies {{getAssertion()}} with the data it needs to generate an assertion. Its -member {{AssertionOptions/challenge}} must be present, while its other members are optional. +The {{AssertionRequest}} dictionary supplies {{getAssertion()}} with the data it needs to generate an assertion. Its +member {{AssertionRequest/challenge}} must be present, while its other members are optional. - dictionary AssertionOptions { + dictionary AssertionRequest { required BufferSource challenge; unsigned long timeout; USVString rpId; @@ -896,7 +896,7 @@ member {{AssertionOptions/challenge}} must be present, while its other members a }; -
+
: challenge :: This member represents a challenge that the selected [=authenticator=] is expected to sign in order to produce an [=authentication assertion=]. @@ -2385,7 +2385,7 @@ error. :: A single [=UTF-8 encoded=] string specifying a FIDO |appId|. : Client processing -:: If {{AssertionOptions/rpId}} is present, reject promise with a DOMException +:: If {{AssertionRequest/rpId}} is present, reject promise with a DOMException whose name is "{{NotAllowedError}}", and terminate this algorithm. Replace the calculation of |rpId| in Step 3 of [[#getAssertion]] with the following procedure: The client uses the value of |appid| to perform From 3cdf1bfbf3252e33354549275566be70e73e7f18 Mon Sep 17 00:00:00 2001 From: Mike West Date: Fri, 14 Apr 2017 21:31:09 +0200 Subject: [PATCH 7/9] fixup @equalsJeffH --- index.bs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/index.bs b/index.bs index 94001a3c7..c4931e2a6 100644 --- a/index.bs +++ b/index.bs @@ -718,15 +718,15 @@ authorizing an authenticator with which to complete the operation.
: clientDataJSON :: This attribute contains a [=JSON-serialized client data|JSON serialization=] of the [=client data=] passed to the - authenticator by the client in order to generate this response. + authenticator by the client in its call to either {{makeCredential()}} or {{getAssertion()}}.
### Information about Scoped Credential (interface AuthenticatorAttestationResponse) ### {#iface-authenticatorattestationresponse} The {{AuthenticatorAttestationResponse}} interface represents the [=authenticator=]'s response to a client's request -to create a new [=scoped credential=]. It contains information about the credential that can be used to identify it -for later use, and metadata that can be used by the [=[RP]=] to assess the characteristics of the credential during -registration. +for the creation of a new [=scoped credential=]. It contains information about the new credential that can be used to +identify it for later use, and metadata that can be used by the [=[RP]=] to assess the characteristics of the credential +during registration.
     [SecureContext]
@@ -742,21 +742,23 @@ registration.
         over it.
 
     :   attestationObject
-    ::  This attribute contains an [=attestation object=]. The contents of the object are determined by the
-        [=attestation statement format=] used by the authenticator. The object is opaque to, and cryptographically
-        protected against tampering by, the client. It contains the credential's unique identifier, the [=credential
-        public key=], and the attestation statement. It also contains any additional information that the [RP]'s
-        server requires to validate the attestation statement, as well as to decode and validate the bindings of both
-        the client and authenticator data. For more details, see [[#cred-attestation]] as well as
+    ::  This attribute contains an [=attestation object=], which is opaque to, and cryptographically protected against
+        tampering by, the client. The [=attestation object=] contains both [=authenticator data=] and an attestation
+        statement. The former contains the AAGUID, a unique credential ID, and the [=credential public key=]. The
+        contents of the attestation statement are determined by the [=attestation statement format=] used by the
+        [=authenticator=]. It also contains any additional information that the [RP]'s server requires to validate the
+        attestation statement, as well as to decode and validate the [=authenticator data=] along with the
+        [=JSON-serialized client data=]. For more details, see [[#cred-attestation]] as well as
         [Figure 3](#fig-attStructs).
 
### Web Authentication Assertion (interface AuthenticatorAssertionResponse) ### {#iface-authenticatorassertionresponse} -The {{AuthenticatorAssertionResponse}} interface represents that [=authenticator=]'s response to a client's request -to generate an [=authentication assertion=]. This response contains a cryptographic signature proving possession of -the [=credential private key=], and optionally evidence of [=user consent=] to a specific transaction. +The {{AuthenticatorAssertionResponse}} interface represents an [=authenticator=]'s response to a client's request for +generation of a new [=authentication assertion=] given the [=[RP]=]'s challenge and optional list of credentials it is +aware of. This response contains a cryptographic signature proving possession of the [=credential private key=], and +optionally evidence of [=user consent=] to a specific transaction.
     [SecureContext]

From 4f4b79f41354f58f250a46b311d3dc1f521cacf7 Mon Sep 17 00:00:00 2001
From: Mike West 
Date: Fri, 14 Apr 2017 21:35:33 +0200
Subject: [PATCH 8/9] fixup revert AssertionRequest.

---
 index.bs | 46 +++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/index.bs b/index.bs
index b207c6d2b..990eb7959 100644
--- a/index.bs
+++ b/index.bs
@@ -384,7 +384,7 @@ The Web Authentication API is defined by the union of the Web IDL fragments pres
             optional ScopedCredentialOptions     options
         );
 
-        Promise getAssertion(AssertionRequest request);
+        Promise getAssertion(AssertionOptions options);
     };
 
 
@@ -409,9 +409,9 @@ This method takes the following parameters:
     authenticator already has a credential for the specified value of {{RelyingPartyUserInfo/id}} in {{accountInformation}}, and if this
     credential is not listed in the {{ScopedCredentialOptions/excludeList}} member of {{options}}, then after successful
     execution of this method:
-    - Any calls to {{getAssertion()}} that do not specify {{AssertionRequest/allowList}} will not result in the older
+    - Any calls to {{getAssertion()}} that do not specify {{AssertionOptions/allowList}} will not result in the older
         credential being offered to the user.
-    - Any calls to {{getAssertion()}} that specify the older credential in the {{AssertionRequest/allowList}} may also not
+    - Any calls to {{getAssertion()}} that specify the older credential in the {{AssertionOptions/allowList}} may also not
         result in it being offered to the user.
 
 - The cryptoParameters parameter supplies information about the desired properties of the credential to be created.
@@ -560,18 +560,18 @@ some criteria to indicate what credentials are acceptable to it. The user agent
 specified criteria, and guides the user to pick one that the script should be allowed to use. The user may choose not to provide
 a credential even if one is present, for example to maintain privacy.
 
-
+
This method takes the following parameters: : options - :: This dictionary contains the data necessary to generate an assertion, as described in [[#assertion-request]]. + :: This dictionary contains the data necessary to generate an assertion, as described in [[#assertion-options]].
When this method is invoked, the user agent MUST execute the following algorithm: -1. If the {{AssertionRequest/timeout}} member of {{request}} is [=present=], check if its value lies within a reasonable range +1. If the {{AssertionOptions/timeout}} member of {{options}} is [=present=], 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 the {{AssertionRequest/timeout}} member of {{request}} is [=present|not present=], then set + this adjusted value. If the {{AssertionOptions/timeout}} member of {{options}} is [=present|not present=], then set |adjustedTimeout| to a platform-specific default. 1. Let |global| be this {{WebAuthentication}} object's [=global object|environment settings object's global object=]. @@ -580,20 +580,20 @@ When this method is invoked, the user agent MUST execute the following algorithm |callerOrigin| is an [=opaque origin=], return [=a promise rejected with=] a {{DOMException}} whose name is "{{NotAllowedError}}", and terminate this algorithm. -1. If the {{AssertionRequest/rpId}} member of {{request}} is [=present|not present=], then set |rpId| to |callerOrigin|. +1. If the {{AssertionOptions/rpId}} member of {{options}} is [=present|not present=], then set |rpId| to |callerOrigin|. Otherwise: 1. Let |effectiveDomain| be the |callerOrigin|'s [=effective domain=]. 1. If |effectiveDomain| is null, then return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}" and terminate this algorithm. - 1. If {{AssertionRequest/rpId}} [=is not a registrable domain suffix of and is not equal to=] + 1. If {{AssertionOptions/rpId}} [=is not a registrable domain suffix of and is not equal to=] |effectiveDomain|, return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}", and terminate this algorithm. - 1. Set |rpId| to the {{AssertionRequest/rpId}}. + 1. Set |rpId| to the {{AssertionOptions/rpId}}. 1. Let |clientExtensions| be a new [=list=]. -1. If the {{AssertionRequest/extensions}} member of {{request}} is [=present=], then [=map/for each=] - |extension| → |argument| of {{request}}.{{AssertionRequest/extensions}}: +1. If the {{AssertionOptions/extensions}} member of {{options}} is [=present=], then [=map/for each=] + |extension| → |argument| of {{options}}.{{AssertionOptions/extensions}}: 1. If |extension| is not supported by this client platform, then [=continue=]. 1. Otherwise, let |result| be the result of running |extension|'s [=client processing=] algorithm on |argument|. If the algorithm returned an error, [=continue=]. @@ -602,7 +602,7 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |collectedclientData| be a new {{CollectedClientData}} instance whose fields are: : {{CollectedClientData/challenge}} - :: The [=base64url encoding=] of {{request}}.{{AssertionRequest/challenge}} + :: The [=base64url encoding=] of {{options}}.{{AssertionOptions/challenge}} : {{origin}} :: The [=unicode serialization of an origin|unicode serialization=] of |rpId| : {{hashAlg}} @@ -623,11 +623,11 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |credentialList| be a new [=list=]. - 1. If {{request}}.{{AssertionRequest/allowList}} [=list/is not empty=], execute a + 1. If {{options}}.{{AssertionOptions/allowList}} [=list/is not empty=], execute a platform-specific procedure to determine which, if any, credentials in - {{request}}.{{AssertionRequest/allowList}} are present on this |authenticator| by matching with - {{request}}.{{AssertionRequest/allowList}}.{{ScopedCredentialDescriptor/id}} and - {{request}}.{{AssertionRequest/allowList}}.{{ScopedCredentialDescriptor/type}}, and set |credentialList| to + {{options}}.{{AssertionOptions/allowList}} are present on this |authenticator| by matching with + {{options}}.{{AssertionOptions/allowList}}.{{ScopedCredentialDescriptor/id}} and + {{options}}.{{AssertionOptions/allowList}}.{{ScopedCredentialDescriptor/type}}, and set |credentialList| to this filtered list. 1. If |credentialList| [=list/is empty=] then [=continue=]. @@ -881,13 +881,13 @@ user consent to a specific transaction. The structure of these signatures is def
-## Options for Assertion Generation (dictionary AssertionRequest) ## {#assertion-request} +## Options for Assertion Generation (dictionary AssertionOptions) ## {#assertion-options} -The {{AssertionRequest}} dictionary supplies {{getAssertion()}} with the data it needs to generate an assertion. Its -member {{AssertionRequest/challenge}} must be present, while its other members are optional. +The {{AssertionOptions}} dictionary supplies {{getAssertion()}} with the data it needs to generate an assertion. Its +member {{AssertionOptions/challenge}} must be present, while its other members are optional. - dictionary AssertionRequest { + dictionary AssertionOptions { required BufferSource challenge; unsigned long timeout; USVString rpId; @@ -896,7 +896,7 @@ member {{AssertionRequest/challenge}} must be present, while its other members a }; -
+
: challenge :: This member represents a challenge that the selected [=authenticator=] is expected to sign in order to produce an [=authentication assertion=]. @@ -2385,7 +2385,7 @@ error. :: A single [=UTF-8 encoded=] string specifying a FIDO |appId|. : Client processing -:: If {{AssertionRequest/rpId}} is present, reject promise with a DOMException +:: If {{AssertionOptions/rpId}} is present, reject promise with a DOMException whose name is "{{NotAllowedError}}", and terminate this algorithm. Replace the calculation of |rpId| in Step 3 of [[#getAssertion]] with the following procedure: The client uses the value of |appid| to perform From 805891752a579d84c677f512539c34f05658cf8d Mon Sep 17 00:00:00 2001 From: Mike West Date: Fri, 14 Apr 2017 21:55:54 +0200 Subject: [PATCH 9/9] fixup @equalsJeffH --- index.bs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/index.bs b/index.bs index ca3f342e7..9fc908cb6 100644 --- a/index.bs +++ b/index.bs @@ -406,6 +406,11 @@ created credential. When this method is invoked, the user agent MUST execute the following algorithm: +1. If any of the {{ScopedCredentialEntity/name}} member of {{options}}.{{MakeCredentialOptions/rp}}, the + {{ScopedCredentialEntity/name}} member of {{options}}.{{MakeCredentialOptions/user}}, or the {{ScopedCredentialEntity/id}} + member of {{options}}.{{MakeCredentialOptions/user}} are [=present|not present=], return [=a promise rejected with=] a + {{TypeError}} [=simple exception=]. + 1. If the {{MakeCredentialOptions/timeout}} member of {{options}} is [=present=], 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 the {{MakeCredentialOptions/timeout}} member of {{options}} is [=present|not @@ -420,7 +425,8 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. If the {{ScopedCredentialEntity/id}} member of {{options}}.{{MakeCredentialOptions/rp}} is [=present|not present=], then set |rpId| to |callerOrigin|. - Otherwise: + Otherwise: + 1. Let |effectiveDomain| be the |callerOrigin|'s [=effective domain=]. 1. If |effectiveDomain| is null, then return [=a promise rejected with=] a {{DOMException}} whose name is "{{SecurityError}}" and terminate this algorithm. @@ -481,7 +487,7 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=set/For each=] |authenticator| in |currentlyAvailableAuthenticators|: 1. Let |excludeList| be a new [=list=]. - 1. [=list/For each=] credential |C| in {{options}}.{{MakeCredentialOptions/exclude}}: + 1. [=list/For each=] credential |C| in {{options}}.{{MakeCredentialOptions/excludeList}}: 1. If |C|.{{transports}} [=list/is not empty=], and |authenticator| is connected over a transport not mentioned in |C|.{{transports}}, the client MAY [=continue=]. 1. Otherwise, [=list/Append=] |C| to |excludeList|. @@ -796,17 +802,14 @@ user consent to a specific transaction. The structure of these signatures is def dictionary MakeCredentialOptions { - // Relying Party / User Metadata: required ScopedCredentialEntity rp; required ScopedCredentialEntity user; - // Attestation configuration: required BufferSource challenge; required sequence<ScopedCredentialParameters> parameters; - // Optional constraints: unsigned long timeout; - sequence<ScopedCredentialDescriptor> exclude; + sequence<ScopedCredentialDescriptor> excludeList; Attachment attachment; AuthenticationExtensions extensions; }; @@ -835,7 +838,7 @@ user consent to a specific transaction. The structure of these signatures is def same {{ScopedCredentialEntity/id}}. : <dfn>challenge</dfn> - :: This member contains a channelge intended to be used for generating the newly created credential's [=attestation object=]. + :: This member contains a challenge intended to be used for generating the newly created credential's [=attestation object=]. : <dfn>parameters</dfn> :: This member contains information about the desired properties of the credential to be created. The sequence is ordered @@ -846,7 +849,7 @@ user consent to a specific transaction. The structure of these signatures is def :: This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, and may be overridden by the platform. - : <dfn>exclude</dfn> + : <dfn>excludeList</dfn> :: This member is intended for use by [=[RPS]=] that wish to limit the creation of multiple credentials for the same account on a single authenticator. The platform is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter.