From 5fcf35e16ca0fc2644135a3a4d7fa5a715137d28 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Fri, 17 May 2024 17:13:42 +0200 Subject: [PATCH 1/5] Add sign extension --- index.bs | 498 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 498 insertions(+) diff --git a/index.bs b/index.bs index fa1f38edb..bd498faeb 100644 --- a/index.bs +++ b/index.bs @@ -7642,6 +7642,496 @@ To Create a new supplemental public key record, perform t [=set/append=] this [=supplemental public key record=] to |credentialRecord|.[$credential record/supplementalPubKeys$]. +### 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 required values of the [=authData/flags/UP=] and [=authData/flags/UV=] [=flags=] +for the signing key pair are fixed at the time of creation. +If additional signing key pairs are required, +or signing key pairs with different settings for the [=flags=], +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. + +Although this extension can be used with [=discoverable credentials=], +it does not support usage 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 data; + }; + + +
+ : 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. + + : data + :: Data to be signed. + If present, the [=authenticator=] will sign this value using the newly generated signing private key. +
+ + + dictionary AuthenticationExtensionsSignSignInputs { + required BufferSource data; + required record<USVString, COSEKeyRef> keyHandleByCredential; + }; + typedef BufferSource COSEKeyRef; + + +
+ : data + :: Data to be signed. + The [=authenticator=] will sign this value using the signing private key. + + : 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. +
+ + +: 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: + + - `data`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/data}} + encoded as a CBOR byte string, if present. + Otherwise omit this entry. + + - `alg`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/algorithms}} + encoded as 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}}: + The [=authenticator extension output=] |authData|.[=authData/extensions=]["sign"][pk] + parsed as an {{ArrayBuffer}}. + + - {{AuthenticationExtensionsSignGeneratedKey/keyHandle}}: + An {{ArrayBuffer}} constructed as follows: + + 1. Let |parsedPk| be |authData|.[=authData/extensions=]["sign"][pk] parsed as a CBOR map. + 1. Remove all entries from |parsedPk| whose key is not one of `kty`, `kid` or `alg`. + 1. Let {{AuthenticationExtensionsSignGeneratedKey/keyHandle}} be an {{ArrayBuffer}} containing |parsedPk| encoded as CBOR. + + - {{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 `data`, `alg`, `flags`, `pk`, `kty`, `kid` 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: + - `data`: |extSign|.{{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/data}} 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 `data`, `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 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/data}} + 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 [=authenticator extension outputs=] + conveyed in the [=attestation object=], after verifying the [=attestation statement=]. + + : 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 the key handle + from the signing public key conveyed in the [=authenticator extension outputs=] + of the [=attestation object=], after verifying the [=attestation statement=]. +
+ + +: 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 + data = 0 + kty = 1 + kid = 2 + alg = 3 + flags = 4 + key-refs = 5 + + $$extensionInput //= ( + sign: { + ; Registration (key generation) input + ? data => bstr, + alg => [ + COSEAlgorithmIdentifier ], + ? flags => &(unattended: 0b000, require_up: 0b001, require_uv: 0b101) .default 0b001, + // + ; Authentication (signing) input + data => bstr, + key-refs => [ + bstr .cbor COSE_Key_Ref ], + }, + ) + ``` + +Note: The `key-refs` (5) 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=]) +:: Using the |extensions| argument to 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 |createFlags| be the value of |extSign|[flags]. + + 1. Use |createFlags|, |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|, |createFlags| 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: + - `pk`: |P_cose| encoded as a CBOR byte string. + - `sig`: The result of signing |extensions|["sign"][data], if present, using private key |p|, + if |chosenAlg| supports signing during registration. + Otherwise omit this entry. + + The CBOR map keys `alg`, `flags`, `pk`, `kid`, and `sig` 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|[data] 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|, |createFlags| 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 |createFlags| 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 |createFlags| 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 |createFlags|, |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|[data] using the private key referenced by |keyRef|. + + The CBOR map keys `data`, `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 + sig = 6 + pk = 7 + + $$extensionOutput //= ( + sign: { + ; Registration (key generation) outputs + pk => bstr, ; Generated signing public key + ? sig => bstr, ; Signature over data input, if present + // + ; Authentication (signing) outputs + sig => bstr, ; Signature over data 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 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|, |createFlags| 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. |createFlags| 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|, |createFlags| 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 |createFlags| be |kidParams|[1]. + +1. Let |auxIkm| be |kidParams|[2]. + + # User Agent Automation # {#sctn-automation} For the purposes of user agent automation and [=web application=] testing, this document defines a number of [[WebDriver]] [=extension commands=]. @@ -9272,6 +9762,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" } } From 3c77994f20b20f55463833b91504ee90d9ddd324 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 21 May 2024 05:07:42 +0200 Subject: [PATCH 2/5] Add attestation for sign public key --- index.bs | 226 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 181 insertions(+), 45 deletions(-) diff --git a/index.bs b/index.bs index bd498faeb..d373e9084 100644 --- a/index.bs +++ b/index.bs @@ -1427,7 +1427,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=]". @@ -7669,10 +7669,9 @@ and use the generated public key as verification material for a [=verifiable cre 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 required values of the [=authData/flags/UP=] and [=authData/flags/UV=] [=flags=] -for the signing key pair are fixed at the time of creation. +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 settings for the [=flags=], +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, @@ -7681,8 +7680,17 @@ 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 usage with an empty {{PublicKeyCredentialRequestOptions/allowCredentials}} +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. @@ -7760,7 +7768,7 @@ where neither the signing key pair nor the associated [=credential=] need to con The [=authenticator=] will sign this value using the signing private key. : keyHandleByCredential - :: A record mapping [=base64url encoding|base64url encoded=] [=credential IDs=] to signing key handles to use for each credential. + :: 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. @@ -7771,12 +7779,23 @@ where neither the signing key pair nor the associated [=credential=] need to con 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]] + defined in [[#sctn-createCredential]]. 1. Let |extSign| denote |pkOptions|.{{PublicKeyCredentialCreationOptions/extensions}}.{{AuthenticationExtensionsClientInputs/sign}}. @@ -7793,7 +7812,7 @@ where neither the signing key pair nor the associated [=credential=] need to con Otherwise omit this entry. - `alg`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/algorithms}} - encoded as CBOR array of integers, in order. + 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`. @@ -7805,22 +7824,24 @@ where neither the signing key pair nor the associated [=credential=] need to con - {{AuthenticationExtensionsSignOutputs/generatedKey}}: An {{AuthenticationExtensionsSignGeneratedKey}} value with the members: - {{AuthenticationExtensionsSignGeneratedKey/publicKey}}: - The [=authenticator extension output=] |authData|.[=authData/extensions=]["sign"][pk] - parsed as an {{ArrayBuffer}}. + 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 |parsedPk| be |authData|.[=authData/extensions=]["sign"][pk] parsed as a CBOR map. - 1. Remove all entries from |parsedPk| whose key is not one of `kty`, `kid` or `alg`. - 1. Let {{AuthenticationExtensionsSignGeneratedKey/keyHandle}} be an {{ArrayBuffer}} containing |parsedPk| encoded as CBOR. + 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 `data`, `alg`, `flags`, `pk`, `kty`, `kid` and `sig` are aliases defined below + The CBOR map keys `data`, `alg`, `flags`, `att-obj` and `sig` are aliases defined below in the CDDL for the [=authenticator extension input=] and [=authenticator extension output=]. @@ -7893,7 +7914,7 @@ where neither the signing key pair nor the associated [=credential=] need to con
: generatedKey - :: The generated public key and key handle. + :: The generated public key and [=signing key handle=]. Present if and only if the {{AuthenticationExtensionsSignInputs/generateKey}} input was present. : signature @@ -7916,8 +7937,10 @@ where neither the signing key pair nor the associated [=credential=] need to con :: 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 [=authenticator extension outputs=] - conveyed in the [=attestation object=], after verifying the [=attestation statement=]. + [=[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. @@ -7926,9 +7949,8 @@ where neither the signing key pair nor the associated [=credential=] need to con 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 the key handle - from the signing public key conveyed in the [=authenticator extension outputs=] - of the [=attestation object=], after verifying the [=attestation statement=]. + [=[RPS]=] that request attestation SHOULD instead construct key handles + as described for the [=client extension input=] {{AuthenticationExtensionsSignSignInputs/keyHandleByCredential}}.
@@ -7949,7 +7971,9 @@ where neither the signing key pair nor the associated [=credential=] need to con ; Registration (key generation) input ? data => bstr, alg => [ + COSEAlgorithmIdentifier ], - ? flags => &(unattended: 0b000, require_up: 0b001, require_uv: 0b101) .default 0b001, + ? flags => &(unattended: 0b000, + require-up: 0b001, + require-uv: 0b101) .default 0b001, // ; Authentication (signing) input data => bstr, @@ -7958,15 +7982,56 @@ where neither the signing key pair nor the associated [=credential=] need to con ) ``` -Note: The `key-refs` (5) 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. + : data + :: The data to sign. + MAY be present during [=registration ceremonies=]. + MUST be present during [=authentication ceremonies=]. + + : 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=]. + + 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 verification=] but will not require [=user presence=]. + - 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=]) -:: Using the |extensions| argument to the [=authenticatorMakeCredential=] operation, - let |extSign| denote |extensions|["sign"]. +:: 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 @@ -7983,13 +8048,17 @@ when the extension input is embedded in the CTAP2 message structure. 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 |createFlags| be the value of |extSign|[flags]. + 1. Let |signFlags| be the value of |extSign|[flags]. - 1. Use |createFlags|, |auxIkm| and a per-credential authenticator secret + 1. If |signFlags| is not one of the values `unattended` (`0b001`), `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|, |createFlags| and |auxIkm|, + 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. @@ -8001,12 +8070,37 @@ when the extension input is embedded in the CTAP2 message structure. 1. Set |P_cose|[kid] to |kid|. 1. Set |authData|.[=authData/extensions=]["sign"] to a new CBOR map with the entries: - - `pk`: |P_cose| encoded as a CBOR byte string. + - `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"][data], if present, using private key |p|, if |chosenAlg| supports signing during registration. Otherwise omit this entry. - The CBOR map keys `alg`, `flags`, `pk`, `kid`, and `sig` are aliases defined above and below + The CBOR map keys `alg`, `flags`, `kid`, `sig` and `att-obj` are aliases defined above and below in the CDDL for the [=authenticator extension input=] and [=authenticator extension output=]. @@ -8036,7 +8130,7 @@ when the extension input is embedded in the CTAP2 message structure. 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|, |createFlags| and |auxIkm|. + 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]]. @@ -8045,15 +8139,15 @@ when the extension input is embedded in the CTAP2 message structure. 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 |createFlags| but not in |authData|.[=authData/flags=], + 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 |createFlags| but not in |authData|.[=authData/flags=], + 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 |createFlags|, |auxIkm|, and a per-credential authenticator secret + 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|. @@ -8070,36 +8164,78 @@ when the extension input is embedded in the CTAP2 message structure. ``` ; The symbolic names on the left are represented in CBOR by the integers on the right + flags = 4 sig = 6 - pk = 7 + att-obj = 7 $$extensionOutput //= ( sign: { ; Registration (key generation) outputs - pk => bstr, ; Generated signing public key - ? sig => bstr, ; Signature over data input, if present + att-obj => bstr .cbor attObj, ; Attestation object for signing key pair + ? sig => bstr, ; Signature over data input, if present // ; Authentication (signing) outputs - sig => bstr, ; Signature over data input + sig => bstr, ; Signature over data 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 `data`, 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 key handle |kid| +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|, |createFlags| and |auxIkm|, producing the output |kid|, perform the following steps: +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. |createFlags| encoded as a CBOR unsigned 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: @@ -8109,7 +8245,7 @@ To encode |chosenAlg|, |createFlags| and |auxIkm|, producing the output |kid|, p 1. Let |kid| be |kidMac| || |kidParams|. -To decode |kid|, producing the output |chosenAlg|, |createFlags| and |auxIkm|, perform the following steps: +To decode |kid|, producing the output |chosenAlg|, |signFlags| and |auxIkm|, perform the following steps: 1. Let |macKey| be a per-credential authenticator secret. @@ -8127,7 +8263,7 @@ To decode |kid|, producing the output |chosenAlg|, |createFlags| and |auxIkm|, p 1. Let |chosenAlg| be |kidParams|[0]. -1. Let |createFlags| be |kidParams|[1]. +1. Let |signFlags| be |kidParams|[1]. 1. Let |auxIkm| be |kidParams|[2]. From 215f20ba3722774a1fd0bdad2ccd0f74285ced34 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 4 Jul 2024 15:01:21 +0200 Subject: [PATCH 3/5] Fix UP/UV mixup --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index d373e9084..3259926fa 100644 --- a/index.bs +++ b/index.bs @@ -8001,7 +8001,7 @@ where neither the signing key pair nor the associated [=credential=] need to con 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 verification=] but will not require [=user presence=]. + - 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`). From 03a6d0e104dbf4556d53d0a26236cb656241d33f Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 4 Jul 2024 15:04:45 +0200 Subject: [PATCH 4/5] Fix value in a reference to signFlags:unattended --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 3259926fa..271c950fa 100644 --- a/index.bs +++ b/index.bs @@ -8050,7 +8050,7 @@ where neither the signing key pair nor the associated [=credential=] need to con 1. Let |signFlags| be the value of |extSign|[flags]. - 1. If |signFlags| is not one of the values `unattended` (`0b001`), `require-up` (`0b001`) or `require-uv` (`0b101`), + 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`. From 183e6700e3e54bd61aa70cefedef09432b328099 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Wed, 11 Sep 2024 17:41:16 +0200 Subject: [PATCH 5/5] Add outline of signing extension expecting pre-hashed data Note that as noted in the inline `ISSUE` annotations, what "pre-hashed" means is currently underspecified and will need to be clarified. --- index.bs | 79 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/index.bs b/index.bs index 4b6ad3df5..fb55cfbf4 100644 --- a/index.bs +++ b/index.bs @@ -7696,7 +7696,7 @@ where neither the signing key pair nor the associated [=credential=] need to con dictionary AuthenticationExtensionsSignGenerateKeyInputs { required sequence<COSEAlgorithmIdentifier> algorithms; - BufferSource data; + BufferSource phData; }; @@ -7706,24 +7706,37 @@ where neither the signing key pair nor the associated [=credential=] need to con 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. - : data - :: Data to be signed. + 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 data; + required BufferSource phData; required record<USVString, COSEKeyRef> keyHandleByCredential; }; typedef BufferSource COSEKeyRef;
- : data - :: Data to be signed. + : 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}}, @@ -7764,7 +7777,7 @@ where neither the signing key pair nor the associated [=credential=] need to con 1. Set the `sign` [=authenticator extension input=] to a CBOR map with the entries: - - `data`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/data}} + - `phData`: |extSign|.{{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/phData}} encoded as a CBOR byte string, if present. Otherwise omit this entry. @@ -7798,7 +7811,7 @@ where neither the signing key pair nor the associated [=credential=] need to con parsed as an {{ArrayBuffer}}, if present. Otherwise omit this member. - The CBOR map keys `data`, `alg`, `flags`, `att-obj` and `sig` are aliases defined below + 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=]. @@ -7839,7 +7852,7 @@ where neither the signing key pair nor the associated [=credential=] need to con return a {{DOMException}} whose name is “{{SyntaxError}}”. 1. Set the `sign` authenticator extension input to a CBOR map with the entries: - - `data`: |extSign|.{{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/data}} encoded as a CBOR byte string. + - `phData`: |extSign|.{{AuthenticationExtensionsSignInputs/sign}}.{{AuthenticationExtensionsSignSignInputs/phData}} encoded as a CBOR byte string. - `key-refs`: |keyHandles|. 1. After the [=authenticatorGetAssertion=] operation is successful, @@ -7853,7 +7866,7 @@ where neither the signing key pair nor the associated [=credential=] need to con The [=authenticator extension output=] |authData|.[=authData/extensions=]["sign"][sig] parsed as an {{ArrayBuffer}}. - The CBOR map keys `data`, `key-refs` and `sig` are aliases defined below + 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=]. @@ -7878,7 +7891,7 @@ where neither the signing key pair nor the associated [=credential=] need to con :: The generated signature. Present if and only if the {{AuthenticationExtensionsSignInputs/sign}} input was present - or the {{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/data}} + or the {{AuthenticationExtensionsSignInputs/generateKey}}.{{AuthenticationExtensionsSignGenerateKeyInputs/phData}} input was present.
@@ -7916,7 +7929,7 @@ where neither the signing key pair nor the associated [=credential=] need to con ``` ; The symbolic names on the left are represented in CBOR by the integers on the right - data = 0 + phData = 0 kty = 1 kid = 2 alg = 3 @@ -7926,29 +7939,37 @@ where neither the signing key pair nor the associated [=credential=] need to con $$extensionInput //= ( sign: { ; Registration (key generation) input - ? data => bstr, + ? phData => bstr, alg => [ + COSEAlgorithmIdentifier ], ? flags => &(unattended: 0b000, require-up: 0b001, require-uv: 0b101) .default 0b001, // ; Authentication (signing) input - data => bstr, + phData => bstr, key-refs => [ + bstr .cbor COSE_Key_Ref ], }, ) ``` - : data - :: The data to sign. + : 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. @@ -8053,11 +8074,16 @@ where neither the signing key pair nor the associated [=credential=] need to con - |hash|: |hash|. - - `sig`: The result of signing |extensions|["sign"][data], if present, using private key |p|, + - `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 CBOR map keys `alg`, `flags`, `kid`, `sig` and `att-obj` are aliases defined above and below + 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=]. @@ -8070,7 +8096,7 @@ where neither the signing key pair nor the associated [=credential=] need to con 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|[data] is not present or |extSign|[key-refs] is not present, + 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`. @@ -8110,9 +8136,14 @@ where neither the signing key pair nor the associated [=credential=] need to con 1. Set |authData|.[=authData/extensions=]["sign"] to a new CBOR map with the entries: - - `sig`: The result of signing |extSign|[data] using the private key referenced by |keyRef|. + - `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 `data`, `key-refs`, `kid`, `alg` and `sig` are aliases defined above and below + 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=]. @@ -8129,10 +8160,10 @@ where neither the signing key pair nor the associated [=credential=] need to con sign: { ; Registration (key generation) outputs att-obj => bstr .cbor attObj, ; Attestation object for signing key pair - ? sig => bstr, ; Signature over data input, if present + ? sig => bstr, ; Signature over phData input, if present // ; Authentication (signing) outputs - sig => bstr, ; Signature over data input + sig => bstr, ; Signature over phData input // ; Attestation fields flags => &(unattended: 0b000, @@ -8151,7 +8182,7 @@ where neither the signing key pair nor the associated [=credential=] need to con MUST NOT be present in [=authentication ceremonies=]. : sig - :: A signature over the extension input `data`, if present, by the signing private key. + :: 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=].