diff --git a/index.bs b/index.bs index 0e61497b8..fb55cfbf4 100644 --- a/index.bs +++ b/index.bs @@ -1424,7 +1424,7 @@ BCP 14 [[!RFC2119]] [[!RFC8174]] when, and only when, they appear in all capital A user handle is an opaque [=byte sequence=] with a maximum size of 64 bytes, and is not meant to be displayed to the user. It MUST NOT contain personally identifying information, see [[#sctn-user-handle-privacy]]. -: User Present +: User Present :: Upon successful completion of a [=test of user presence|user presence test=], the user is said to be "[=user present|present=]". @@ -7598,7 +7598,662 @@ However, [=authenticators=] that do not utilize [[!FIDO-CTAP]] do not necessaril This section defines extensions that are both [=client extensions=] and [=authenticator extensions=]. -This section is currently empty. + +### Signing extension (sign) ### {#sctn-sign-extension} + +This [=authenticator extension|authenticator=] [=registration extension=] and [=authentication extension=] +allows a [=[RP]=] to sign arbitrary data using an asymmetric key pair associated with a [=credential=] +but different from the [=credential key pair=]. +A [=registration ceremony=] creates the signing key pair and emits the signing public key, +and [=authentication ceremonies=] can use the signing private key to sign arbitrary data. +The signing private key is held exclusively by the [=authenticator=]. + +The high-level usage flow is as follows: + +1. To create a signing key pair, the [=[RP]=] initiates a [=registration ceremony=] and requests the extension. + The [=authenticator=] returns a signing public key and a signing key handle for the key pair. + +1. To sign some chosen data, the [=[RP]=] initiates an [=authentication ceremony=] and requests the extension + with one or more [=signing key handles=] for key pairs eligible to perform the signature. + The [=authenticator=] returns a signature over the given data. + Unlike an [=assertion signature=], the given data is signed unaltered; + the signed data does not include [=authenticator data=] or [=client data=]. + + This step can be repeated any number of times. + +As a motivating example use case, a [=[RP]=] could generate an asymmetric key pair +and use the generated public key as verification material for a [=verifiable credential=]. +Proofs for such a verifiable credential could then be generated only by getting an assertion from the associated WebAuthn credential. + +Each [=credential=] can be associated with at most one signing key pair, +and the [=user presence=] and [=user verification=] policy for the signing key pair is fixed at the time of creation. +If additional signing key pairs are required, +or signing key pairs with different [=user presence=] or [=user verification=] policies, +the [=[RP]=] MAY create a new [=credential=] for each. +In that case, the [=[RP]=] SHOULD use a different [=user handle=] for each such [=registration ceremony=], +to avoid overwriting existing credentials, +and SHOULD NOT specify the {{PublicKeyCredentialCreationOptions/excludeCredentials}} parameter, +to allow creating multiple credentials on the same [=authenticator=]. +Additional credentials created for this purpose SHOULD be stored and managed separately from ordinary authentication credentials, +and SHOULD NOT be used for other purposes than signing data with the associated signing key pair. + +[=Attestation=] is supported for signing key pairs. +This attestation signs over the same [=RP ID=], [=authenticator data=] [=flags=], +[=/AAGUID=] and [=hash of the serialized client data=] +as the attestation for the associated [=credential=], +but is not otherwise coupled to the associated [=credential=]. +The attestation also encodes the [=user presence=] and [=user verification=] policy of the signing key pair +since unlike the associated credential, +the signing key pair does not sign over an [=authenticator data=] structure. + +Although this extension can be used with [=discoverable credentials=], +it does not support use with an empty {{PublicKeyCredentialRequestOptions/allowCredentials}} +because the intended use is for signing data that is meaningful on its own. +This is unlike a random authentication challenge, which may be meaningless on its own +and is used only to guarantee that an authentication signature was generated recently. +In order to sign meaningful data, the [=[RP]=] must first know what is to be signed, +thus presumably must also first know which user is performing the signature, +and thus also which signing keys are eligible. +Thus, the signing use case is largely incompatible with the anonymous authentication challenge use case. +Therefore the restriction to non-empty {{PublicKeyCredentialRequestOptions/allowCredentials}} +is unlikely to impose any additional restriction in practice, +but does enable support for stateless [=authenticator=] implementations +where neither the signing key pair nor the associated [=credential=] need to consume storage space on the [=authenticator=]. + + +: Extension identifier +:: `sign` + +: Operation applicability +:: [=registration extension|Registration=] and [=authentication extension|authentication=] + +: Client extension input +:: + partial dictionary AuthenticationExtensionsClientInputs { + AuthenticationExtensionsSignInputs sign; + }; + + dictionary AuthenticationExtensionsSignInputs { + AuthenticationExtensionsSignGenerateKeyInputs generateKey; + AuthenticationExtensionsSignSignInputs sign; + }; + + +
+ : generateKey + :: If present, the [=authenticator=] is requested to generate a new signing key pair + and return the signing public key in the extension output. + + This member MUST be present during a [=registration ceremony=], and only during a [=registration ceremony=]. + + : sign + :: If present, the [=authenticator=] is requested to sign the {{AuthenticationExtensionsSignSignInputs/data}} member + using a previously generated signing private key. + + This member MUST be present during an [=authentication ceremony=], and only during an [=authentication ceremony=]. +
+ + + dictionary AuthenticationExtensionsSignGenerateKeyInputs { + required sequence<COSEAlgorithmIdentifier> algorithms; + BufferSource phData; + }; + + +
+ : algorithms + :: A list of acceptable signature algorithms, ordered from most preferred to least preferred. + The [=authenticator=] will create a signing key pair of the most preferred type possible. + If none of the listed types can be created, the [=registration ceremony=] fails. + + Because {{AuthenticationExtensionsSignGenerateKeyInputs/phData}} must be pre-hashed, + {{AuthenticationExtensionsSignGenerateKeyInputs/algorithms}} MUST NOT contain values representing algorithms + with incompatible pre-hashing procedures + if {{AuthenticationExtensionsSignGenerateKeyInputs/phData}} is present. + + : phData + :: Pre-hashed data to be signed. + If present, the [=authenticator=] will sign this value using the newly generated signing private key. + + The data MUST be pre-hashed as appropriate for all signature algorithms listed in {{AuthenticationExtensionsSignGenerateKeyInputs/algorithms}}. + + ISSUE: Need to define pre-hashing more precisely. +
+ + + dictionary AuthenticationExtensionsSignSignInputs { + required BufferSource phData; + required record<USVString, COSEKeyRef> keyHandleByCredential; + }; + typedef BufferSource COSEKeyRef; + + +
+ : phData + :: Pre-hashed data to be signed. + The [=authenticator=] will sign this value using the signing private key. + + The data MUST be pre-hashed as appropriate for the signature algorithm of the private key. + + ISSUE: Need to define pre-hashing more precisely. + + : keyHandleByCredential + :: A record mapping [=base64url encoding|base64url encoded=] [=credential IDs=] to [=signing key handles=] to use for each credential. + This MUST contain an [=map/entry=] for each [=credential ID=] in {{PublicKeyCredentialRequestOptions/allowCredentials}}, + and no other entries. + + {{COSEKeyRef}} is a type alias for a {{BufferSource}} + that MUST contain a CBOR map encoding a COSE_Key_Ref object [[!ARKG]]. + + If the authenticator [=contains=] any credentials whose [=credential IDs=] appear as [=map/keys=], + the authenticator selects one of them and uses the corresponding [=map/value=] + to retrieve or re-derive the signing private key. + If not, the [=authentication ceremony=] fails. + + A suitable [=map/value=] for this record MAY be retrieved from the [=client extension output=] + {{AuthenticationExtensionsSignOutputs/generatedKey}}.{{AuthenticationExtensionsSignGeneratedKey/keyHandle}}. + Alternatively, if the [=[RP]=] needs [=attestation=] for the signing key pair, + the [=[RP]=] MUST instead verify the [=attestation object=] + embedded as the [=authenticator extension output=] + [=authData/extensions=]["sign"][att-obj (7)] + and construct the [=signing key handle=] from + [=authData/extensions=]["sign"][att-obj (7)]["authData"].[=authData/attestedCredentialData=].[=authData/attestedCredentialData/credentialPublicKey=] + using the procedure to [=extension/sign/construct a key handle from a COSE_Key=] + defined in [[#sctn-sign-extension-key-handle-from-cose-key]]. +
+ + +: Client extension processing ([=registration extension|registration=]) +:: These extension processing steps use the variables |pkOptions| and |credentialCreationData| + defined in [[#sctn-createCredential]]. + + 1. Let |extSign| denote |pkOptions|.{{PublicKeyCredentialCreationOptions/extensions}}.{{AuthenticationExtensionsClientInputs/sign}}. + + 1. If |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}} is not present, + return a {{DOMException}} whose name is “{{NotSupportedError}}”. + + 1. If |extSign|.{{AuthenticationExtensionsSignInputs/sign}} is present, + return a {{DOMException}} whose name is “{{NotSupportedError}}”. + + 1. Set the `sign` [=authenticator extension input=] to a CBOR map with the entries: + + - `phData`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/phData}} + encoded as a CBOR byte string, if present. + Otherwise omit this entry. + + - `alg`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/algorithms}} + encoded as a CBOR array of integers, in order. + + - `flags`: The CDDL value `0b101` if |pkOptions|.{{PublicKeyCredentialCreationOptions/authenticatorSelection}}.{{AuthenticatorSelectionCriteria/userVerification}} is set to {{UserVerificationRequirement/required}}, + otherwise the CDDL value `0b001`. + + 1. After the [=authenticatorMakeCredential=] operation is successful, + let |authData| denote |credentialCreationData|.[=credentialCreationData/attestationObjectResult=]["authData"]. + Set the [=client extension output=] |credentialCreationData|.[=credentialCreationData/clientExtensionResults=].{{AuthenticationExtensionsClientOutputs/sign}} + to an {{AuthenticationExtensionsSignOutputs}} value with the members: + + - {{AuthenticationExtensionsSignOutputs/generatedKey}}: An {{AuthenticationExtensionsSignGeneratedKey}} value with the members: + - {{AuthenticationExtensionsSignGeneratedKey/publicKey}}: + An {{ArrayBuffer}} containing + the [=authData/attestedCredentialData=].[=authData/attestedCredentialData/credentialPublicKey=] part + of |authData|.[=authData/extensions=]["sign"][att-obj]["authData"]. + + - {{AuthenticationExtensionsSignGeneratedKey/keyHandle}}: + An {{ArrayBuffer}} constructed as follows: + + 1. Let |pk| be the value of {{AuthenticationExtensionsSignGeneratedKey/publicKey}} parsed as a CBOR map. + 1. Let {{AuthenticationExtensionsSignGeneratedKey/keyHandle}} be an {{ArrayBuffer}} + containing the result of [=extension/sign/constructing a key handle from a COSE_Key=] + given the COSE_Key structure |pk|. + + - {{AuthenticationExtensionsSignOutputs/signature}}: + The [=authenticator extension output=] |authData|.[=authData/extensions=]["sign"][sig] + parsed as an {{ArrayBuffer}}, if present. + Otherwise omit this member. + + The CBOR map keys `phData`, `alg`, `flags`, `att-obj` and `sig` are aliases defined below + in the CDDL for the [=authenticator extension input=] and [=authenticator extension output=]. + + +: Client extension processing ([=authentication extension|authentication=]) +:: These extension processing steps use the variables |pkOptions| and |assertionCreationData| + defined in [[#sctn-getAssertion]]. + + 1. Let |extSign| denote |pkOptions|.{{PublicKeyCredentialRequestOptions/extensions}}.{{AuthenticationExtensionsClientInputs/sign}}. + + 1. If |extSign|.{{AuthenticationExtensionsSignInputs/sign}} is not present, + return a {{DOMException}} whose name is “{{NotSupportedError}}”. + + 1. If |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}} is present, + return a {{DOMException}} whose name is “{{NotSupportedError}}”. + + 1. If |pkOptions|.{{PublicKeyCredentialRequestOptions/allowCredentials}} [=list/is empty=], + return a {{DOMException}} whose name is “{{NotSupportedError}}”. + + 1. If the [=map/size=] of |extSign|.{{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/keyHandleByCredential}} + does not equal the [=list/size=] of |pkOptions|.{{PublicKeyCredentialRequestOptions/allowCredentials}}, + return a {{DOMException}} whose name is “{{NotSupportedError}}”. + + 1. Let |keyHandles| be a new CBOR array. + + 1. [=list/For each=] |allowedCredential| in |pkOptions|.{{PublicKeyCredentialRequestOptions/allowCredentials}}: + + 1. Let |encodedCredentialId| be the base64url encoding of |allowedCredential|.{{PublicKeyCredentialDescriptor/id}}. + 1. Let |keyHandle| be |extSign|.{{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/keyHandleByCredential}}[|encodedCredentialId|]. + 1. If |keyHandle| is undefined, return a {{DOMException}} whose name is “{{SyntaxError}}”. + 1. Append |keyHandle| to |keyHandles|, encoded as a CBOR byte string. + + If the [=client=] divides {{PublicKeyCredentialRequestOptions/allowCredentials}} into smaller batches + to fit [=authenticator=] message length limits, + the client MUST also divide |keyHandles| into batches of the same size and in the same order. + + 1. If the [=list/size=] of |keyHandles| does not equal the [=list/size=] of + |pkOptions|.{{PublicKeyCredentialRequestOptions/allowCredentials}}, + return a {{DOMException}} whose name is “{{SyntaxError}}”. + + 1. Set the `sign` authenticator extension input to a CBOR map with the entries: + - `phData`: |extSign|.{{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/phData}} encoded as a CBOR byte string. + - `key-refs`: |keyHandles|. + + 1. After the [=authenticatorGetAssertion=] operation is successful, + let |authData| denote |assertionCreationData|.[=assertionCreationData/authenticatorDataResult=]. + Set the [=client extension output=] |assertionCreationData|.[=assertionCreationData/clientExtensionResults=].{{AuthenticationExtensionsClientOutputs/sign}} + to an {{AuthenticationExtensionsSignOutputs}} value with the members: + + - {{AuthenticationExtensionsSignOutputs/generatedKey}}: Omit this member. + + - {{AuthenticationExtensionsSignOutputs/signature}}: + The [=authenticator extension output=] |authData|.[=authData/extensions=]["sign"][sig] + parsed as an {{ArrayBuffer}}. + + The CBOR map keys `phData`, `key-refs` and `sig` are aliases defined below + in the CDDL for the [=authenticator extension input=] and [=authenticator extension output=]. + + +: Client extension output +:: + partial dictionary AuthenticationExtensionsClientOutputs { + AuthenticationExtensionsSignOutputs sign; + }; + + dictionary AuthenticationExtensionsSignOutputs { + AuthenticationExtensionsSignGeneratedKey generatedKey; + ArrayBuffer signature; + }; + + +
+ : generatedKey + :: The generated public key and [=signing key handle=]. + Present if and only if the {{AuthenticationExtensionsSignInputs/generateKey}} input was present. + + : signature + :: The generated signature. + Present if and only if + the {{AuthenticationExtensionsSignInputs/sign}} input was present + or the {{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/phData}} + input was present. +
+ + + dictionary AuthenticationExtensionsSignGeneratedKey { + required ArrayBuffer publicKey; + required ArrayBuffer keyHandle; + }; + + +
+ : publicKey + :: The generated signing public key in COSE_Key format. + + This member is intended for use by [=[RPS]=] that do not request [=attestation=]. + [=[RPS]=] that request attestation SHOULD instead retrieve the generated public key + from the [=attestation object=] embedded in the [=authenticator extension outputs=] + conveyed in the [=attestation object=] of the associated credential, + after verifying both [=attestation objects=]. + + : keyHandle + :: The [=signing key handle=], a byte array encoding a COSE_Key_Ref structure referencing the generated signing private key. + The [=[RP]=] MUST store this in order to later set it as one of the values in the + {{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/keyHandleByCredential}} + input to request generation of a signature. + + This member is intended for use by [=[RPS]=] that do not request [=attestation=]. + [=[RPS]=] that request attestation SHOULD instead construct key handles + as described for the [=client extension input=] {{AuthenticationExtensionsSignSignInputs/keyHandleByCredential}}. +
+ + +: Authenticator extension input +:: A CBOR map with the structure of the following CDDL: + + ``` + ; The symbolic names on the left are represented in CBOR by the integers on the right + phData = 0 + kty = 1 + kid = 2 + alg = 3 + flags = 4 + key-refs = 5 + + $$extensionInput //= ( + sign: { + ; Registration (key generation) input + ? phData => bstr, + alg => [ + COSEAlgorithmIdentifier ], + ? flags => &(unattended: 0b000, + require-up: 0b001, + require-uv: 0b101) .default 0b001, + // + ; Authentication (signing) input + phData => bstr, + key-refs => [ + bstr .cbor COSE_Key_Ref ], + }, + ) + ``` + + : phData + :: The pre-hashed data to sign. + MAY be present during [=registration ceremonies=]. + MUST be present during [=authentication ceremonies=]. + MUST be pre-hashed as appropriate for each algorithm in `alg`. + + ISSUE: Need to define pre-hashing more precisely. + + : alg + :: A list of acceptable signature algorithms, ordered from most preferred to least preferred. + MUST be present during [=registration ceremonies=]. + MUST NOT be present during [=authentication ceremonies=]. + + If `phData` is present, then `alg` MUST NOT contain values + representing signature algorithms with incompatible pre-hashing procedures. + + ISSUE: Need to define pre-hashing more precisely. + + The [=authenticator=] will create a signing key pair of the most preferred type possible. + If none of the listed types can be created, the [=registration ceremony=] fails. + + : flags + :: [=Authenticator data=] [=flags=] that MUST be set when generating a signature with this signing private key. + MAY be present during [=registration ceremonies=]. + MUST NOT be present during [=authentication ceremonies=]. + + - If `unattended` (`0b000`), signatures will not require [=user presence=] or [=user verification=]. + - If `require-up` (`0b001`), signatures will require [=user presence=] but will not require [=user verification=]. + - If `require-uv` (`0b101`), signatures will require [=user presence=] and [=user verification=]. + + If not present during a [=registration ceremony=], the default is `require-up` (`0b001`). + + This setting is recorded in the [=attestation object=] for the signing key pair. + + : key-refs + :: A list of [=signing key handles=] eligible for generating a signature. + MUST NOT be present during [=registration ceremonies=]. + MUST be present during [=authentication ceremonies=]. + MUST have [=list/size=] equal to that of {{PublicKeyCredentialRequestOptions/allowCredentials}}, + and each [=list/item=] MUST represent the signing key pair associated with the [=credential=] + identified by the corresponding [=list/item=] in {{PublicKeyCredentialRequestOptions/allowCredentials}}. + + Suitable values for this entry MAY be constructed + from the [=authenticator extension output=] + [=authData/extensions=]["sign"][att-obj]["authData"].[=authData/attestedCredentialData=].[=authData/attestedCredentialData/credentialPublicKey=] + using the procedure to [=extension/sign/construct a key handle from a COSE_Key=] + defined in [[#sctn-sign-extension-key-handle-from-cose-key]]. + + Note: The `key-refs` entry is defined as an array of byte strings containing CBOR-encoded data + instead of direct CBOR maps because the [=CTAP2 canonical CBOR encoding form=] allows at most 4 levels of nested CBOR structures. + If `key-refs` would contain CBOR maps as items, those maps would exceed this nesting limit + when the extension input is embedded in the CTAP2 message structure. + + +: Authenticator extension processing ([=registration extension|registration=]) +:: These processing steps use the |hash|, |rpEntity|, and |extensions| parameters + and the |attestationFormat| variable in the [=authenticatorMakeCredential=] operation. + Let |extSign| denote |extensions|["sign"]. + Let |authData| denote the [=authenticator data=] that will be returned from the [=authenticatorMakeCredential=] operation. + + 1. Let |auxIkm| denote some, possibly empty, random entropy + and/or auxiliary data of the [=authenticator's=] choice to be used to generate a signing key pair. + + 1. Let |chosenAlg| be null. + + 1. [=list/For each=] |candidateAlg| in |extSign|[alg]: + + 1. If the [=authenticator=] supports |candidateAlg| for signing operations, + let |chosenAlg| be |candidateAlg| and [=break=]. + + 1. If |chosenAlg| is null, + return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_INVALID_CREDENTIAL`. + + 1. Let |signFlags| be the value of |extSign|[flags]. + + 1. If |signFlags| is not one of the values `unattended` (`0b000`), `require-up` (`0b001`) or `require-uv` (`0b101`), + return an error code equivalent to "{{SyntaxError}}" and terminate these processing steps. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_INVALID_OPTION`. + + 1. Use |signFlags|, |auxIkm| and a per-credential authenticator secret + as the seeds to deterministically generate a new key pair for the algorithm |chosenAlg|. + Let |p| be the generated private key and |P| be the corresponding public key. + + 1. Let |kid| be an authenticator-specific encoding of |chosenAlg|, |signFlags| and |auxIkm|, + which the authenticator can later use to re-generate the same key pair |p|, |P|. + The encoding SHOULD include integrity protection + to ensure that a given |kid| is valid for a particular authenticator. + + An example implementation of this encoding is given in [[#sctn-sign-extension-example-key-handle-encoding]]. + + 1. Let |P_cose| be a CBOR map encoding |P| in COSE_Key format. + + 1. Set |P_cose|[kid] to |kid|. + + 1. Set |authData|.[=authData/extensions=]["sign"] to a new CBOR map with the entries: + - `att-obj`: a CBOR byte array + encoding an [=attestation object=] generated as described in [[#sctn-generating-an-attestation-object]] + using the inputs: + + - |attestationFormat|: |attestationFormat|. + - |authData|: an [=authenticator data=] structure with the contents: + + - [=authData/rpIdHash=]: |authData|.[=authData/rpIdHash=]. + - [=authData/flags=]: |authData|.[=authData/flags=]. + - [=authData/signCount=]: 0. + - [=authData/attestedCredentialData=]: An [=attested credential data=] structure with the contents: + + - [=authData/attestedCredentialData/aaguid=]: |authData|.[=authData/attestedCredentialData=].[=authData/attestedCredentialData/aaguid=]. + - [=authData/attestedCredentialData/credentialIdLength=]: 0. + - [=authData/attestedCredentialData/credentialId=]: An empty byte string. + - [=authData/attestedCredentialData/credentialPublicKey=]: |P_cose| encoded in CBOR. + + - [=authData/extensions=]: A CBOR map with the entries: + - `"sign"`: A CBOR map with the entries: + - `flags`: |signFlags| encoded as a CBOR unsigned integer. + + Note: The `"sign"` key here is a CDDL text string literal, + but `flags` is an alias of an integer value. + + - |hash|: |hash|. + + - `sig`: The result of signing |extensions|["sign"][phData], if present, using private key |p|, + if |chosenAlg| supports signing during registration. + Otherwise omit this entry. + + The signing procedure MUST interpret |extensions|["sign"][phData] as pre-hashed + as appropriate for the chosen signing algorithm. + + ISSUE: Need to define pre-hashing more precisely. + + The CBOR map keys `alg`, `flags`, `kid`, `sig`, `att-obj` and `phData` are aliases defined above and below + in the CDDL for the [=authenticator extension input=] and [=authenticator extension output=]. + + +: Authenticator extension processing ([=authentication extension|authentication=]) +:: Using the |extensions| argument to the [=authenticatorGetAssertion=] operation, + let |extSign| denote |extensions|["sign"]. + Let |authData| denote the [=authenticator data=] that will be returned from the [=authenticatorGetAssertion=] operation. + + 1. If |allowCredentialDescriptorList| is empty, + return an error code equivalent to "{{NotAllowedError}}" and terminate these processing steps. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_NO_CREDENTIALS`. + + 1. If |extSign|[phData] is not present or |extSign|[key-refs] is not present, + or if the [=list/size=] of |extSign|[key-refs] does not equal the [=list/size=] of |allowCredentialDescriptorList|, + return an error code equivalent to "{{UnknownError}}" and terminate these processing steps. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_INVALID_OPTION`. + + 1. Let |credentialId| be the [=credential ID=] of the [=credential=] being used for this assertion. + + 1. Let |credentialIdIndex| be the index of |credentialId| in |allowCredentialDescriptorList|. + + 1. Let |keyRefCbor| be |extSign|[key-refs][|credentialIdIndex|]. + + 1. If |keyRefCbor| is null or undefined, + return an error code equivalent to "{{UnknownError}}" and terminate these processing steps. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_INVALID_OPTION`. + + 1. Let |keyRef| be |keyRefCbor| decoded as a COSE_Key_Ref strucure. + + 1. Decode the authenticator-specific encoding of |keyRef|[kid] to extract the encoded |chosenAlg|, |signFlags| and |auxIkm|. + This procedure SHOULD verify integrity to ensure that |keyRef|[kid] was generated by this authenticator. + + An example implementation of this decoding is given in [[#sctn-sign-extension-example-key-handle-encoding]]. + + 1. If |keyRef|[alg] is present and does not equal |chosenAlg|, + return an error code equivalent to "{{NotSupportedError}}" and terminate the operation. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_INVALID_CREDENTIAL`. + + 1. If the [=authData/flags/UP=] bit is set in |signFlags| but not in |authData|.[=authData/flags=], + return an error code equivalent to "{{ConstraintError}}" and terminate the operation. + Implementations in [[FIDO-CTAP]] return the error code `CTAP2_ERR_UP_REQUIRED`. + + 1. If the [=authData/flags/UV=] bit is set in |signFlags| but not in |authData|.[=authData/flags=], + return an error code equivalent to "{{ConstraintError}}" and terminate the operation. + Implementations in [[FIDO-CTAP]] return the error code`CTAP2_ERR_PUAT_REQUIRED`. + + 1. Use |signFlags|, |auxIkm|, and a per-credential authenticator secret + as the seeds to deterministically re-generate the key pair with private key |p| and public key |P| + for the algorithm |chosenAlg|. + + 1. Set |authData|.[=authData/extensions=]["sign"] + to a new CBOR map with the entries: + - `sig`: The result of signing |extSign|[phData] using the private key referenced by |keyRef|. + + The signing procedure MUST interpret |extSign|[phData] as pre-hashed + as appropriate for the chosen signing algorithm. + + ISSUE: Need to define pre-hashing more precisely. + + The CBOR map keys `phData`, `key-refs`, `kid`, `alg` and `sig` are aliases defined above and below + in the CDDL for the [=authenticator extension input=] and [=authenticator extension output=]. + + +: Authenticator extension output +:: A CBOR map with the structure of the following CDDL: + + ``` + ; The symbolic names on the left are represented in CBOR by the integers on the right + flags = 4 + sig = 6 + att-obj = 7 + + $$extensionOutput //= ( + sign: { + ; Registration (key generation) outputs + att-obj => bstr .cbor attObj, ; Attestation object for signing key pair + ? sig => bstr, ; Signature over phData input, if present + // + ; Authentication (signing) outputs + sig => bstr, ; Signature over phData input + // + ; Attestation fields + flags => &(unattended: 0b000, + require-up: 0b001, + require-uv: 0b101) + }, + ) + ``` + + Note: The `att-obj` entry is defined as a byte string containing CBOR-encoded data + instead of a direct CBOR map because the [=CTAP2 canonical CBOR encoding form=] allows at most 4 levels of nested CBOR structures. + + : att-obj + :: An [=attestation object=] for the signing key pair. + MUST be present in [=registration ceremonies=]. + MUST NOT be present in [=authentication ceremonies=]. + + : sig + :: A signature over the extension input `phData`, if present, by the signing private key. + MAY be present in [=registration ceremonies=]. + MUST be present in [=authentication ceremonies=]. + + : flags + :: A copy of the `flags` input. + Present only in the [=attestation object=] embedded within the `att-obj` output during [=registration ceremonies=]. + This represents whether signing operations with this signing private key + require [=user presence=] and [=user verification=]: + + - If `unattended` (`0b000`), signatures do not require [=user presence=] or [=user verification=]. + - If `require-up` (`0b001`), signatures require [=user verification=] but do not require [=user presence=]. + - If `require-uv` (`0b101`), signatures require [=user presence=] and [=user verification=]. + +#### Constructing a key handle from a COSE_Key #### {#sctn-sign-extension-key-handle-from-cose-key} + +To construct a key handle from a COSE_Key +given a COSE_Key structure |coseKey|, +a [=[RP]=] or [=client=] proceeds as follows: + +1. Let |keyHandle| be a copy of |coseKey|. +1. Remove all entries from |keyHandle| whose key is not one of `kty`, `kid` or `alg`. +1. Return |keyHandle| encoded in CBOR. + +The CBOR map keys `kty`, `kid` and `alg` are aliases defined above +in the CDDL for the [=authenticator extension input=]. + + +#### Example key handle encoding #### {#sctn-sign-extension-example-key-handle-encoding} + +This section defines one possible implementation of the encoding and decoding of the [=signing key handle=] |kid| +in the [=authenticator extension processing=] steps defined above. +[=Authenticator=] implementations MAY use these encoding and decoding procedures, +or MAY use different encodings with the same inputs and outputs. + +To encode |chosenAlg|, |signFlags| and |auxIkm|, producing the output |kid|, perform the following steps: + +1. Let |macKey| be a per-credential authenticator secret. + +1. Let |kidParams| be a CBOR array with the items: + 1. |chosenAlg| encoded as a CBOR integer. + 1. |signFlags| encoded as a CBOR unsigned integer. + 1. |auxIkm| encoded as a CBOR byte string. + +1. Let |kidMac| be the output of HMAC-SHA-256 [[RFC2104]] with the inputs: + + - Secret key `K`: |macKey| + - Input `text`: |kidParams| || UTF8Encode("sign") || |authData|.[=authData/rpIdHash=]. + +1. Let |kid| be |kidMac| || |kidParams|. + +To decode |kid|, producing the output |chosenAlg|, |signFlags| and |auxIkm|, perform the following steps: + +1. Let |macKey| be a per-credential authenticator secret. + +1. Let |mac| be the first 32 bytes of |kid| and let |kidParams| be the remaining bytes of |kid| after removing the first 32 bytes. + +1. Verify that |mac| equals the output of HMAC-SHA-256 [[RFC2104]] with the inputs: + + - Secret key `K`: |macKey| + - Input `text`: |kidParams| || UTF8Encode("sign") || |authData|.[=authData/rpIdHash=]. + + If not, this |kid| was generated by a different authenticator. + Return an error code equivalent to "{{NotAllowedError}}" and terminate the extension processing steps. + +1. Parse |kidParams| as a CBOR array. + +1. Let |chosenAlg| be |kidParams|[0]. + +1. Let |signFlags| be |kidParams|[1]. + +1. Let |auxIkm| be |kidParams|[2]. # User Agent Automation # {#sctn-automation} @@ -9221,6 +9876,14 @@ for their contributions as our W3C Team Contacts. "title": "EduPerson", "href": "https://refeds.org/eduperson", "date": "ongoing" + }, + + "ARKG": { + "authors": ["E. Lundberg", "J. Bradley", "P. Altmann"], + "title": "The Asynchronous Remote Key Generation (ARKG) algorithm (Editor's copy)", + "href": "https://yubico.github.io/arkg-rfc/draft-bradleylundberg-cfrg-arkg.html", + "status": "IETF Internet-Draft", + "date": "17 May, 2024" } }