Skip to content

Feature Request: Support pre-computed clientDataHash (parity with Android/iOS APIs) #124

@Zhao-code-ai

Description

@Zhao-code-ai

Summary

Add support for accepting a pre-computed clientDataHash (SHA-256) as an alternative to clientDataJSON in the D-Bus API. This aligns with Android and iOS platform APIs, and enables a wider range of WebAuthn integration scenarios.

Background

The CTAP2 specification defines that authenticator operations (authenticatorMakeCredential and authenticatorGetAssertion) accept a hash of the client data, not the raw JSON:

hash (0x01): Hash of the serialized client data, provided by the client.

Reference: FIDO CTAP2 Specification §6.1

While browser-based WebAuthn flows typically construct clientDataJSON locally, there are several scenarios where the caller may already have the hash:

  1. Cross-device authentication (CTAP2 Hybrid/caBLE) - The initiating device may provide the hash directly
  2. Native application integrations - Apps may negotiate client data with their backend
  3. Remote desktop/VDI scenarios - The remote server constructs clientData and transmits only the hash
  4. Proxy/relay architectures - Intermediate systems may only forward the hash

Prior Art - Platform API Parity

Both Android and iOS platform APIs support this pattern:

Android (Credential Manager API)

val request = GetPublicKeyCredentialOption(
    requestJson = "...",
    clientDataHash = clientDataHashBytes  // Optional pre-computed hash
)

Reference: Android Credential Manager Documentation

iOS (ASAuthorizationPublicKeyCredentialProvider)

let request = provider.createCredentialAssertionRequest(challenge: challenge)
request.clientDataHash = clientDataHash  // Supports pre-computed hash

Reference: Apple Developer Documentation

Adding this support to credentialsd would bring Linux to feature parity with these platforms.

Proposed API Change

Add an optional client_data_hash parameter to the D-Bus methods:

Option A: New optional parameter (backward compatible)

<method name="MakeCredential">
    <arg name="request_json" type="s" direction="in"/>
    <arg name="client_data_hash" type="ay" direction="in"/>  <!-- NEW: optional 32-byte SHA-256 -->
    <arg name="response" type="a{sv}" direction="out"/>
</method>

Behavior:

  • If client_data_hash is provided (non-empty), use it directly
  • If client_data_hash is empty, compute hash from request_json.clientDataJSON (current behavior)

Option B: Separate methods

<method name="MakeCredentialWithHash">
    <arg name="request_json" type="s" direction="in"/>
    <arg name="client_data_hash" type="ay" direction="in"/>
    <arg name="response" type="a{sv}" direction="out"/>
</method>

Use Case

This feature enables various integration scenarios where the caller has a pre-computed hash rather than raw JSON:

  • Cross-device flows where another device initiated the WebAuthn ceremony
  • Native applications with custom client data handling
  • Remote desktop environments where authentication is redirected to the local machine
  • Enterprise SSO integrations with proxy architectures

The key benefit is flexibility - allowing callers to provide either the raw JSON (current behavior) or a pre-computed hash when that's what they have available.

Security Considerations

This change maintains the same security model:

  • The authenticator still requires user interaction (touch/PIN)
  • The UI still displays the relying party information
  • The cryptographic signature is still bound to the hash

The only difference is who computes the hash - the caller vs the credential service.

Implementation Notes

Looking at libwebauthn, the underlying register() and sign() functions may already work with the hash internally. The change would primarily be in:

  1. D-Bus interface definition (xyz.iinuwa.credentials.xml)
  2. Request parsing in credentialsd
  3. Passing the hash through to libwebauthn

Related

Questions

  1. Would you prefer Option A (optional parameter) or Option B (new method)?
  2. Are there any security considerations I might have missed?
  3. Is this something you're planning to implement, or would you be open to accepting a community contribution? I'd be happy to work on a PR if that would be helpful.

Thank you for considering this feature request!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions