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|. -
  • - If |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialRpEntity/id}} is [=present=]: - 1. If |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialRpEntity/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. + If |options|.{{MakePublicKeyCredentialOptions/rp}}.{{PublicKeyCredentialEntity/id}} +
    + + : Is [=present=] + :: If |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|. +
    - Note: |rpId| 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}}.{{PublicKeyCredentialRpEntity/id}} when calling + Note: |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()}}.
  • 1. Let |credTypesAndPubKeyAlgs| be a new [=list=] whose [=list/items=] are pairs of {{PublicKeyCredentialType}} and a {{COSEAlgorithmIdentifier}}. -1. [=list/For each=] |current| of |options|.{{MakePublicKeyCredentialOptions/pubKeyCredParams}}: +1. [=list/For each=] |current| of |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:
    -
    If the |adjustedTimeout| timer expires,
    -
    [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| - and [=set/remove=] |authenticator| from |issuedRequests|.
    - -
    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|. -
    - -
    If any |authenticator| returns an error status,
    -
    [=set/Remove=] |authenticator| from |issuedRequests|.
    - -
    If any |authenticator| indicates success,
    -
    - 1. [=set/Remove=] |authenticator| from |issuedRequests|. - 2. Let |attestationObject| be a new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the - bytes of the value returned from the successful [=authenticatorMakeCredential=] operation (which is - 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. -
    + : If the |adjustedTimeout| timer expires, + :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| + and [=set/remove=] |authenticator| from |issuedRequests|. + + : 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|. + + : 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 |credentialCreationData| be a [=struct=] whose [=items=] are: + + : 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. +
    1. Return a {{DOMException}} whose name is "{{NotAllowedError}}". @@ -798,8 +841,7 @@ method is invoked, the user agent MUST: Set |adjustedTimeout| to this adjusted value. If the {{PublicKeyCredentialRequestOptions/timeout}} member of |options| is [=present|not present=], then set |adjustedTimeout| 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 |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 @@ -888,6 +930,10 @@ 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. [=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: -
    +
    -
    If the |adjustedTimeout| timer expires,
    -
    [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| - and [=set/remove=] |authenticator| from |issuedRequests|.
    - -
    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|. -
    - -
    If any |authenticator| returns an error status,
    -
    [=set/Remove=] |authenticator| from |issuedRequests|.
    - -
    If any |authenticator| indicates success,
    -
    - 1. [=set/Remove=] |authenticator| from |issuedRequests|. - 2. Let |value| be a new {{PublicKeyCredential}} associated with |global| whose fields are: - - : {{PublicKeyCredential/[[identifier]]}} - :: A new {{ArrayBuffer}}, created using |global|'s [=%ArrayBuffer%=], containing the bytes of the credential ID - returned from the successful [=authenticatorGetAssertion=] operation, as defined in [[#op-get-assertion]]. - : {{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. -
    -
    + : If the |adjustedTimeout| timer expires, + :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on + |authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. + + : 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|. + + : If any |authenticator| returns an error status, + :: [=set/Remove=] |authenticator| from |issuedRequests|. + + : If any |authenticator| indicates success, + :: 1. [=set/Remove=] |authenticator| from |issuedRequests|. + 2. Let |value| be a new {{PublicKeyCredential}} 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]]. + + : {{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. +
    1. Return a {{DOMException}} whose name is "{{NotAllowedError}}". @@ -1724,14 +1772,17 @@ The following operations can be invoked by the client in an authenticator sessio This operation must be invoked in an authenticator session which has no other operations in progress. It takes the following input parameters: -: |rpId| -:: The caller's [=RP ID=], as determined by the user agent and the client. + : |hash| :: The [=hash of the serialized client data=], provided by the client. : |rpEntity| :: The [=[RP]=]'s {{PublicKeyCredentialRpEntity}}. : |userEntity| :: The user account's {{PublicKeyCredentialUserEntity}}, containing the [=user handle=] given by the [=[RP]=]. +: |requireResidentKey| +:: |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}.{{requireResidentKey}}. +: |requireUserVerification| +:: |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}.{{requireUserVerification}}. : |credTypesAndPubKeyAlgs| :: A sequence of pairs of {{PublicKeyCredentialType}} and public key algorithms ({{COSEAlgorithmIdentifier}}) requested by the [=[RP]=]. This sequence is ordered from most preferred to least preferred. The platform makes a best-effort to create the most @@ -1740,10 +1791,6 @@ input parameters: :: An optional list of {{PublicKeyCredentialDescriptor}} objects provided by the [=[RP]=] with the intention that, if any of these are known to the authenticator, it should not create a new credential. |excludeCredentialDescriptorList| contains a list of known credentials. -: |requireResidentKey| -:: |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}.{{requireResidentKey}}. -: |requireUserVerification| -:: |options|.{{MakePublicKeyCredentialOptions/authenticatorSelection}}.{{requireUserVerification}} : |extensions| :: A [=map=] from [=extension identifiers=] to their [=authenticator extension inputs=], created by the client based on the extensions requested by the [=[RP]=], if any. @@ -1771,8 +1818,8 @@ When this operation is invoked, the authenticator must perform the following pro 1. Let |credentialId| be a new identifier for this credential that is globally unique with high probability across all credentials with the same type across all authenticators. 1. Let |userHandle| be |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: