fix(passkey-crypto): use base64url everywhere for the PRF salt#8715
Open
fix(passkey-crypto): use base64url everywhere for the PRF salt#8715
Conversation
The attach and derive flows were feeding different bytes to the WebAuthn
PRF extension for the same passkey, so the password derived at attach
time could not decrypt the keychain blob written with that same password
(ccm tag mismatch on every transaction approval).
Three encoding inconsistencies caused this:
- deriveEnterpriseSalt returned hex while the server stores base64url
and the WebAuthn extension expects raw bytes — every consumer had to
re-encode, and one of them did it wrong.
- attachPasskeyToWallet ran the hex output back through a
hex-to-base64url conversion before handing it to provider.get, so
the browser PRF saw the hex characters interpreted as base64 garbage.
- prfHelpers.buildEvalByCredential tried to convert the stored
base64url salt to hex via Buffer.from(...).toString('hex'), which is
a no-op under the browser Buffer polyfill and a real conversion in
Node — same code, different bytes.
Standardise on base64url end-to-end: deriveEnterpriseSalt emits
base64url, attachPasskeyToWallet passes that string straight through
to the PRF eval, and prfHelpers reads device.prfSalt unchanged. The
WebAuthn provider layer is the single point that decodes base64url to
bytes for navigator.credentials.get.
Refs: WCN-410
TICKET: WCN-410
mohammadalfaiyazbitgo
requested changes
May 8, 2026
Replace the duplicated `.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')` pattern (and its inverse) with a small `base64url` utility module shared by deriveEnterpriseSalt, prfHelpers, registerPasskey, and attachPasskeyToWallet. Addresses PR review feedback to deduplicate the encoding logic. TICKET: WCN-410
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The attach and derive flows were feeding different bytes to the WebAuthn PRF extension for the same passkey, so the password derived at attach time could not decrypt the keychain blob written with that same password (ccm tag mismatch on every transaction approval).
Three encoding inconsistencies caused this:
Standardise on base64url end-to-end: deriveEnterpriseSalt emits base64url, attachPasskeyToWallet passes that string straight through to the PRF eval, and prfHelpers reads device.prfSalt unchanged. The WebAuthn provider layer is the single point that decodes base64url to bytes for navigator.credentials.get.
Refs: WCN-410
TICKET: WCN-410