diff --git a/index.bs b/index.bs
index 869a6f9d8..4b673683b 100644
--- a/index.bs
+++ b/index.bs
@@ -40,6 +40,10 @@ Markup Shorthands: css off, markdown on
+spec: ECMAScript; urlPrefix: https://tc39.github.io/ecma262/#
+ type: method
+ for: JSON; text: stringify; url: sec-json.stringify
+
spec: HTML52; urlPrefix: https://w3c.github.io/html/
type: dfn
@@ -53,6 +57,10 @@ spec: HTML52; urlPrefix: https://w3c.github.io/html/
type: interface
text: Navigator
+spec: TokenBinding; urlPrefix: https://tools.ietf.org/html/draft-ietf-tokbind-protocol-13#
+ type: dfn
+ text: Token Binding ID; url: section-3.2
+
spec: WebCryptoAPI; urlPrefix: https://www.w3.org/TR/WebCryptoAPI/
type: dfn
text: normalizing an algorithm; url: dfn-normalize-an-algorithm
@@ -61,6 +69,7 @@ spec: WebCryptoAPI; urlPrefix: https://www.w3.org/TR/WebCryptoAPI/
+spec:infra; type:dfn; text:list
spec:webidl; type:interface; text:Promise
@@ -161,7 +170,8 @@ or a combination of both.
## Dependencies ## {#dependencies}
-This specification relies on several other underlying specifications.
+This specification relies on several other underlying specifications, listed
+below and in [[#index-defined-elsewhere]].
: Base64url encoding
:: The term Base64url Encoding refers to the base64 encoding using the URL- and filename-safe character set defined
@@ -372,6 +382,7 @@ underlying platform, which may involve data storage managed by the browser or th
approve this operation. On success, the promise will be resolved with a {{ScopedCredentialInfo}} object describing the newly
created credential.
+
This method takes the following parameters:
@@ -397,6 +408,7 @@ This method takes the following parameters:
[[#credential-options]].
+
When this method is invoked, the user agent MUST execute the following algorithm:
@@ -405,13 +417,10 @@ When this method is invoked, the user agent MUST execute the following algorithm
value. If {{ScopedCredentialOptions/timeout}} was not specified, then set |adjustedTimeout| to a platform-specific
default.
-1. Let |promise| be [=a new Promise=]. Return |promise| and start a timer for |adjustedTimeout| milliseconds.
- Then asynchronously continue executing the following steps. If any fatal error is encountered in this process other than the
- ones enumerated below, cancel the timer, reject |promise| with a {{DOMException}} whose name is "{{UnknownError}}", and terminate
- this algorithm.
+ Issue: Put some constraints on the "reasonable range".
1. Set |callerOrigin| to the current settings object's origin. If |callerOrigin| is
- an opaque origin, reject |promise| with a {{DOMException}} whose name is "{{NotAllowedError}}", and
+ an opaque origin, [=reject=] |promise| with a {{DOMException}} whose name is "{{NotAllowedError}}", and
terminate this algorithm.
1. If the {{ScopedCredentialOptions/rpId}} member of {{options}} is not present, then set |rpId| to
@@ -424,58 +433,150 @@ When this method is invoked, the user agent MUST execute the following algorithm
terminate this algorithm.
1. Set |rpId| to the {{ScopedCredentialOptions/rpId}}.
-1. Process each element of {{cryptoParameters}} using the following steps, to produce a new sequence |normalizedParameters|.
- - Let |current| be the currently selected element of {{cryptoParameters}}.
- - If `current.type` does not contain a {{ScopedCredentialType}} supported by this implementation, then stop processing
- |current| and move on to the next element in {{cryptoParameters}}.
- - Let |normalizedAlgorithm| be the result of normalizing an algorithm [[!WebCryptoAPI]],
- with |alg| set to `current.algorithm` and |op| set to 'generateKey'. If an error occurs during this
- procedure, then stop processing |current| and move on to the next element in {{cryptoParameters}}.
- - Add a new object of type {{ScopedCredentialParameters}} to |normalizedParameters|, with |type| set to `current.type` and
- |algorithm| set to |normalizedAlgorithm|.
-
-1. If |normalizedAlgorithm| is empty and {{cryptoParameters}} was not empty, cancel the timer started in step 2, reject
- |promise| with a DOMException whose name is "{{NotSupportedError}}", and terminate this algorithm.
-
-1. If the {{ScopedCredentialOptions/extensions}} member of {{options}} is present, process any extensions supported by
- this client platform, to produce the extension data that needs to be sent to the authenticator. If an error is encountered
- while processing an extension, skip that extension and do not produce any extension data for it. Call the result of this
- processing |clientExtensions|.
+ Issue(w3c/webauthn#259): The rest of this algorithm assumes |rpId| is an
+ [=origin=], but the above step sometimes produces a string.
+
+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. If |current|.{{ScopedCredentialParameters/type}}
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
+ |current|.{{algorithm}}
and |op| set to `"generateKey"`. If
+ an error occurs during this procedure, then [=continue=].
+ 1. [=list/Append=] the pair of
+ |current|.{{ScopedCredentialParameters/type}}
and
+ |normalizedAlgorithm| to |normalizedParameters|.
+
+1. If |normalizedParameters| is empty and {{cryptoParameters}} was 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
+ {{options}}.{{ScopedCredentialOptions/extensions}}
:
+ 1. If |extension| is not supported by this client platform, then either:
+ * [=Continue=], or
+ * Let |result| be a CBOR ([[!RFC7049]]) encoding of |extension|.
+
+ Issue(w3c/webauthn#363): Define this encoding more precisely.
+ 1. Otherwise, let |result| be the result of running |extension|'s [=client
+ processing=] algorithm on |argument|. If the algorithm returned an
+ error, [=continue=].
+
+ Issue(w3c/webauthn#363): Ensure all extensions define a client
+ processing algorithm.
+ 1. [=list/Append=] |result| to |clientExtensions|.
+
+1. Let |clientData| be a new {{ClientData}} instance whose fields are:
+ : {{challenge}}
+ :: The [=base64url encoding=] of {{attestationChallenge}}
+ : {{origin}}
+ :: The [=unicode serialization of an origin|unicode serialization=] of |rpId|
+ : {{hashAlg}}
+ :: UA-chosen
+
+ Issue(w3c/webauthn#362): We need *some* constraints on the possible hash
+ algorithms, or else sites will fail on unusual UAs.
+ : {{tokenBinding}}
+ :: The [=Token Binding ID=] associated with |callerOrigin| (if any)
+
+ Issue(w3c/webauthn#360): Make sure this association was set up properly.
+ : {{ClientData/extensions}}
+ :: |clientExtensions|
+
+1. Let |clientDataJSON| be the [=UTF-8 encoding=] of the result of calling the
+ initial value of {{JSON/stringify|JSON.stringify}} on |clientData|.
+
+ Issue: Some extensions contain ArrayBuffers, which don't stringify well.
+ What's the intent here?
+1. Let |clientDataHash| be the hash of |clientDataJSON| using
+ |clientData|.{{hashAlg}}
.
+
+1. Let |issuedRequests| and |currentlyAvailableAuthenticators| be new [=ordered
+ sets=].
+
+1. For each |authenticator| currently available on this platform, if
+ {{options}}.{{ScopedCredentialOptions/attachment}}
is 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 {{options}}.{{ScopedCredentialOptions/excludeList}}
:
+ 1. If |C| has an empty {{transports}} list, [=list/append=] |C| to
+ |excludeList| and [=continue=].
+ 1. If |authenticator| is connected over a transport not mentioned in
+ |C|.{{transports}}
, the client MAY [=continue=].
+
+ Issue: I'm not sure this captures the intent of the original wording.
+ 1. [=list/Append=] |C| to |excludeList|.
+ 1. [=In parallel=], invoke the authenticatorMakeCredential operation
+ on |authenticator| with |rpId|, |clientDataHash|,
+ {{accountInformation}}, |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 following steps [=in parallel=]. If any fatal error is encountered in this algorithm other than the
+ ones enumerated below, cancel the timer, [=reject=] |promise| with a DOMException whose name is "{{UnknownError}}", and terminate
+ this algorithm.
-1. Use {{attestationChallenge}}, |callerOrigin| and |rpId|, along with the token binding key associated with |callerOrigin| (if
- any), to create a {{ClientData}} structure representing this request. Choose a hash algorithm for {{ClientData/hashAlg}} and
- compute the {{ScopedCredentialInfo/clientDataJSON}} and its clientDataHash.
+ Issue: What kinds of fatal errors are you worried about? I suggest we just
+ remove that sentence.
-1. Initialize |issuedRequests| and |currentlyAvailableAuthenticators| to empty lists.
+1. While |issuedRequests| is not empty, perform the following actions depending upon the |adjustedTimeout| timer and responses
+ from the authenticators:
+
-1. For each authenticator currently available on this platform, add the authenticator to |currentlyAvailableAuthenticators|
- unless the {{ScopedCredentialOptions/attachment}} member of {{options}} is present. In that case, let |attachment|
- be {{ScopedCredentialOptions/attachment}}, and add the authenticator to |currentlyAvailableAuthenticators| if its attachment
- modality matches |attachment|.
+ - If the |adjustedTimeout| timer expires,
-1. For each authenticator in |currentlyAvailableAuthenticators|: asynchronously invoke the authenticatorMakeCredential
- operation on that authenticator with |rpId|, clientDataHash, {{accountInformation}}, |normalizedParameters|,
- {{ScopedCredentialOptions/excludeList}} and |clientExtensions| as parameters. Add a corresponding entry to |issuedRequests|.
- - For each credential |C| in the {{ScopedCredentialOptions/excludeList}} member of {{options}} that has a non-empty
- |transports| list, optionally use only the specified transports to test for the existence of |C|.
+ - [=set/For each=]
+ |authenticator| in |issuedRequests| invoke the
+ authenticatorCancel operation on |authenticator| and
+ [=set/remove=] |authenticator| from |issuedRequests|.
-1. 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.
- - If any authenticator returns an error status, delete the corresponding entry from |issuedRequests|.
- - If any authenticator indicates success:
- - Remove this authenticator's entry from |issuedRequests|.
- - Create a new {{ScopedCredentialInfo}} object named |value| and populate its fields with the values returned from the
- authenticator as well as the {{ScopedCredentialInfo/clientDataJSON}} computed earlier.
- - For each remaining entry in |issuedRequests| invoke the authenticatorCancel operation on that authenticator and
- remove its entry from the list.
- - Resolve |promise| with |value| and terminate this algorithm.
+ - If any |authenticator| returns a status indicating that the user cancelled the operation,
-1. Reject |promise| with a {{DOMException}} whose name is "{{NotAllowedError}}", and terminate this algorithm.
+ -
+ 1. [=set/Remove=] |authenticator| from |issuedRequests|.
+ 2. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke
+ the authenticatorCancel operation on |authenticator| and
+ [=set/remove=] it from |issuedRequests|.
+
+
+
+ - If any |authenticator| returns an error status,
+
+ - [=set/Remove=] |authenticator| from |issuedRequests|.
+
+ - If any |authenticator| indicates success,
+
+ -
+ 1. [=set/Remove=] |authenticator| from |issuedRequests|.
+ 2. Let |value| be a new {{ScopedCredentialInfo}} object whose fields are:
+ : {{ScopedCredentialInfo/clientDataJSON}}
+ :: A new {{ArrayBuffer}} containing the bytes of |clientDataJSON|.
+ : {{ScopedCredentialInfo/attestationObject}}
+ :: A new {{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 |authenticator| and
+ [=set/remove=] it from |issuedRequests|.
+ 4. [=Resolve=] |promise| with |value| and terminate this algorithm.
+
+
+
+1. [=Reject=] |promise| with a {{DOMException}} whose name is
+ "{{NotAllowedError}}".
+
+ Issue: {{NotAllowedError}} seems incorrect for at least the timeout and
+ cancelled exit conditions above.
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.
@@ -542,7 +643,7 @@ When this method is invoked, the user agent MUST execute the following algorithm
execute a platform-specific procedure to determine which, if any, credentials listed in {{AssertionOptions/allowList}}
might be present on this authenticator, and set |credentialList| to this filtered list. If no such filtering is
possible, set |credentialList| to an empty list.
- - For each credential C within the |credentialList| that has a non-empty |transports| list, optionally use only the
+ - For each credential C within the |credentialList| that has a non-empty {{transports}} list, optionally use only the
specified transports to get assertions using credential C.
- If the above filtering process concludes that none of the credentials on the {{AssertionOptions/allowList}} can possibly
be on this authenticator, do not perform any of the following steps for this authenticator, and proceed to the next
@@ -2115,7 +2216,7 @@ Note: Extensions should aim to define authenticator arguments that are as small
over low-bandwidth links such as Bluetooth Low-Energy or NFC.
-## Extending client processing ## {#extension-client-processing}
+## Extending client processing ## {#extension-client-processing}
Extensions may define additional processing requirements on the client platform during the creation of credentials or the
generation of an assertion. In order for the [RP] to verify the processing took place, or if the processing has a result
@@ -2932,6 +3033,14 @@ Brad Hill, Jing Jin, Anne van Kesteren, Giridhar Mandyam, Axel Nennker, Yaron Sh
"href": "https://tools.ietf.org/html/draft-greevenbosch-appsawg-cbor-cddl",
"status": "Internet Draft (work in progress)",
"date": "21 September 2016"
+ },
+
+ "TokenBinding": {
+ "authors": ["A. Popov", "M. Nystroem", "D. Balfanz", "A. Langley", "J. Hodges"],
+ "title": "The Token Binding Protocol Version 1.0",
+ "href": "https://tools.ietf.org/html/draft-ietf-tokbind-protocol-13",
+ "status": "Internet-Draft",
+ "date": "February 16, 2017"
}
}