-
Notifications
You must be signed in to change notification settings - Fork 257
Add "Credential Manager Trust Group (CMTG) Key" extension #2377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b0c1b60
a67d081
ae644a8
75d43e6
01db582
0a4ead0
cd9a036
5f7b9f1
adcef86
1f3fc61
e2e857c
4920b67
a579300
85df71a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,4 +23,5 @@ VCHAR | |
| attestn | ||
| RSASSA | ||
| PKCS1 | ||
| bytestrings | ||
| bytestrings | ||
| cmtg | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1043,6 +1043,7 @@ BCP 14 [[!RFC2119]] [[!RFC8174]] when, and only when, they appear in all capital | |||||
| : <dfn>Credential Private Key</dfn> | ||||||
| : <dfn>Credential Public Key</dfn> | ||||||
| : <dfn>User Public Key</dfn> | ||||||
| : <dfn>User Credential</dfn> | ||||||
| :: A [=credential key pair=] is a pair of asymmetric cryptographic keys generated by an [=authenticator=] | ||||||
| and [=scoped=] to a specific [=[WRP]=]. It is the central part of a [=public key credential=]. | ||||||
|
|
||||||
|
|
@@ -1060,6 +1061,20 @@ BCP 14 [[!RFC2119]] [[!RFC8174]] when, and only when, they appear in all capital | |||||
| Note: The [=credential public key=] is referred to as the [=user public key=] in FIDO UAF [[UAFProtocol]], and in FIDO U2F | ||||||
| [[FIDO-U2F-Message-Formats]] and some parts of this specification that relate to it. | ||||||
|
|
||||||
| : <dfn>Credential Manager Trust Group Key</dfn> | ||||||
| : <dfn>Credential Manager Trust Group Private Key</dfn> | ||||||
| : <dfn>Credential Manager Trust Group Public Key</dfn> | ||||||
| :: A [=Credential Manager Trust Group Key=], is a [=authenticator=]- / [=credential manager=]-, [=[RP]=]-, and [=user credential=]-specific | ||||||
| public key pair created upon a [=[RP]=]'s request via the [=cmtgKey=] [=WebAuthn extension=]. | ||||||
|
|
||||||
| The [=Credential Manager Trust Group Public Key=] is conveyed to the [=[RP]=] during a | ||||||
| [=registration ceremony|registration=] or [=authentication ceremony|authentication=] ceremony | ||||||
| as part of the [=cmtgKey=] extension output. | ||||||
|
|
||||||
| The [=Credential Manager Trust Group Private Key=] is stored by the [=authenticator=] / [=credential manager=]. | ||||||
|
|
||||||
| See [[#sctn-cmtg-key-extension]]. | ||||||
|
|
||||||
| : <dfn>Credential Properties</dfn> | ||||||
| :: A [=credential property=] is some characteristic property of a [=public key credential source=], such as whether it is a | ||||||
| [=client-side discoverable credential=] or a [=server-side credential=]. | ||||||
|
|
@@ -7738,15 +7753,227 @@ However, [=authenticators=] that do not utilize [[!FIDO-CTAP]] do not necessaril | |||||
|
|
||||||
|
|
||||||
| : Authenticator extension processing | ||||||
| :: [=largeblob|This extension=] directs the user-agent to cause the large blob to be stored on, or retrieved from, the authenticator. It thus does not specify any direct authenticator interaction for [=[RPS]=]. | ||||||
| :: [=largeblob|This extension=] directs the user-agent to cause the large blob to be stored on, | ||||||
| or retrieved from, the authenticator. It thus does not specify any direct authenticator interaction for [=[RPS]=]. | ||||||
|
|
||||||
|
|
||||||
| ## Authenticator Extensions ## {#sctn-defined-authenticator-extensions} | ||||||
|
|
||||||
| This section defines extensions that are both [=client extensions=] and [=authenticator extensions=]. | ||||||
|
|
||||||
| This section is currently empty. | ||||||
| ### Credential Manager Trust Group Key extension (<dfn>cmtgKey</dfn>) ### {#sctn-cmtg-key-extension} | ||||||
|
|
||||||
| This [=authenticator extension|authenticator=] [=registration extension=] and [=authentication extension=] | ||||||
| enables an [=authenticator=]/[=credential manager=] to provide a signal to a [=[RP]=] | ||||||
| that two devices possessing the same [=backed up=] credential | ||||||
| have established a trust relationship through a non-remote interaction, | ||||||
| such as a local setup or physical proximity. | ||||||
|
|
||||||
| This is done by creating an additional [=public key credential source=]-specific [=Credential Manager Trust Group key pair=] | ||||||
| in the [=authenticator=], if such a key pair needs to be created for the | ||||||
| [=public key credential source=] being created or exercised on the specific device, | ||||||
| and returning one of the [=Credential Manager Trust Group public keys=] | ||||||
| along with a signature by the [=Credential Manager Trust Group private key=] to the [=[RP]=]. | ||||||
|
|
||||||
| This is done each time this [=cmtgKey=] extension is included with either a | ||||||
| {{CredentialsContainer/create()|navigator.credentials.create()}} or {{CredentialsContainer/get()|navigator.credentials.get()}} call. | ||||||
|
|
||||||
| #### Relying Party Usage #### {#sctn-cmtg-key-extension-usage} | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the details for when a new key pair is minted should not be under "relying party usage" imo. Paragraphs 3 onwards are all about authenticator actions, with no mention of what RPs should do with this information. Those can go under the previous heading instead. |
||||||
|
|
||||||
| This extension is intended for use by those [=[RPS]=] employing risk-analysis systems informing their sign-in decisions. | ||||||
|
|
||||||
| This extension provides a "trust group" signal <i>when used consistently</i> with both | ||||||
| {{CredentialsContainer/create()|navigator.credentials.create()}} and {{CredentialsContainer/get()|navigator.credentials.get()}} operations. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional: consider adding details on how to use the signal and what it means. Something like: When a relying party observes a new CMTG public key during a create or assert operation, the CMTG public key should be added to the credential record. On subsequent assertions, after validating the CMTG signature, if an existing CMTG public key is observed, the relying party should use this as a signal that there is a strong relationship between the device that produced an assertion and previously used devices. Otherwise, if the CMTG public key is new, the device producing the assertion may not have a strong relationship with previously used devices. The new CMTG public key should be added to the credential record, signaling the start of a separate trust group. An invalid CMTG signature is not expected and should invalidate the entire request. |
||||||
|
|
||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's also add some javascript examples, both on the spec and the explainer. The explainer doesn't have any javascript for processing a response. |
||||||
| When a [=[RP]=] uses the `cmtgKey` extension during a {{CredentialsContainer/create()|create()}} option on the first device (`dev1`), | ||||||
| the selected [=authenticator=]/[=credential manager=] (`cm1`) generates a new [=Credential Manager Trust Group Key=] pair. | ||||||
| The extension output includes the public key and a signature generated using the | ||||||
| [=Credential Manager Trust Group private key=] (`cmtgKey1`). | ||||||
|
|
||||||
| A subsequent {{CredentialsContainer/get()|get()}} operation (with the `cmtgKey` extension) on `dev1` | ||||||
| using the same credential and the same authenticator/credential manager (`cm1`), | ||||||
| will include a signature from the same [=Credential Manager Trust Group private key=], `cmtgKey1`. | ||||||
|
|
||||||
| `cmtgKey1` is only synced to an authenticator/credential manager on another device (`dev2`) | ||||||
| if a non-remote relationship exists between the source (`dev1`) and destination (`dev2`) device. | ||||||
|
|
||||||
| If a third device (`dev3`) is introduced (with `cm1` configured), | ||||||
| which does not share a non-remote relationship with `dev1`or `dev2` | ||||||
| (as evaluated by the authenticator/credential manager, `cm1`), | ||||||
| a new [=Credential Manager Trust Group private key=] (`cmtgKey2`) is generated and its public key | ||||||
| is returned to the [=[RP]=] along with it's public key, signaling the start of a separate trust group. | ||||||
|
|
||||||
| #### Extension Definition #### {#sctn-cmtg-key-extension-definition} | ||||||
|
|
||||||
| : Extension identifier | ||||||
| :: `cmtgKey` | ||||||
|
|
||||||
| : Operation applicability | ||||||
| :: [=registration extension|Registration=] and [=authentication extension|authentication=] | ||||||
|
|
||||||
| : Client extension input | ||||||
| :: The Boolean value [TRUE] to indicate that this extension is requested by the [=[RP]=]. | ||||||
| <xmp class="idl"> | ||||||
| partial dictionary AuthenticationExtensionsClientInputs { | ||||||
| boolean cmtgKey; | ||||||
| }; | ||||||
| </xmp> | ||||||
|
|
||||||
| : Client extension processing | ||||||
| :: None, except creating the authenticator extension input from the client extension input. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Somewhere we need a discussion of what happens when the UA understands the extension but the authenticator does not. In that case, no CMTG will be returned. Perhaps this is the right place for it. |
||||||
|
|
||||||
| : Client extension output | ||||||
| :: An ArrayBuffer containing the COSE_Key-encoded [=Credential Manager Trust Group public key=] | ||||||
| that was returned in the authenticator extension output | ||||||
| and the signature returned as the [=unsigned extension output=]. | ||||||
| <xmp class="idl"> | ||||||
| dictionary AuthenticationExtensionsCmtgKeyOutputs { | ||||||
| ArrayBuffer cmtgKey; | ||||||
| ArrayBuffer signature; | ||||||
| }; | ||||||
|
|
||||||
| partial dictionary AuthenticationExtensionsClientOutputs { | ||||||
| AuthenticationExtensionsCmtgKeyOutputs cmtgKey; | ||||||
| }; | ||||||
| </xmp> | ||||||
|
|
||||||
| : Authenticator extension input | ||||||
| :: The Boolean value [TRUE], encoded in CBOR (major type 7, value 21). | ||||||
|
|
||||||
| ``` | ||||||
| $$extensionInput //= ( | ||||||
| cmtgKey: true, | ||||||
| ) | ||||||
| ``` | ||||||
|
|
||||||
| : Authenticator extension output | ||||||
| :: A byte string containing the COSE_Key-encoded [=Credential Manager Trust Group public key=]: | ||||||
|
|
||||||
| ``` | ||||||
| $$extensionOutput //= ( | ||||||
| cmtgKey: bstr, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And the signature as well? |
||||||
| ) | ||||||
| ``` | ||||||
|
|
||||||
| : Unsigned extension output | ||||||
| :: A CBOR byte string containing a signature generated with the Credential Manager Trust Group Key's private key. | ||||||
|
|
||||||
| : Authenticator extension processing | ||||||
| :: For both [=authenticatorMakeCredential=] and [=authenticatorGetAssertion=] operations: | ||||||
| 1. Create or select the [=public key credential source=] as usual (see [[#sctn-op-make-cred]], | ||||||
| or [[#sctn-op-get-assertion]] as appropriate). | ||||||
|
|
||||||
| 1. If the [=public key credential source=] is not [=backup eligible=], | ||||||
| terminate these processing steps as this extension only applies to [=multi-device credentials=]. | ||||||
|
|
||||||
| 1. If a [=Credential Manager Trust Group Key=] does not already exist for this {[=public key credential source/id|Credential ID=], | ||||||
| [=public key credential source/rpId|RP ID=], [=public key credential source/rpId|userHandle=]} tuple in the [=authenticator=]/[=credential manager=], | ||||||
|
Comment on lines
+7869
to
+7870
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As written, CMTG keys seem to have a 1:1 relationship with public key credentials. Even if we don't define the mechanism that determines which devices belong to a trust group, we should incorporate the concept of trust groups to the execution steps:
We should have a definition for "credential manager trust group" as well. |
||||||
| create it using the same public key algorithm as that used by the [=user credential=]'s [=credential key pair=], | ||||||
| otherwise locate the existing [=Credential Manager Trust Group Key=]. | ||||||
|
|
||||||
| 1. Let |cmtgPublicKey| be the newly created or existing [=Credential Manager Trust Group Key=], | ||||||
| in COSE_Key format [=credentialPublicKey|in the same fashion as for the user credential's credentialPublicKey=]. | ||||||
|
|
||||||
| 1. Let |cmtgPrivateKey| be the newly created or existing [=Credential Manager Trust Group private key=]. | ||||||
|
|
||||||
| 1. Let |cmtgKeySig| be the result of signing the [=assertion signature=] [input](#fig-signature) with |cmtgPrivateKey|, | ||||||
| using the same signature algorithm as that used by the [=user credential=]'s [=credential key pair=]. | ||||||
|
|
||||||
| Note: the [=assertion signature=] [input](#fig-signature) and |cmtgKeySig| covers the [=[RP]=]'s {{PublicKeyCredentialCreationOptions/challenge}} | ||||||
| because it includes the [=hash of the serialized client data=]. Thus the [=[RP]=] knows that |cmtgKeySig| is a fresh signature. | ||||||
|
|
||||||
| 1. Output |cmtgKeySig| as the extension's [=unsigned extension output=]. | ||||||
|
|
||||||
| Note: |cmtgKeySig| cannot be included in the [=authenticator extension output=] because it is returned inside the [=authenticator data=] | ||||||
| and that would imply that the signature signs over itself. | ||||||
|
|
||||||
| #### `cmtgKey` Extension Output Verification Procedures #### {#sctn-cmtg-key-extension-verification} | ||||||
|
|
||||||
| Verifying the <code>[=cmtgKey=]</code> extension output is performed by the [=[RP]=] whenever a [=Credential Manager Trust Group Key=] is returned within the extension output. | ||||||
|
|
||||||
| ##### Registration (`create()`) ##### {#sctn-cmtg-key-extension-verification-create} | ||||||
|
|
||||||
| If the `cmtgKey` extension was included on a {{CredentialsContainer/create()|navigator.credentials.create()}} call | ||||||
| and a [=Credential Manager Trust Group Key=] is returned by an [=authenticator=], | ||||||
| the below verification steps are performed in the context of <a href=#reg-ceremony-verify-extension-outputs>this step</a> of [[#sctn-registering-a-new-credential]] | ||||||
| using these variables established therein: |credential|, |clientExtensionResults|, |authData|, and |hash|. | ||||||
|
|
||||||
| 1. Let |attObjForCmtgKey| be the value of the {{AuthenticationExtensionsClientOutputs/cmtgKey}} member of |clientExtensionResults|. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe from what you wrote above, So I think you want something like |
||||||
|
|
||||||
| 1. Verify that |attObjForCmtgKey| is valid CBOR conforming to the syntax defined above | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to the comment above, |signature| and |cmtgKey| are not CBOR members, they're javascript members. Perhaps you wanted to have the RP verify the integrity of the CBOR encoded COSE public key? |
||||||
| and perform CBOR decoding on it to extract the contained fields: |signature|, |cmtgKey|. | ||||||
|
|
||||||
| Note: The latter |attObjForCmtgKey| fields are referenced exclusively in the below steps | ||||||
| and are not to be confused with other fields with the same names in other portions of the top-level [=attestation object=]. | ||||||
|
|
||||||
| 1. Verify that the algorithm used for the signature in {{AuthenticationExtensionsCmtgKeyOutputs}} | ||||||
| matches the COSE algorithm identifier of the [=credentialPublicKey=] within the [=attestedCredentialData=] | ||||||
| of |authData|. | ||||||
|
|
||||||
| 1. Verify that {{AuthenticationExtensionsCmtgKeyOutputs/signature}} is a valid signature over the [=assertion signature=] [input](#fig-signature) | ||||||
| (i.e. `authData` and `hash`) by the [=Credential Manager Trust Group Key=] |cmtgKey|. | ||||||
|
|
||||||
| 1. Complete the steps from [[#sctn-registering-a-new-credential]] and, if those steps are successful, | ||||||
| store the |cmtgKey| value indexed to the <code>|credential|.{{Credential/id}}</code> in the [=user account=]. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should refer to the credential record object here instead. In fact, the credential record object should be updated to add CMTG public keys. |
||||||
|
|
||||||
| See also [[#sctn-cmtg-key-extension-usage]] for further details. | ||||||
|
|
||||||
| ##### Authentication (`get()`) ##### {#sctn-cmtg-key-extension-verification-get} | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Same comments apply as above) |
||||||
|
|
||||||
| If the `cmtgKey` extension was included on a {{CredentialsContainer/get()|navigator.credentials.get()}} call, | ||||||
| then the below verification steps are performed in the context of <a href=#authn-ceremony-verify-extension-outputs>this step</a> of [[#sctn-verifying-assertion]] | ||||||
| using these variables established therein: |credential|, |clientExtensionResults|, |authData|, and |hash|. | ||||||
| [=[RP]=] policy may specify whether a response without a `cmtgKey` is acceptable. | ||||||
|
|
||||||
| 1. Let |attObjForCmtgKey| be the value of the `cmtgKey` member of |clientExtensionResults|. | ||||||
|
|
||||||
| 1. Verify that |attObjForCmtgKey| is valid CBOR conforming to the syntax defined above | ||||||
| and perform CBOR decoding on it to extract the contained fields: |signature|, |cmtgKey|. | ||||||
|
|
||||||
| Note: The latter |attObjForCmtgKey| fields are referenced exclusively in the below steps | ||||||
| and are not to be confused with other fields with the same names in other portions of [=authenticator data=]. | ||||||
|
|
||||||
| 1. Verify that the algorithm used for the signature in {{AuthenticationExtensionsCmtgKeyOutputs}} | ||||||
| matches the algorithm of the public key previously stored for the credential | ||||||
| identified by the [=credentialId=]. | ||||||
|
|
||||||
| 1. Verify that {{AuthenticationExtensionsCmtgKeyOutputs/signature}} is a valid signature over the [=assertion signature=] [input](#fig-signature) | ||||||
| (i.e. `authData` and `hash`) by the [=Credential Manager Trust Group public key=] |cmtgKey|. | ||||||
| (The signature algorithm is the same as for the [=user credential=].) | ||||||
|
|
||||||
| 1. If the [=[RP]=]'s [=user account=] mapped to the <code>|credential|.{{Credential/id}}</code> in play (i.e., for the user being authenticated) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should refer to the credential record object here as well. |
||||||
| hold a `cmtgKey` value corresponding to the extracted |attObjForCmtgKey| fields, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| then perform binary equality checks between the corresponding stored value and the extracted field value. | ||||||
| The [=[RP]=] MAY have more than one `cmtgKey` value mapped to the [=user account=] and <code>|credential|.{{Credential/id}}</code> pair | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of this note why not make L7937 a loop per stored CMTG key. |
||||||
| and each value MUST be checked. | ||||||
|
|
||||||
| If the above set of binary equality checks resulted in: | ||||||
|
|
||||||
| <dl class="switch"> | ||||||
| : more than one match | ||||||
| :: Some form of error has occurred. | ||||||
| Terminate these verification steps. | ||||||
|
|
||||||
| : exactly one match | ||||||
| :: The [=authenticator=]/[=credential manager=] is part of a previously seen trust group: | ||||||
|
|
||||||
| Terminate these verification steps. | ||||||
|
|
||||||
| : zero matches | ||||||
| :: This is possibly a new [=Credential Manager Trust Group Key=], signifying a new trust group: | ||||||
|
|
||||||
| Store the extracted |cmtgKey| value indexed to the <code>|credential|.{{Credential/id}}</code> in the [=user account=]. | ||||||
| Terminate these verification steps. | ||||||
|
|
||||||
| </dl> | ||||||
|
|
||||||
| 1. Otherwise, the [=[RP]=] does not have |attObjForCmtgKey| fields presently mapped to this [=user account=] | ||||||
| and <code>|credential|.{{Credential/id}}</code> pair: | ||||||
|
|
||||||
| 1. Store the extracted |cmtgKey| value indexed to the <code>|credential|.{{Credential/id}}</code> in the [=user account=]. | ||||||
| Terminate these verification steps. | ||||||
|
|
||||||
| See also [[#sctn-cmtg-key-extension-usage]]. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to add virtual authenticator support for this feature? It feels it should be pretty simple, and it'll be required to write WPTs. |
||||||
|
|
||||||
| # User Agent Automation # {#sctn-automation} | ||||||
|
|
||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: having "/[=credential manager=]" everywhere is awkward. Do we really need to introduce this term to the spec? I'd say drop the "credential manager". It's cleaner.