diff --git a/index.bs b/index.bs index 89e05d10e..27cec2f24 100644 --- a/index.bs +++ b/index.bs @@ -7517,6 +7517,218 @@ Note: this extension may be implemented for [=authenticators=] that do not use [ :: The results of evaluating the PRF for the inputs given in {{AuthenticationExtensionsPRFInputs/eval}} or {{AuthenticationExtensionsPRFInputs/evalByCredential}}. Outputs may not be available during [=registration=]; see comments in {{AuthenticationExtensionsPRFInputs/eval}}. + +#### Test vectors: Web Authentication API #### {#prf-extension-test-vectors-webauthn} + +[INFORMATIVE] + +The following examples may be used to test [=[WAC]=] implementations of and [=[WRP]=] usage of the [=prf=] extension. +The examples are not exhaustive. + +- The {{AuthenticationExtensionsPRFOutputs/enabled}} output is always present during [=registration ceremonies=], + and never present during [=authentication ceremonies=]: + + + // Example extension inputs: + { prf: {} } + + // Example client extension outputs from navigator.credentials.create(): + { prf: { enabled: true } } + { prf: { enabled: false } } + + // Example client extension outputs from navigator.credentials.get(): + { prf: {} } + + +- The {{AuthenticationExtensionsPRFOutputs/results}} output may be present + during [=registration ceremonies=] or [=authentication ceremonies=] + if the {{AuthenticationExtensionsPRFInputs/eval}} or {{AuthenticationExtensionsPRFInputs/evalByCredential}} input is present: + + + // Example extension inputs: + { prf: { eval: { first: new Uint8Array([1, 2, 3, 4]) } } } + + // Example client extension outputs from navigator.credentials.create(): + { prf: { enabled: true } } + { prf: { enabled: false } } + { prf: { enabled: true, results: { first: ArrayBuffer } } } + + // Example client extension outputs from navigator.credentials.get(): + { prf: {} } + { prf: { results: { first: ArrayBuffer } } } + + +- The {{AuthenticationExtensionsPRFOutputs/results}}.{{AuthenticationExtensionsPRFValues/second}} output + is present if and only if the {{AuthenticationExtensionsPRFOutputs/results}} output is present + and the {{AuthenticationExtensionsPRFValues/second}} input was present in the chosen PRF inputs: + + + // Example extension inputs: + { + prf: { + eval: { + first: new Uint8Array([1, 2, 3, 4]), + second: new Uint8Array([5, 6, 7, 8]), + }, + evalByCredential: { + "e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE": { + first: new Uint8Array([9, 10, 11, 12]), + } + } + } + } + + // Example client extension outputs from navigator.credentials.get() if credential "e02eZ9lP..." was used: + { prf: { results: { first: ArrayBuffer } } } + + // Example client extension outputs from navigator.credentials.get() if a different credential was used: + { prf: {} } + { prf: { results: { first: ArrayBuffer, second: ArrayBuffer } } } + + +- The {{AuthenticationExtensionsPRFValues/first}} and {{AuthenticationExtensionsPRFValues/second}} outputs + may be any {{BufferSource}} type. + Equal {{AuthenticationExtensionsPRFValues/first}} and {{AuthenticationExtensionsPRFValues/second}} inputs + result in equal {{AuthenticationExtensionsPRFValues/first}} and {{AuthenticationExtensionsPRFValues/second}} outputs: + + + // Example extension inputs: + { + prf: { + evalByCredential: { + "e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE": { + first: new Uint8Array([9, 10, 11, 12]), + second: new Uint8Array([9, 10, 11, 12]) + } + } + } + } + + // Example client extension outputs from navigator.credentials.get(): + { + prf: { + results: { + first: new Uint8Array([0xc4, 0x17, 0x2e, 0x98, 0x2e, 0x90, 0x97, 0xc3, 0x9a, 0x6c, 0x0c, 0xb7, 0x20, 0xcb, 0x37, 0x5b, 0x92, 0xe3, 0xfc, 0xad, 0x15, 0x4a, 0x63, 0xe4, 0x3a, 0x93, 0xf1, 0x09, 0x6b, 0x1e, 0x19, 0x73]), + second: new Uint32Array([0x982e17c4, 0xc397902e, 0xb70c6c9a, 0x5b37cb20, 0xadfce392, 0xe4634a15, 0x09f1933a, 0x73191e6b]), + } + } + } + + +Pseudo-random values used in this section were generated as follows: + +- "e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE" = Base64Url(SHA-256(UTF-8("WebAuthn PRF test vectors") || 0x00)) +- h'c4172e982e9097c39a6c0cb720cb375b92e3fcad154a63e43a93f1096b1e1973' = SHA-256(UTF-8("WebAuthn PRF test vectors") || 0x01) + + +#### Test vectors: CTAP2 `hmac-secret` extension #### {#prf-extension-test-vectors-ctap} + +[INFORMATIVE] + +The following examples may be used to test [=[WAC]=] implementations +of how the [=prf=] extension uses the [[FIDO-CTAP]] `hmac-secret` extension. +The examples are given in CDDL [[RFC8610]] notation. +The examples are not exhaustive. + +- The following shared definitions are used in all subsequent examples: + + + ; Given input parameters: + platform_key_agreement_private_key = 0x0971bc7fb1be48270adcd3d9a5fc15d5fb0f335b3071ff36a54c007fa6c76514 + authenticator_key_agreement_public_key = { + 1: 2, + 3: -25, + -1: 1, + -2: h'a30522c2de402b561965c3cf949a1cab020c6f6ea36fcf7e911ac1a0f1515300', + -3: h'9961a929abdb2f42e6566771887d41484d889e735e3248518a53112d2b915f00', + } + authenticator_cred_random = h'437e065e723a98b2f08f39d8baf7c53ecb3c363c5e5104bdaaf5d5ca2e028154' + + + The {{AuthenticationExtensionsPRFValues/first}} and {{AuthenticationExtensionsPRFValues/second}} inputs + are mapped in the examples as `prf_eval_first` and `prf_eval_second`, respectively. + The `prf_results_first` and `prf_results_second` values in the examples + are mapped to the + {{AuthenticationExtensionsPRFOutputs/results}}.{{AuthenticationExtensionsPRFValues/first}} + and {{AuthenticationExtensionsPRFOutputs/results}}.{{AuthenticationExtensionsPRFValues/second}} + outputs, respectively. + +- Single input case using PIN protocol 2: + + + ; Inputs from Relying Party: + prf_eval_first = h'576562417574686e20505246207465737420766563746f727302' + + ; Client computes: + shared_secret = h'0c63083de8170101d38bcf8bd72309568ddb4550867e23404b35d85712f7c20d8bc911ee23c06034cbc14290b9669bec07739053c5a416e313ef905c79955876' + salt1 = h'527413ebb48293772df30f031c5ac4650c7de14bf9498671ae163447b6a772b3' + salt_enc = h'437e065e723a98b2f08f39d8baf7c53ebbb2ed3e746b87576fd81f95def5757cad24be18eaef892e97692e684e07da53' + + ; Authenticator computes: + output1 = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' + output_enc = h'3bfaa48f7952330d63e35ff8cd5bca48d2a12823828915749287256ab146272f9fb437bf65691243c3f504bd7ea6d5e6' + + ; Client decrypts: + prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' + + +- Two input case using PIN protocol 2: + + + ; Inputs from Relying Party: + prf_eval_first = h'576562417574686e20505246207465737420766563746f727302' + prf_eval_second = h'576562417574686e20505246207465737420766563746f727303' + + ; Client computes: + shared_secret = h'0c63083de8170101d38bcf8bd72309568ddb4550867e23404b35d85712f7c20d8bc911ee23c06034cbc14290b9669bec07739053c5a416e313ef905c79955876' + salt1 = h'527413ebb48293772df30f031c5ac4650c7de14bf9498671ae163447b6a772b3' + salt2 = h'd68ac03329a10ee5e0ec834492bb9a96a0e547baf563bf78ccbe8789b22e776b' + salt_enc = h'23dde5e3462daf36559b85c4ac5f9656aa9bfd81c1dc2bf8533c8b9f3882854786b4f500e25b4e3d81f7fc7c742362294d92926c883b3fae1a3673246464bf730446e1fa4698c432a9092477c5dde5e3' + + ; Authenticator computes: + output1 = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' + output2 = h'a62a8773b19cda90d7ed4ef72a80a804320dbd3997e2f663805ad1fd3293d50b' + output_enc = h'90ee52f739043bc17b3488a74306d7801debb5b61f18662c648a25b5b5678ede482cdaff99a537a44f064fcb10ce6e04dfd27619dc96a0daff8507e499296b1eecf0981f7c8518b277a7a3018f5ec6fb' + + ; Client decrypts: + prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' + prf_results_second = h'a62a8773b19cda90d7ed4ef72a80a804320dbd3997e2f663805ad1fd3293d50b' + + +- Single input case using PIN protocol 1: + + + ; Inputs from Relying Party: + prf_eval_first = h'576562417574686e20505246207465737420766563746f727302' + + ; Client computes: + shared_secret = h'23e5ed7157c25892b77732fb9c8a107e3518800db2af4142f9f4adfacb771d39' + salt1 = h'527413ebb48293772df30f031c5ac4650c7de14bf9498671ae163447b6a772b3' + salt_enc = h'ab8c878bb05d04700f077ed91845ec9c503c925cb12b327ddbeb4243c397f913' + + ; Authenticator computes: + output1 = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' + output_enc = h'15d4e4f3f04109b492b575c1b38c28585b6719cf8d61304215108d939f37ccfb' + + ; Client decrypts: + prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae' + + +Inputs and pseudo-random values used in this section were generated as follows: + +- seed = UTF-8("WebAuthn PRF test vectors") +- prf_eval_first = seed || 0x02 +- prf_eval_second = seed || 0x03 +- platform_key_agreement_private_key = SHA-256(seed || 0x04) +- authenticator_key_agreement_public_key = P256-Public-Key(sk) + where sk = SHA-256(seed || 0x05) +- authenticator_cred_random = SHA-256(seed || 0x06) +- `iv` in single-input `salt_enc` with PIN protocol 2: Truncated SHA-256(seed || 0x07) +- `iv` in two-input `salt_enc` with PIN protocol 2: Truncated SHA-256(seed || 0x08) +- `iv` in single-input `output_enc` with PIN protocol 2: Truncated SHA-256(seed || 0x09) +- `iv` in two-input `output_enc` with PIN protocol 2: Truncated SHA-256(seed || 0x0a) + + ### Large blob storage extension (largeBlob) ### {#sctn-large-blob-extension} This [=client extension|client=] [=registration extension=] and [=authentication extension=] allows a [=[RP]=] to store opaque data associated with a credential. Since [=authenticators=] can only store small amounts of data, and most [=[RPS]=] are online services that can store arbitrary amounts of state for a user, this is only useful in specific cases. For example, the [=[RP]=] might wish to issue certificates rather than run a centralised authentication service.