Skip to content

test(passkey): add PRF output support to the virtual authenticator - #21115

Draft
vpomerleau wants to merge 3 commits into
mainfrom
FXA-14268
Draft

test(passkey): add PRF output support to the virtual authenticator#21115
vpomerleau wants to merge 3 commits into
mainfrom
FXA-14268

Conversation

@vpomerleau

Copy link
Copy Markdown
Contributor

Because

  • Nothing in the test stack could produce a PRF output, so the kB wrap work in this epic could not be tested above the unit layer.
  • Two consumers were blocked on it: auth-server integration tests, and functional tests whose polyfill delegates its crypto to this authenticator.

This pull request

  • Derives a deterministic per-credential, per-UV-state PRF output, hashing the salt under the WebAuthn PRF prefix.
  • Reports prf.enabled at registration only; registration-time outputs sit behind an opt-in.
  • Sets the ED flag over a signed hmac-secret extension at registration.
  • Models an authenticator with no PRF support via prfSupported: false.
  • Surfaces the output to page code through the Playwright polyfill as an ArrayBuffer, with stack-free contract tests under tests/unit.
  • Retires the adapter spec's hand-patched prf.enabled in favour of the real path.
  • Moves the virtual authenticator behind a new @fxa/accounts/passkey/testing entry point.

Issue that this pull request solves

Closes: FXA-14268

Checklist

Put an x in the boxes that apply

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).
  • I have manually reviewed all AI generated code.

How to review (Optional)

  • Key files/areas to focus on: libs/accounts/passkey/src/lib/virtual-authenticator.ts
  • Suggested review order: 8bd97ed3cf (entry point) → authenticator → polyfill
  • Risky or complex parts: all test-only; derivePrfOutput is deterministic by construction and is not a real KDF

Screenshots (Optional)

Please attach the screenshots of the changes made in case of change in user interface.

Other information (Optional)

Any other information that is important to this pull request.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds deterministic PRF support to the test-only virtual authenticator and exposes it through functional-test browser polyfills.

Changes:

  • Models supported, unsupported, registration, and assertion PRF behavior.
  • Adds Playwright and unit coverage for PRF outputs.
  • Moves authenticator helpers to a testing entry point.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tsconfig.base.json Maps the testing entry point.
packages/fxa-auth-server/test/remote/passkeys.in.spec.ts Uses the testing import.
packages/fxa-auth-server/jest.config.js Resolves the testing entry point.
packages/functional-tests/tests/unit/passkeyPolyfillPrf.spec.ts Tests browser-side PRF behavior.
packages/functional-tests/package.json Declares the passkey dependency.
packages/functional-tests/lib/passkeyPolyfill.ts Bridges PRF data across browser and Node contexts.
libs/accounts/passkey/src/testing.ts Exports test-only authenticator helpers.
libs/accounts/passkey/src/lib/webauthn-adapter.spec.ts Uses real PRF capability output.
libs/accounts/passkey/src/lib/virtual-authenticator.ts Implements deterministic PRF modeling.
libs/accounts/passkey/src/lib/virtual-authenticator.spec.ts Covers authenticator PRF behavior.
libs/accounts/passkey/src/index.ts Removes test helpers from production exports.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +349 to +351
// PRF rides the CTAP `hmac-secret` authenticator extension, reported in
// authData under the ED flag and so covered by the signature, unlike the
// client extension results. Registration only: at assertion a real device
Comment on lines +10 to +12
derivePrfOutput,
VirtualAuthenticator,
type VirtualCeremonyExtensions,
Because:
- The virtual authenticator is test-only, but the package barrel exported it,
  so anything importing @fxa/accounts/passkey could reach it.
- The PRF work adds derivePrfOutput, which looks like a key-derivation function
  and should not sit one autocomplete away from production passkey code.

This commit:
- Adds a `@fxa/accounts/passkey/testing` entry point holding the fake.
- Drops the virtual authenticator from the package barrel.
- Excludes the fake from the lib build; every consumer resolves to source.
- Repoints the auth-server remote spec at the new entry point.
- Maps the subpath ahead of the greedy accounts pattern in auth-server's jest
  config, which would otherwise resolve it under `passkey/testing/src`.
Because:
- Nothing in the test stack could produce a PRF output, so the kB wrap work
  could not be tested above the unit layer.
- The adapter spec hand-patched clientExtensionResults to route around the gap,
  leaving the fake's PRF path with no coverage at all.

This commit:
- Derives a deterministic per-credential output, hashing the salt under the
  `WebAuthn PRF` prefix as a real client does.
- Reports `prf.enabled` at registration only; outputs sit behind an opt-in,
  since a CTAP2 device yields secrets at assertion.
- Sets the ED flag over a signed `hmac-secret` extension at registration.
- Models an authenticator with no PRF support via `prfSupported: false`.
- Pins both domain-separation steps and their composition, and retires the
  adapter spec's hand-patch in favour of the real path.
Because:
- The browser shim dropped `extensions`, so no eval salt ever reached the
  virtual authenticator and no output reached page code.
- Page code needs the output as an ArrayBuffer, as a real browser returns it —
  binary outputs are what keep kB out of the request body.

This commit:
- Forwards PRF eval salts to Node and decodes outputs to ArrayBuffers.
- Fixes DataView option values silently converting to empty bytes.
- Adds two tests covering the browser shim seam, the one part of the polyfill
  no unit test can reach.
- Declares the Nx dependency on `accounts-passkey`.

Closes #FXA-14268
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants