Skip to content

Commit

Permalink
Merge pull request #2174 from w3c/issue-2088-prf-test-vectors
Browse files Browse the repository at this point in the history
Add test vectors for PRF extension
  • Loading branch information
nicksteele authored Oct 9, 2024
2 parents cfa7333 + a231517 commit d920442
Showing 1 changed file with 212 additions and 0 deletions.
212 changes: 212 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -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}}.
</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=]:

<xmp 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: {} }
</xmp>

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

<xmp 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 } } }
</xmp>

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

<xmp 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 } } }
</xmp>

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

<xmp 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([0x982e17c4, 0xc397902e, 0xb70c6c9a, 0x5b37cb20, 0xadfce392, 0xe4634a15, 0x09f1933a, 0x73191e6b]),
}
}
}
</xmp>

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&apos;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:

<xmp class="example" highlight="cddl">
; 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'
</xmp>

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:

<xmp class="example" highlight="cddl">
; 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'
</xmp>

- Two input case using PIN protocol 2:

<xmp class="example" highlight="cddl">
; 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'
</xmp>

- Single input case using PIN protocol 1:

<xmp class="example" highlight="cddl">
; 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'
</xmp>

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 || 0x0a)</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

0 comments on commit d920442

Please sign in to comment.