From d879b79a8c3e7a73d134d63fc84db9948c278a7b Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Mon, 16 Oct 2017 18:22:29 +0200 Subject: [PATCH 01/29] Only exclude CredIDs matching the RPID Only credentials in the exclude credentials list that match this RPID should result in a not allowed error. --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index a7923e8b4..d3b4b991d 100644 --- a/index.bs +++ b/index.bs @@ -1762,8 +1762,8 @@ When this operation is invoked, the authenticator must perform the following pro 1. Check if at least one of the specified combinations of {{PublicKeyCredentialType}} and cryptographic parameters in |credTypesAndPubKeyAlgs| is supported. If not, return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. -1. Check if a credential matching an [=list/item=] of |excludeCredentialDescriptorList| is present on this authenticator. If - so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. +1. Check if a credential matching an [=list/item=] of |excludeCredentialDescriptorList| is present on this authenticator for + the supplied |rpId|. If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. If |requireResidentKey| is |true| and the authenticator cannot store a [=Client-side-resident Credential Private Key=], return an error code equivalent to "{{ConstraintError}}" and terminate the operation. 1. If |requireUserVerification| is |true| and the authenticator cannot perform user verification, From be4c139c8bdf0bc1fab835d63194fcf8b527b814 Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Mon, 23 Oct 2017 10:14:06 +0200 Subject: [PATCH 02/29] Change |rpId| to rpEntity.id --- index.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.bs b/index.bs index d3b4b991d..aeb1d9f02 100644 --- a/index.bs +++ b/index.bs @@ -1763,7 +1763,8 @@ When this operation is invoked, the authenticator must perform the following pro |credTypesAndPubKeyAlgs| is supported. If not, return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. 1. Check if a credential matching an [=list/item=] of |excludeCredentialDescriptorList| is present on this authenticator for - the supplied |rpId|. If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. + the supplied |rpEntity|.{{PublicKeyCredentialRpEntity/id}}. If so, return an error code equivalent to + "{{NotAllowedError}}" and terminate the operation. 1. If |requireResidentKey| is |true| and the authenticator cannot store a [=Client-side-resident Credential Private Key=], return an error code equivalent to "{{ConstraintError}}" and terminate the operation. 1. If |requireUserVerification| is |true| and the authenticator cannot perform user verification, From 4794adbb4ad20e4c0543ad7fb203149c0ce5fda9 Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Mon, 23 Oct 2017 19:40:08 +0200 Subject: [PATCH 03/29] Fix getAssertion too. --- index.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.bs b/index.bs index aeb1d9f02..39bff8cfb 100644 --- a/index.bs +++ b/index.bs @@ -1830,7 +1830,8 @@ When this method is invoked, the [=authenticator=] must perform the following pr equivalent to "{{UnknownError}}" and terminate the operation. 1. If |allowCredentialDescriptorList| was not supplied, set it to a list of all credentials stored for |rpId| (as determined by an exact match of |rpId|). -1. Remove any items from |allowCredentialDescriptorList| that are not present on this [=authenticator=]. +1. Remove any items from |allowCredentialDescriptorList| that are not present on this [=authenticator=] for + the supplied |rpEntity|.{{PublicKeyCredentialRpEntity/id}} 1. If |allowCredentialDescriptorList| is now empty, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. Prompt the user to select a [=public key credential|credential=] |selectedCredential| from |allowCredentialDescriptorList|. From a242e6a93c6874741385db1943c5e5cef82a9264 Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Mon, 23 Oct 2017 19:41:49 +0200 Subject: [PATCH 04/29] In this case it is |rpId| --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 39bff8cfb..9ddaf69a6 100644 --- a/index.bs +++ b/index.bs @@ -1831,7 +1831,7 @@ When this method is invoked, the [=authenticator=] must perform the following pr 1. If |allowCredentialDescriptorList| was not supplied, set it to a list of all credentials stored for |rpId| (as determined by an exact match of |rpId|). 1. Remove any items from |allowCredentialDescriptorList| that are not present on this [=authenticator=] for - the supplied |rpEntity|.{{PublicKeyCredentialRpEntity/id}} + the supplied |rpId|. 1. If |allowCredentialDescriptorList| is now empty, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. Prompt the user to select a [=public key credential|credential=] |selectedCredential| from |allowCredentialDescriptorList|. From af041112f1644967731fc340c0ac1bee74e2cea9 Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Thu, 2 Nov 2017 16:40:00 +0100 Subject: [PATCH 05/29] Improved language. --- index.bs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index 9ddaf69a6..7d61e2109 100644 --- a/index.bs +++ b/index.bs @@ -1762,9 +1762,10 @@ When this operation is invoked, the authenticator must perform the following pro 1. Check if at least one of the specified combinations of {{PublicKeyCredentialType}} and cryptographic parameters in |credTypesAndPubKeyAlgs| is supported. If not, return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. -1. Check if a credential matching an [=list/item=] of |excludeCredentialDescriptorList| is present on this authenticator for - the supplied |rpEntity|.{{PublicKeyCredentialRpEntity/id}}. If so, return an error code equivalent to - "{{NotAllowedError}}" and terminate the operation. +1. Check if any credential bound to this authenticator matches an [=list/item=] of |excludeCredentialDescriptorList|. A match + occurs if a credential matches |rpEntity|.{{PublicKeyCredentialRpEntity/id}}, |excludeCredentialDescriptorList|. + {{PublicKeyCredentialDescriptor/id}}, and |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/type}}. + If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. If |requireResidentKey| is |true| and the authenticator cannot store a [=Client-side-resident Credential Private Key=], return an error code equivalent to "{{ConstraintError}}" and terminate the operation. 1. If |requireUserVerification| is |true| and the authenticator cannot perform user verification, From 558c01377e5e1cc386fa9cf4c335af528ff7bc04 Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Thu, 2 Nov 2017 16:56:14 +0100 Subject: [PATCH 06/29] Fix up makeCredential with the same fixes. Also added a reference to the list item back in the correct place. --- index.bs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 7d61e2109..017abe556 100644 --- a/index.bs +++ b/index.bs @@ -1763,8 +1763,9 @@ When this operation is invoked, the authenticator must perform the following pro |credTypesAndPubKeyAlgs| is supported. If not, return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. 1. Check if any credential bound to this authenticator matches an [=list/item=] of |excludeCredentialDescriptorList|. A match - occurs if a credential matches |rpEntity|.{{PublicKeyCredentialRpEntity/id}}, |excludeCredentialDescriptorList|. - {{PublicKeyCredentialDescriptor/id}}, and |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/type}}. + occurs if a credential matches |rpEntity|.{{PublicKeyCredentialRpEntity/id}} and an |excludeCredentialDescriptorList| + item's |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/id}} and + |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/type}}. If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. If |requireResidentKey| is |true| and the authenticator cannot store a [=Client-side-resident Credential Private Key=], return an error code equivalent to "{{ConstraintError}}" and terminate the operation. @@ -1831,8 +1832,10 @@ When this method is invoked, the [=authenticator=] must perform the following pr equivalent to "{{UnknownError}}" and terminate the operation. 1. If |allowCredentialDescriptorList| was not supplied, set it to a list of all credentials stored for |rpId| (as determined by an exact match of |rpId|). -1. Remove any items from |allowCredentialDescriptorList| that are not present on this [=authenticator=] for - the supplied |rpId|. +1. Remove any items from |allowCredentialDescriptorList| that do not match a credential bound to this authenticator. A match + occurs if a credential matches |rpId| and an |allowCredentialDescriptorList| item's |allowCredentialDescriptorList| + {{PublicKeyCredentialDescriptor/id}} and |allowCredentialDescriptorList|{{PublicKeyCredentialDescriptor/type}}. + If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. If |allowCredentialDescriptorList| is now empty, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. Prompt the user to select a [=public key credential|credential=] |selectedCredential| from |allowCredentialDescriptorList|. From e051327afd111b69bfd741942b24a139efbe7ebe Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Thu, 2 Nov 2017 16:57:43 +0100 Subject: [PATCH 07/29] Update index.bs --- index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/index.bs b/index.bs index 017abe556..94c3c8274 100644 --- a/index.bs +++ b/index.bs @@ -1835,7 +1835,6 @@ When this method is invoked, the [=authenticator=] must perform the following pr 1. Remove any items from |allowCredentialDescriptorList| that do not match a credential bound to this authenticator. A match occurs if a credential matches |rpId| and an |allowCredentialDescriptorList| item's |allowCredentialDescriptorList| {{PublicKeyCredentialDescriptor/id}} and |allowCredentialDescriptorList|{{PublicKeyCredentialDescriptor/type}}. - If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. If |allowCredentialDescriptorList| is now empty, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. Prompt the user to select a [=public key credential|credential=] |selectedCredential| from |allowCredentialDescriptorList|. From 6e5f27fb19aebd99583c77c8f4ceb70b8bba54ff Mon Sep 17 00:00:00 2001 From: Johan Verrept Date: Thu, 2 Nov 2017 17:02:26 +0100 Subject: [PATCH 08/29] Fix indent. --- index.bs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 94c3c8274..4bd19aa9b 100644 --- a/index.bs +++ b/index.bs @@ -1763,10 +1763,10 @@ When this operation is invoked, the authenticator must perform the following pro |credTypesAndPubKeyAlgs| is supported. If not, return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. 1. Check if any credential bound to this authenticator matches an [=list/item=] of |excludeCredentialDescriptorList|. A match - occurs if a credential matches |rpEntity|.{{PublicKeyCredentialRpEntity/id}} and an |excludeCredentialDescriptorList| - item's |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/id}} and - |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/type}}. - If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. + occurs if a credential matches |rpEntity|.{{PublicKeyCredentialRpEntity/id}} and an |excludeCredentialDescriptorList| + item's |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/id}} and + |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/type}}. + If so, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. If |requireResidentKey| is |true| and the authenticator cannot store a [=Client-side-resident Credential Private Key=], return an error code equivalent to "{{ConstraintError}}" and terminate the operation. 1. If |requireUserVerification| is |true| and the authenticator cannot perform user verification, @@ -1833,8 +1833,8 @@ When this method is invoked, the [=authenticator=] must perform the following pr 1. If |allowCredentialDescriptorList| was not supplied, set it to a list of all credentials stored for |rpId| (as determined by an exact match of |rpId|). 1. Remove any items from |allowCredentialDescriptorList| that do not match a credential bound to this authenticator. A match - occurs if a credential matches |rpId| and an |allowCredentialDescriptorList| item's |allowCredentialDescriptorList| - {{PublicKeyCredentialDescriptor/id}} and |allowCredentialDescriptorList|{{PublicKeyCredentialDescriptor/type}}. + occurs if a credential matches |rpId| and an |allowCredentialDescriptorList| item's |allowCredentialDescriptorList| + {{PublicKeyCredentialDescriptor/id}} and |allowCredentialDescriptorList|{{PublicKeyCredentialDescriptor/type}}. 1. If |allowCredentialDescriptorList| is now empty, return an error code equivalent to "{{NotAllowedError}}" and terminate the operation. 1. Prompt the user to select a [=public key credential|credential=] |selectedCredential| from |allowCredentialDescriptorList|. From 9f5df060fc78da739e408e4aff2e7edd165e6fe3 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Fri, 3 Nov 2017 11:20:34 +0100 Subject: [PATCH 09/29] Make PublicKeyCredentialEntity hierarchy required members required in IDL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This resolves #587. Summary: - Make member `PublicKeyCredentialEntity.name` required - Make member `PublicKeyCredentialUserEntity.id` required - Make member `PublicKeyCredentialUserEntity.displayName` required - Remove algorithm step from _§5.1.3 Create a new credential_ that instructed to throw an exception if any of the above members were missing --- index.bs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/index.bs b/index.bs index b4157bc4f..634484d4a 100644 --- a/index.bs +++ b/index.bs @@ -639,12 +639,6 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |options| be the value of |options|.{{CredentialCreationOptions/publicKey}}. -1. If any of the {{PublicKeyCredentialEntity/name}} member of |options|.{{MakePublicKeyCredentialOptions/rp}}, the - {{PublicKeyCredentialEntity/name}} member of |options|.{{MakePublicKeyCredentialOptions/user}}, - the {{PublicKeyCredentialUserEntity/displayName}} member of |options|.{{MakePublicKeyCredentialOptions/user}}, - or the {{PublicKeyCredentialUserEntity/id}} - member of |options|.{{MakePublicKeyCredentialOptions/user}} are [=present|not present=], return a {{TypeError}} [=simple exception=]. - 1. If the {{MakePublicKeyCredentialOptions/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 a timer |lifetimeTimer| to this adjusted value. If the {{MakePublicKeyCredentialOptions/timeout}} member of |options| is [=present|not @@ -1260,8 +1254,8 @@ optionally evidence of [=user consent=] to a specific transaction. : rp :: This member contains data about the [=[RP]=] responsible for the request. - Its value's {{PublicKeyCredentialEntity/name}} member is required, and contains the friendly name of the [=[RP]=] - (e.g. "Acme Corporation", "Widgets, Inc.", or "Awesome Site". + Its value's {{PublicKeyCredentialEntity/name}} member contains the friendly name of the [=[RP]=] (e.g. "Acme Corporation", + "Widgets, Inc.", or "Awesome Site". Its value's {{PublicKeyCredentialRpEntity/id}} member specifies the [=relying party identifier=] with which the credential should be associated. If omitted, its value will be the {{CredentialsContainer}} object's [=relevant @@ -1270,14 +1264,14 @@ optionally evidence of [=user consent=] to a specific transaction. : user :: This member contains data about the user account for which the [=[RP]=] is requesting attestation. - Its value's {{PublicKeyCredentialEntity/name}} member is required, and contains a name for the user account - (e.g., "john.p.smith@example.com" or "+14255551234"). + Its value's {{PublicKeyCredentialEntity/name}} member contains a name for the user account (e.g., + "john.p.smith@example.com" or "+14255551234"). - Its value's {{PublicKeyCredentialUserEntity/displayName}} member is required, and contains a friendly name for the user - account (e.g., "John P. Smith"). + Its value's {{PublicKeyCredentialUserEntity/displayName}} member contains a friendly name for the user account (e.g., + "John P. Smith"). - Its value's {{PublicKeyCredentialUserEntity/id}} member is required and contains the [=user handle=] for the account, - specified by the [=[RP]=]. + Its value's {{PublicKeyCredentialUserEntity/id}} member contains the [=user handle=] for the account, specified by the + [=[RP]=]. : challenge :: This member contains a challenge intended to be used for generating the newly created credential's [=attestation @@ -1316,8 +1310,8 @@ associated. dictionary PublicKeyCredentialEntity { - DOMString name; - USVString icon; + required DOMString name; + USVString icon; };
@@ -1358,8 +1352,8 @@ credential.
     dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
-        BufferSource   id;
-        DOMString      displayName;
+        required BufferSource   id;
+        required DOMString      displayName;
     };
 
From 931b46eece69f5d780ce4b317e3a377a3a67f85c Mon Sep 17 00:00:00 2001 From: Angelo Liao Date: Wed, 8 Nov 2017 15:41:53 -0800 Subject: [PATCH 10/29] Make create() and get() abortable (#544) * do not call authenticatorMakeCredential() with separate |rpId| fixes #466 * credID returned by authnrGetAssn() is optional if allowCreds has exactly 1 member fixes #472 * fixup global object reference per domenic, improves #472 * indent 4.1.4 step 18et al to clarify relation to prior step * fix line indent * do not call authenticatorMakeCredential() with separate |rpId| fixes #466 * credID returned by authnrGetAssn() is optional if allowCreds has exactly 1 member fixes #472 * fixup global object reference per domenic, improves #472 * indent 4.1.4 step 18et al to clarify relation to prior step * fix line indent * post rebase-on-master, fix dangling MakeCredentialOptions * fix error in resolving rebase conflicts * further rebase conflict resolution error fixups * convert switch steps to colon-denotation * tag 'while' * primary changes for improving #472 mostly complete * further issue #472 cleanups * del 'cancel the timer' from #creatCredential fixes #535 * polish constructResultantCredentialCallback method description * marked authenticator model section as non-normative * marked relying party operation section as non-normative * fix proper subset tweak * Added abort signal object and steps to webauthn * fixed a minor issue with linking * add minor edits to focus on the main things * getting the blank line correct * Added a example section to explain how abort should be used * fix up example * committing before computer dies * updated grammars of the example based on feedback * update example text * Updated with the section on switching tab; complete the PR * minor tweak * finished polishing the spec * whoops one leftover * finally figured out how to remove last two linking errors * take out abortsignal from extension; edit promise rejection --- index.bs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index ce2ec4872..06e35fea5 100644 --- a/index.bs +++ b/index.bs @@ -91,10 +91,20 @@ spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-creden for: CredentialsContainer type: method text: create(); url: dom-credentialscontainer-create + type: dfn + text: signal spec: mixed-content; urlPrefix: www.w3.org/TR/mixed-content/ type: dfn text: a priori authenticated + +spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/ + type: dfn + text: visibility states + +spec: WHATWG HTML; urlPrefix: https://html.spec.whatwg.org/ + type: dfn + text: focus
- ## Authenticator Responses (interface AuthenticatorResponse) ## {#iface-authenticatorresponse} [=Authenticators=] respond to [=[RP]=] requests by returning an object derived from the @@ -1467,7 +1498,7 @@ an assertion. Its {{PublicKeyCredentialRequestOptions/challenge}} member must be :: This optional member contains a list of {{PublicKeyCredentialDescriptor}} object representing [=public key 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 list). - + : 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 @@ -1475,6 +1506,33 @@ an assertion. Its {{PublicKeyCredentialRequestOptions/challenge}} member must be +## Abort operations with `AbortSignal` ## {#abortoperation} + +Developers are encouraged to leverage the {{AbortController}} to manage the +{{PublicKeyCredential/[[Create]](options)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} operations. +See [[dom#abortcontroller-api-integration]] section for detailed instructions. + + Note: [[dom#abortcontroller-api-integration]] section specifies that web platform APIs integrating with the + {{AbortController}} must reject the promise immediately once the [=AbortSignal/aborted flag=] is set. + Given the complex inheritance and parallelization structure of the {{PublicKeyCredential/[[Create]](options)}} + and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} methods, the algorithms for the two APIs fulfills this + requirement by checking the [=AbortSignal/aborted flag=] in three places. In the case of + {{PublicKeyCredential/[[Create]](options)}}, the aborted flag is checked first in + [[credential-management-1#algorithm-create]] right before calling {{Credential/[[Create]](options)}}, + then in [[#createCredential]] right before authenticator sessions start, and finally + during authenticator sessions. The same goes for + {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}}. + +The [=visibility states|visibility=] and [=focus=] state of the [=Window=] object determines whether the +{{PublicKeyCredential/[[Create]](options)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} operations +should continue. When the [=Window=] object associated with the [[=Document=] loses focus, +{{PublicKeyCredential/[[Create]](options)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} operations +SHOULD be aborted. + + Issue: The WHATWG HTML WG is discussing whether to provide a hook when a browsing context gains or + loses focuses. If a hook is provided, the above paragraph will be updated to include the hook. + See [WHATWG HTML WG Issue #2711](https://github.com/whatwg/html/issues/2711) for more details. + ## Authentication Extensions (typedef AuthenticationExtensions) ## {#iface-authentication-extensions}
@@ -3808,6 +3866,42 @@ extension for transaction authorization.
     });
 
+## Aborting Authentication Operations ## {#sample-aborting} + +The below example shows how a developer may use the AbortSignal parameter to abort a +credential registration operation. A similiar procedure applies to an authentication operation. + +
+    const authAbortController = new AbortController(); 
+    const authAbortSignal = authAbortController.signal;
+
+    authAbortSignal.onabort = function () {
+        // Once the page knows the abort started, inform user it is attempting to abort.  
+    }
+
+    var options = {
+        // A list of options. 
+    }
+
+    navigator.credentials.create({
+        publicKey: options, 
+        signal: authAbortSignal})
+        .then(function (attestation) {
+            // Register the user. 
+        }).catch(function (error) {
+            if (error == "AbortError") {
+                // Inform user the credential hasn't been created. 
+                // Let the server know a key hasn't been created. 
+            }
+        });
+
+    // Assume widget shows up whenever auth occurs. 
+    if (widget == "disappear") {
+        authAbortSignal.abort(); 
+
+    }
+
+ ## Decommissioning ## {#sample-decommissioning} From d468a75b6a723867d24add0bd01bd7225acbcdbf Mon Sep 17 00:00:00 2001 From: =JeffH Date: Thu, 9 Nov 2017 07:49:23 -0800 Subject: [PATCH 11/29] fix #254: credman alignment: update #getAssertion section a la PR #498 (#665) * actually improve #254, and fix #661 * DiscoFrmExtSource(options) -> (origin, options) * make [[DiscoFrmExtSource]]'s exposition match [[Create]]'s * deal with yet another fix #254 straggler in [[Create]] * get rid of |global| in [[DiscoFrmExtSource]] * remove 'in parallel' and 'global' stuff from #discover-from-external-source alg * work on #discover-from-external-source alg to improve #254 * finish (one hopes) work on #discover-from-external-source alg to fix #254 * minor editorial * repair #createCredential intro parag, improves issue #671 * complete fix #671 --- index.bs | 272 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 167 insertions(+), 105 deletions(-) diff --git a/index.bs b/index.bs index 06e35fea5..0daa4b44b 100644 --- a/index.bs +++ b/index.bs @@ -58,7 +58,9 @@ spec: ECMAScript; urlPrefix: https://tc39.github.io/ecma262/# for: JSON; text: stringify; url: sec-json.stringify type: dfn text: %ArrayBuffer%; url: sec-arraybuffer-constructor - text: internal slot; url: sec-object-internal-methods-and-internal-slots + url: sec-object-internal-methods-and-internal-slots + text: internal method + text: internal slot spec: HTML52; urlPrefix: https://w3c.github.io/html/ @@ -87,7 +89,8 @@ spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-creden text: CredentialRequestOptions; url: dictdef-credentialrequestoptions for: Credential type: method - text: [[Create]](options) + text: [[Create]](origin, options) + text: [[DiscoverFromExternalSource]](origin, options) for: CredentialsContainer type: method text: create(); url: dom-credentialscontainer-create @@ -595,8 +598,8 @@ that are returned to the caller when a new credential is created, or a new asser {{PublicKeyCredential}}'s [=interface object=] inherits {{Credential}}'s implementation of {{Credential/[[CollectFromCredentialStore]](options)}} and {{Credential/[[Store]](credential)}}, and defines its own -implementation of {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} and -{{PublicKeyCredential/[[Create]](options)}}. +implementation of {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options)}} and +{{PublicKeyCredential/[[Create]](origin, options)}}. ### `CredentialCreationOptions` Extension ### {#credentialcreationoptions-extension} @@ -621,30 +624,35 @@ To support obtaining assertions via {{CredentialsContainer/get()|navigator.crede -### Create a new credential - PublicKeyCredential's `[[Create]](options)` method ### {#createCredential} +### Create a new credential - PublicKeyCredential's `[[Create]](origin, options)` method ### {#createCredential} -
+
{{PublicKeyCredential}}'s [=interface object=]'s implementation of the -\[[Create]](options) method allows scripts to call -{{CredentialsContainer/create()|navigator.credentials.create()}} to request the creation of a new [=credential key pair=] -and {{PublicKeyCredential}}, managed by an [=authenticator=]. -On success, the returned {{promise}} will be resolved with a {{PublicKeyCredential}} containing an -{{AuthenticatorAttestationResponse}} object. This {{CredentialsContainer/create()|navigator.credentials.create()}} -operation can be aborted by leveraging the {{AbortController}}; see -[[dom#abortcontroller-api-integration]] for detailed instructions. -Note: This algorithm is synchronous; the {{Promise}} resolution/rejection is handled by -{{CredentialsContainer/create()|navigator.credentials.create()}}. +\[[Create]](origin, options) [=internal method=] [[CREDENTIAL-MANAGEMENT-1]] allows +[=[RP]=] scripts to call {{CredentialsContainer/create()|navigator.credentials.create()}} to request the creation of a new +[=public key credential source=], bound to an [=authenticator=]. This +{{CredentialsContainer/create()|navigator.credentials.create()}} operation can be aborted by leveraging the {{AbortController}}; +see [[dom#abortcontroller-api-integration]] for detailed instructions. -This method accepts a single argument: -
+This method accepts two arguments: + +
+ + : origin + :: This argument is the [=relevant settings object=]'s [=environment settings object/origin=], as determined by the + calling {{CredentialsContainer/create()}} implementation. + : options :: This argument is a {{CredentialCreationOptions}} object whose - |options|.{{CredentialCreationOptions/publicKey}} member contains a {{MakePublicKeyCredentialOptions}} object - specifying the desired attributes of the to-be-created [=public key credential=]. + |options|.{{CredentialCreationOptions/publicKey}} member contains a {{MakePublicKeyCredentialOptions}} + object specifying the desired attributes of the to-be-created [=public key credential=].
+Note: This algorithm is synchronous: the {{Promise}} resolution/rejection is handled by +{{CredentialsContainer/create()|navigator.credentials.create()}}. + When this method is invoked, the user agent MUST execute the following algorithm: 1. Assert: |options|.{{CredentialCreationOptions/publicKey}} is [=present=]. @@ -656,11 +664,7 @@ When this method is invoked, the user agent MUST execute the following algorithm |lifetimeTimer| to this adjusted value. If the {{MakePublicKeyCredentialOptions/timeout}} member of |options| is [=present|not present=], then set |lifetimeTimer| to a platform-specific default. -1. Let |global| be the {{PublicKeyCredential}}'s [=interface object=]'s [=global object|environment settings object's global - object=]. - -1. Let |callerOrigin| be the [=environment settings object/origin=] specified by this {{PublicKeyCredential}} [=interface - object=]'s [=relevant settings object=]. If |callerOrigin| is an [=opaque origin=], return a {{DOMException}} whose name is +1. Let |callerOrigin| be {{PublicKeyCredential/[[Create]](origin, options)/origin}}. If |callerOrigin| is an [=opaque origin=], return a {{DOMException}} whose name is "{{NotAllowedError}}", and terminate this algorithm. 1. Let |effectiveDomain| be the |callerOrigin|'s [=effective domain=]. @@ -813,15 +817,15 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |credentialCreationData| be a [=struct=] whose [=items=] are: - : attestationObjectResult + : attestationObjectResult :: whose value is the bytes returned from the successful [=authenticatorMakeCredential=] operation. Note: this value is attObj, as defined in [[#generating-an-attestation-object]]. - : clientDataJSONResult + : clientDataJSONResult :: whose value is the bytes of |clientDataJSON|. - : clientExtensionResults + : clientExtensionResults :: whose value is an {{AuthenticationExtensions}} object containing [=extension identifier=] → [=client extension output=] entries. The entries are created by running each extension's [=client extension processing=] algorithm to create the [=client extension outputs=], for each @@ -845,14 +849,14 @@ When this method is invoked, the user agent MUST execute the following algorithm : {{AuthenticatorResponse/clientDataJSON}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of - |credentialCreationData|.[=clientDataJSONResult=]. + |credentialCreationData|.[=credentialCreationData/clientDataJSONResult=]. : {{AuthenticatorAttestationResponse/attestationObject}} :: |attestationObject| : {{PublicKeyCredential/[[clientExtensionsResults]]}} :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of - |credentialCreationData|.[=clientExtensionResults=]. + |credentialCreationData|.[=credentialCreationData/clientExtensionResults=]. 1. Return |pubKeyCred|. @@ -873,7 +877,7 @@ authorizing an authenticator. ### Use an existing credential to make an assertion ### {#getAssertion} [=[RPS]=] call navigator.credentials.get({publicKey:..., ...}) to -discover and use an existing [=public key credential=], with the user's consent. The script optionally specifies some criteria +discover and use an existing [=public key credential=], with the [=user consent|user's consent=]. [=[RP]=] script optionally specifies some criteria to indicate what [=credential sources=] are acceptable to it. The user agent and/or platform locates [=credential sources=] matching the specified criteria, and guides the user to pick one that the script will be allowed to use. The user may choose to decline the entire interaction even if a [=credential source=] is present, for example to maintain privacy. If the user picks a @@ -883,19 +887,37 @@ decline the entire interaction even if a [=credential source=] is present, for e The {{CredentialsContainer/get()}} implementation [[CREDENTIAL-MANAGEMENT-1]] calls PublicKeyCredential.{{PublicKeyCredential/[[CollectFromCredentialStore]]()}} to collect any [=credentials=] that -should be available without [=user mediation=] (roughly, this specification's [=authorization gesture=]), and if it doesn't find -exactly one of those, it calls PublicKeyCredential.{{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} to have +should be available without [=user mediation=] (roughly, this specification's [=authorization gesture=]), and if it does not find +exactly one of those, it then calls PublicKeyCredential.{{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} to have the user select a [=credential source=]. -Since this specification requires an [=authorization gesture=] to create any [=credentials=], PublicKeyCredential.\[[CollectFromCredentialStore]](options) inherits the default behavior of +Since this specification requires an [=authorization gesture=] to create any [=credentials=], the PublicKeyCredential.\[[CollectFromCredentialStore]](options) [=internal method=] inherits the default behavior of {{Credential/[[CollectFromCredentialStore]]()|Credential.[[CollectFromCredentialStore]]()}}, of returning an empty set. -
PublicKeyCredential's `[[DiscoverFromExternalSource]](options)` method
-
-When the PublicKeyCredential.\[[DiscoverFromExternalSource]](options) -method is invoked, the user agent MUST: +
PublicKeyCredential's `[[DiscoverFromExternalSource]](origin, options)` method
+ +
+ +The {{PublicKeyCredential}}.\[[DiscoverFromExternalSource]](origin, options) [=internal method=] accepts two arguments: + +
+ + : origin + :: This argument is the [=relevant settings object=]'s [=environment settings object/origin=], as determined by the + calling {{CredentialsContainer/get()}} implementation, i.e., {{CredentialsContainer}}'s Request a `Credential` abstract operation. + + : options + :: This argument is a {{CredentialRequestOptions}} object whose + |options|.{{CredentialRequestOptions/publicKey}} member contains a {{PublicKeyCredentialRequestOptions}} + object specifying the desired attributes of the [=public key credential=] to discover. +
+ +Note: This algorithm is synchronous: the {{Promise}} resolution/rejection is handled by +{{CredentialsContainer/get()|navigator.credentials.get()}}. + +When this method is invoked, the user agent MUST execute the following algorithm: 1. Assert: |options|.{{CredentialRequestOptions/publicKey}} is [=present=]. @@ -906,11 +928,8 @@ method is invoked, the user agent MUST: Set a timer |lifetimeTimer| to this adjusted value. If the {{PublicKeyCredentialRequestOptions/timeout}} member of |options| is [=present|not present=], then set |lifetimeTimer| to a platform-specific default. -1. Let |global| be the {{PublicKeyCredential}}'s [=interface object=]'s [=relevant global object=]. - -1. Let |callerOrigin| be the [=environment settings object/origin=] specified by this {{PublicKeyCredential}} [=interface - object=]'s [=relevant settings object=]. If |callerOrigin| is an [=opaque origin=], return a {{DOMException}} whose name is - "{{NotAllowedError}}", and terminate this algorithm. +1. Let |callerOrigin| be {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options)/origin}}. If |callerOrigin| is + an [=opaque origin=], return a {{DOMException}} whose name is "{{NotAllowedError}}", and terminate this algorithm. 1. Let |effectiveDomain| be the |callerOrigin|'s [=effective domain=]. If [=effective domain=] is not a [=valid domain=], then return a @@ -1004,9 +1023,13 @@ method is invoked, the user agent MUST: : [=list/is not empty=] :: 1. Let |distinctTransports| be a new [=ordered set=]. - 1. If |allowCredentialDescriptorList| has exactly one value, let |savedCredentialId| be a new {{ArrayBuffer}}, - created using |global|'s [=%ArrayBuffer%=], and containing the bytes of - |allowCredentialDescriptorList|[0].id. + 1. If |allowCredentialDescriptorList| has exactly one value, let |savedCredentialId| be a new + {{PublicKeyCredentialDescriptor}}.{{PublicKeyCredentialDescriptor/id}} and set its value to |allowCredentialDescriptorList|[0].id's + value (see [here](#authenticatorGetAssertion-return-values) in [[#op-get-assertion]] for more information). + + Issue: The foregoing step _may_ be incorrect, in that we are attempting to create |savedCredentialId| + here and use it later below, and we do not have a global in which to allocate a place for it. Perhaps this + is good enough? addendum: [@jcjones feels the above step is likely good enough](https://github.com/w3c/webauthn/pull/665#discussion_r148130187). 1. [=list/For each=] credential descriptor |C| in |allowCredentialDescriptorList|, [=set/append=] each value, if any, of |C|.{{transports}} to |distinctTransports|. @@ -1021,19 +1044,19 @@ method is invoked, the user agent MUST: configuration knowledge of the appropriate transport to use with |authenticator| in making its selection. - Then, using |transport|, invoke [=in parallel=] the [=authenticatorGetAssertion=] operation on + Then, using |transport|, invoke the [=authenticatorGetAssertion=] operation on |authenticator|, with |rpId|, |clientDataHash|, |allowCredentialDescriptorList|, and |authenticatorExtensions| as parameters. : [=list/is empty=] :: Using local configuration knowledge of the appropriate transport to use with |authenticator|, - invoke [=in parallel=] the [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, + invoke the [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, |clientDataHash|, |allowCredentialDescriptorList|, and |clientExtensions| as parameters.
: [=list/is empty=] :: Using local configuration knowledge of the appropriate transport to use with |authenticator|, invoke - [=in parallel=] the [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, |clientDataHash|, + the [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, |clientDataHash|, and |clientExtensions| as parameters. Note: In this case, the [=[RP]=] did not supply a list of acceptable credential descriptors. Thus the @@ -1043,62 +1066,97 @@ method is invoked, the user agent MUST: 1. [=set/Append=] |authenticator| to |issuedRequests|. -1. Execute the following steps [=in parallel=]. The [=task source=] for these [=tasks=] is the [=dom manipulation task source=]. +1. While |issuedRequests| [=list/is not empty=], perform the following actions depending upon |lifetimeTimer| + and responses from the authenticators: - 1. While |issuedRequests| [=list/is not empty=], perform the following actions depending upon |lifetimeTimer| - and responses from the authenticators: +
-
+ : If |lifetimeTimer| expires, + :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on + |authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. + + : If the {{CredentialRequestOptions/signal}} member is [=present=] and the [=AbortSignal/aborted flag=] is set to + true, + :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| + and [=set/remove=] |authenticator| from |issuedRequests|. Then + return a {{DOMException}} whose name is "{{AbortError}}" and terminate this algorithm. + + : If any |authenticator| returns a status indicating that the user cancelled the operation, + :: 1. [=set/Remove=] |authenticator| from |issuedRequests|. + 1. [=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|. + + 1. Let assertionCreationData be a [=struct=] whose [=items=] are: - : If |lifetimeTimer| expires, - :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on - |authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. + : credentialIdResult + :: If |savedCredentialId| exists, set the value of [=credentialIdResult=] to be the bytes of + |savedCredentialId|. Otherwise, set the value of [=credentialIdResult=] to be the bytes of the + [=credential ID=] returned from the successful [=authenticatorGetAssertion=] operation, as defined in + [[#op-get-assertion]]. + + : clientDataJSONResult + :: whose value is the bytes of |clientDataJSON|. - : If the {{CredentialRequestOptions/signal}} member is [=present=] and the [=AbortSignal/aborted flag=] is set to - true, - :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| - and [=set/remove=] |authenticator| from |issuedRequests|. Then - return a {{DOMException}} whose name is "{{AbortError}}" and terminate this algorithm. + : authenticatorDataResult + :: whose value is the bytes of the [=authenticator data=] returned by the [=authenticator=]. - : If any |authenticator| returns a status indicating that the user cancelled the operation, - :: 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|. + : signatureResult + :: whose value is the bytes of the signature value returned by the [=authenticator=]. - : If any |authenticator| returns an error status, - :: [=set/Remove=] |authenticator| from |issuedRequests|. + : userHandleResult + :: whose value is the bytes of the [=user handle=] returned by the [=authenticator=]. - : If any |authenticator| indicates success, - :: 1. [=set/Remove=] |authenticator| from |issuedRequests|. - 2. Let |value| be a new {{PublicKeyCredential}} associated with |global| whose fields are: + : clientExtensionResults + :: whose value is an {{AuthenticationExtensions}} object containing [=extension identifier=] → + [=client extension output=] entries. The entries are created by running each extension's + [=client extension processing=] algorithm to create the [=client extension outputs=], for each + [=client extension=] in {{AuthenticatorResponse/clientDataJSON}}.clientExtensions. + + 1. Let |constructAssertionAlg| be an algorithm that takes a [=global object=] + |global|, and whose steps are: + + 1. Let |pubKeyCred| be a new {{PublicKeyCredential}} object associated with |global| whose fields are: : {{PublicKeyCredential/[[identifier]]}} - :: Create a new {{ArrayBuffer}}, using |global|'s [=%ArrayBuffer%=]. - If |savedCredentialId| exists, set the value of the new {{ArrayBuffer}} to be the bytes of - |savedCredentialId|. Otherwise, set the value of the new {{ArrayBuffer}} to be the bytes of the - [=credential ID=] returned from the successful [=authenticatorGetAssertion=] operation, as defined in - [[#op-get-assertion]]. + :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of + |assertionCreationData|.[=credentialIdResult=]. : {{PublicKeyCredential/response}} :: A new {{AuthenticatorAssertionResponse}} object associated with |global| whose fields are: - : {{AuthenticatorResponse/clientDataJSON}} - :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of - |clientDataJSON|. - : {{AuthenticatorAssertionResponse/authenticatorData}} - :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the - returned {{authenticatorData}}. - : {{AuthenticatorAssertionResponse/signature}} - :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the - returned {{signature}}. - : {{AuthenticatorAssertionResponse/userHandle}} - :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the [=user handle=] - returned from the successful [=authenticatorGetAssertion=] operation, as defined in - [[#op-get-assertion]]. - - 3. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation - on |authenticator| and [=set/remove=] it from |issuedRequests|. - 4. Return |value| and terminate this algorithm. -
+ + : {{AuthenticatorResponse/clientDataJSON}} + :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of + |assertionCreationData|.[=assertionCreationData/clientDataJSONResult=]. + + : {{AuthenticatorAssertionResponse/authenticatorData}} + :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of + |assertionCreationData|.[=assertionCreationData/authenticatorDataResult=]. + + : {{AuthenticatorAssertionResponse/signature}} + :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of + |assertionCreationData|.[=assertionCreationData/signatureResult=]. + + : {{AuthenticatorAssertionResponse/userHandle}} + :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of + |assertionCreationData|.[=assertionCreationData/userHandleResult=]. + + : {{PublicKeyCredential/[[clientExtensionsResults]]}} + :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of + |assertionCreationData|.[=assertionCreationData/clientExtensionResults=]. + + 1. Return |pubKeyCred|. + + 1. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation + on |authenticator| and [=set/remove=] it from |issuedRequests|. + + 1. Return |constructAssertionAlg| and terminate this algorithm. +
1. Return a {{DOMException}} whose name is "{{NotAllowedError}}". @@ -2011,16 +2069,19 @@ When this method is invoked, the [=authenticator=] must perform the following pr 1. If any error occurred while generating the [=assertion signature=], return an error code equivalent to "{{UnknownError}}" and terminate the operation. -1. Return to the user agent: - - |selectedCredential|'s [=credential ID=], if either a list of credentials of length 2 or greater was supplied by the client, - or no such list was supplied. +
  • + Return to the user agent: + - |selectedCredential|'s [=credential ID=], if either a list of credentials of length 2 or greater was supplied by the + client, or no such list was supplied. Otherwise, return only the below values. - Note: If the client supplies a list of exactly one credential and it was successfully employed, then its [=credential ID=] - is not returned since the client already knows it. + Note: If the client supplies a list of exactly one credential and it was successfully employed, then its + [=credential ID=] is not returned since the client already knows it. This saves transmitting these bytes over + what may be a constrained connection in what is likely a common case. - - |authenticatorData| - - |signature| - - The [=user handle=] associated with |selectedCredential|. + - |authenticatorData| + - |signature| + - The [=user handle=] associated with |selectedCredential|. +
  • If the authenticator cannot find any credential corresponding to the specified [=[RP]=] that matches the specified criteria, it terminates the operation and returns an error. @@ -2364,7 +2425,7 @@ When registering a new credential, represented by a {{AuthenticatorAttestationRe 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 - {{PublicKeyCredential/[[Create]](options)/options}}.{{MakePublicKeyCredentialOptions/user}} passed to + {{PublicKeyCredential/[[Create]](origin, options)/options}}.{{MakePublicKeyCredentialOptions/user}} passed to {{CredentialsContainer/create()}}, by associating it with the [=credentialId=] and [=credentialPublicKey=] in the [=attestedCredentialData=] in |authData|, as appropriate for the [=[RP]=]'s system. @@ -3182,9 +3243,10 @@ error. :: A single JSON string specifying a FIDO |appId|. : Client extension processing -:: If {{PublicKeyCredentialRequestOptions/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 +:: If {{PublicKeyCredentialRequestOptions/rpId}} is present, return a DOMException + whose name is "{{NotAllowedError}}", and terminate this algorithm ([[#discover-from-external-source]]). + + Otherwise, replace the calculation of |rpId| in Step 6 of [[#discover-from-external-source]] with the following procedure: The client uses the value of |appid| to perform the AppId validation procedure (as defined by [[FIDO-APPID]]). If valid, the value of |rpId| for all client processing should be replaced by the From 0e93926d7c77afd07e75002880f15b53e5137bf2 Mon Sep 17 00:00:00 2001 From: gmandyam Date: Thu, 9 Nov 2017 11:33:22 -0800 Subject: [PATCH 12/29] Modify SafetyNet descriptive text (#643) * Update index.bs Biometric Selection Criteria extension * Update index.bs * Update index.bs * Update index.bs * Update index.bs --- index.bs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 0daa4b44b..24430d08a 100644 --- a/index.bs +++ b/index.bs @@ -2858,7 +2858,9 @@ When the [=authenticator=] in question is a platform-provided Authenticator on c statement is based on the [SafetyNet API](https://developer.android.com/training/safetynet/index.html#compat-check-response). In this case the [=authenticator data=] is completely controlled by the caller of the SafetyNet API (typically an application running on the Android platform) and the attestation statement only provides some statements about the health of the platform -and the identity of the calling application. +and the identity of the calling application. This attestation does not provide information regarding provenance of the authenticator +and its associated data. Therefore platform-provided authenticators should make use of the Android Key Attestation when available, +even if the SafetyNet API is also present. : Attestation statement format identifier :: android-safetynet @@ -3581,7 +3583,6 @@ This [=registration extension=] and [=authentication extension=] enables use of 01 -- Subitem 3: CBOR short for Matcher Protection Type Software - # IANA Considerations # {#sctn-IANA} ## WebAuthn Attestation Statement Format Identifier Registrations ## {#sctn-att-fmt-reg} From 63564a4ff5261dcd7f1e2e626ce81b7b96ebeb2f Mon Sep 17 00:00:00 2001 From: rlin1 Date: Thu, 9 Nov 2017 11:39:24 -0800 Subject: [PATCH 13/29] replaced authenticatio key by credential private key. Close #590 --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 0daa4b44b..d3d1500f7 100644 --- a/index.bs +++ b/index.bs @@ -2246,7 +2246,7 @@ WebAuthn supports multiple attestation types: : Self Attestation :: In the case of [=self attestation=], also known as surrogate basic attestation [[UAFProtocol]], the Authenticator does not have - any specific attestation key. Instead it uses the authentication key itself to create the attestation signature. + any specific attestation key. Instead it uses the credential private key to create the attestation signature. Authenticators without meaningful protection measures for an attestation private key typically use this attestation type. : Privacy CA From 40875f1e798bac1cd7f6393c16da39d671e32ebb Mon Sep 17 00:00:00 2001 From: rlin1 Date: Thu, 9 Nov 2017 11:45:26 -0800 Subject: [PATCH 14/29] use the registered ext ids in examples --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 24430d08a..2acdb2b73 100644 --- a/index.bs +++ b/index.bs @@ -3783,7 +3783,7 @@ The sample code for generating and registering a new key follows: timeout: 60000, // 1 minute excludeCredentials: [], // No exclude list of PKCredDescriptors - extensions: {"webauthn.location": true} // Include location information + extensions: {"loc": true} // Include location information // in attestation }; @@ -3917,7 +3917,7 @@ extension for transaction authorization. challenge: encoder.encode("climb a mountain"), timeout: 60000, // 1 minute allowCredentials: [acceptableCredential1, acceptableCredential2], - extensions: { 'webauthn.txauth.simple': + extensions: { 'txAuthSimple': "Wave your hands in the air like you just don't care" } }; From 1194ce5b3204240561e0e075342d3ea303c40d4c Mon Sep 17 00:00:00 2001 From: Rolf Lindemann Date: Thu, 9 Nov 2017 20:53:10 +0100 Subject: [PATCH 15/29] Updated authnr def (#678) * updated the definition of authenticator * updated according to comment From 474d0254a0d1db20d77da89b10a5c124148b75d3 Mon Sep 17 00:00:00 2001 From: balfanz Date: Thu, 9 Nov 2017 13:22:31 -0800 Subject: [PATCH 16/29] Clarify semantics of isPlatformAuthenticatorAvailable This closes #627. --- index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 7d8cb85a0..66632d115 100644 --- a/index.bs +++ b/index.bs @@ -1189,9 +1189,9 @@ When this method is invoked, the user agent MUST execute the following algorithm
    -[=[RPS]=] use this method to determine whether they can create a new credential using a [=platform authenticator=]. -Upon invocation, the [=client=] employs a platform-specific procedure to discover available [=platform authenticators=]. -If successful, the [=client=] then assesses whether the user is willing to create a credential using one of the available [=platform authenticators=]. +[=[RPS]=] use this method to determine whether they can create a new credential using a user verifying [=platform authenticator=]. +Upon invocation, the [=client=] employs a platform-specific procedure to discover available user-verifying [=platform authenticators=]. +If successful, the [=client=] then assesses whether the user is willing to create a credential using one of the available user verifying [=platform authenticators=]. This assessment may include various factors, such as: - Whether the user is running in private or incognito mode. - Whether the user has configured the [=client=] to not create such credentials. @@ -3799,7 +3799,7 @@ The sample code for generating and registering a new key follows: ## Registration Specifically with Platform Authenticator ## {#sample-registration-with-platform-authenticator} This is flow for when the [=[RP]=] is specifically interested in creating a public key credential with -a [=platform authenticator=]. +a user verifying [=platform authenticator=]. 1. The user visits example.com and clicks on the login button, which redirects the user to login.example.com. From 25a35a9229825dec100e9e65dcf3647c24d6001c Mon Sep 17 00:00:00 2001 From: balfanz Date: Thu, 9 Nov 2017 13:38:14 -0800 Subject: [PATCH 17/29] changing name of method changing name of method to isUserVerifyingPlatformAuthenticatorAvailable --- index.bs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.bs b/index.bs index 66632d115..25885c6ca 100644 --- a/index.bs +++ b/index.bs @@ -1185,9 +1185,9 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Return a {{DOMException}} whose name is "{{NotSupportedError}}", and terminate this algorithm -### Platform Authenticator Availability - PublicKeyCredential's `isPlatformAuthenticatorAvailable()` method ### {#isPlatformAuthenticatorAvailable} +### Availability of User-Verifying Platform Authenticator - PublicKeyCredential's `isUserVerifyingPlatformAuthenticatorAvailable()` method ### {#isUserVerifyingPlatformAuthenticatorAvailable} -
    +
    [=[RPS]=] use this method to determine whether they can create a new credential using a user verifying [=platform authenticator=]. Upon invocation, the [=client=] employs a platform-specific procedure to discover available user-verifying [=platform authenticators=]. @@ -1216,7 +1216,7 @@ but short enough that the dangling promise will still be resolved in a reasonabl
         partial interface PublicKeyCredential {
    -        static Promise < boolean > isPlatformAuthenticatorAvailable();
    +        static Promise < boolean > isUserVerifyingPlatformAuthenticatorAvailable();
         };
     
    @@ -3796,7 +3796,7 @@ The sample code for generating and registering a new key follows: }); -## Registration Specifically with Platform Authenticator ## {#sample-registration-with-platform-authenticator} +## Registration Specifically with User Verifying Platform Authenticator ## {#sample-registration-with-platform-authenticator} This is flow for when the [=[RP]=] is specifically interested in creating a public key credential with a user verifying [=platform authenticator=]. @@ -3817,7 +3817,7 @@ a user verifying [=platform authenticator=].
         if (!PublicKeyCredential) { /* Platform not capable of the API. Handle error. */ }
     
    -    PublicKeyCredential.isPlatformAuthenticatorAvailable()
    +    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
             .then(function (userIntent) {
     
                 // If the user has affirmed willingness to register with RP using an available platform authenticator
    
    From 1dd484021d437d9046b1b65e90c8b0880a5f6606 Mon Sep 17 00:00:00 2001
    From: balfanz 
    Date: Thu, 9 Nov 2017 13:43:22 -0800
    Subject: [PATCH 18/29] adding references
    
    Added references to the definition of user verification.
    ---
     index.bs | 12 ++++++------
     1 file changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/index.bs b/index.bs
    index 25885c6ca..8cb5b730c 100644
    --- a/index.bs
    +++ b/index.bs
    @@ -1189,9 +1189,9 @@ When this method is invoked, the user agent MUST execute the following algorithm
     
     
    -[=[RPS]=] use this method to determine whether they can create a new credential using a user verifying [=platform authenticator=]. -Upon invocation, the [=client=] employs a platform-specific procedure to discover available user-verifying [=platform authenticators=]. -If successful, the [=client=] then assesses whether the user is willing to create a credential using one of the available user verifying [=platform authenticators=]. +[=[RPS]=] use this method to determine whether they can create a new credential using a [=user verification|user-verifying=] [=platform authenticator=]. +Upon invocation, the [=client=] employs a platform-specific procedure to discover available [=user verification|user-verifying=] [=platform authenticators=]. +If successful, the [=client=] then assesses whether the user is willing to create a credential using one of the available [=user verification|user-verifying=] [=platform authenticators=]. This assessment may include various factors, such as: - Whether the user is running in private or incognito mode. - Whether the user has configured the [=client=] to not create such credentials. @@ -1207,8 +1207,8 @@ This method has no arguments and returns a boolean value. If the promise will return False, the [=client=] SHOULD wait a fixed period of time from the invocation of the method before returning False. This is done so that callers can not distinguish between -the case where the user was unwilling to create a credential using one of the available [=platform authenticators=] and -the case where no [=platform authenticator=] exists. +the case where the user was unwilling to create a credential using one of the available [=user verification|user-verifying=] [=platform authenticators=] and +the case where no [=user verification|user-verifying=] [=platform authenticator=] exists. Trying to make these cases indistinguishable is done in an attempt to not provide additional information that could be used for fingerprinting. A timeout value on the order of 10 minutes is recommended; this is enough time for successful user interactions to be performed @@ -3799,7 +3799,7 @@ The sample code for generating and registering a new key follows: ## Registration Specifically with User Verifying Platform Authenticator ## {#sample-registration-with-platform-authenticator} This is flow for when the [=[RP]=] is specifically interested in creating a public key credential with -a user verifying [=platform authenticator=]. +a [=user verification|user-verifying=] [=platform authenticator=]. 1. The user visits example.com and clicks on the login button, which redirects the user to login.example.com. From 5f4f3e64ae77843d50f85b2f5b632a47f0088c00 Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Thu, 9 Nov 2017 14:00:38 -0800 Subject: [PATCH 19/29] Fix attestation types supported for each format --- index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 8cb5b730c..6161213fc 100644 --- a/index.bs +++ b/index.bs @@ -2669,7 +2669,7 @@ engine. :: tpm : Attestation types supported -:: Privacy CA, ECDAA +:: [=Privacy CA=], [=ECDAA=] : Syntax :: The syntax of a TPM Attestation statement is as follows: @@ -2800,7 +2800,7 @@ the attestation=] is consistent with the fields of the attestation certificate's :: android-key : Attestation types supported -:: Basic +:: [=Basic Attestation=] : Syntax :: An Android key attestation statement consists simply of the Android attestation statement, which is a series of @@ -2866,7 +2866,7 @@ even if the SafetyNet API is also present. :: android-safetynet : Attestation types supported -:: Basic +:: [=Basic Attestation=] : Syntax :: The syntax of an Android Attestation statement is defined as follows: @@ -2924,7 +2924,7 @@ This attestation statement format is used with FIDO U2F authenticators using the :: fido-u2f : Attestation types supported -:: Basic, [=self attestation=] +:: [=Basic Attestation=], [=Self Attestation=], [=Privacy CA=] : Syntax :: The syntax of a FIDO U2F attestation statement is defined as follows: From 21f5886f77d0a50c427beb64315275eb2b41d4da Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Thu, 9 Nov 2017 13:37:36 -0800 Subject: [PATCH 20/29] Fix #404 - Add a Security Consideration for Cryptographic Challenges --- index.bs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 6161213fc..65a0c09f6 100644 --- a/index.bs +++ b/index.bs @@ -1541,7 +1541,7 @@ an assertion. Its {{PublicKeyCredentialRequestOptions/challenge}} member must be
    : challenge :: This member represents a challenge that the selected [=authenticator=] signs, along with other data, when producing an - [=authentication assertion=]. + [=authentication assertion=]. See the [[#cryptographic-challenges]] security consideration. : timeout :: This optional member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. @@ -1627,6 +1627,7 @@ following Web IDL.
    The challenge member contains the base64url encoding of the challenge provided by the RP. + See the [[#cryptographic-challenges]] security consideration. The origin member contains the fully qualified [=origin=] of the requester, as provided to the authenticator by the client, in the syntax defined by [[RFC6454]]. @@ -3114,7 +3115,8 @@ The entry key is the [=extension identifier=] and the value is the [=client exte
         var assertionPromise = navigator.credentials.get({
             publicKey: {
    -            challenge: "...",
    +            // The challenge must be produced by the server, see the Security Considerations
    +            challenge: new Uint8Array([4,99,22 /* 29 more random bytes generated by the server */]),
                 extensions: {
                     "webauthnExample_foobar": 42
                 }
    @@ -3180,7 +3182,8 @@ the use of the extension. The [=[RP]=] sets this value in its request for an ass
         var assertionPromise =
             navigator.credentials.get({
                 publicKey: {
    -                challenge: "SGFuIFNvbG8gc2hvdCBmaXJzdC4",
    +                // The challenge must be produced by the server, see the Security Considerations
    +                challenge: new Uint8Array([11,103,35 /* 29 more random bytes generated by the server */]),
                     allowCredentials: [], /* Empty filter */
                     extensions: { 'webauthnExample_geo': true }
                 }
    @@ -3753,7 +3756,8 @@ The sample code for generating and registering a new key follows:
         if (!PublicKeyCredential) { /* Platform not capable. Handle error. */ }
     
         var publicKey = {
    -      challenge: Uint8Array.from(window.atob("PGifxAoBwCkWkm4b1CiIl5otCphiIh6MijdjbWFjomA="), c=>c.charCodeAt(0)),
    +      // The challenge must be produced by the server, see the Security Considerations
    +      challenge: new Uint8Array([21,31,105 /* 29 more random bytes generated by the server */]),
     
           // Relying Party:
           rp: {
    @@ -3883,7 +3887,8 @@ credentials, then the sample code for performing such an authentication might lo
         if (!PublicKeyCredential) { /* Platform not capable. Handle error. */ }
     
         var options = {
    -                    challenge: new TextEncoder().encode("climb a mountain"),
    +                    // The challenge must be produced by the server, see the Security Considerations
    +                    challenge: new Uint8Array([4,101,15 /* 29 more random bytes generated by the server */]),
                         timeout: 60000,  // 1 minute
                         allowCredentials: [{ type: "public-key" }]
                       };
    @@ -3914,7 +3919,8 @@ extension for transaction authorization.
         };
     
         var options = {
    -                    challenge: encoder.encode("climb a mountain"),
    +                    // The challenge must be produced by the server, see the Security Considerations
    +                    challenge: new Uint8Array([8,18,33 /* 29 more random bytes generated by the server */]),
                         timeout: 60000,  // 1 minute
                         allowCredentials: [acceptableCredential1, acceptableCredential2],
                         extensions: { 'webauthn.txauth.simple':
    @@ -3989,6 +3995,16 @@ handled on the server side and do not need support from the API specified here.
         * Sometime later, the server deregisters this credential due to inactivity.
     
     
    +# Security Considerations # {#security-considerations}
    +
    +## Cryptographic Challenges ## {#cryptographic-challenges}
    +As a cryptographic protocol, Web Authentication is dependent upon randomized challenges
    +to avoid replay attacks. Therefore, the [=challenge=] fields MUST be randomly generated
    +by the [=Relying Party=] in an environment they trust, and the challenge in the client's
    +response MUST match what was generated. This should be done in a fashion that does not rely
    +upon a client's behavior; e.g.: the Relying Party should store the challenge temporarily
    +until the operation is complete. Tolerating a mismatch will compromise the security
    +of the protocol.
     
     
     # Acknowledgements # {#acknowledgements}
    
    From abf8afea9183450ce2175e976c6d23216c46e2da Mon Sep 17 00:00:00 2001
    From: "J.C. Jones" 
    Date: Thu, 9 Nov 2017 09:49:13 -0800
    Subject: [PATCH 21/29] Resolve #292 - Clarify that only one operation is
     permitted per authenticator session
    
    ---
     index.bs | 22 ++++++++++++----------
     1 file changed, 12 insertions(+), 10 deletions(-)
    
    diff --git a/index.bs b/index.bs
    index 6161213fc..5f47edb95 100644
    --- a/index.bs
    +++ b/index.bs
    @@ -1577,8 +1577,8 @@ See [[dom#abortcontroller-api-integration]] section for detailed instructions.
         requirement by checking the [=AbortSignal/aborted flag=] in three places. In the case of 
         {{PublicKeyCredential/[[Create]](options)}}, the aborted flag is checked first in 
         [[credential-management-1#algorithm-create]] right before calling {{Credential/[[Create]](options)}}, 
    -    then in [[#createCredential]] right before authenticator sessions start, and finally 
    -    during authenticator sessions. The same goes for 
    +    then in [[#createCredential]] right before [=authenticator session=]s start, and finally
    +    during [=authenticator session=]s. The same goes for
         {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}}.
     
     The [=visibility states|visibility=] and [=focus=] state of the [=Window=] object determines whether the 
    @@ -1929,7 +1929,7 @@ Authenticators:
     ## Authenticator operations ## {#authenticator-ops}
     
     A client must connect to an authenticator in order to invoke any of the operations of that authenticator. This connection
    -defines an authenticator session. An authenticator must maintain isolation between sessions. It may do this by only allowing one
    +defines an authenticator session. An authenticator must maintain isolation between sessions. It may do this by only allowing one
     session to exist at any particular time, or by providing more complicated session management.
     
     The following operations can be invoked by the client in an authenticator session.
    @@ -1937,8 +1937,7 @@ The following operations can be invoked by the client in an authenticator sessio
     
     

    The authenticatorMakeCredential operation

    -This operation must be invoked in an authenticator session which has no other operations in progress. It takes the following -input parameters: +It takes the following input parameters: : |hash| @@ -1963,7 +1962,9 @@ input parameters: :: A [=map=] from [=extension identifiers=] to their [=authenticator extension inputs=], created by the client based on the extensions requested by the [=[RP]=], if any. -When this operation is invoked, the authenticator must perform the following procedure: +Note: Before performing this operation, all other operations in progress in the [=authenticator session=] must be aborted by setting their [=AbortSignal/aborted flag=] to true. + +When this operation is invoked, the [=authenticator=] must perform the following procedure: 1. Check if all the supplied parameters are syntactically well-formed and of the correct length. If not, return an error code equivalent to "{{UnknownError}}" and terminate the operation. 1. Check if at least one of the specified combinations of {{PublicKeyCredentialType}} and cryptographic parameters in @@ -2020,8 +2021,7 @@ On successful completion of this operation, the authenticator returns the [=atte

    The authenticatorGetAssertion operation

    -This operation must be invoked in an authenticator session which has no other operations in progress. It takes the following -input parameters: +It takes the following input parameters: : |rpId| :: The caller's [=RP ID=], as determined by the user agent and the client. @@ -2034,6 +2034,8 @@ input parameters: :: A [=map=] from [=extension identifiers=] to their [=authenticator extension inputs=], created by the client based on the extensions requested by the [=[RP]=], if any. +Note: Before performing this operation, all other operations in progress in the [=authenticator session=] must be aborted by setting their [=AbortSignal/aborted flag=] to true. + When this method is invoked, the [=authenticator=] must perform the following procedure: 1. Check if all the supplied parameters are syntactically well-formed and of the correct length. If not, return an error code equivalent to "{{UnknownError}}" and terminate the operation. @@ -2093,12 +2095,12 @@ If the user refuses consent, the authenticator returns an appropriate error stat This operation takes no input parameters and returns no result. -When this operation is invoked by the client in an authenticator session, it has the effect of terminating any +When this operation is invoked by the client in an [=authenticator session=], it has the effect of terminating any [=authenticatorMakeCredential=] or [=authenticatorGetAssertion=] operation currently in progress in that authenticator session. The authenticator stops prompting for, or accepting, any user input related to authorizing the canceled operation. The client ignores any further responses from the authenticator for the canceled operation. -This operation is ignored if it is invoked in an authenticator session which does not have an [=authenticatorMakeCredential=] +This operation is ignored if it is invoked in an [=authenticator session=] which does not have an [=authenticatorMakeCredential=] or [=authenticatorGetAssertion=] operation currently in progress. From 28657152284a74519b4ae60c1c22b985ec4fb21d Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Thu, 9 Nov 2017 14:11:15 -0800 Subject: [PATCH 22/29] Review updates --- index.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index 5f47edb95..1c861c3d2 100644 --- a/index.bs +++ b/index.bs @@ -1576,9 +1576,9 @@ See [[dom#abortcontroller-api-integration]] section for detailed instructions. and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} methods, the algorithms for the two APIs fulfills this requirement by checking the [=AbortSignal/aborted flag=] in three places. In the case of {{PublicKeyCredential/[[Create]](options)}}, the aborted flag is checked first in - [[credential-management-1#algorithm-create]] right before calling {{Credential/[[Create]](options)}}, - then in [[#createCredential]] right before [=authenticator session=]s start, and finally - during [=authenticator session=]s. The same goes for + [[credential-management-1#algorithm-create]] immediately before calling {{Credential/[[Create]](options)}}, + then in [[#createCredential]] right before [=authenticator sessions=] start, and finally + during [=authenticator sessions=]. The same goes for {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}}. The [=visibility states|visibility=] and [=focus=] state of the [=Window=] object determines whether the From f496efac6ce2e84692e1bc1d42e6453ba90e2584 Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Thu, 9 Nov 2017 14:12:55 -0800 Subject: [PATCH 23/29] Review updates --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 65a0c09f6..3549cc21e 100644 --- a/index.bs +++ b/index.bs @@ -3999,9 +3999,9 @@ handled on the server side and do not need support from the API specified here. ## Cryptographic Challenges ## {#cryptographic-challenges} As a cryptographic protocol, Web Authentication is dependent upon randomized challenges -to avoid replay attacks. Therefore, the [=challenge=] fields MUST be randomly generated +to avoid replay attacks. Therefore, the [=challenge=] field MUST be randomly generated by the [=Relying Party=] in an environment they trust, and the challenge in the client's -response MUST match what was generated. This should be done in a fashion that does not rely +response must match what was generated. This should be done in a fashion that does not rely upon a client's behavior; e.g.: the Relying Party should store the challenge temporarily until the operation is complete. Tolerating a mismatch will compromise the security of the protocol. From 31ddb22449a62bcb05b901234fb29a80281953a6 Mon Sep 17 00:00:00 2001 From: Rolf Lindemann Date: Thu, 9 Nov 2017 23:16:02 +0100 Subject: [PATCH 24/29] Fix uvm 368 (#675) * fix copy and paste error * improve wording --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 23c009852..e1f7b291b 100644 --- a/index.bs +++ b/index.bs @@ -3530,7 +3530,7 @@ This [=registration extension=] and [=authentication extension=] enables use of :: The Boolean value `true`, encoded in CBOR (major type 7, value 21). : Authenticator extension processing -:: The [=authenticator=] sets the [=authenticator extension output=] to be a user verification index indicating the method used +:: The [=authenticator=] sets the [=authenticator extension output=] to be one or more user verification methods indicating the method(s) used by the user to authorize the operation, as defined below. This extension can be added to attestation objects and assertions. : Authenticator extension output From fa787d0238cb97a1535219b2a77d5361f116522d Mon Sep 17 00:00:00 2001 From: balfanz Date: Thu, 9 Nov 2017 14:21:46 -0800 Subject: [PATCH 25/29] Adding a type field to CollectedClientData --- index.bs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.bs b/index.bs index e1f7b291b..24a54fc20 100644 --- a/index.bs +++ b/index.bs @@ -729,6 +729,8 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=map/Set=] |authenticatorExtensions|[|extensionId|] to the [=base64url encoding=] of |authenticatorExtensionInput|. 1. Let |collectedClientData| be a new {{CollectedClientData}} instance whose fields are: + : {{CollectedClientData/type}} + :: The string `webauthn.create`. : {{CollectedClientData/challenge}} :: The [=base64url encoding=] of |options|.{{MakePublicKeyCredentialOptions/challenge}}. : {{CollectedClientData/origin}} @@ -972,6 +974,8 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=map/Set=] |authenticatorExtensions|[|extensionId|] to the [=base64url encoding=] of |authenticatorExtensionInput|. 1. Let |collectedClientData| be a new {{CollectedClientData}} instance whose fields are: + : {{CollectedClientData/type}} + :: The string `webauthn.get`. : {{CollectedClientData/challenge}} :: The [=base64url encoding=] of |options|.{{PublicKeyCredentialRequestOptions/challenge}} : {{CollectedClientData/origin}} @@ -1616,6 +1620,7 @@ following Web IDL.
         dictionary CollectedClientData {
    +        required DOMString           type;
             required DOMString           challenge;
             required DOMString           origin;
             required DOMString           hashAlgorithm;
    @@ -1626,6 +1631,9 @@ following Web IDL.
     
    + The type member contains the string `webauthn.create` when creating new credentials, and `webauthn.get` + when getting an assertion from an existing credential. + The challenge member contains the base64url encoding of the challenge provided by the RP. The origin member contains the fully qualified [=origin=] of the requester, as provided to the authenticator by From fda86222f8fb5b2f879bbdb2b9f093299dd42241 Mon Sep 17 00:00:00 2001 From: balfanz Date: Thu, 9 Nov 2017 14:28:38 -0800 Subject: [PATCH 26/29] adding RP processing rules. --- index.bs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.bs b/index.bs index 24a54fc20..211a3d516 100644 --- a/index.bs +++ b/index.bs @@ -2386,6 +2386,8 @@ When registering a new credential, represented by a {{AuthenticatorAttestationRe {{AuthenticatorAttestationResponse}} object to extract the [=client data=] |C| claimed as collected during the credential creation. +2. Verify that the {{CollectedClientData/type}} in |C| is the string `webauthn.create`. + 2. Verify that the {{CollectedClientData/challenge}} in |C| matches the challenge that was sent to the authenticator in the {{CredentialsContainer/create()}} call. @@ -2470,6 +2472,8 @@ When verifying a given {{PublicKeyCredential}} structure (|credential|) as part 3. Perform JSON deserialization on |cData| to extract the [=client data=] |C| used for the signature. +3. Verify that the {{CollectedClientData/type}} in |C| is the string `webauthn.get`. + 4. Verify that the {{CollectedClientData/challenge}} member of |C| matches the challenge that was sent to the authenticator in the {{PublicKeyCredentialRequestOptions}} passed to the {{CredentialsContainer/get()}} call. From 59683f65dbd7c89234d858d6eef5d598f76e9c23 Mon Sep 17 00:00:00 2001 From: balfanz Date: Thu, 9 Nov 2017 14:44:38 -0800 Subject: [PATCH 27/29] Added explanation... ...as to what this new field is for. --- index.bs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 211a3d516..1102fb37b 100644 --- a/index.bs +++ b/index.bs @@ -730,7 +730,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/type}} - :: The string `webauthn.create`. + :: The string "webauthn.create". : {{CollectedClientData/challenge}} :: The [=base64url encoding=] of |options|.{{MakePublicKeyCredentialOptions/challenge}}. : {{CollectedClientData/origin}} @@ -975,7 +975,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/type}} - :: The string `webauthn.get`. + :: The string "webauthn.get". : {{CollectedClientData/challenge}} :: The [=base64url encoding=] of |options|.{{PublicKeyCredentialRequestOptions/challenge}} : {{CollectedClientData/origin}} @@ -1631,8 +1631,9 @@ following Web IDL.
    - The type member contains the string `webauthn.create` when creating new credentials, and `webauthn.get` - when getting an assertion from an existing credential. + The type member contains the string "webauthn.create" when creating new credentials, and "webauthn.get" + when getting an assertion from an existing credential. The purpose of this member is to prevent certain types of signature + confusion attacks (where an attacker substitutes one legitimate signature for another). The challenge member contains the base64url encoding of the challenge provided by the RP. From 66f094f134f7c20d3cfd9f54d3f11deb7146764e Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Thu, 9 Nov 2017 16:42:10 -0800 Subject: [PATCH 28/29] Update per @equalsJeffH comments --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 1c861c3d2..4b0abdbb0 100644 --- a/index.bs +++ b/index.bs @@ -1962,7 +1962,7 @@ It takes the following input parameters: :: A [=map=] from [=extension identifiers=] to their [=authenticator extension inputs=], created by the client based on the extensions requested by the [=[RP]=], if any. -Note: Before performing this operation, all other operations in progress in the [=authenticator session=] must be aborted by setting their [=AbortSignal/aborted flag=] to true. +Note: Before performing this operation, all other operations in progress in the [=authenticator session=] must be aborted by running the [=authenticatorCancel=] operation. When this operation is invoked, the [=authenticator=] must perform the following procedure: 1. Check if all the supplied parameters are syntactically well-formed and of the correct length. If not, return an error code @@ -2034,7 +2034,7 @@ It takes the following input parameters: :: A [=map=] from [=extension identifiers=] to their [=authenticator extension inputs=], created by the client based on the extensions requested by the [=[RP]=], if any. -Note: Before performing this operation, all other operations in progress in the [=authenticator session=] must be aborted by setting their [=AbortSignal/aborted flag=] to true. +Note: Before performing this operation, all other operations in progress in the [=authenticator session=] must be aborted by running the [=authenticatorCancel=] operation. When this method is invoked, the [=authenticator=] must perform the following procedure: 1. Check if all the supplied parameters are syntactically well-formed and of the correct length. If not, return an error code From 641eed3514e210e2ead67a26c6ed3ef259f5383f Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Fri, 10 Nov 2017 16:26:03 +0100 Subject: [PATCH 29/29] Nit: "set" -> "pair" --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 1102fb37b..e1a0d481d 100644 --- a/index.bs +++ b/index.bs @@ -1992,7 +1992,7 @@ When this operation is invoked, the authenticator must perform the following pro equivalent to "{{NotAllowedError}}" and terminate the operation. The Authenticator and user agent MAY skip this prompt if the Authenticator is a [=platform authenticator=] and |excludeCredentialDescriptorList| is empty. 1. Once user consent has been obtained, generate a new credential object: - 1. Let (|publicKey|,|privateKey|) be a new set of cryptographic keys using the combination of {{PublicKeyCredentialType}} + 1. Let (|publicKey|,|privateKey|) be a new pair of cryptographic keys using the combination of {{PublicKeyCredentialType}} and cryptographic parameters represented by the first [=list/item=] in |credTypesAndPubKeyAlgs| that is supported by this authenticator. 1. Let |credentialId| be a new identifier for this credential that is globally unique with high probability across all