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/
 
@@ -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: +
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" } }