Skip to content

Commit f2fe03d

Browse files
docs: hmac-secret-mc extension (#350)
* updated titles * reorganized doc, added new section headers * hmac-secret vs hmac-secret-mc * updated hmac-secret section * hmac-secret-mc info * updated extraction section * overview and salt info * updated release note * updated hmac-secret sample code * hmac-secret-mc sample code * docs(fido): show proper extension support checking --------- Co-authored-by: Dennis Dyallo <dennisdyallo@gmail.com>
1 parent 9ccc79b commit f2fe03d

File tree

3 files changed

+114
-71
lines changed

3 files changed

+114
-71
lines changed

docs/users-manual/application-fido2/hmac-secret.md

Lines changed: 112 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
uid: Fido2HmacSecret
33
---
44

5-
<!-- Copyright 2023 Yubico AB
5+
<!-- Copyright 2025 Yubico AB
66
77
Licensed under the Apache License, Version 2.0 (the "License");
88
you may not use this file except in compliance with the License.
@@ -16,112 +16,155 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1616
See the License for the specific language governing permissions and
1717
limitations under the License. -->
1818

19-
# FIDO2 HMAC secret ("hmac-secret" extension)
19+
# FIDO2 hmac-secret and hmac-secret-mc extensions
2020

21-
When you get the [AuthenticatorInfo](xref:Yubico.YubiKey.Fido2.AuthenticatorInfo), you can
22-
check the extensions to see if "hmac-secret" is supported.
21+
The SDK and YubiKey (depending on firmware version) support the hmac-secret and hmac-secret-mc extensions, which enable the creation of a symmetric secret value scoped to a credential. This secret, which can be used for encryption and decryption, supports the use of WedAuthn's [Pseudo-Random Function (PRF)](https://developers.yubico.com/WebAuthn/Concepts/PRF_Extension/index.html) with YubiKeys.
22+
23+
When requested, the YubiKey generates the hmac secret by performing HMAC with SHA-256 using
24+
the secret value it has associated with the credential as the key plus one or two salts provided
25+
by the client. It then encrypts the result (returned as a byte array) using the ECDH-derived shared secret key (the key used to encrypt all communications between the client and the YubiKey). The hmac secret can only be requested during ``MakeCredential()`` (hmac-secret-mc) or ``GetAssertions()`` (hmac-secret).
26+
27+
hmac-secret and hmac-secret-mc are supported for both discoverable and non-discoverable credentials.
28+
29+
## Salts
30+
31+
The client must provide one or two 32-byte salts to the YubiKey when requesting the secret. If one salt is provided, the YubiKey will return a secret value of 32 bytes in length; if two salts are provided, the YubiKey will return two secret values, each 32 bytes in length.
32+
33+
According to the [CTAP standard](https://fidoalliance.org/specs/fido-v2.2-ps-20250714/fido-client-to-authenticator-protocol-v2.2-ps-20250714.html#sctn-hmac-secret-extension), the second secret value returned in the two-salt scenario "can be used when the platform wants to roll over the symmetric secret in one operation."
34+
35+
## hmac-secret vs hmac-secret-mc
36+
37+
The fundamental difference between the hmac-secret and hmac-secret-mc extensions is when the secret is returned by the YubiKey.
38+
39+
With hmac-secret, the secret is returned during ``GetAssertions()``. However, with hmac-secret-mc, the secret is returned during ``MakeCredential()``.
40+
41+
hmac-secret-mc is useful in situations where the secret is needed immediately upon creation of a new credential. By returning the secret in a single operation instead of two (``MakeCredential()`` followed by ``GetAssertions()``), the amount of user interaction required, including user presence and PIN/UV validation, is reduced.
42+
43+
## Verify support for hmac-secret and hmac-secret-mc
44+
45+
The hmac-secret-mc extension is only supported for YubiKeys with firmware version 5.8 and later. To verify whether a particular YubiKey supports the hmac-secret and hmac-secret-mc extensions, check the key's [AuthenticatorInfo](xref:Yubico.YubiKey.Fido2.AuthenticatorInfo):
2346

2447
```C#
25-
using (fido2Session = new Fido2Session(yubiKeyDevice))
48+
using (fido2Session = new Fido2Session(yubiKey))
2649
{
27-
if (fido2Session.AuthenticatorInfo.Extensions.Contains<string>("hmac-secret"))
50+
if (fido2Session.AuthenticatorInfo.IsExtensionSupported(Extensions.HmacSecret))
51+
{
52+
. . .
53+
}
54+
else if (fido2Session.AuthenticatorInfo.IsExtensionSupported(Extensions.HmacSecretMc))
2855
{
2956
. . .
3057
}
3158
}
3259
```
3360

34-
If it is, when making a credential you can specify that the YubiKey create a secret value
35-
associated with that credential. Later on when getting an assertion, you can ask the
36-
YubiKey to retrieve that secret. What you do with that secret is up to you. The standard
37-
remarks that it can be used to encrypt or decrypt data.
61+
## Enabling the hmac-secret extension and requesting the secret
3862

39-
Each client will have access to this secret value, so that it is possible to securely
40-
share information among clients. The secret value is actually built from a value on the
41-
YubiKey and a salt provided by the client. The standard says, "The authenticator and the
42-
platform each only have the part of the complete secret to prevent offline attacks."
43-
Hence, for all clients to share this secret, each client must use the same salt.
63+
With hmac-secret, the extension needs to be enabled for a credential during ``MakeCredential()`` in order to return the secret during ``GetAssertions()``. It is not possible to add the extension to an existing credential.
4464

45-
## Requesting the YubiKey create this secret
46-
47-
The YubiKey will generate a secret for a credential only if instructed to do so at the
48-
time the credential is made. It is not possible to "add" this secret to an existing
49-
credential.
65+
To enable the hmac-secret extension, we must add it to the parameters for MakeCredential prior to calling the ``MakeCredential()`` method:
5066

5167
```csharp
52-
using (fido2Session = new Fido2Session(yubiKeyDevice))
68+
using (fido2Session = new Fido2Session(yubiKey))
5369
{
54-
var makeCredentialParameters = new MakeCredentialParameters(rp, userEntity);
55-
makeCredentialParameters.AddHmacSecretExtension(fido2Session.AuthenticatorInfo);
56-
. . .
57-
MakeCredentialData credentialData = fido2Session.MakeCredential(makeCredentialParameters);
70+
// Your app's key collector, which will be used to check user presence and perform PIN/UV
71+
// verification during MakeCredential().
72+
fido2Session.KeyCollector = SomeKeyCollectorDelegate;
73+
74+
// Create the parameters for MakeCredential (relyingParty, userEntity, and clientDataHashValue
75+
// set elsewhere).
76+
var makeCredentialParameters = new MakeCredentialParameters(relyingParty, userEntity)
77+
{
78+
ClientDataHash = clientDataHashValue
79+
80+
};
81+
82+
// Add the hmac-secret extension plus the "rk" option (to make the credential discoverable).
83+
makeCredentialParameters.AddHmacSecretExtension(fido2Session.AuthenticatorInfo);
84+
makeCredentialParameters.AddOption(AuthenticatorOptions.rk, true);
85+
86+
// Create the hmac-secret enabled credential.
87+
MakeCredentialData credentialData = fido2Session.MakeCredential(makeCredentialParameters);
5888
}
5989
```
6090

61-
## Requesting the secret
62-
63-
When getting an assertion, you specify you want the YubiKey to return the assertion and
64-
the secret value. If you don't, the YubiKey will return the assertion, but it won't return
65-
the secret.
91+
Once the extension has been added to a credential, we can return the secret with ``GetAssertions()``. However, we must first add the request for the secret along with the salt(s) to the parameters for GetAssertion via ``RequestHmacSecretExtension(salt1, salt2)``. Providing a second salt is not required.
6692

6793
```csharp
6894
using (fido2Session = new Fido2Session(yubiKeyDevice))
6995
{
70-
var getAssertionParameters = new GetAssertionParameters(rp, clientDataHash);
71-
getAssertionParameters.RequestHmacSecretExtension(salt);
72-
. . .
73-
IReadOnlyList<GetAssertionData> assertionDataList = fido2Session.GetAssertions(makeCredentialParameters);
96+
// Your app's key collector, which will be used to check user presence and perform PIN/UV
97+
// verification during GetAssertions().
98+
fido2Session.KeyCollector = SomeKeyCollectorDelegate;
99+
100+
// Create the parameters for GetAssertion (relyingParty and clientDataHash set elsewhere)
101+
var getAssertionParameters = new GetAssertionParameters(relyingParty, clientDataHashCreate);
102+
103+
// Add the request for the hmac secret and provide a salt (set elsewhere).
104+
getAssertionParameters.RequestHmacSecretExtension(salt1);
105+
106+
// Get the assertion and hmac secret using the parameters set above.
107+
IReadOnlyList<GetAssertionData> assertionDataList = fido2Session.GetAssertions(getAssertionParameters);
74108
}
75109
```
76110

77-
## Extracting the secret
111+
The secret will be returned in the ``GetAssertionData``.
112+
113+
## Enabling the hmac-secret-mc extension and requesting the secret
78114

79-
Once you have an assertion, you will find the secret in the `Extensions` in the
80-
`GetAssertionData.AuthenticatorData` property. There is a method in that class that will
81-
parse and decrypt the value returned.
115+
With hmac-secret-mc, the extension needs to be enabled for a credential during ``MakeCredential()`` *and* the salt(s) must be provided in order to return the secret. To do so, we must add the extension and salt(s) to the parameters for MakeCredential prior to calling the ``MakeCredential()`` method.
116+
117+
If the operation is successful, the secret will be returned in the ``MakeCredentialData``.
82118

83119
```csharp
84-
using (fido2Session = new Fido2Session(yubiKeyDevice))
120+
using (fido2Session = new Fido2Session(yubiKey))
85121
{
86-
. . .
87-
byte[] hmacSecretValue = assertionDataList[0].AuthenticatorData.GetHmacSecretExtension(
88-
fido2Session.AuthProtocol);
89-
}
90-
```
122+
// Your app's key collector, which will be used to check user presence and perform PIN/UV
123+
// verification during MakeCredential().
124+
fido2Session.KeyCollector = SomeKeyCollectorDelegate;
91125

92-
The result will be an array 32 bytes long.
126+
// Create the parameters for MakeCredential (relyingParty, userEntity, and clientDataHashValue
127+
// set elsewhere).
128+
var makeCredentialParameters = new MakeCredentialParameters(relyingParty, userEntity)
129+
{
130+
ClientDataHash = clientDataHashValue
93131

94-
## Decrypting the value returned
132+
};
95133

96-
In order to generate the "hmac-secret", the YubiKey will perform HMAC with SHA-256 using
97-
the secret value it has associated with the credential as the key, and the salt provided
98-
(along with possibly other data) as the data to MAC. It will then encrypt that result
99-
using the shared key (the key shared between the client and the YubiKey, the result of the
100-
ECDH operation used to encrypt all communications between the client and the YubiKey).
134+
// Add the hmac-secret-mc extension with salts (set elsewhere) plus the "rk" option
135+
// (to make the credential discoverable).
136+
makeCredentialParameters.AddHmacSecretMcExtension(fido2Session.AuthenticatorInfo, salt1, salt2);
137+
makeCredentialParameters.AddOption(AuthenticatorOptions.rk, true);
101138

102-
The value returned by the YubiKey is 32 bytes. The
103-
`AuthenticatorData.GetHmacSecretExtension` method will decrypt that value and return the
104-
result.
139+
// Create the credential and return the hmac secret.
140+
MakeCredentialData credentialData = fido2Session.MakeCredential(makeCredentialParameters);
141+
}
142+
```
143+
144+
## Extracting and decrypting the secret
105145

106-
## Two salts
146+
Once the secret has been returned, we can extract and decrypt it using the ``AuthenticatorData.GetHmacSecretExtension()`` method.
107147

108-
It is possible to pass in two 32-byte salts to the
109-
`GetAssertionParameters.RequestHmacSecretExtension` method. In that case, the YubiKey will
110-
return two values. The standard says the second value is used "...when the platform wants
111-
to roll over the symmetric secret...".
148+
If the secret was generated using one salt, the result will be a 32-byte value. In the case of two salts, the result will be 64 bytes in length, with the first 32 bytes representing the value generated with `salt1` and the second 32 bytes representing the value generated with `salt2`.
149+
150+
To perform the extraction and decryption on ``GetAssertionData`` (hmac-secret), perform an operation like shown in the following code sample. Note that if authenticator data was returned for more that one credential, we must specify which credential's secret we'd like to extract.
112151

113152
```csharp
114-
using (fido2Session = new Fido2Session(yubiKeyDevice))
153+
using (fido2Session = new Fido2Session(yubiKey))
115154
{
116-
var getAssertionParameters = new GetAssertionParameters(rp, clientDataHash);
117-
getAssertionParameters.RequestHmacSecretExtension(salt1, salt2);
118-
. . .
119-
IReadOnlyList<GetAssertionData> assertionDataList = fido2Session.GetAssertions(makeCredentialParameters);
120-
. . .
121-
byte[] hmacSecretValue = assertionDataList[0].AuthenticatorData.GetHmacSecretExtension(
122-
fido2Session.AuthProtocol);
155+
. . .
156+
// If the YubiKey contains multiple credentials for the relyingParty, this returns the hmac secret
157+
// from the first credential's data.
158+
byte[] hmacSecretValue = assertionDataList[0].AuthenticatorData.GetHmacSecretExtension(fido2Session.AuthProtocol);
123159
}
124160
```
125161

126-
The result will be an array 64 bytes long. The first 32 bytes make up the result based on
127-
`salt1`, and the second 32 bytes make up the result based on `salt2`.
162+
For extraction and decryption on ``MakeCredentialData`` (hmac-secret-mc), we do not need to specify a particular credential given that only one was created at the time the secret was returned:
163+
164+
```csharp
165+
using (fido2Session = new Fido2Session(yubiKey))
166+
{
167+
. . .
168+
byte[] hmacSecretValue = credentialData.AuthenticatorData.GetHmacSecretExtension(fido2Session.AuthProtocol);
169+
}
170+
```

docs/users-manual/getting-started/whats-new.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Features:
6262

6363
- thirdPartyPayment extension: The [GetThirdPartyPaymentExtension](xref:Yubico.YubiKey.Fido2.AuthenticatorData.GetThirdPartyPaymentExtension) method has been added to check for and return the status of the thirdPartyPayment extension. The thirdPartyPayment extension enables YubiKeys to be used for cross-domain credentials without redirects, as required by Secure Payment Confirmation (SPC) workflows.
6464

65-
- hmac-secret-mc extension: [GetHmacSecretExtension](xref:Yubico.YubiKey.Fido2.AuthenticatorData.GetHmacSecretExtension%28Yubico.YubiKey.Fido2.PinProtocols.PinUvAuthProtocolBase%29) now handles both hmac-secret and hmac-secret-mc extensions when extracting and decrypting secrets. The hmac-secret-mc extension enables PRF (Pseudo-Random Function) during [MakeCredential()](xref:Yubico.YubiKey.Fido2.Fido2Session.MakeCredential%28Yubico.YubiKey.Fido2.MakeCredentialParameters%29).
65+
- [hmac-secret-mc extension](xref:Fido2HmacSecret): This extension enables the retrieval of a symmetric secret during ``MakeCredential()``. The secret, which can be used for encryption/decryption, supports the use of PRF (Pseudo-Random Function) with YubiKeys.
6666

6767
- Additional ``AuthenticatorInfo`` properties: The SDK now supports parsing of several new [AuthenticatorInfo](xref:Yubico.YubiKey.Fido2.AuthenticatorInfo) properties, which are returned when calling the [GetInfoCommand()](xref:Yubico.YubiKey.Fido2.Commands.GetInfoCommand). Properties include ``AttestationFormats``, ``UvCountSinceLastPinEntry``, ``LongTouchForReset``, ``EncIdentifier``, ``TransportsForReset``, ``PinComplexityPolicy``, ``PinComplexityPolicyUrl``, and ``MaxPinLength``.
6868

docs/users-manual/toc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@
337337
href: application-fido2/cred-blobs.md
338338
- name: Large blobs
339339
href: application-fido2/large-blobs.md
340-
- name: HMAC secret extension
340+
- name: HMAC secret extensions
341341
href: application-fido2/hmac-secret.md
342342
- name: Commands
343343
items:

0 commit comments

Comments
 (0)