Skip to content
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

Add test vectors for PRF extension #2174

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 212 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -7504,6 +7504,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}}.
</div>


#### 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=]:

<pre class="example" highlight="js">
// 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: {} }
</pre>

- The {{AuthenticationExtensionsPRFOutputs/results}} output may be present
during [=registration ceremonies=] or [=authentication ceremonies=]
if the {{AuthenticationExtensionsPRFInputs/eval}} or {{AuthenticationExtensionsPRFInputs/evalByCredential}} input is present:

<pre class="example" highlight="js">
// 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 } } }
</pre>

- The <code>{{AuthenticationExtensionsPRFOutputs/results}}.{{AuthenticationExtensionsPRFValues/second}}</code> output
is present if and only if the {{AuthenticationExtensionsPRFOutputs/results}} output is present
and the <code>{{AuthenticationExtensionsPRFValues/second}}</code> input was present in the chosen PRF inputs:

<pre class="example" highlight="js">
// 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 } } }
</pre>

- 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:

<pre class="example" highlight="js">
// 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([0x98172ec4, 0xc390972e, 0xb76c0c9a, 0x5bcb3720, 0xade3fc92, 0xe44a6315, 0x0993f13a, 0x731e196b]),
}
}
}
</pre>

Pseudo-random values used in this section were generated as follows:

- <code>"e02eZ9lPp0UdkF4vGRO4-NxlhWBkL1FCmsmb1tTfRyE" = Base64Url(SHA-256(UTF-8("WebAuthn PRF test vectors") || 0x00))</code>
- <code>h'c4172e982e9097c39a6c0cb720cb375b92e3fcad154a63e43a93f1096b1e1973' = SHA-256(UTF-8("WebAuthn PRF test vectors") || 0x01)</code>


#### 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:

<pre class="example">
; 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'
</pre>

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
<code>{{AuthenticationExtensionsPRFOutputs/results}}.{{AuthenticationExtensionsPRFValues/first}}</code>
and <code>{{AuthenticationExtensionsPRFOutputs/results}}.{{AuthenticationExtensionsPRFValues/second}}</code>
outputs, respectively.

- Single input case using PIN protocol 2:

<pre class="example">
; 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'
</pre>

- Two input case using PIN protocol 2:

<pre class="example">
; 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'27cc2400050f7ef4d0d37a916518dd33acd741e3a70bb5a91921c8a80ac73d656536843f593b86771246daabf32e1527616955b4981f5e6d30c13329bf460bacd6b4049b8bbea823438078f6224c58a8'

; Client decrypts:
prf_results_first = h'3c33e07d202c3b029cc21f1722767021bf27d595933b3d2b6a1b9d5dddc77fae'
prf_results_second = h'a62a8773b19cda90d7ed4ef72a80a804320dbd3997e2f663805ad1fd3293d50b'
</pre>

- Single input case using PIN protocol 1:

<pre class="example">
; 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'
</pre>

Inputs and pseudo-random values used in this section were generated as follows:

- <code>seed = UTF-8("WebAuthn PRF test vectors")</code>
- <code>prf_eval_first = seed || 0x02</code>
- <code>prf_eval_second = seed || 0x03</code>
- <code>platform_key_agreement_private_key = SHA-256(seed || 0x04)</code>
- <code>authenticator_key_agreement_public_key = P256-Public-Key(sk)</code>
where <code>sk = SHA-256(seed || 0x05)</code>
- <code>authenticator_cred_random = SHA-256(seed || 0x06)</code>
- `iv` in single-input `salt_enc` with PIN protocol 2: Truncated <code>SHA-256(seed || 0x07)</code>
- `iv` in two-input `salt_enc` with PIN protocol 2: Truncated <code>SHA-256(seed || 0x08)</code>
- `iv` in single-input `output_enc` with PIN protocol 2: Truncated <code>SHA-256(seed || 0x09)</code>
- `iv` in two-input `output_enc` with PIN protocol 2: Truncated <code>SHA-256(seed || 0x10)</code>


### Large blob storage extension (<dfn>largeBlob</dfn>) ### {#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.
Expand Down