Table of Contents

Class GetAssertionParameters

Namespace
Yubico.YubiKey.Fido2
Assembly
Yubico.YubiKey.dll

This collects and encodes the information needed to get a FIDO2 assertion.

public class GetAssertionParameters
Inheritance
object
GetAssertionParameters

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 RelyingParty

The 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

PinUvAuthProtocol?

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

RelyingParty

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 string

The 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 or encodedValue 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 string

The option to add. This is the key of the option key/value pair.

optionValue bool

The 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 CredentialId

The 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 PinUvAuthProtocolBase

An instance of one of the subclasses of PinUvAuthProtocolBase, for which the Encapsulate 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, or salt2 is not null and is not exactly 32 bytes.