diff --git a/index.bs b/index.bs
index 0fa1fd01e..41b360afa 100644
--- a/index.bs
+++ b/index.bs
@@ -93,7 +93,7 @@ spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-creden
text: create(); url: dom-credentialscontainer-create
spec: mixed-content; urlPrefix: www.w3.org/TR/mixed-content/
- type: dfn
+ type: dfn
text: a priori authenticated
@@ -101,6 +101,7 @@ spec: mixed-content; urlPrefix: www.w3.org/TR/mixed-content/
spec:credential-management; type:dfn; text:credentials
spec:html; type:dfn; for:environment settings object; text:global object
spec:infra; type:dfn; text:list
+spec:infra; type:dfn; for:struct; text:item
spec:url; type:dfn; text:domain
spec:url; type:dfn; for:url; text:host
spec:url; type:dfn; text:valid domain;
@@ -136,7 +137,7 @@ is [=Registration=], where a [=public key credential=] is created on an [=authen
with the present user's account (the account may already exist or may be created at this time). The second is
[=Authentication=], where the [=[RP]=] is presented with an [=Authentication Assertion=] proving the presence
and consent of the user who registered the [=public key credential=]. Functionally, the [=Web Authentication API=] comprises
-a {{PublicKeyCredential}} which extends the Credential Management API [[CREDENTIAL-MANAGEMENT-1]], and infrastructure which
+a {{PublicKeyCredential}} which extends the Credential Management API [[!CREDENTIAL-MANAGEMENT-1]], and infrastructure which
allows those credentials to be used with {{CredentialsContainer/create()|navigator.credentials.create()}} and
{{CredentialsContainer/get()|navigator.credentials.get()}}. The former is used during [=Registration=], and the
latter during [=Authentication=].
@@ -583,11 +584,11 @@ 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}},
+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=].
+ 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
@@ -609,38 +610,43 @@ When this method is invoked, the user agent MUST execute the following algorithm
such as [=domain=], [=ipv4 address=], [=ipv6 address=], [=opaque host=], or [=empty host=].
Only the [=domain=] format of [=host=] is allowed here.
-1. Let |rpId| be |effectiveDomain|.
-
|options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialEntity/id}}
+ |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialEntity/id}}
[=is not a
+ registrable domain suffix of and is not equal to=] |effectiveDomain|, return a {{DOMException}} whose name
+ is "{{SecurityError}}", and terminate this algorithm.
- 1. Set |rpId| to |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}.
+ : Is [=present|not present=]
+ :: Set |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialEntity/id}}
to
+ |effectiveDomain|.
+ |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialEntity/id}}
represents the
+ caller's [=RP ID=]. The [=RP ID=] defaults to being the caller's [=environment settings object/origin=]'s
+ [=effective domain=] unless the caller has explicitly set
+ |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialEntity/id}}
when calling
{{CredentialsContainer/create()}}.
|options|.{{MakePublicKeyCredentialOptions/pubKeyCredParams}}
:
+
1. If |current|.{{PublicKeyCredentialParameters/type}}
does not contain a {{PublicKeyCredentialType}} supported
by this implementation, then [=continue=].
1. Let |alg| be |current|.{{PublicKeyCredentialParameters/alg}}
.
1. [=list/Append=] the pair of |current|.{{PublicKeyCredentialParameters/type}}
and |alg| to
|credTypesAndPubKeyAlgs|.
-1. If |credTypesAndPubKeyAlgs| [=list/is empty=] and |options|.{{MakePublicKeyCredentialOptions/pubKeyCredParams}}
- [=list/is not empty=], cancel the timer started in step 2, return a {{DOMException}} whose name is "{{NotSupportedError}}",
- and terminate this algorithm.
+1. If |credTypesAndPubKeyAlgs| [=list/is empty=] and |options|.{{MakePublicKeyCredentialOptions/pubKeyCredParams}}
+ [=list/is not empty=], return a {{DOMException}} whose name is "{{NotSupportedError}}", and terminate this algorithm.
1. Let |clientExtensions| be a new [=map=] and let |authenticatorExtensions| be a new [=map=].
@@ -684,7 +690,7 @@ When this method is invoked, the user agent MUST execute the following algorithm
1. If |currentlyAvailableAuthenticators| [=list/is empty=], return a {{DOMException}} whose name is
"{{NotFoundError}}", and terminate this algorithm.
-1. If |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}} is [=present|present=], iterate through
+1. If |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}
is [=present|present=], iterate through
|currentlyAvailableAuthenticators| and do the following [=set/for each=] |authenticator|:
1. If {{AuthenticatorSelectionCriteria/authenticatorAttachment}} is [=present|present=] and its value is not equal
to |authenticator|'s attachment modality, [=iteration/continue=].
@@ -701,58 +707,95 @@ When this method is invoked, the user agent MUST execute the following algorithm
1. [=set/For each=] |authenticator| in |currentlyAvailableAuthenticators|:
1. Let |excludeCredentialDescriptorList| be a new [=list=].
+
1. [=list/For each=] credential descriptor |C| in |options|.{{MakePublicKeyCredentialOptions/excludeCredentials}}
:
1. If |C|.{{transports}}
[=list/is not empty=], and |authenticator| is connected over a transport not
mentioned in |C|.{{transports}}
, the client MAY [=continue=].
1. Otherwise, [=list/Append=] |C| to |excludeCredentialDescriptorList|.
- 1. [=In parallel=], invoke the [=authenticatorMakeCredential=] operation on |authenticator| with |rpId|,
- |clientDataHash|, |options|.{{MakePublicKeyCredentialOptions/rp}}, |options|.{{MakePublicKeyCredentialOptions/user}},
+
+
+ 1. Invoke the [=authenticatorMakeCredential=] operation on |authenticator| with
+ |clientDataHash|,
+ |options|.{{MakePublicKeyCredentialOptions/rp}}
, |options|.{{MakePublicKeyCredentialOptions/user}}
,
|options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}.{{AuthenticatorSelectionCriteria/requireResidentKey}}
,
- |credTypesAndPubKeyAlgs|, |excludeCredentialDescriptorList|, and |authenticatorExtensions| as parameters.
+ |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}.{{AuthenticatorSelectionCriteria/requireUserVerification}}
,
+ |credTypesAndPubKeyAlgs|,
+ |excludeCredentialDescriptorList|,
+ and |authenticatorExtensions| as parameters.
+
1. [=set/Append=] |authenticator| to |issuedRequests|.
-1. Start a timer for |adjustedTimeout| milliseconds. Then execute the following steps [=in parallel=]. The [=task source=] for
- these [=tasks=] is the [=dom manipulation task source=].
+1. Start a timer for |adjustedTimeout| milliseconds.
-1. While |issuedRequests| [=list/is not empty=], perform the following actions depending upon the |adjustedTimeout| timer and
- responses from the authenticators:
+1. [=While=] |issuedRequests| [=list/is not empty=], perform the following actions depending upon the |adjustedTimeout| timer
+ and responses from the authenticators:
attObj
, as defined in [[#generating-an-attestation-object]]).
- 3. Let |id| be |attestationObject|.authData.[=attestedCredentialData=].[=credentialId=]
.
- 4. Let |value| be a new {{PublicKeyCredential}} object associated with |global| whose fields are:
- : {{PublicKeyCredential/[[identifier]]}}
- :: |id|
- : {{PublicKeyCredential/response}}
- :: A new {{AuthenticatorAttestationResponse}} object associated with |global| whose fields are:
- : {{AuthenticatorResponse/clientDataJSON}}
- :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of |clientDataJSON|.
- : {{AuthenticatorAttestationResponse/attestationObject}}
- :: |attestationObject|
-
- 5. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on
- |authenticator| and [=set/remove=] it from |issuedRequests|.
- 6. Return |value| and terminate this algorithm.
- 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
+ :: whose value is the bytes of |clientDataJSON|.
+
+ : 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 |constructCredentialAlg| be an algorithm that takes a [=global object=]
+ |global|, and whose steps are:
+
+ 1. Let |attestationObject| be a new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the
+ bytes of |credentialCreationData|.[=attestationObjectResult=]
's value.
+
+ 1. Let |id| be |attestationObject|.authData.[=attestedCredentialData=].[=credentialId=]
.
+
+ 1. Let |pubKeyCred| be a new {{PublicKeyCredential}} object associated with |global| whose fields are:
+
+ : {{PublicKeyCredential/[[identifier]]}}
+ :: |id|
+
+ : {{PublicKeyCredential/response}}
+ :: A new {{AuthenticatorAttestationResponse}} object associated with |global| whose fields are:
+
+ : {{AuthenticatorResponse/clientDataJSON}}
+ :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of
+ |credentialCreationData|.[=clientDataJSONResult=]
.
+
+ : {{AuthenticatorAttestationResponse/attestationObject}}
+ :: |attestationObject|
+
+ Issue: need to place [=clientExtensionResults=] data somewhere such that the data is subsequently available
+ to RP script when the latter invokes `PublicKeyCredential.getClientExtensionResults()`.
+ See [issue #657](https://github.com/w3c/webauthn/issues/657).
+
+ 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 |constructCredentialAlg| and terminate this algorithm.
+
|allowCredentialDescriptorList|[0].id
.
+
1. [=list/For each=] credential descriptor |C| in |allowCredentialDescriptorList|,
[=set/append=] each value, if any, of |C|.{{transports}}
to |distinctTransports|.
@@ -927,52 +973,54 @@ method is invoked, the user agent MUST:
1. Start a timer for |adjustedTimeout| milliseconds. Then 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 the |adjustedTimeout| timer and
- responses from the authenticators:
+ 1. While |issuedRequests| [=list/is not empty=], perform the following actions depending upon the |adjustedTimeout| timer
+ and responses from the authenticators:
- |userEntity|.{{PublicKeyCredentialUserEntity/id}}
.
- 1. Associate the |credentialId| and |privateKey| with |rpId| and |userHandle|.
- 1. Delete any older credentials with the same |rpId| and |userHandle| that are stored locally by the [=authenticator=].
+ 1. Associate the |credentialId| and |privateKey| with |rpEntity|.{{PublicKeyCredentialRpEntity/id}}
and |userHandle|.
+ 1. Delete any older credentials with the same |rpEntity|.{{PublicKeyCredentialRpEntity/id}}
and |userHandle| that are stored locally by the [=authenticator=].
1. If any error occurred while creating the new credential object, return an error code equivalent to "{{UnknownError}}" and
terminate the operation.
1. Let |processedExtensions| be the result of [=authenticator extension processing=] for each supported [=extension identifier=]/input
@@ -1848,8 +1895,14 @@ 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
+ - |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.
+
+ 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.
+
- |authenticatorData|
- |signature|
- The [=user handle=] associated with |selectedCredential|.
@@ -2601,7 +2654,7 @@ the attestation=] is consistent with the fields of the attestation certificate's
The authenticator produces |sig| by concatenating |authenticatorData| and |clientDataHash|,
and signing the result using the credential private key. It sets |alg| to the algorithm of the signature format.
-
+
: Verification procedure
:: Verification is performed as follows: