Class GetAssertionParameters
This collects and encodes the information needed to get a FIDO2 assertion.
public class GetAssertionParameters
- Inheritance
-
objectGetAssertionParameters
Remarks
There are seven elements that are inputs to a FIDO2 assertion (see section 6.2 of the FIDO2 standard). Two of them are required and five are optional.
When you need to get an assertion, you will collect all the required
along with any optional parameters and build an instance of this class.
Then pass that object to the GetAssertion
method or command.
Constructors
GetAssertionParameters(RelyingParty, ReadOnlyMemory<byte>)
Constructs a new instance of GetAssertionParameters.
public GetAssertionParameters(RelyingParty relyingParty, ReadOnlyMemory<byte> clientDataHash)
Parameters
relyingParty
RelyingPartyThe relying party for which the assertion is to be obtained. This constructor copies a reference to the input object. This constructor will copy a reference to the input.
clientDataHash
ReadOnlyMemory<byte>The client data hash for the current connection. This constructor will copy a reference to the input.
Remarks
Both the relying party and client data hash are required parameters. All others are optional.
Properties
AllowList
The list of credentialIds for which the authenticator must generate a new assertion. This is an optional parameter, so it can be null. This is generally used to specify a non-discoverable credential.
public IReadOnlyList<CredentialId>? AllowList { get; }
Property Value
- IReadOnlyList<CredentialId>
Remarks
To add an entry to the list, call AllowCredential(CredentialId).
ClientDataHash
The original clientDataHash
that was provided by the client.
It contains the challenge. This is a required element.
public ReadOnlyMemory<byte> ClientDataHash { get; set; }
Property Value
- ReadOnlyMemory<byte>
Extensions
The list of extensions. This is an optional parameter, so it can be null.
public IReadOnlyDictionary<string, byte[]>? Extensions { get; }
Property Value
- IReadOnlyDictionary<string, byte[]>
Remarks
To add an entry to the list, call AddExtension(string, byte[]).
Each extension is a key/value pair. All keys are strings, but each extension has its own definition of a value. It could be an int, or it could be a map containing a string and a boolean,. It is the caller's responsibility to encode the value.
For each value, the standard (or the vendor in the case of vendor-defined extensions) will define the structure of the value. From that structure the value can be encoded following CBOR rules. The result of the encoding the value is what is stored in this dictionary.
Options
The list of authenticator options. Each standard-defined option is a key/value pair, where the key is a string and the value is a boolean. This is an optional parameter, so it can be null.
public IReadOnlyDictionary<string, bool>? Options { get; }
Property Value
- IReadOnlyDictionary<string, bool>
Remarks
To add options, call AddOption(string, bool). The standard lists two option keys: "up" and "uv". Any other option on a YubiKey will yield an error. In addition, YubiKeys that are not BIO series will not allow "uv".
PinUvAuthParam
The result of calling the PinProtocol's method AuthenticateUsingPinToken(byte[], byte[]) using the PIN token as the key and the client data hash as the message. This is an optional parameter, so it can be null.
Note
If you get assertions by calling the > Fido2Session method GetAssertions(GetAssertionParameters), > you do not need to set this property, the SDK will do so. If you get an assertion using the commands, you must set this property.
public ReadOnlyMemory<byte>? PinUvAuthParam { get; set; }
Property Value
- ReadOnlyMemory<byte>?
Remarks
If you are getting assertions using GetAssertions(GetAssertionParameters), you do NOT need to set this property, the SDK will take care of it. But if you are getting assertions using the GetAssertionCommand, then you must set this property.
In order to obtain the pinUvAuthParam
, choose a protocol and
build the appropriate PinUvAuthProtocolBase object.
Obtain the YubiKey's Key Agreement public key and call the protocol
object's Encapsulate
method. Next obtain the PIN token.
Finally, call the protocol object's
AuthenticateUsingPinToken(byte[], byte[])
method using the
ClientDataHash
as the message to authenticate. Note that the
first argument in this call is the PIN token, which is an encrypted
value. Do not decrypt the PIN token. The result of that
authentication operation is the PinUvAuthParam
Protocol
The protocol chosen by the platform. This is an optional parameter, so it can be null.
public PinUvAuthProtocol? Protocol { get; set; }
Property Value
Remarks
If you are getting assertions using GetAssertions(GetAssertionParameters), you do NOT need to set this property, the SDK will take care of it. But if you are getting assertions using the GetAssertionCommand, then you must set this property.
RelyingParty
The relying party's ID, along with an optional descriptive string. This is a required element.
public RelyingParty RelyingParty { get; set; }
Property Value
Methods
AddExtension(string, byte[])
Add an entry to the extensions list. Once an entry is added to the list, it is not possible to remove it.
public void AddExtension(string extensionKey, byte[] encodedValue)
Parameters
extensionKey
stringThe key of key/value to add.
encodedValue
byte[]The CBOR-encoded value of key/value to add.
Remarks
If there is no list yet when this method is called, one will be created. That is, even if the Extensions is null, you can call the method to add an entry.
Each extension is a key/value pair. For each extension the key is a string (such as "credProtect" or "hmac-secret"). However, each value is different. There will be a definition of the value that accompanies each key. It will be possible to encode that definition using the rules of CBOR. The caller supplies the key and the encoded value.
Exceptions
- ArgumentNullException
The
extensionKey
orencodedValue
arg is null.
AddOption(string, bool)
Add an entry to the list of options. Once an entry is added to the list, it is not possible to remove it.
public void AddOption(string optionKey, bool optionValue)
Parameters
optionKey
stringThe option to add. This is the key of the option key/value pair.
optionValue
boolThe value this option will possess.
Remarks
If the Options
list already contains an entry with the given
optionKey
, this method will replace it.
The standard lists two option keys: "up" and "uv". Any other option on a YubiKey will yield an error. In addition, YubiKeys that are not BIO series will not allow "uv".
Exceptions
- ArgumentNullException
The
optionKey
arg is null.
AllowCredential(CredentialId)
Add an entry to the allow list. Once a credential is added to the allow list, it is not possible to remove it.
public void AllowCredential(CredentialId credentialId)
Parameters
credentialId
CredentialIdThe
credentialId
to add.
Remarks
If there is no list yet when this method is called, one will be created. That is, even if the AllowList is null, you can call the method to add an entry.
Exceptions
- ArgumentNullException
The
credentialId
arg is null.
CborEncode()
Return a new byte array that is the object encoded following the FIDO2/CBOR standard.
public byte[] CborEncode()
Returns
- byte[]
The encoded construct.
Exceptions
- InvalidOperationException
The object contains no data.
EncodeHmacSecretExtension(PinUvAuthProtocolBase)
Encode the "hmac-secret" extension. This call will be valid only if the RequestHmacSecretExtension(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>?) has been called, and the Encapsulate(CoseKey) method has been successfully called. The hmac-secret extension must be encoded before calling the GetAssertionCommand.
Note
If you use GetAssertions(GetAssertionParameters) to get any assertion, you do not need to call this method.
public void EncodeHmacSecretExtension(PinUvAuthProtocolBase authProtocol)
Parameters
authProtocol
PinUvAuthProtocolBaseAn instance of one of the subclasses of
PinUvAuthProtocolBase
, for which theEncapsulate
method has been called.
Remarks
If you want the hmac-secret extension value returned along with the
assertion, then call the RequestHmacSecretExtension
method
with a salt. If you will be using the GetAssertionCommand
to
get the assertion, then you must call this method to encode the
extension. The authProtocol
you supply must be an object for
which the
Encapsulate(CoseKey) method
has been called.
If the RequestHmacSecretExtension
method has not been called,
this method will do nothing. If it has been called, but the
authProtocol
has not been encapsulated, this method will throw
an exception.
The result of this method is stored inside this object. If there is already an encoded hmac-secret extension in the object, this method will build a new one and replace the old one. This might be necessary if a new authenticator public key is retrieved since the last time this method has been called.
See also the documentation for the RequestHmacSecretExtension(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>?) method, which also includes some code samples.
Exceptions
- ArgumentNullException
The
authProtocol
arg is null.- InvalidOperationException
The Encapsulate method for the
authProtocol
has not been called.
RequestCredBlobExtension()
Specify that the YubiKey should return the credBlob with the assertion. Once this extension is added to this object, it is not possible to remove it.
public void RequestCredBlobExtension()
Remarks
Because this extension is used more often, a dedicated method is provided as a convenience. Note that the credBlob extension is valid only for discoverable credentials.
If there is no credBlob stored with the credential, then the YubiKey will simply not return anything. It is not an error.
The credBlob data will be with the assertion returned. It will be in the AuthenticatorData and can be retrieved using GetCredBlobExtension()
Note that there will be a credBlob only if the credential was made with the "credBlob" extension. See AddCredBlobExtension(byte[], AuthenticatorInfo).
RequestHmacSecretExtension(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>?)
Specify that the YubiKey should return the "hmac-secret" with the assertion. Provide the salt (or salts) to use, which must be exactly 32 bytes long. Once this extension is added to this object, it is not possible to remove it, although it is possible to "change" the salt by calling this method again with a different salt.
public void RequestHmacSecretExtension(ReadOnlyMemory<byte> salt1, ReadOnlyMemory<byte>? salt2 = null)
Parameters
salt1
ReadOnlyMemory<byte>The salt the YubiKey will use in combination with the stored secret to build the resulting value.
salt2
ReadOnlyMemory<byte>?An optional second salt the YubiKey can use in combination with the stored secret to build a second value. If no arg is given, the default of null will be used (the YubiKey will not build a second result).
Remarks
Because this extension is used more often, a dedicated method is provided as a convenience. Note that the hmac-secret extension is valid for both discoverable and non-discoverable credentials.
Note that there will be an hmac-secret only if the credential was made with the "hmac-secret" extension. See AddHmacSecretExtension(AuthenticatorInfo). If the "hmac-secret" extension was not specified when making the credential, then the YubiKey will simply not return anything. It is not an error.
If you are getting assertions using GetAssertions(GetAssertionParameters), calling this method is sufficient, the SDK will take care of everything else needed to get the hmac-secret extension.
var gaParams = new GetAssertionParameters(relyingParty, clientDataHash);
gaParams.RequestHmacSecretExtension(salt);
IReadOnlyList<GetAssertionData> assertions = fido2.GetAssertions(gaParams);
But if you are getting assertions using the GetAssertionCommand, then you must call EncodeHmacSecretExtension(PinUvAuthProtocolBase) with an appropriate instance of PinUvAuthProtocolBase for which the Encapsulate(CoseKey) method has been successfully called. If the HmacSecret extension is not encoded, then it will not be sent to the YubiKey, and the value will not be returned.
var pinProtocol = new PinUvAuthProtocolTwo();
var keyAgreeCmd = new new GetKeyAgreementCommand(PinProtocol.Protocol);
GetKeyAgreementResponse keyAgreeRsp = Connection.SendCommand(keyAgreeCmd);
CoseEcPublicKey authenticatorPublicKey = keyAgreeRsp.GetData();
pinProtocol.Encapsulate(authenticatorPublicKey);
var getTokenCmd = new GetPinUvAuthTokenUsingPinCommand(
protocol, currentPin, PinUvAuthTokenPermissions.GetAssertion, null);
GetPinUvAuthTokenResponse getTokenRsp = Connection.SendCommand(getTokenCmd);
ReadOnlyMemory<byte> pinToken = getTokenRsp.GetData();
byte[] pinUvAuthParam = pinProtocol.AuthenticateUsingPinToken(
pinToken, clientDataHash);
var gaParams = new GetAssertionParameters(relyingParty, clientDataHash);
gaParams.Protocol = protocol.Protocol;
gaParams.PinUvAuthParam = pinUvAuthParam;
gaParams.AddOption("up", true);
gaParams.RequestHmacSecretExtension(salt);
gaParams.EncodeHmacSecretExtension(pinProtocol);
var cmd = new GetAssertionCommand(gaParams);
GetAssertionResponse rsp = connection.SendCommand(cmd);
GetAssertionData assertion = rsp.GetData();
The caller supplies a 32-byte salt which will be combined with the YubiKey's secret stored with the credential to produce the output. A second 32-byte salt is optional, but if provided, the YubiKey will build a second result. The standard indicates that the second secret is to be used when a secret rolls over.
The hmac-secret data will be returned with the assertion. The result is returned in the AuthenticatorData and can be retrieved using GetHmacSecretExtension(PinUvAuthProtocolBase)
References to the salt inputs will be stored in this object. If there is already salt data in the object, this method will replace the previous references with the new ones. It will also delete any encoding (see EncodeHmacSecretExtension(PinUvAuthProtocolBase)).
If an invalid salt is passed in, this method will throw an exception.
In the unlikely event that you are replacing a salt, and you catch
the exception and use the GetAssertionParameters
object
anyway, the previous salt which was being replaced will be removed as
well. If salt1
is invalid, both previous salts will be
removed. For example, if there is a valid "salt1" and "salt2" in the
object, and you call this method with a valid salt1 and an invalid
salt2, then the original salt1 would be replaced and the original
salt2 would be removed. If you catch the exception and get an
assertion with this parameter object, only one hmac-secret value
would be returned, one based on salt1
.
Exceptions
- ArgumentException
Either
salt1
is not exactly 32 bytes, orsalt2
is not null and is not exactly 32 bytes.