Skip to content

Add hmac-secret-mc CTAP 2.2 extension for PRF at MakeCredential time#167

Draft
Copilot wants to merge 5 commits intomasterfrom
copilot/add-hmac-secret-mc-support
Draft

Add hmac-secret-mc CTAP 2.2 extension for PRF at MakeCredential time#167
Copilot wants to merge 5 commits intomasterfrom
copilot/add-hmac-secret-mc-support

Conversation

Copy link

Copilot AI commented Feb 17, 2026

Adds support for the hmac-secret-mc CTAP 2.2 extension, enabling PRF evaluation during credential registration rather than requiring a subsequent GetAssertion roundtrip.

Shared PRF→HMAC logic

  • Extracted prf_value_to_hmac_input() and CalculatedHMACGetSecretInput into a dedicated proto::extensions::prf module, shared between GetAssertion (hmac-secret) and MakeCredential (hmac-secret-mc)
  • Added Deserialize to PRFValue with proper default serde attributes for JSON/CBOR deserialization support

CTAP request layer

  • Added hmac-secret-mc field (Option<CalculatedHMACGetSecretInput>) to Ctap2MakeCredentialsRequestExtensions, reusing the same wire format as hmac-secret in GetAssertion
  • Added calculate_hmac_secret_mc() — mirrors calculate_hmac() from GetAssertion: encrypts PRF-derived salts with the ECDH shared secret
  • MC follows the same internal pattern as GA: prf_input stored internally (#[serde(skip)]), calculated after user verification using the shared prf_value_to_hmac_input()

Shared secret negotiation

CTAP response layer

  • Added hmac-secret-mc field (Option<Ctap2HMACGetSecretOutput>) to Ctap2MakeCredentialsResponseExtensions
  • Response decryption reuses existing decrypt_output() infrastructure

WebAuthn-level types

  • MakeCredentialPrfInput: uses eval: Option<PRFValue> with proper serde support for both JSON and binary deserialization
  • MakeCredentialPrfOutput: added results: Option<PRFValue> to carry decrypted PRF output

Orchestration

  • _webauthn_make_credential_fido2 now calls calculate_hmac_secret_mc() after user verification and passes auth_data through to response processing for decryption

Usage

let extensions = MakeCredentialsRequestExtensions {
    prf: Some(MakeCredentialPrfInput {
        eval: Some(PRFValue { first: [1u8; 32], second: None }),
    }),
    ..Default::default()
};
// Response will include prf.results if authenticator supports hmac-secret-mc
Original prompt

This section details on the original issue you should resolve

<issue_title>Extensions: hmac-secret-mc</issue_title>
<issue_description>* Add support for hmac-secret-mc (spec link) CTAP extension

  • Support PRF at MakeCredential time, backed by said extension

Note: See @msirringhaus's comment on updating needs_shared_secret for MC: #146 (comment)</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@kalvdans
Copy link
Contributor

Don't create a PR until you have some changes to show.

Co-authored-by: AlfioEmanueleFresta <621062+AlfioEmanueleFresta@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for hmac-secret-mc CTAP extension Add hmac-secret-mc CTAP 2.2 extension for PRF at MakeCredential time Feb 17, 2026
Copy link
Member

@AlfioEmanueleFresta AlfioEmanueleFresta left a comment

Choose a reason for hiding this comment

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

Please address the comments. You now have access to fetch the FIDO specs, so you can try those requests again.

});
}

fn prf_eval_to_hmac_input(

Choose a reason for hiding this comment

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

You should reuse the existing HMAC <-> PRF logic (eg. Ctap2GetAssertionRequestExtensions.prf_to_hmac_input), refactoring it so it can be shared across MC and GA.

Copy link
Author

Choose a reason for hiding this comment

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

Extracted prf_value_to_hmac_input as a shared pub(crate) function in get_assertion.rs that both GA's prf_to_hmac_input and MC's from_webauthn_request now call. Removed the duplicate prf_eval_to_hmac_input from MC. See commit 2ea1691.

/// With hmac-secret-mc (CTAP 2.2), PRF evaluation can occur at registration time.
/// We still accept the raw JSON value for backward compatibility.
#[serde(rename = "eval")]
pub _eval: Option<JsonValue>,

Choose a reason for hiding this comment

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

You do not need to keep the old _eval value. You can break compatibility with old libwebauthn versions.

Copy link
Author

Choose a reason for hiding this comment

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

Removed _eval: Option<JsonValue> entirely. MakeCredentialPrfInput now has just eval: Option<PRFValue> with proper Deserialize support. Added Deserialize to PRFValue so it works for both JSON and binary deserialization paths. See commit 2ea1691.

Copilot AI and others added 2 commits February 18, 2026 09:31
…akeCredentialPrfInput

Co-authored-by: AlfioEmanueleFresta <621062+AlfioEmanueleFresta@users.noreply.github.com>
Co-authored-by: AlfioEmanueleFresta <621062+AlfioEmanueleFresta@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 18, 2026

Please address the comments. You now have access to fetch the FIDO specs, so you can try those requests again.

All three review comments addressed in commits 2ea1691 and 1d0e025:

  1. Shared prf_value_to_hmac_input function for GA and MC
  2. Consistent MC implementation following GA patterns
  3. Removed _eval, using typed eval: Option<PRFValue> with proper serde support

All 112 tests pass.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • fidoalliance.org
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

/// https://w3c.github.io/webauthn/#prf
///
/// Shared between GetAssertion (hmac-secret) and MakeCredential (hmac-secret-mc).
pub(crate) fn prf_value_to_hmac_input(ev: &PRFValue) -> HMACGetSecretInput {

Choose a reason for hiding this comment

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

Can you move this to its own module, as it's not get_assertion specific. proto::extensions::prf, maybe.

Copy link
Author

Choose a reason for hiding this comment

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

Moved prf_value_to_hmac_input and CalculatedHMACGetSecretInput to proto::extensions::prf module. Both get_assertion.rs and make_credential.rs now import from crate::proto::extensions::prf. See commit 8395abe.

@@ -100,7 +100,7 @@ async fn run_test_battery(channel: &mut HidChannel<'_>, using_pin: bool) {
let challenge: [u8; 32] = thread_rng().gen();

let extensions = MakeCredentialsRequestExtensions {

Choose a reason for hiding this comment

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

Modify this test to actually include PRF evaluation.

Copy link
Author

Choose a reason for hiding this comment

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

Updated the test to include PRF eval values (first: [1; 32]) in the MakeCredentialPrfInput. The virtual authenticator doesn't support hmac-secret-mc, so the result is still None, but the eval input is now exercised through the code path. See commit 8395abe.

pub eval: Option<super::PRFValue>,
}

impl MakeCredentialPrfInput {

Choose a reason for hiding this comment

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

Constructor seems unnecessary.

Copy link
Author

Choose a reason for hiding this comment

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

Removed the constructor. See commit 8395abe.

…, remove constructor

Co-authored-by: AlfioEmanueleFresta <621062+AlfioEmanueleFresta@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 18, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

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.

Extensions: hmac-secret-mc

3 participants

Comments