Class PivSession
Create a session and perform PIV operations within that session.
public sealed class PivSession : ApplicationSession
- Inheritance
-
objectPivSession
- Inherited Members
Remarks
When you need to perform PIV operations, instantiate this class to create a session, then call on the methods in the class.
Generally you will choose the YubiKey to use by building an instance of IYubiKeyDevice. This object will represent the actual hardware.
IYubiKeyDevice SelectYubiKey()
{
IEnumerable<IYubiKeyDevice> yubiKeyList = YubiKey.FindAll();
foreach (IYubiKeyDevice current in yubiKeyList)
{
/* determine which YubiKey to use */
if(selected)
{
return current;
}
}
}
Once you have the YubiKey to use, you will build an instance of this
PivSession
class to represent the PIV application on the hardware.
Because this class implements IDisposable
, use the using
keyword. For example,
IYubiKeyDevice yubiKeyToUse = SelectYubiKey();
using (var piv = new PivSession(yubiKeyToUse))
{
/* Perform PIV operations. */
}
If this class is used as part of a using
expression, when the
session goes out of scope, the Dispose
method will be called to
dispose the active PIV session, clearing any authenticated state, and
ultimately releasing the connection to the YubiKey.
Note that while a session is open, any management key authentication and PIN verification will be active. That is, you need to authenticate the management key or verify the PIN only once per session. Touch might be needed more than once.
There are some exceptions to the "verify the PIN once per session" rule. For example, to change a PIN, you need to enter the current and new PIN, even if the current PIN has been verified. The documentation for each method in this class will indicate if the PIN is needed, and if so, must it be verified or entered. See also the User's Manual entries on the PIV PIN, PUK, and Management Key and PIV commands access control.
Note that PIN/PUK/Management Key verification or authentication will
happen automatically when you call a method that needs it. You can
call the TryVerifyPin
or TryAuthenticateManagementKey
methods if you want, but any method that can be executed only if the PIN
and/or management key has been verified or authenticated will determine
if the appropriate values have been verified/authenticated, and if not,
will make the appropriate calls to do so. The caller must supply a
PIN/PUK/management key collector delegate (callback).
This class needs a delegate (callback): a method to enter the PIN, PUK, or management key. Although some operations will not need this delegate, any useful application will almost certainly call one or more methods that do need it. You will need to set the appropriate property after instantiating this class.
using (var pivSession = new PivSession(yubiKeyToUse))
{
KeyCollector = SomeCollectorDelegate;
};
You supply the delegate as the KeyCollector
property. See also the
User's Manual entry on
delegates in the SDK.
Note that the YubiKey is manufactured with default PIN, PUK, and management key values. This is a requirement of the PIV standard.
management key (hex): 01 02 03 04 05 06 07 08
01 02 03 04 05 06 07 08
01 02 03 04 05 06 07 08
<pre><code class="lang-csharp">PIN (hex): 31 32 33 34 35 36
as an ASCII string, this would be "123456"</code></pre>
<pre><code class="lang-csharp">PUK (hex): 31 32 33 34 35 36 37 38
as an ASCII string, this would be "12345678"</code></pre>
The PIN, PUK, and management key are supplied as byte arrays. The reason is that they can be binary data (they are not necessarily strings, ASCII or otherwise), and a byte array can be overwritten to limit the contents' exposure. See the User's Manual entries on sensitive data.
This class will also need a random number generator and Triple-DES and AES encryptors/decryptors. It will get them from CryptographyProviders. That class will return default implementations, unless you replace them. Very few applications will choose to replace the defaults, but if you want to, see the documentation for that class and the User's Manual entry on alternate crypto implementations to learn how to do so.
Constructors
PivSession(IYubiKeyDevice, ScpKeyParameters?)
Create an instance of PivSession
, the object that represents
the PIV application on the YubiKey. The communication between the SDK
and the YubiKey will be protected by SCP03.
public PivSession(IYubiKeyDevice yubiKey, ScpKeyParameters? keyParameters = null)
Parameters
yubiKey
IYubiKeyDeviceThe object that represents the actual YubiKey which will perform the operations.
keyParameters
ScpKeyParametersThe SCP key parameters, if any, to use in establishing the SCP connection.
Remarks
See the User's Manual entry on SCP03 for more information on this communication protocol.
Because this class implements IDisposable
, use the using
keyword. For example,
IYubiKeyDevice yubiKeyToUse = SelectYubiKey();
// Assume you have some method that obtains the appropriate SCP03
// key set.
using StaticKeys scp03Keys = CollectScp03Keys();
using (var piv = new PivSession(yubiKeyToUse, scp03Keys))
{
/* Perform PIV operations. */
}
Exceptions
- ArgumentNullException
The
yubiKey
argument is null.- InvalidOperationException
This exception is thrown when unable to determine the management key type.
Properties
KeyCollector
The Delegate this class will call when it needs a PIN, PUK, or management key.
public Func<KeyEntryData, bool>? KeyCollector { get; set; }
Property Value
- Func<KeyEntryData, bool>
Remarks
The delegate provided will read the KeyEntryData
which
contains the information needed to determine what to collect and
methods to submit what was collected. The delegate will return
true
for success or false
for "cancel". A cancel will
usually happen when the user has clicked a "Cancel" button. That is
often the case when the user has entered the wrong value a number of
times, the remaining tries count is getting low, and they would like
to stop trying before the YubiKey is blocked.
Note that the SDK will call the KeyCollector
with a
Request
of Release
when the process completes. In this
case, the KeyCollector
MUST NOT throw an exception. The
Release
is called from inside a finally
block, and it
is a bad idea to throw exceptions from inside finally
.
ManagementKeyAlgorithm
This specifies the algorithm of the management key.
public PivAlgorithm ManagementKeyAlgorithm { get; }
Property Value
ManagementKeyAuthenticated
This indicates whether the management key is authenticated or not.
public bool ManagementKeyAuthenticated { get; }
Property Value
- bool
Remarks
Upon instantiation of this class, this property will be set to
false
. If the management key is authenticated (either single
or mutual), it will be updated to true
. To see the result of a
management key authentication process, see the property
ManagementKeyAuthenticationResult
.
ManagementKeyAuthenticationResult
This reports the result of the latest management key authentication attempt.
public AuthenticateManagementKeyResult ManagementKeyAuthenticationResult { get; }
Property Value
Remarks
Upon instantiation of this class, this property will be set to
AuthenticateManagementKeyResult.Unauthenticated
. After
authentication is attempted, this will be updated to the result.
The ManagementKeyAuthenticated
property reports on whether the
management key is authenticated or not, this reports on the result of
an authentication.
For example, if the management key is authenticated, this will be
either SingleAuthenticated
or MutualFullyAuthenticated
.
If it is "single" and you want "Mutual", you know to run the
TryAuthenticateManagementKey
method again, this time
specifying mutual auth.
Another example would be if ManagementKeyAuthenticated
is
false
, you can check to see if this property is
Unauthenticated
(never attempted), or maybe it is
MutualYubiKeyAuthenticationFailed
which indicates you might be
connected to a counterfeit YubiKey.
PinVerified
This indicates the current state of the PIN verification.
public bool PinVerified { get; }
Property Value
- bool
Remarks
Upon instantiation of this class, this property will be set to
false
. If the PIN is authenticated (using
TryVerifyPin
), this will be updated to true
Methods
AuthenticateManagementKey(bool)
Authenticate the management key, throw an exception if the user cancels.
public void AuthenticateManagementKey(bool mutualAuthentication = true)
Parameters
mutualAuthentication
boolIf
true
the method will perform mutual authentication, iffalse
, only the application will authenticate to the YubiKey.
Remarks
This is the same as TryAuthenticateManagementKey
, except this
method will throw an exception if the KeyCollected
indicates
user cancellation.
See the TryAuthenticateManagementKey(bool) method for further documentation on this method.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
ChangeManagementKey(PivTouchPolicy)
Change the management key, throw an exception if the user cancels. The default management key algorithm will be used. (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.)
public void ChangeManagementKey(PivTouchPolicy touchPolicy = PivTouchPolicy.Default)
Parameters
touchPolicy
PivTouchPolicy
Remarks
This is the same as TryChangeManagementKey(PivTouchPolicy)
,
except this method will throw an exception if the KeyCollector
indicates user cancellation.
See the TryChangeManagementKey(PivTouchPolicy) method for further documentation on this method.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
ChangeManagementKey(PivTouchPolicy, PivAlgorithm)
Change the management key, throw an exception if the user cancels. The new key will be of the specified algorithm.
public void ChangeManagementKey(PivTouchPolicy touchPolicy, PivAlgorithm newKeyAlgorithm)
Parameters
touchPolicy
PivTouchPolicynewKeyAlgorithm
PivAlgorithm
Remarks
This is the same as
TryChangeManagementKey(PivTouchPolicy,PivAlgorithm)
,
except this method will throw an exception if the KeyCollecter
indicates user cancellation.
See the TryChangeManagementKey(PivTouchPolicy, PivAlgorithm) method for further documentation on this method.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
ChangePin()
Change the PIN, throw an exception if the user cancels.
public void ChangePin()
Remarks
This is the same as TryChangePin
, except this method will
throw an exception if the KeyCollector
indicates user
cancellation.
See the TryChangePin() method for further documentation on this method.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled PIN collection.
- SecurityException
The remaining retries count indicates the PIN is blocked.
ChangePinAndPukRetryCounts(byte, byte)
Change the retry counts for the PIN and PUK.
Warning
This will reset the PIN and PUK to their default values as well as set the retry counts.
public void ChangePinAndPukRetryCounts(byte newRetryCountPin, byte newRetryCountPuk)
Parameters
newRetryCountPin
byteThe PIN's new retry count.
newRetryCountPuk
byteThe PUK's new retry count.
Remarks
See the user's manual entry on changing the retry counts.
The retry count is the number of times a wrong PIN or PUK can be entered before the PIN or PUK is blocked. The YubiKey is manufactured with a retry count of three for both the PIN and PUK.
Call this method to change the retry count of both the PIN and PUK. It is allowed to change the counts to different values. For example, it is acceptable to change the PIN retry count to 7 and the PUK retry count to 4. > [!NOTE] > You must change the retry counts of both the PIN and PUK. There is > no way to change the retry count for only one secret.
Supply the new retry counts in this method. The maximum retry count is 255, hence, the input arguments are bytes. The minimum retry count is 1. If one of the arguments is 0, this method will throw an exception. Note that a retry count of 1 means there are no retries. If the user enters the wrong PIN or PUK just once, the secret is blocked.
After resetting the retry counts, the PIN and PUK will be reset to their default values (PIN: "123456", PUK: "12345678"). Even though you never reset the application (ResetApplication()) or explicitly changed the PIN and PUK (TryChangePin() and TryChangePuk()), after changing the retry counts, the PIN and PUK will be the defaults.
You will likely want to write your application to immediately follow changing the retry counts with setting the PIN and PUK: (TryChangePin() and TryChangePuk(). Another option is to change these counts during the initial user setup before changing the PIN and PUK from their defaults, then never offer the user the option of changing the retry counts again.
In order to perform this operation, the management key must be authenticated and the PIN must be verified during this session. If the have not been authenticated/verified, this method will call AuthenticateManagementKey(bool) and VerifyPin(). That is, your application does not need to authenticate the management key and verify the PIN separately, this method will determine if they have been authenticated/verified or not, and if not, it will make the calls to perform authentication and verification.
The authentication and verification methods will collect the
management key and PIN using the KeyCollector
delegate. If no
such delegate has been set, this method will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the Authenticate
and Verify
methods will call the
KeyCollector
requesting the management key or PIN, and it is
possible that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication or verification
method noting the cancellation. In that case, this method will throw
an exception. If you want the authentication to return false
on user cancellation, you must call
TryAuthenticateManagementKey(bool) or
TryVerifyPin() directly before calling this method.
Exceptions
- ArgumentException
The new retry count provided is invalid.
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
ChangePuk()
Change the PUK (PIN Unblocking Key), throw an exception if the user cancels.
public void ChangePuk()
Remarks
This is the same as TryChangePuk
, except this method will
throw an exception if the KeyCollector
indicates user
cancellation.
See the TryChangePuk() method for further documentation on this method.
Note: YubiKey Bio Multi-protocol Edition (MPE) keys do not have a PUK.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled PUK collection.
- SecurityException
The remaining retries count indicates the PUK is blocked.
CreateAttestationStatement(byte)
Create an attestation statement for the private key in the given slot.
public X509Certificate2 CreateAttestationStatement(byte slotNumber)
Parameters
slotNumber
byteThe slot containing the key to be attested.
Returns
- X509Certificate2
The resulting attestation statement (a certificate).
Remarks
See the User's Manual entry on PIV attestation for more information on attestation statements.
Note that attestation is a feature available on YubiKeys version 4.3 and later.
An attestation statement is an X.509 certificate that certifies a private key was generated by a YubiKey.
It is possible to create attestation statements only for keys
generated on a YubiKey.
If the slotNumber
argument is for any other slot, or if there
is no key in the slot, or if the key in the slot was imported and not
generated by the YubiKey, this method will throw an exception.
Note that it is not possible to get an attestation statement for the key in slot F9. That is the attestation key itself.
The key that will sign the attestation statement is the "attestation key" in slot F9. To verify the attestation statement, chain up to the attestation key's cert (see the method GetAttestationCertificate()), which will chain to a root. The YubiKey is manufactured with an attestation key and cert that chain to the Yubico root cert. The User's Manual entry on PIV attestation has more information on chaining attestation statements.
It is possible to replace the attestation key and cert. In that case, the attestation statement created by this method will chain up to a different root. See ReplaceAttestationKeyAndCertificate(IPrivateKey, X509Certificate2). There are restrictions on the key and certificate. The documentation for the Replace method lists those restrictions.
It is not necessary to authenticate the management key or verify the PIN in order to create an attestation statement.
Exceptions
- ArgumentException
The slot specified is not valid for creating an attestation statement.
- InvalidOperationException
The YubiKey is pre-4.3, or there is no YubiKey-generated key in the slot, or the attestation key and cert were replaced with invalid values, or the YubiKey could not complete the task for some reason such as unreliable connection.
Decrypt(byte, ReadOnlyMemory<byte>)
Decrypt the given data using the key in the given slot.
public byte[] Decrypt(byte slotNumber, ReadOnlyMemory<byte> dataToDecrypt)
Parameters
slotNumber
byteThe slot containing the key to use.
dataToDecrypt
ReadOnlyMemory<byte>The ciphertext.
Returns
- byte[]
The resulting decrypted block.
Remarks
The YubiKey supports decryption only with RSA keys.
This method returns the raw decrypted data, if it can decrypt. It will not parse the formatted data. If it cannot decrypt for some reason, it will throw an exception.
If the slot specified is not one that can decrypt, or it does not contain a key, or it contains an ECC key (instead of RSA), this method will throw an exception. If the input data is not the correct length, the method will throw an exception.
If the key is RSA 1024, then the input must be exactly 128 bytes. If the key is RSA 2048, then the input must be exactly 256 bytes. If the key is RSA 3072, then the input must be exactly 384 bytes. If the key is RSA 4096, then the input must be exactly 512 bytes. If the input data is not the correct length, the method will throw an exception.
The return will be the raw decrypted data. You can use the RsaFormat class to parse the data and extract the actual unpadded plaintext. That class will be able to parse from either PKCS #1 v1.5 or a subset of PKCS #1 OAEP. However, if that class does not support the exact format you want, you will have to write your own parsing code.
Decrypting might require the PIN and/or touch, depending on the PIN and touch policies specified at the time the key was generated or imported.
If a PIN is required, this method will call the necessary routines to verify the PIN. See VerifyPin() for more information on PIN verification. If the user cancels, this method will throw an exception.
If touch is required, the YubiKey itself will flash its touch signal
and wait. If the YubiKey is not touched before the touch timeout, the
YubiKey will return with an error, and this method will throw an
exception (OperationCanceledException
). Note that this method
will not make another effort to decrypt if the YubiKey is not
touched, it will simply throw the exception.
Note that on YubiKeys prior to version 5.3, it is not possible to know programmatically what the PIN or touch policies are without actually trying to decrypt. Also, it is not possible to know programmatically if an authentication failure is due to PIN or touch. This means that on older YubiKeys, this method will try to decrypt without the PIN, and if it does not work because of authentication failure, it will not know if the failure was due to PIN or touch. Hence, it will try to verify the PIN then try to sign again. This all means that on older YubiKeys, it is possible a YubiKey slot was originally configured with a PIN policy of "never" and a touch policy of "always", and this method will call for the PIN anyway. This happens if the user does not touch the YubiKey before the timeout. See the User's Manual entry on keeping track of slot contents.
Exceptions
- ArgumentException
The slot number given was not valid, or the data to decrypt was an invalid length.
- InvalidOperationException
There was no key in the slot specified or the data did not match the key (e.g. the data to decrypt was 128 bytes long but the key was RSA 2048).
- OperationCanceledException
Either the PIN was required and the user canceled collection or touch was required and the user did not touch within the timeout period.
- SecurityException
The remaining retries count indicates the PIN is blocked.
DeleteKey(byte)
Deletes/clears any key at a given PivSlot.
public void DeleteKey(byte slotToClear)
Parameters
slotToClear
byteThe Yubikey slot of the key you want to clear. This must be a valid slot number.
Remarks
Internally this method attempts to authenticate to the Yubikey by calling AuthenticateManagementKey(bool) which may in turn throw its' own exceptions.
Exceptions
- InvalidOperationException
Either the call to the Yubikey was unsuccessful or there wasn't any
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection. Refer to the specific exception message.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
- NotSupportedException
Thrown when the Yubikey doesn't support the Delete-operation.
- See Also
DeleteMsroots()
Delete any contents stored in the MSROOTS data objects.
public void DeleteMsroots()
Remarks
In order to perform this operation, the management key must be
authenticated during this session. If it has not been authenticated,
this method will call AuthenticateManagementKey(bool). That
is, your application does not need to authenticate the management key
separately (i.e., call TryAuthenticateManagementKey
or
AuthenticateManagementKey
), this method will determine if the
management key has been authenticated or not, and if not, it will
make the call to perform mutual authentication.
The authentication method will collect the management key using the
KeyCollector
delegate. If no such delegate has been set, it
will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the AuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication method noting
the cancellation. In that case, it will throw an exception. If you
want the authentication to return false
on user cancellation,
you must call TryAuthenticateManagementKey(bool) directly
before calling this method.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
Dispose(bool)
protected override void Dispose(bool disposing)
Parameters
disposing
bool
GenerateKeyPair(byte, KeyType, PivPinPolicy, PivTouchPolicy)
Generate a new key pair in the given slot.
public IPublicKey GenerateKeyPair(byte slotNumber, KeyType keyType, PivPinPolicy pinPolicy = PivPinPolicy.Default, PivTouchPolicy touchPolicy = PivTouchPolicy.Default)
Parameters
slotNumber
byteThe slot into which the key pair will be generated.
keyType
KeyTypeThe type of the key to generate.
pinPolicy
PivPinPolicyThe PIN policy the key will have. If no argument is given, the policy will be
Default
.touchPolicy
PivTouchPolicyThe touch policy the key will have. If no argument is given, the policy will be
Default
.
Returns
- IPublicKey
The public key partner to the private key generated on the YubiKey.
Remarks
When you generate a key pair, you specify which slot will hold this new key. If there is a key in that slot already, this method will replace it. That old key will be gone and there will be nothing you can do to recover it. Hence, use this method with caution.
You also have the opportunity to specify the PIN and touch policies
of the private key generated. These policies describe what will be
required when using the key. For example, if the PIN policy is
Always
, then every time the key is used (to sign, decrypt, or
perform key agreement), it will be necessary to verify the PIV PIN.
With the touch policy, for instance, setting it to Always
will
require touch every time the key is used. This method has the
policies as optional arguments. If you do not specify these
arguments, the key pair will be generated with the policies set to
Default
. Currently for all YubiKeys, the default PIN
policy is Once
, and the default touch policy is Never
.
This method will return the public key partner to the private key generated in the slot. For YubiKeys before version 5.3, it is the only time you will have the opportunity to obtain the public key, so make sure your application manages it right from the start. Beginning with version 5.3, it is possible to get a public key out of a slot at any time.
Note that while this method will return the public key, you will still need to obtain a certificate for the private key outside of this SDK. Once you have the certificate, you can load it into the YubiKey using the ImportCertificate(byte, X509Certificate2, bool) method.
In order to perform this operation, the management key must be
authenticated during this session. If it has not been authenticated,
this method will call AuthenticateManagementKey(bool). That
is, your application does not need to authenticate the management key
separately (i.e., call TryAuthenticateManagementKey
or
AuthenticateManagementKey
), this method will determine if the
management key has been authenticated or not, and if not, it will
make the call to perform mutual authentication.
The authentication method will collect the management key using the
KeyCollector
delegate. If no such delegate has been set, it
will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the AuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication method noting
the cancellation. In that case, it will throw an exception. If you
want the authentication to return false
on user cancellation,
you must call TryAuthenticateManagementKey(bool) directly
before calling this method.
Exceptions
- ArgumentException
The slot or algorithm specified is not valid for generating a key pair.
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
- NotSupportedException
If the specified PivAlgorithm is not supported by the provided IYubiKeyDevice.
GetAttestationCertificate()
Get the attestation certificate.
public X509Certificate2 GetAttestationCertificate()
Returns
- X509Certificate2
The attestation cert.
Remarks
Note that attestation is a feature available on YubiKeys version 4.3 and later.
The private key in slot F9 (PivSlot.Attestation
) is the key used
to sign the attestation statement (see
CreateAttestationStatement(byte)). To verify the
attestation statement, one needs the certificate of the key that signed
it. The certificate returned by this method is that certificate.
Root Cert
|
[CA Cert] (there may or may not be a CA cert between
| the root and Attestation Cert)
|
Attestation Cert (returned by this method)
|
Attestation Statement (returned by CreateAttestationStatement)
The YubiKey is manufactured with an attestation key and cert that chain to the Yubico root cert. The User's Manual entry on PIV attestation has more information on chaining attestation statements and certs.
It is possible to replace the attestation key and cert. In that case, the attestation statement created by this method will chain up to a different root. See ReplaceAttestationKeyAndCertificate(IPrivateKey, X509Certificate2).
Exceptions
- InvalidOperationException
The YubiKey is pre-4.3, or there is no attestation certificate, or it could not complete the task for some reason such as unreliable connection.
- TlvException
If the attestation certificate was replaced by data that is not a certificate.
GetBioMetadata()
Get information about YubiKey Bio multi-protocol.
public PivBioMetadata GetBioMetadata()
Returns
- PivBioMetadata
A new instance of a
PivBioMetadata
object.
Remarks
This feature is available only on YubiKey Bio multi-protocol keys (FW 5.6 and later). If you call
this method on an incompatible YubiKey, it will throw a NotSupportedException
.
IEnumerable<IYubiKeyDevice> list = YubiKey.FindByTransport(Transport.UsbSmartCard);
IYubiKeyDevice yubiKey = list.First();
using (var pivSession = new PivSession(yubiKey))
{
try
{
var bioMetaData = PivSession.GetBioMetadata();
/* use bioMetaData */
}
catch (NotSupportedException e) {
/* this device does not support Bio multi-protocol metadata */
}
}
See the User's Manual entry on getting bio metadata for specifics about what information is returned.
Exceptions
- NotSupportedException
The queried YubiKey does not support bio metadata.
- ApduException
The operation could not be completed.
GetCertificate(byte)
Get the certificate in the given slot.
public X509Certificate2 GetCertificate(byte slotNumber)
Parameters
slotNumber
byteThe slot containing the requested cert.
Returns
- X509Certificate2
The cert residing in the slot specified.
Remarks
After obtaining a cert, you can install it into the slot containing the associated private key (ImportCertificate(byte, X509Certificate2, bool)). Later on, when you need the cert (e.g. to send it along with a signed message), call this method to retrieve it.
It is not necessary to authenticate the management key nor verify the PIN in order to obtain a certificate.
If the slotNumber
given is for a slot that does not hold
asymmetric keys, or if there is no cert in the slot, this method will
throw an exception.
If you want to get the attestation cert, do not use this method, call
GetAttestationCertificate(). If you call this method with
slot number 0xF9
(PivSlot.Attestation
) it will throw an
exception.
Exceptions
- ArgumentException
The slot specified is not valid for getting a certificate.
- InvalidOperationException
The slot did not contain a cert, or the YubiKey had some other error, such as unreliable connection.
GetMetadata(byte)
Get information about the specified slot.
public PivMetadata GetMetadata(byte slotNumber)
Parameters
slotNumber
byteThe slot for which the information is requested.
Returns
- PivMetadata
A new instance of a
PivMetadata
object containing information about the given slot.
Remarks
This feature is available only on YubiKeys 5.3 and later. If you call this method on an earlier YubiKey, it will throw an exception. A good idea is to verify that the version number is valid before calling.
IEnumerable<IYubiKeyDevice> list = YubiKey.FindByTransport(Transport.UsbSmartCard);
IYubiKeyDevice yubiKey = list.First();
using (var pivSession = new PivSession(yubiKey))
{
if (yubiKey.FirmwareVersion >= new FirmwareVersion(5, 3, 0))
{
PivMetadata metadataSlot9A =
pivSession.GetMetadata(PivSlot.Authentication);
}
}
See the User's Manual entry on getting metadata for specific information about what information is returned. Different slots return different sets of data. That page also lists the valid slots for which metadata is available.
Exceptions
- ArgumentException
The slot specified is not valid for getting metadata.
- InvalidOperationException
The YubiKey queried does not support metadata, or the operation could not be completed because of some error such as unreliable connection.
GetPinOnlyMode()
Return an enum indicating the PIN-only mode, if any, for which the YubiKey PIV application is configured.
public PivPinOnlyMode GetPinOnlyMode()
Returns
- PivPinOnlyMode
A
PivPinOnlyMode
, which is an enum indicating the mode or modes.
Remarks
PIN-only mode means that the application does not need to enter the management key in order to perform PIV operations that normally require it, only the PIN is needed.
See the User's Manual entry on PIV PIN-only mode for a deeper discussion of this feature.
This returns a result based on the contents of ADMIN DATA. That storage location contains information about PIN-protected and PIN-derived. It is possible for a different application to overwrite the data to make it inaccurate. That is unlikely, however, if all applications follow good programming practices outlined by the SDK documentation. This method will not actually verify the management key in order to ensure the return value is correct.
If the ADMIN DATA is overwritten, it is possible to call TryRecoverPinOnlyMode() to restore the YubiKey to a proper PIN-only state.
Note also that it is possible that the ADMIN DATA says the YubiKey is
PIN-protected, but some app has overwritten the data in PRINTED. In
that case, this method will return a result indicating
PinProtected
, when in reality PIN-protected is unavailable.
That is because this returns a value based only on the contents of
ADMIN DATA. The method TryRecoverPinOnlyMode
will check more
than ADMIN DATA.
Note that the return is a bit field and the return can be one or more of the bits set. There are bits that indicate a YubiKey is unavailable for PIN-protected or PIN-derived. Call this method before trying to set a YubiKey to PIN-only to make sure it is not already set, and if not, it can be set.
Note that this returns the PIN-only mode for the PIV application on the YubiKey, it has nothing to do with OATH, FIDO, or OpenPGP.
Exceptions
- InvalidOperationException
The YubiKey is not able to return the ADMIN DATA.
ImportCertificate(byte, X509Certificate2, bool)
Import a certificate into the given slot.
public void ImportCertificate(byte slotNumber, X509Certificate2 certificate, bool compress = false)
Parameters
slotNumber
byteThe slot into which the key will be imported.
certificate
X509Certificate2The certificate to import into the YubiKey.
compress
boolIf true the certificate will be compressed before being stored on the YubiKey.
Remarks
When you import a certificate, you specify which slot will hold this cert. If there is a cert in that slot already, this method will replace it.
The PIV standard specifies that the maximum length of a cert is 1,856 bytes. The YubiKey allows for certs up to 3,052 bytes. However, if you want your application to be PIV-compliant, then use certs no longer than 1,856 bytes.
This method will not verify that the cert matches the private key in the slot. It will simply store the cert given in the slot specified.
In order to perform this operation, the management key must be
authenticated during this session. If it has not been authenticated,
this method will call AuthenticateManagementKey(bool). That
is, your application does not need to authenticate the management key
separately (i.e., call TryAuthenticateManagementKey
or
AuthenticateManagementKey
), this method will determine if the
management key has been authenticated or not, and if not, it will
make the call to perform mutual authentication.
The authentication method will collect the management key using the
KeyCollector
delegate. If no such delegate has been set, it
will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the AuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication method noting
the cancellation. In that case, it will throw an exception. If you
want the authentication to return false
on user cancellation,
you must call TryAuthenticateManagementKey(bool) directly
before calling this method.
Exceptions
- ArgumentNullException
The
certificate
argument isnull
.- ArgumentException
The slot specified is not valid for importing a certificate.
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
ImportPrivateKey(byte, IPrivateKey, PivPinPolicy, PivTouchPolicy)
Import a private key into the given slot.
public void ImportPrivateKey(byte slotNumber, IPrivateKey privateKey, PivPinPolicy pinPolicy = PivPinPolicy.Default, PivTouchPolicy touchPolicy = PivTouchPolicy.Default)
Parameters
slotNumber
byteThe slot into which the key will be imported.
privateKey
IPrivateKeyThe private key parameters and values to import into the YubiKey.
pinPolicy
PivPinPolicyThe PIN policy the key will have. If no argument is given, the policy will be
Default
.touchPolicy
PivTouchPolicyThe touch policy the key will have. If no argument is given, the policy will be
Default
.
Remarks
When you import a key, you specify which slot will hold this key. If there is a key in that slot already, this method will replace it. That old key will be gone and there will be nothing you can do to recover it. Hence, use this method with caution.
This method will not return to you the public key partner to the private key imported into the slot. For YubiKeys before version 5.3, you will not have the opportunity to obtain the public key, so make sure your application manages it right from the start. Beginning with version 5.3, it is possible to get a public key out of a slot at any time.
You also have the opportunity to specify the PIN and touch policies
of the private key generated. These policies describe what will be
required when using the key. For example, if the PIN policy is
Always
, then every time the key is used (to sign, decrypt, or
perform key agreement), it will be necessary to verify the PIV PIN.
With the touch policy, for instance, setting it to Always
will
require touch every time the key is used. This method has the
policies as optional arguments. If you do not specify these
arguments, the key pair will be generated with the policies set to
Default
. Currently for all YubiKeys, the default PIN
policy is Once
, and the default touch policy is Never
.
In order to perform this operation, the management key must be
authenticated during this session. If it has not been authenticated,
this method will call AuthenticateManagementKey(bool). That
is, your application does not need to authenticate the management key
separately (i.e., call TryAuthenticateManagementKey
or
AuthenticateManagementKey
), this method will determine if the
management key has been authenticated or not, and if not, it will
make the call to perform mutual authentication.
The authentication method will collect the management key using the
KeyCollector
delegate. If no such delegate has been set, it
will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the AuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication method noting
the cancellation. In that case, it will throw an exception. If you
want the authentication to return false
on user cancellation,
you must call TryAuthenticateManagementKey(bool) directly
before calling this method.
Exceptions
- ArgumentNullException
The
privateKey
argument isnull
.- ArgumentException
The slot specified is not valid for generating a key pair, or the
privateKey
object is empty.- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
- NotSupportedException
If the specified PivAlgorithm is not supported by the provided IYubiKeyDevice.
KeyAgree(byte, IPublicKey)
Perform Phase 2 of EC Diffie-Hellman Key Agreement using the private key in the given slot, and the corresponding party's public key.
public byte[] KeyAgree(byte slotNumber, IPublicKey correspondentPublicKey)
Parameters
slotNumber
byteThe slot containing the key to use.
correspondentPublicKey
IPublicKeyThe correspondent's public key.
Returns
- byte[]
The resulting shared secret data.
Remarks
The YubiKey supports key agreement only with ECC keys.
This method returns the raw shared secret data, if it can perform the key agreement operation. It will not perform any derivation operations. The result will be the same size as the key. That is, for a 256-bit ECC key, the shared secret is 32 bytes, and for a 384-bit key, the shared secret is 48 bytes.
The data returned is not formatted, nor encoded, it is simply a byte array. It happens to be the x coordinate of an ECC point that is the result of an EC scalar multiplication operation.
Key Agreement might require the PIN and/or touch, depending on the PIN and touch policies specified at the time the key was generated or imported.
If a PIN is required, this method will call the necessary routines to verify the PIN. See VerifyPin() for more information on PIN verification. If the user cancels, this method will throw an exception.
If touch is required, the YubiKey itself will flash its touch signal
and wait. If the YubiKey is not touched before the touch timeout, the
YubiKey will return with an error, and this method will throw an
exception (OperationCanceledException
). Note that this method
will not make another effort to perform key agreement if the YubiKey
is not touched, it will simply throw the exception.
Note that on YubiKeys prior to version 5.3, it is not possible to know programmatically what the PIN or touch policies are without actually trying to perform key agreement. Also, it is not possible to know programmatically if an authentication failure is due to PIN or touch. This means that on older YubiKeys, this method will try to perform the key agreement operation without the PIN, and if it does not work because of authentication failure, it will not know if the failure was due to PIN or touch. Hence, it will try to verify the PIN then try to perform the key agreement operation again. This all means that on older YubiKeys, it is possible a YubiKey slot was originally configured with a PIN policy of "never" and a touch policy of "always", and this method will call for the PIN anyway. This happens if the user does not touch the YubiKey before the timeout. See the User's Manual entry on keeping track of slot contents.
Exceptions
- ArgumentNullException
The
correspondentPublicKey
argument is null.- ArgumentException
The slot number given was not valid, or the public key was invalid (e.g. empty, wrong algorithm).
- InvalidOperationException
There was no key in the slot specified or the public key did not match the private key (e.g. the public key was for ECC P256 but the private key in the given slot was ECC P384).
- OperationCanceledException
Either the PIN was required and the user canceled collection or touch was required and the user did not touch within the timeout period.
- SecurityException
The remaining retries count indicates the PIN is blocked.
MoveKey(byte, byte)
Moves a key from one slot to another. The source slot must not be the Attestation-slot and the destination slot must be empty. Any key except the attestation key can be moved from one slot to another.
public void MoveKey(byte sourceSlot, byte destinationSlot)
Parameters
sourceSlot
byteThe Yubikey slot of the key you want to move. This must be a valid slot number.
destinationSlot
byteThe target Yubikey slot for the key you want to move. This must be a valid slot number.
Remarks
Internally this method attempts to authenticate to the Yubikey by calling AuthenticateManagementKey(bool) which may in turn throw its' own exceptions.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid key, the slot contained an attestation key, the or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
- NotSupportedException
Thrown when the Yubikey doesn't support the Move-operation.
ReadMsroots()
Returns the contents
of the MSROOTS data objects.
public byte[] ReadMsroots()
Returns
- byte[]
A new byte array containing the data stored in the MSROOTS data objects.
Remarks
The YubiKey PIV application can store data objects. There is a set of data elements defined by the PIV standard. See the User's Manual entry on GET DATA for information on these elements and their tags. The standard also allows for vendor-defined data objects. MSROOTS is one such vendor-defined element.
The intention of the MSROOTS data object is to store and retrieve a PKCS 7 construction containing a set of root certificates. These certificates will make it easier for the SDK to interface with the Microsoft Smart Card Base Crypto Service Provider (CSP).
Very few applications will need to use this feature. If you don't already know what the MSROOTS are, how to use them, and that they are part of your application already, then you almost certainly will never need to use this method.
This method will return whatever data is stored in the YubiKey under the tag "MSROOTS". This method will not verify that the data is a PKCS 7 construction, or that it contains root certificates, it will simply return the bytes from the data object.
While it is necessary to authenticate the management key in order to store the MSROOTS data (see WriteMsroots(ReadOnlySpan<byte>)), it is not needed to retrieve this data. Anyone with access to a YubiKey can retrieve this data.
The method will return the data as a new byte array. It is possible there is no data on the YubiKey in the MSROOTS data objects. In that case, this method will return an empty byte array (Length of 0).
Note that YubiKey stores the data formatted as a TLV:
tag || length || value
for example, it might be
53 20 (contents, 32 bytes)
or
7F 61 20 (contents, 32 bytes)
The tag used varies depending on the data being stored. This method
returns the contents, not the full TLV.
Note that the full amount of data might be stored in more than one data object. This method will collect all the data in all the MSROOTS data objects (in order) and concatenate.
Exceptions
- InvalidOperationException
The YubiKey encountered an error, such as an unreliable connection.
ReadMsrootsStream()
Returns the contents of the MSROOTS data objects as a Stream
.
public Stream ReadMsrootsStream()
Returns
- Stream
A new
Stream
which will be readable and will contain the MSROOTS contents.
Remarks
This is the same as the ReadMsroots() method that returns a byte
array, except this method returns a Stream
.
Exceptions
- InvalidOperationException
The YubiKey encountered an error, such as an unreliable connection.
ReadObject<T>()
Read the data at the storage location specified by the defined data
tag for the PivDataObject T
, storing and
returning this data in a new object of type T
.
public T ReadObject<T>() where T : PivDataObject, new()
Returns
- T
A new object of the type
T
. It contains the data stored on the YubiKey under the object's defined data tag. If there is no data stored, the returned object'sIsEmpty
property will betrue
.
Type Parameters
T
The type of PivDataObject to create, set, and return.
Remarks
For example,
using CardholderUniqueId chuid = pivSession.ReadObject<CardholderUniqueId>();
See also the user's manual entry on PIV data objects.
It is possible that there is no data on the YubiKey in the specified
storage location. If so, this method will return a new object with
the IsEmpty property set to true
.
If there is data stored under the specified data tag, this method
will expect it to be formatted as defined by the class T
. If
it is not formatted as expected, this method will throw an exception.
Note that there is a method that can read using an alternate tag. This method will use the defined tag for the given class.
Exceptions
- ArgumentException
The data is not properly encoded for the data object.
ReadObject<T>(int)
Read the data at the storage location specified by the given
dataTag
, storing and returning this data in a new object of
type T
.
public T ReadObject<T>(int dataTag) where T : PivDataObject, new()
Parameters
dataTag
intThe alternate data tag, the tag of the storage location to look.
Returns
- T
A new object of the type
T
. It contains the data stored on the YubiKey under the object's defined data tag. If there is no data stored, the returned object'sIsEmpty
property will betrue
.
Type Parameters
T
The type of PivDataObject to create, set, and return.
Remarks
For example,
using CardholderUniqueId chuid = pivSession.ReadObject<CardholderUniqueId>(0x005FFF55);
See also the user's manual entry on PIV data objects.
This is the same as the ReadObject<T>() method that takes no
arguments, except this one will get the data in the storage location
specified by dataTag
, as opposed to the defined data tag for
the class T
. This method will still expect the data to be
formatted as defined in the class T
, it's just that the data
is stored under a different tag.
This method is used when you have stored data under an alternate tag. It is likely you will never need this feature, and it is dangerous, because if done incorrectly, sensitive data that should require PIN verification to access will be available without a PIN). But there are rare cases when this feature is useful.
Exceptions
- ArgumentException
The
dataTag
in not allowed to be an alternate tag, or the data from the YubiKey is not properly encoded for the data object.
ReplaceAttestationKeyAndCertificate(IPrivateKey, X509Certificate2)
Replace the attestation key and certificate.
public void ReplaceAttestationKeyAndCertificate(IPrivateKey privateKey, X509Certificate2 certificate)
Parameters
privateKey
IPrivateKeyThe private key that will be the new attestation key.
certificate
X509Certificate2The cert that will be the new attestation cert.
Remarks
See the User's Manual entry on PIV attestation for more information on attestation statements and replacing them.
Note that attestation is a feature available on YubiKeys version 4.3 and later.
The YubiKey is manufactured with an attestation key and cert. This is the key that is used to sign the attestation statement, and the cert that verifies the attestation key.
This key was generated by Yubico, and the cert chains to a Yubico root. They are shared by many YubiKeys. If you want to replace them with your own, call this method.
Note that if you replace the Yubico key and cert, there is no way to recover them, they will be gone for good. So use this method with caution.
Note also that this is an operation that very few users will want to do. There are some companies who want to make sure the cert that is the attestation statement chains to one of their roots, instead of a Yubico root. For those companies, this feature is available. However, this is not common. If you are wondering if you want to replace the attestation key and cert, you almost certainly do not. If this is not already a requirement in your application, it almost certainly is not something you will be doing.
There are limitations placed on the key and cert. The key must be
either RSA-2048, RSA-3072, RSA-4096, ECC-P256, or ECC-P384. The cert must be X.509, it
must be version 2 or 3, the full DER encoding of the
SubjectName
must be fewer than 1029 bytes, and the total
length of the certificate must be fewer than 3052 bytes. This method
will verify that these restrictions are met.
YubiKeys before version 5 allowed 1024-bit RSA keys as the attestation key. However, this method, regardless of the YubiKey version, will not accept 1024-bit RSA keys.
This method will NOT, however, verify that the public key represented in the cert is indeed the partner to the private key specified. If you want to make sure they match, see the User's Manual entry on PIV attestation for a discussion on verifying compatibility.
Due to space and compute limitations, the YubiKey itself does not verify the inputs before loading them. That means it is possible to load bad key/cert combinations. For example, it is possible to load a cert that contains a subject key that is not the partner to the private key. In that case, the YubiKey will create attestation statements that do not verify or do not chain to a root. In other cases, the YubiKey might simply return an error when requested to build an attestation statement. Hence, you must be certain the key and cert you load are correct, and you should thoroughly test the attestation statements before deployment.
The method will not verify the cert itself, nor will it verify the validity dates inside the cert.
In order to perform this operation, the management key must be
authenticated during this session. If it has not been authenticated,
this method will call AuthenticateManagementKey(bool). That
is, your application does not need to authenticate the management key
separately (i.e., call TryAuthenticateManagementKey
or
AuthenticateManagementKey
), this method will determine if the
management key has been authenticated or not, and if not, it will
make the call to perform mutual authentication.
The authentication method will collect the management key using the
KeyCollector
delegate. If no such delegate has been set, it
will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the AuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication method noting
the cancellation. In that case, it will throw an exception. If you
want the authentication to return false
on user cancellation,
you must call TryAuthenticateManagementKey(bool) directly
before calling this method.
Exceptions
- ArgumentNullException
One of the inputs is
null
.- ArgumentException
One of the inputs is not allowed (e.g. private key is 1024-bit RSA).
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
ResetApplication()
Reset the PIV application to the default state.
public void ResetApplication()
Remarks
This will delete all keys and certs in all the asymmetric key slots other than F9, delete any added information to the data elements and set the PIN, PUK, and management key to their default values. That is, this will set the PIV application's state to what it was upon manufacture. See the User's Manual entries on the PIV PIN, PUK, and management key and data elements for more information on the defaults and data added to elements.
Note that this has no effect on the other YubiKey applications. This does NOT reset OTP, OATH, OpenPgp Card, FIDO U2F, or FIDO2.
Users will generally want to reset only if both the PIN and PUK are blocked. If a PIN has been blocked, it can only be restored using the PUK, but if the PUK is also blocked, there is no way to recover the PIN. Once there is no PIN, and no way to recover it, there is very little useful work the PIV application on a YubiKey can do. Resetting the application does not make the situation worse, but it does improve things somewhat, because the PIV application is usable again, just with new key pairs.
However, it is important to note that this method will reset the PIV application even if the PIN and/or PUK are not blocked. The YubiKey will not allow itself to be reset until both the PIN and PUK are blocked. This method will take steps necessary to block the PIN and PUK, then call on the YubiKey to reset.
This method does not work with YubiKey Bio Multi-protocol Edition (MPE) keys. For MPE keys, use DeviceReset() instead.
Exceptions
- SecurityException
The application could not be reset because of some error such as unreliable connection.
ResetPin()
Reset the PIN, using the PUK (PIN Unblocking Key), throw an exception if the user cancels.
public void ResetPin()
Remarks
This is the same as TryResetPin
, except this method will
throw an exception if the KeyCollector
indicates user
cancellation.
See the TryResetPin() method for further documentation on this method.
If the PUK is blocked, this method will not execute. If a YubiKey is configured PIN-only, the PUK will be blocked.
Note: YubiKey Bio Multi-protocol Edition (MPE) keys do not have a PUK.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled PUK and PIN collection.
- SecurityException
The remaining retries count indicates the PUK is blocked.
SetPinOnlyMode(PivPinOnlyMode)
Set the YubiKey's PIV application to be PIN-only with a PIN-derived and/or PIN-Protected management key. The default management key algorithm will be used (AES-192 for YubiKeys with firmware 5.7.x and later, TDES for keys with firmware 5.6.x and earlier). This sets the YubiKey to either
PivPinOnlyMode.PinProtected
PivPinOnlyMode.PinDerived
PivPinOnlyMode.PinProtected | PivPinOnlyMode.PinDerived
PivPinOnlyMode.None
If the YubiKey is set to PinProtected, PinDerived, or both, the PUK will also be blocked.
Warning
You should not set a YubiKey for PIN-derived, this feature is provided only for backwards compatibility.
public void SetPinOnlyMode(PivPinOnlyMode pinOnlyMode)
Parameters
pinOnlyMode
PivPinOnlyModeThe mode to which the YubiKey is to be set.
Remarks
PIN-only mode means that the application does not need to enter the management key in order to perform PIV operations that normally require it, only the PIN is needed.
See the documentation for SetPinOnlyMode(PivPinOnlyMode, PivAlgorithm) and the User's Manual entry on PIV PIN-only mode for a deeper discussion of this feature.
Note that this sets the PIV application on the specific YubiKey to a PIN-only mode, it has nothing to do with OATH, FIDO, or OpenPGP.
Note also that this will make sure that the management key algorithm will be default management key algorithm (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.), even if the current management key is a different algorithm. This behavior matches how this method operated in previous versions of the SDK.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, one of the keys provided was not of a valid key algorithm type (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.), the data stored on the YubiKey is incompatible with PIN-only, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled management key or PIN collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated, or the remaining retries count indicates the PIN is blocked.
SetPinOnlyMode(PivPinOnlyMode, PivAlgorithm)
Set the YubiKey's PIV application to be PIN-only with a PIN-derived and/or PIN-Protected management key of the specified algorithm. This sets the YubiKey to either
PivPinOnlyMode.PinProtected
PivPinOnlyMode.PinDerived
PivPinOnlyMode.PinProtected | PivPinOnlyMode.PinDerived
PivPinOnlyMode.None
If the YubiKey is set to PinProtected, PinDerived, or both, the PUK will also be blocked.
Warning
You should not set a YubiKey for PIN-derived, this feature is provided only for backwards compatibility.
public void SetPinOnlyMode(PivPinOnlyMode pinOnlyMode, PivAlgorithm mgmtKeyAlgorithm)
Parameters
pinOnlyMode
PivPinOnlyModeThe mode to which the YubiKey is to be set.
mgmtKeyAlgorithm
PivAlgorithmThe algorithm to which the management key will be set.
Remarks
PIN-only mode means that the application does not need to enter the management key in order to perform PIV operations that normally require it, only the PIN is needed.
See the User's Manual entry on PIV PIN-only mode for a deeper discussion of this feature.
Note that this sets the PIV application on the specific YubiKey to a PIN-only mode, it has nothing to do with OATH, FIDO, or OpenPGP.
Upon successful completion of this method, the PUK will be blocked.
The management key derived and/or stored in PRINTED will be for the
specified algorithm. For all YubiKeys, TripleDes
is a valid
algorithm. For YubiKeys 5.4.2 and later, it is possible to set the
management key to an AES key. For YubiKeys 5.7 and later, AES192 is the default.
Before setting the mgmtKeyAlgorithm
arg to an AES algorithm, make sure it is
allowed on the YubiKey. You can use the HasFeature
call. For
example,
PivAlgorithm mgmtKeyAlgorithm = yubiKey.HasFeature(YubiKeyFeature.PivAesManagementKey) ?
PivAlgorithm.Aes192 : PivAlgorithm.TripleDes;
pivSession.SetPinOnlyMode(PivPinOnlyMode.PinProtected, mgmtKeyAlgorithm);
If the algorithm is not supported by the YubiKey, this method will
throw an exception. It will not change the YubiKey, it will not set
it to PIN-only.
If the YubiKey is already set to the specified PIN-protected mode and algorithm, this will not reset the YubiKey, but will simply authenticate the management key.
If the YubiKey is already set to PIN-only, but not the specified mode, this method will make sure the YubiKey is set to both PIN-only modes.
If the YubiKey is already set to PIN-only, but not the specified algorithm, this method will change to a new management key of the specified algorithm.
If the requested pinOnlyMode
is both, then this will make sure
the YubiKey is both PIN-protected and PIN-derived.
If the input pinOnlyMode
is None
, and the YubiKey is
currently set to PIN-only (and neither PinProtected nor PinDerived is
Unavailable), this method will remove the contents of the storage
locations ADMIN DATA and PRINTED, and reset the management key to the
default management key.
In this case, the mgmtKeyAlgorithm
arg will be ignored, the
management key's algorithm after removing PIN-only status will be
the default management key algorithm (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.).
The touch policy of the management key will also be set
to the default (Never). Note that the management key must be
authenticated and the PIN verified in order to perform this task.
This method will authenticate the management key using the PIN-only
mode to which the YubiKey is currently set, then clear the contents.
It will then change the management key to the default value. Hence,
after setting the YubiKey out of PIN-only mode, you should change the
management key. Note also that the PUK will still be blocked. The
only way to unblock the PUK is to reset the retry counts. This will
set both the PIN and PUK to their default values. Resetting the retry
counts requires management key authentication.
If the input pinOnlyMode
is None
, and the YubiKey is
currently set to one PIN-only mode, but the other is Unavailable,
this method will clear the one that is set but leave the one that is
Unavailable as is. For example, suppose the current mode is
PinProtected | PinDerivedUnavailable
, then after setting to
None, the PRINTED storage area will be empty and the ADMIN DATA
storage area will be left as is.
If the input pinOnlyMode
is None
, and the YubiKey is
currently NOT set to either PIN-only modes, this method will do
nothing. It will not remove anything from ADMIN DATA or PRINTED, it
will not try to authenticate the management key, nor will it try to
verify the PIN. It will not change the management to the default. It
will ignore the mgmtKeyAlgorithm
argument.
If a YubiKey is currently set to both modes, and you call this method with only one of the modes, this method will NOT "remove" the other mode.
If a YubiKey is currently set to both PIN-only modes and you want to
"remove" one of them, call this method and set the YubiKey to
None
, then call this method a second time and set the YubiKey
to the desired mode.
In order to set the YubiKey to be PIN-only, this method must
authenticate the management key. Even if the management key is already
authenticated, this method will authenticate. It will try to
authenticate using the PIN-only techniques, and if that does not
work, it will try to authenticate using the default management key. If
either of those techniques works, the user will not have to enter the
management key. But if the YubiKey is not PIN-only, and the default
management key does not authenticate, the method will call on the
KeyCollector
to obtain the correct value.
If the mode to set is PIN-protected, then this method will use the existing mgmt key, unless it is the default. In that case, this method will generate a new, random mgmt key, set the YubiKey with this new value, and PIN-protect the new key.
This method also requires the PIN to be verified. If setting to
PIN-derived, even if the PIN is already verified, this method will
call on the KeyCollector
to obtain the PIN. If setting to
PIN-protected, this method will verify the PIN only if it has not yet
been verified.
Note that this method will throw an exception if the current contents of ADMIN DATA and/or PRINTED are not compatible with PIN-only mode. If there are no current contents, then this method will set one or both of those storage locations with appropriate data. But if there is already something in one or both, and it is not PIN-only information, then this method will not replace that data, it will throw an exception.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, one of the keys provided was not of a valid key algorithm type, the data stored on the YubiKey is incompatible with PIN-only, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled management key or PIN collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated, or the remaining retries count indicates the PIN is blocked.
Sign(byte, ReadOnlyMemory<byte>)
Create a digital signature using the key in the given slot.
public byte[] Sign(byte slotNumber, ReadOnlyMemory<byte> dataToSign)
Parameters
slotNumber
byteThe slot containing the key to use.
dataToSign
ReadOnlyMemory<byte>The formatted message digest.
Returns
- byte[]
The resulting signature.
Remarks
The caller supplies the data to sign in the form of a formatted message digest.
This method returns the digital signature created, if it can build one. Otherwise it will throw an exception.
If the slot specified is not one that can sign, or it does not contain a key, this method will throw an exception. If the input data is not the correct length, the method will throw an exception.
If the key is ECC P-256, then the formatted digest is simply the message digest itself, but it must be exactly 32 bytes. If the input is not exactly 32 bytes, the method will throw an exception. If the input data is shorter than 32 bytes, prepend pad bytes of 00 until the length is exactly 32 bytes. You will almost certainly want to use SHA-256 as the digest algorithm. The signature will be the BER encoding of
SEQUENCE {
r INTEGER,
s INTEGER }
If the key is ECC P-384, then the formatted digest is simply the message digest itself, but it must be exactly 48 bytes. If the input is not exactly 48 bytes, the method will throw an exception. If the input data is shorter than 48 bytes, prepend pad bytes of 00 until the length is exactly 48 bytes. You will almost certainly want to use SHA-384 as the digest algorithm. The signature will be the BER encoding of
SEQUENCE {
r INTEGER,
s INTEGER }
If the key is RSA 1024/2048/3072/4096, then the input must be exactly 128/256/384/512 bytes, otherwise the method will throw an exception. You can use the RsaFormat class to format the data. That class will be able to format the digest into either PKCS #1 v1.5 or a subset of PKCS #1 PSS. However, if that class does not support the exact format you want, you will have to write your own formatting code and guarantee the input to this method is exactly 128/256/384/512 bytes (prepend pad bytes of 00 until the length is exactly 128/256/384/512 if needed). The signature will be a 128/256/384/512-byte block.
Signing might require the PIN and/or touch, depending on the PIN and touch policies specified at the time the key was generated or imported.
If a PIN is required, this method will call the necessary routines to verify the PIN. See VerifyPin() for more information on PIN verification. If the user cancels, this method will throw an exception.
If touch is required, the YubiKey itself will flash its touch signal
and wait. If the YubiKey is not touched before the touch timeout, the
YubiKey will return with an error, and this method will throw an
exception (OperationCanceledException
). Note that this method
will not make another effort to sign if the YubiKey is not touched,
it will simply throw the exception.
Note that on YubiKeys prior to version 5.3, it is not possible to know programmatically what the PIN or touch policies are without actually trying to sign. Also, it is not possible to know programmatically if an authentication failure is due to PIN or touch. This means that on older YubiKeys, this method will try to sign without the PIN, and if it does not work because of authentication failure, it will not know if the failure was due to PIN or touch. Hence, it will try to verify the PIN then try to sign again. This all means that on older YubiKeys, it is possible a YubiKey slot was originally configured with a PIN policy of "never" and a touch policy of "always", and this method will call for the PIN anyway. This happens if the user does not touch the YubiKey before the timeout. See the User's Manual entry on keeping track of slot contents.
Exceptions
- ArgumentException
The slot number given was not valid, or the data to sign was an invalid length.
- InvalidOperationException
There was no key in the slot specified or the data did not match the key (e.g. the data to sign was 32 bytes long but the key was ECC P-384).
- OperationCanceledException
Either the PIN was required and the user canceled collection or touch was required and the user did not touch within the timeout period.
- SecurityException
The remaining retries count indicates the PIN is blocked.
- NotSupportedException
If the specified PivAlgorithm is not supported by the provided IYubiKeyDevice.
TryAuthenticateManagementKey(bool)
Try to authenticate the management key.
public bool TryAuthenticateManagementKey(bool mutualAuthentication = true)
Parameters
mutualAuthentication
boolIf
true
the method will perform mutual authentication, iffalse
, only the application will authenticate to the YubiKey.
Returns
- bool
A boolean,
true
if the management key authenticates,false
if the user cancels.
Remarks
You need to authenticate the management key only once per session. But if you have already authenticated, and you call this method, it will perform the authentication again. If the authentication fails the second time, the previous auth will be nullified.
See the ManagementKeyAuthenticated property for the current state of management key authentication.
This method will determine if the YubiKey is set for PIN-only. If so,
it will collect the management key using the PIN and authenticate. If
not, it will use the KeyCollector
to obtain the management key.
The ADMIN DATA and PRINTED storage locations contain information
about PIN-only (PIN-protected, PIN-derived, or both). If that
information is inaccurate (some other application overwrote the data
in one or both locations, PIN-only authentication might fail and this
method will use the KeyCollector
.
If the YubiKey is not set for PIN-only, this method will collect the
management key using the KeyCollector
delegate. If no such
delegate has been set, this method will throw an exception.
Beginning with YubiKey 5.4.2, the management key can be AES as well
as Triple-DES. When the SDK calls the KeyCollector
delegate,
it will not specify the expected algorithm or length of the
management key. If you need to know which algorithm the management
keys is, look at the property
PivSession.ManagementKeyAlgorithm
. Maybe your Key Collector is
an object and you can let it know which algorithm the management key
is so when the management key is requested, the user will know how
many bytes to provide. For example,
KeyCollectorClass.ManagementKeyAlgorithm = pivSession.ManagementKeyAlgorithm;
pivSession.KeyCollector = KeyCollectorClass.KeyCollectorDelegate;
The KeyCollector
has an option to cancel the operation. That
is, this TryAuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to this method noting the
cancellation. In that case, this method will return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
It is possible to perform single or mutual authentication. In single,
only the "off-card" application authenticates itself to the YubiKey.
In mutual authentication, both the off-card application and the
YubiKey authenticate each other. If the bool
argument
mutualAuthentication
is true
, this method will perform
mutual authentication. If false
, it will perform single. The
default is true
, so if no argument is given, this method will
perform mutual authentication.
This method will also set the ManagementKeyAuthenticated
and
ManagementKeyAuthenticationResult
properties. The "Result" is
an AuthenticateManagementKeyResult enum, listing the
possible results. For example, if you call for mutual authentication
and it fails, the property will be set to
AuthenticateManagementKeyResult.MutualOffCardAuthenticationFailed
or MutualYubiKeyAuthenticationFailed
, depending on what went
wrong.
If the management key authenticates, the method will return
true
. If not, and the KeyCollector
cancels the process,
the method will return false
and set the
ManagementKeyAuthenticationResult
property to the failure
reason.
If the call is for mutual authentication, and the off-card
application authenticates but the YubiKey does not, this method will
set the ManagementKeyAuthenticationResult
property to
MutualYubiKeyAuthenticationFailed
and throw an exception.
This can happen when the there is an unreliable connection with the
YubiKey, but it is also possible the device is a fraudulent YubiKey.
In this case it is still possible to call on the connected device to
perform operations, after all, the device trusts the off-card
application. Generally, however, an application will not want to use
the device if this happens. Nonetheless, an application could catch
the exception and continue, either try again or use the device
knowing it is untrusted.
The method will call the KeyCollector
delegate to obtain the
management key. If the management key obtained authenticates, the
method will call the KeyCollector
again with the
Request
of Release
. Upon the return from this release
call to the KeyCollector
, the method will return true
and set the ManagementKeyAuthenticated
property to true
and the ManagementKeyAuthenticationResult
property to
SingleAuthenticated
or MutualFullyAuthenticated
. Note
that this method ignores the return from the KeyCollector
when
the request is Release
. That is, this method will return
true
or false
depending on what happened before the
Release
. Note also that the KeyCollector
MUST NEVER
throw an exception when the request is Release
.
If the off-card application authentication fails, the method will
call the KeyCollector
delegate again, this time indicating the
previous management key provided failed to authenticate
(KeyEntryRequest.IsRetry
will be set to true
). The
method will continue to call the KeyCollector
and try to
authenticate as long as the returned management key does not
authenticate, and the return from the KeyCollector
is
true
. If you want to cancel the authentication process after
some number of failed attempts, build your KeyCollector
to
allow the user to cancel or keep track of the failures and return
false
after the limit has been reached.
Note that there is no limit on the number of tries to authenticate the management key. That is, the management key will never be blocked.
Note also that if the call is for mutual authentication and the
YubiKey fails to authenticate, then the method will not call the
KeyCollector
again, it will set the
ManagementKeyAuthenticated
property to false
, the
ManagementKeyAuthenticationResult
property to
MutualYubiKeyAuthenticationFailed
, and throw an exception.
If there is an error during the process, this method will simply call
the KeyCollector
with Release
, set the
ManagementKeyAuthenticated
property to false
, the
ManagementKeyAuthenticationResult
property to
Unauthenticated
, and throw an exception.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
TryAuthenticateManagementKey(ReadOnlyMemory<byte>, bool)
Try to authenticate the management key. This method will use the key
data provided, rather than the KeyCollector
.
public bool TryAuthenticateManagementKey(ReadOnlyMemory<byte> managementKey, bool mutualAuthentication = true)
Parameters
managementKey
ReadOnlyMemory<byte>The key to authenticate.
mutualAuthentication
boolIf
true
the method will perform mutual authentication, iffalse
, only the application will authenticate to the YubiKey. The default istrue
.
Returns
- bool
A boolean,
true
if the management key authenticates,false
if it does not.
Remarks
Normally, an application will not call any
AuthenticateManagementKey
method. Under the covers, the SDK
determines when the management key needs to be verified and calls the
KeyCollector
. It is only at that point the application needs
to supply the key. The SDK will call the application-supplied
KeyCollector
, indicating what it needs (PIN, PUK, management
key), and the KeyCollector
does what it needs to obtain the
value requested. This system also contains a mechanism to report if
the previous value was incorrect. If the management key is never
needed, the key is never provided.
See the User's Manual entry on the Key Collector for a more detailed explanation of this process.
With this method, however, the caller provides the management key and
the KeyCollector
is never contacted.
See the TryAuthenticateManagementKey(bool) method for further documentation on this method.
Generally, it is necessary to authenticate a management key once per session. Once the key is authenticated, any operation that required the key in order to execute, called during that session, will work. The exceptions include changing the management key, and setting a YubiKey to PIN-only.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided. As long as the
application does not perform an operation that requires the
management key even if it has been authenticated in the session, the
KeyCollector
is not needed.
Note that if the management key is needed during the session even
after the key is authenticated using this method (see exceptions
above), and no KeyCollector
is provided, the SDK will throw an
exception.
The management key is provided to this method as a
ReadOnlyMemory<byte>
. It is possible to pass a
byte[]
, because it will be automatically cast. The management
key is 24 bytes, no more, no less.
If the wrong key is provided, this method will return false
.
Exceptions
- InvalidOperationException
The key provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.
- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
TryChangeManagementKey(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, PivTouchPolicy)
Try to change the management key. This method will use the
currentKey
and newKey
provided.
public bool TryChangeManagementKey(ReadOnlyMemory<byte> currentKey, ReadOnlyMemory<byte> newKey, PivTouchPolicy touchPolicy = PivTouchPolicy.Default)
Parameters
currentKey
ReadOnlyMemory<byte>The current management key.
newKey
ReadOnlyMemory<byte>What the management key will be changed to.
touchPolicy
PivTouchPolicyThe touch policy for the new management key. If no argument is given, the policy will be
PivTouchPolicy.Default
.
Returns
- bool
A boolean,
true
if the management key is changed,false
if not.
Remarks
Normally, an application would call the
TryChangeManagementKey(PivTouchPolicy)
method and the SDK
would call on the loaded KeyCollector
to retrieve the current
and new keys. With this method, the caller provides the keys and the
KeyCollector
is never contacted.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided.
See the TryChangeManagementKey(PivTouchPolicy) method for further documentation on this method.
If the wrong current key is provided, this method will return
false
.
Exceptions
- InvalidOperationException
One of the keys provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.
- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
TryChangeManagementKey(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, PivTouchPolicy, PivAlgorithm)
Try to change the management key. This method will use the
currentKey
and newKey
provided. The new key's algorithm
will be as specified.
public bool TryChangeManagementKey(ReadOnlyMemory<byte> currentKey, ReadOnlyMemory<byte> newKey, PivTouchPolicy touchPolicy, PivAlgorithm newKeyAlgorithm)
Parameters
currentKey
ReadOnlyMemory<byte>The current management key.
newKey
ReadOnlyMemory<byte>What the management key will be changed to.
touchPolicy
PivTouchPolicyThe touch policy for the new management key.
newKeyAlgorithm
PivAlgorithmThe algorithm the new management key will be.
Returns
- bool
A boolean,
true
if the management key is changed,false
if not.
Remarks
Normally, an application would call the
TryChangeManagementKey(PivTouchPolicy)
method and the SDK
would call on the loaded KeyCollector
to retrieve the current
and new keys. With this method, the caller provides the keys and the
KeyCollector
is never contacted.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided.
See the TryChangeManagementKey(PivTouchPolicy, PivAlgorithm) method for further documentation on this method.
Note that with this method, a touch policy argument is required, there is no default value.
If the wrong current key is provided, this method will return
false
.
Exceptions
- InvalidOperationException
One of the keys provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.
- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
TryChangeManagementKey(PivTouchPolicy)
Try to change the management key. The default management key algorithm will be used. (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.)
public bool TryChangeManagementKey(PivTouchPolicy touchPolicy = PivTouchPolicy.Default)
Parameters
touchPolicy
PivTouchPolicyThe touch policy for the new management key. If no argument is given, the policy will be
PivTouchPolicy.Default
.
Returns
- bool
A boolean,
true
if the management key is changed,false
if not.
Remarks
Upon manufacture of a YubiKey, the PIV application begins with a default management key (see the User's Manual entry on the management key). This method changes it. Note that this method can be run at any time, either during the initial YubiKey setup to change from the default management key, or later, to change it again.
If the YubiKey is set for PIN-only, this method will throw an exception.
Beginning with YubiKey 5.4.2, the management key can be either
Triple-DES or AES. When changing the management key, the SDK can
obtain the metadata for the management key slot to determine the
algorithm of the current key. However, the caller must supply the
algorithm of the new key (if it is 24 bytes, is it Triple-DES or
AES-192?). There is a Try
method for changing the management
key that has an input argument for the algorithm. This method does
not have such an arg. This one will set the new key to Triple-DES.
The Triple-DES management key is 24 byte long, no more, no less. It is binary. That's 192 bits. But note that because of "parity" bits, the actual bit strength of a Triple-DES key is 124 bits. And then further, there are attacks on Triple-DES that leave its effective bit strength at 112 bits.
In order to change it, the current management key must be
authenticated. If it has already been authenticated in this session,
this method will still make the appropriate calls to authenticate (it
will perform mutual authentication). That is, if you want to change
the management key, it is not necessary to call
TryAuthenticateManagementKey
or
AuthenticateManagementKey
first. You can, but it doesn't
matter, because this method will call it again.
This method will collect the current and new management keys using
the KeyCollector
delegate. If no such delegate has been set,
this method will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, this TryAuthenticateManagementKey
method will call the
KeyCollector
requesting the current management key, and it is
possible that during the collection operations, the user cancels. The
KeyCollector
will return to this method noting the
cancellation. In that case, this method will return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
Along with the key data itself, a management key has a touch policy. See the User's Manual entry on the PIV touch policy.
This method takes in a touch policy argument, but the argument has a
default value, so it is valid to pass no argument to this method. The
default argument value is the Default
touch policy.
Note: touch policy for the management key is available only on YubiKey 4 and later. A YubiKey prior to 4 will ignore the touch policy and simply set the touch policy of the management key to the default.
The touch policy refers to whether use of the management key will
require touch or not, and if so, always or cached. The policy is
specified using the PivTouchPolicy
enum. If the input is
None
or Never
, the YubiKey will not require touch to
complete an operation that requires the management key. Always
means every operation requires touch, even if the YubiKey had been
touched for an operation shortly before. If Cached
, one touch
will last for 15 seconds. That is, touch for an operation, and if a
second operation requires the management key, and it is executing
less than 15 seconds after the first, touch is not required.
Default
will use the YubiKey's default touch policy.
After this method is called, the management key will be authenticated for this session. That is, in order to change the key, the current management key must be authenticated. After changing, the new management key will be considered authenticated, and any subsequent operation that requires management key authentication in order to execute (e.g. generate a key pair) will work.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, one of the keys provided was not a valid Triple-DES or AES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
TryChangeManagementKey(PivTouchPolicy, PivAlgorithm)
Try to change the management key. The new key will be the specified algorithm.
public bool TryChangeManagementKey(PivTouchPolicy touchPolicy, PivAlgorithm newKeyAlgorithm)
Parameters
touchPolicy
PivTouchPolicyThe touch policy for the new management key.
newKeyAlgorithm
PivAlgorithmThe new management key's algorithm.
Returns
- bool
A boolean,
true
if the management key is changed,false
if not.
Remarks
Upon manufacture of a YubiKey, the PIV application begins with a default management key (see the User's Manual entry on the management key). This method changes it. Note that this method can be run at any time, either during the initial YubiKey setup to change from the default management key, or later, to change it again.
If the YubiKey is set for PIN-only, this method will throw an exception.
Beginning with YubiKey 5.4.2, the management key can be either Triple-DES or AES. When changing the management key, the SDK can obtain the metadata for the management key slot to determine the algorithm of the current key. However, the caller must supply the algorithm of the new key (if it is 24 bytes, is it Triple-DES or AES-192?).
Note that a Triple-DES key is 24 byte long, no more, no less. It is binary. That's 192 bits. But because of "parity" bits, the actual bit strength of a Triple-DES key is 124 bits. Furthermore, there are attacks on Triple-DES that leave its effective bit strength at 112 bits.
In order to change it, the current management key must be
authenticated. If it has already been authenticated in this session,
this method will still make the appropriate calls to authenticate (it
will perform mutual authentication). That is, if you want to change
the management key, it is not necessary to call
TryAuthenticateManagementKey
or
AuthenticateManagementKey
first. You can, but it doesn't
matter, because this method will call it again.
This method will collect the current and new management keys using
the KeyCollector
delegate. If no such delegate has been set,
this method will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, this TryAuthenticateManagementKey
method will call the
KeyCollector
requesting the current management key, and it is
possible that during the collection operations, the user cancels. The
KeyCollector
will return to this method noting the
cancellation. In that case, this method will return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
Along with the key data itself, a management key has a touch policy. See the User's Manual entry on the PIV touch policy. This method requires a touch policy argument, it does not have a default.
Note: touch policy for the management key is available only on YubiKey 4 and later. A YubiKey prior to 4 will ignore the touch policy and simply set the touch policy of the management key to the default.
The touch policy refers to whether use of the management key will
require touch or not, and if so, always or cached. The policy is
specified using the PivTouchPolicy
enum. If the input is
None
or Never
, the YubiKey will not require touch to
complete an operation that requires the management key. Always
means every operation requires touch, even if the YubiKey had been
touched for an operation shortly before. If Cached
, one touch
will last for 15 seconds. That is, touch for an operation, and if a
second operation requires the management key, and it is executing
less than 15 seconds after the first, touch is not required.
Default
will use the YubiKey's default touch policy.
After this method is called, the management key will be authenticated for this session. That is, in order to change the key, the current management key must be authenticated. After changing, the new management key will be considered authenticated, and any subsequent operation that requires management key authentication in order to execute (e.g. generate a key pair) will work.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, one of the keys provided was not a valid key for the specified algorithm, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
TryChangePin()
Try to change the PIN.
public bool TryChangePin()
Returns
- bool
A boolean,
true
if the PIN is changed,false
if not.
Remarks
Upon manufacture of a YubiKey, the PIV application begins with a default PIN (see the User's Manual entry on the PIN). This method changes it. Note that this method can be run at any time, either during the initial YubiKey setup to change from the default PIN, or later, to change it again.
The PIN is six to eight bytes byte long. Although most PINs will be
characters, the YubiKey allows any binary data to be a PIN. The
default is the ASCII string "123456"
which is the byte array
0x31 0x32 0x33 0x34 0x35 0x36
In order to change the PIN, both the current PIN and new PIN must be
provided. Even if the current PIN had been verified already (using
one of the methods TryVerifyPin
or VerifyPin
), the
current PIN must be provided again. This method will call the
KeyCollector
delegate with the Request
of
KeyEntryRequest.ChangePivPin
. The KeyCollector
must
then provide to this method both the current and new PIN.
The KeyCollector
has an option to cancel the operation. That
is, this TryChangePin
method will call the KeyCollector
requesting the PIN, and it is possible that during the collection
operations, the user cancels. The KeyCollector
will return to
this method noting the cancellation. In that case, this method will
return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
An incorrect current PIN will decrement the remaining tries count. Hence, trying to change the PIN with the wrong current PIN too many times (retry count times) will cause the PIN to be blocked.
If the wrong current PIN is provided, and the remaining retries count
is not zero, the method will call the KeyCollector
again with
KeyEntryData.IsRetry
set to true
and
KeyEntryData.RetriesRemaining
set to the number of tries
remaining until the PIN is blocked. The KeyCollector
can try
to collect the PIN again, but will likely report the retries
remaining to the user and offer the option of canceling. If the
KeyCollector
returns false
, this method will call the
KeyCollector
with Release
and return false
.
If the wrong current PIN is provided, and the remaining retries count
is zero, the method will call the KeyCollector
again,
indicating Release
and then throw an exception. That is, once
the remaining retries count goes to zero the PIN is blocked. At this
point, this method will not try to collect the PIN any more and will
throw an exception.
If there is an error during the process, this method will simply call
the KeyCollector
with Release
and throw an exception.
Note that when this method calls the KeyCollector
with
Release
, the return from the KeyCollector
is ignored,
this method will return true
or false
depending on what
happened before the Release
.
Changing the PIN does not affect the status of the Session's PIN
verification. That is, the PinVerified
property will not change
after this method completes. If the status is false
(unverified), and the PIN is successfully changed, the PIN will still
be unverified and any operation that requires the PIN (such as
signing), will need the PIN verified (with the new PIN). If the
status is true
(verified) and this method succeeds, the PIN will
still be considered verified (the previous PIN), even though there is
a new PIN. If the status is true
(verified) and this method
fails, the PIN will still be considered verified (the current PIN).
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- SecurityException
The remaining retries count indicates the PIN is blocked.
TryChangePin(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, out int?)
Try to change the PIN. This method will use the currentPin
and
newPin
provided.
public bool TryChangePin(ReadOnlyMemory<byte> currentPin, ReadOnlyMemory<byte> newPin, out int? retriesRemaining)
Parameters
currentPin
ReadOnlyMemory<byte>The current PIN, the PIN that is to be changed.
newPin
ReadOnlyMemory<byte>The new PIN, what the PIN will be changed to.
retriesRemaining
int?An output, it will be set to the number of retries remaining if the current PIN is not verified. If the current PIN is verified and the PIN is changed, this will be set to null.
Returns
- bool
A boolean,
true
if the PIN is changed,false
if not.
Remarks
Normally, an application would call the TryChangePin()
method
(no arguments) and the SDK would call on the loaded
KeyCollector
to retrieve the PINs. With this method, the
caller provides the PINs and the KeyCollector
is never
contacted.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided.
See the TryChangePin() method for further documentation on this method.
If the wrong current PIN is provided, this method will return
false
.
Changing the PIN does not affect the status of the Session's PIN
verification. That is, the PinVerified
property will not change
after this method completes. If the status is false
(unverified), and the PIN is successfully changed, the PIN will still
be unverified and any operation that requires the PIN (such as
signing), will need the PIN verified (with the new PIN). If the
status is true
(verified) and this method succeeds, the PIN will
still be considered verified (the previous PIN), even though there is
a new PIN. If the status is true
(verified) and this method
fails, the PIN will still be considered verified (the current PIN).
If the YubiKey is configured for PIN-derived, this method will update the management key, so that it is derived from the new PIN. Note that if the ADMIN DATA and/or PRINTED storage locations have been overwritten, this method might not be able to correctly update the management key. It is a good idea to call TryRecoverPinOnlyMode() before changing the PIN. See also the User's Manual entry on PIN-only modes.
Exceptions
- InvalidOperationException
The YubiKey had some error, such as unreliable connection.
- SecurityException
The remaining retries count indicates the PIN is blocked.
TryChangePinAndPukRetryCounts(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, byte, byte, out int?)
Try to change the retry counts for both the PIN and PUK. This method
will use the managementKey
and pin
provided.
Warning
This will reset the PIN and PUK to their default values as well as set the retry counts.
public bool TryChangePinAndPukRetryCounts(ReadOnlyMemory<byte> managementKey, ReadOnlyMemory<byte> pin, byte newRetryCountPin, byte newRetryCountPuk, out int? retriesRemaining)
Parameters
managementKey
ReadOnlyMemory<byte>The current management key. If it is
Empty
, the method will authenticate using PIN-only.pin
ReadOnlyMemory<byte>The current PIN.
newRetryCountPin
byteThe PIN's new retry count.
newRetryCountPuk
byteThe PUK's new retry count.
retriesRemaining
int?An output, it will be set to the number of retries remaining if the PIN is not verified. If the management key is not authenticated or the PIN is verified, this will be set to null.
Returns
- bool
A boolean,
true
if the retry counts are changed,false
if not.
Remarks
Normally, an application would call the
ChangePinAndPukRetryCounts(int, int)
method and the SDK would
call on the loaded KeyCollector
to retrieve the management key
and PIN. With this method, the caller provides the management key and
PIN and the KeyCollector
is never contacted.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided.
See the ChangePinAndPukRetryCounts(byte, byte) method for further documentation on this method.
If the wrong management key or PIN is provided, this method will
return false
.
This method will authenticate the management key provided and verify the PIN provided, even if one or both have already been authenticated/verified.
If the YubiKey is configured for PIN-only, the managementKey
argument will be ignored. In this case, you can pass in an empty
management key: ReadOnlyMemory<byte>.Empty
.
Exceptions
- InvalidOperationException
The YubiKey had some error, such as unreliable connection.
- SecurityException
The remaining retries count indicates the PIN is blocked.
TryChangePuk()
Try to change the PUK (PIN Unblocking Key).
public bool TryChangePuk()
Returns
- bool
A boolean,
true
if the PUK is changed,false
if not.
Remarks
Upon manufacture of a YubiKey, the PIV application begins with a default PUK (see the User's Manual entry on the PUK). This method changes it. Note that this method can be run at any time, either during the initial YubiKey setup to change from the default PUK, or later, to change it again.
The PUK must be 6-8 characters. For YubiKeys with firmware versions prior to 5.7, the PUK is allowed to be any character in the 0x00
- 0xFF
range for a total length of 6-8 bytes. For YubiKeys with firmware version 5.7 and above, the PUK is allowed to be any character in the 0x00
- 0x7F
range for a total length of 6-8 Unicode code points. The
default PUK is the ASCII string "12345678"
, which is the byte array
0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
In order to change the PUK, both the the current PUK and new PUK must
be provided. This method will call the KeyCollector
delegate
with the Request
of KeyEntryRequest.ChangePivPuk
. The
KeyCollector
provides both the current and new PUK.
The KeyCollector
has an option to cancel the operation. That
is, this TryChangePuk
method will call the KeyCollector
requesting the PUK, and it is possible that during the collection
operations, the user cancels. The KeyCollector
will return to
this method noting the cancellation. In that case, this method will
return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
An incorrect current PUK will decrement the remaining tries count. Hence, trying to change the PUK with the wrong current PUK too many times (retry count times) will cause the PUK to be blocked.
If the wrong current PUK is provided, and the remaining retries count
is not zero, the method will call the KeyCollector
again with
KeyEntryData.IsRetry
set to true
and
KeyEntryData.RetriesRemaining
set to the number of tries
remaining until the PUK is blocked. The KeyCollector
can try
to collect the PUK again, but will likely report the retries
remaining to the user and offer the option of canceling. If the
KeyCollector
returns false
, this method will call the
KeyCollector
with Release
and return false
.
If the wrong current PUK is provided, and the remaining retries count
is zero, the method will call the KeyCollector
again,
indicating Release
and then throw an exception. That is, once
the remaining retries count goes to zero the PUK is blocked. At this
point, this method will not try to collect the PUK any more and will
throw an exception.
If there is an error during the process, this method will simply call
the KeyCollector
with Release
and throw an exception.
Note that when this method calls the KeyCollector
with
Release
, the return from the KeyCollector
is ignored,
this method will return true
or false
depending on what
happened before the Release
.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- SecurityException
The remaining retries count indicates the PUK is blocked.
TryChangePuk(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, out int?)
Try to change the PUK. This method will use the currentPuk
and
newPuk
provided.
public bool TryChangePuk(ReadOnlyMemory<byte> currentPuk, ReadOnlyMemory<byte> newPuk, out int? retriesRemaining)
Parameters
currentPuk
ReadOnlyMemory<byte>The current PUK, the PUK that is to be changed.
newPuk
ReadOnlyMemory<byte>The new PUK, what the PUK will be changed to.
retriesRemaining
int?An output, it will be set to the number of retries remaining if the current PUK is not correct. If the PUK is changed, this will be set to null.
Returns
- bool
A boolean,
true
if the PUK is changed,false
if not.
Remarks
Normally, an application would call the TryChangePuk()
method
(no arguments) and the SDK would call on the loaded
KeyCollector
to retrieve the PUKs. With this method, the
caller provides the current and new PUKs and the KeyCollector
is never contacted.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided.
See the TryChangePuk() method for further documentation on this method.
If the wrong current PUK is provided, this method will return
false
.
Exceptions
- InvalidOperationException
The YubiKey had some error, such as unreliable connection.
- SecurityException
The remaining retries count indicates the PUK is blocked.
TryReadObject<T>(int, out T)
Try to read the data at the storage location specified by the defined
data tag for the PivDataObject T
,
storing and returning this data in a new object of type T
.
public bool TryReadObject<T>(int dataTag, out T pivDataObject) where T : PivDataObject, new()
Parameters
dataTag
intThe alternate data tag, the tag of the storage location to look.
pivDataObject
TAn output argument, this method will create a new object containing the data from the storage location, as long as it is formatted as expected.
Returns
- bool
A boolean,
true
if the storage location contains data formatted as expected, or no data, andfalse
if the storage location contains data formatted in an unexpected way.
Type Parameters
T
The type of PivDataObject to create, set, and return.
Remarks
For example,
bool isValid = pivSession.TryReadObject<KeyHistory>(out KeyHistory keyHistory);
if (isValid)
{
// perform operations
}
keyHistory.Dispose();
or alternatively,
bool isValid = pivSession.ReadObject<KeyHistory>(out KeyHistory keyHistory);
using (keyHistory)
{
if (isValid)
{
// perform operations
}
}
Note that the PivDataObject
is Disposable
so make sure
you use the using
keyword or call Dispose
directly.
See also the user's manual entry on PIV data objects.
The method will look in the storage location specified by the
dataTag
argument.
It is possible that there is no data on the YubiKey in the specified
storage location. If so, this method will build a new, empty object
as the pivDataObject
and return false.
If there is data and it is formatted as expected, the method will
build a new object set with the data and return true
.
If there is data stored under the specified data tag, and it is not
formatted as expected, this method will build a new, empty object as
the pivDataObject
and return false
.
Exceptions
- ArgumentException
The
dataTag
in not allowed to be an alternate tag.
TryReadObject<T>(out T)
Try to read the data at the storage location specified by the defined
data tag for the PivDataObject T
,
storing and returning this data in a new object of type T
.
public bool TryReadObject<T>(out T pivDataObject) where T : PivDataObject, new()
Parameters
pivDataObject
TAn output argument, this method will create a new object containing the data from the storage location, as long as it is formatted as expected.
Returns
- bool
A boolean,
true
if the storage location contains data formatted as expected, or no data, andfalse
if the storage location contains data formatted in an unexpected way.
Type Parameters
T
The type of PivDataObject to create, set, and return.
Remarks
For example,
bool isValid = pivSession.TryReadObject<PinProtectedData>(out PinProtectedData pinProtect);
if (isValid)
{
// perform operations
}
pinProtect.Dispose();
or alternatively,
bool isValid = pivSession.ReadObject(out PinProtectedData pinProtect);
using (pinProtect)
{
if (isValid)
{
// perform operations
}
}
Note that the PivDataObject
is Disposable
so make sure
you use the using
keyword or call Dispose
directly.
See also the user's manual entry on PIV data objects.
The method will look in the storage location specified by the
defined data tag of the pivDataObject
.
It is possible that there is no data on the YubiKey in the specified
storage location. If so, this method will build a new, empty object
as the pivDataObject
and return false.
If there is data and it is formatted as expected, the method will
build a new object set with the data and return true
.
If there is data stored under the specified data tag, but it is not
formatted as expected, this method will build a new, empty object as
the pivDataObject
and return false
.
TryRecoverPinOnlyMode()
Try to recover the PIN-only state. If successful, this will authenticate the management key and reset the ADMIN DATA and or PRINTED storage locations.
Warning
This can overwrite the contents of ADMIN DATA and/or PRINTED. If some other application relies on that data it will be lost.
public PivPinOnlyMode TryRecoverPinOnlyMode()
Returns
- PivPinOnlyMode
A
PivPinOnlyMode
, which is an enum indicating the mode or modes the YubiKey is in.
Remarks
See the User's Manual entry on PIV PIN-only mode for a deeper discussion of this operation.
The ADMIN DATA contains information about PIN-only. The PIN-protected management key is stored in PRINTED. Applications should never store information in those locations, only Yubico-supplied products should use them. However, it is possible for an application to overwrite the contents of one or both of these storage locations, making the PIN-only data inaccurate.
This method will obtain the data stored in the two storage locations,
and determine if they contain PIN-only data that can be used to
authenticate the management key. If it can't, it will return
PivPinOnlyMode.None
or Unavailable
. If it can, it will
authenticate and set the ADMIN DATA and PRINTED to contain data
compatible with correct PIN-only modes. It will return a
PivPinOnlyMode
value indicating which mode is set.
For example, suppose the data in both is correct, and it indicates
the management key is PIN-protected. After calling this method, the
management key will be authenticated, the storage locations will not
be changed, and the return will be PivPinOnlyMode.PinProtected
.
Another possibility is the ADMIN DATA was overwritten by some
application so it is inaccurate, but the PIN-protected data is still
in PRINTED. This method will be able to authenticate the management
key using that data. It will replace the contents of ADMIN DATA with
correct PIN-only information and return
PivPinOnlyMode.PinProtected
.
If ADMIN DATA and PRINTED contain no data, or if ADMIN DATA contains
correct information that indicates the YubiKey is not set to PIN-only
mode, then this method will not authenticate the management key, it
will not put any data into the storage locations, and it will return
PivPinOnlyMode.None
.
It is possible this method is not able to recover. For example,
suppose the ADMIN DATA is correct and indicates the YubiKey is
PIN-protected, but not PIN-derived (there is no salt to use to derive
a key), but the data in PRINTED is not correct. In this case, the
method will not be able to authenticate the management key as
PIN-protected. It will try to authenticate using the default
management key, and if that does not work, it will call on the
KeyCollector
to obtain the it. If that does succeeds, it will
set ADMIN DATA to indicate the YubiKey is not PIN-protected, it will
clear the contents of PRINTED, and it will return
PivPinOnlyMode.None
. If the KeyCollector
is not able to
provide the management key, this method will not be able to reset the
ADMIN DATA nor PRINTED (management key authentication is necessary to
set a storage location), and will return Unavailable
.
This method will require the PIN to be verified. It is possible that
the PIN has already been verified and this method will verify it
again. If it needs to verify the PIN, it will call on the
KeyCollector
to obtain it.
TryResetPin()
Try to reset the PIN, using the PUK (PIN Unblocking Key).
public bool TryResetPin()
Returns
- bool
A boolean,
true
if the PIN is reset,false
if not.
Remarks
If a user loses (or forgets) the PIN, it is possible to reset it
using the PUK. Whether the PIN has been blocked (the wrong value was
entered too many times in calls to TryVerifyPin
or
TryChangePin
, and the retry count was exhausted) or not, it is
possible to reset the PIN to a new value. That is, if the PIN is
blocked, use this method to unblock it. But even if the PIN is not
blocked, you can use this method to reset it.
This is essentially the same operation as TryChangePin
, except
instead of using the current PIN to provide permission to change the
PIN, it uses the PUK.
If the PUK is blocked, this method will not execute. Note that if a YubiKey is configured PIN-only, the PUK will be blocked.
The PIN is six to eight bytes byte long. Although most PINs will be characters, the YubiKey allows any binary data to be a PIN.
In order to change the PUK, both the the current PUK and a new PIN
must be provided. This method will call the KeyCollector
delegate with the Request
of
KeyEntryRequest.ResetPivPinWithPuk
. The KeyCollector
provides both the current PUK and a new PIN. Once it has both the PUK
and a new PIN, this method will try to reset the PIN. That is, this
method will not verify the current PUK in a separate step, the
current PUK will only be verified for the reset with the new PIN.
The KeyCollector
has an option to cancel the operation. That
is, this TryResetPin
method will call the KeyCollector
requesting the PUK and PIN, and it is possible that during the
collection operations, the user cancels. The KeyCollector
will
return to this method noting the cancellation. In that case, this
method will return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
An incorrect current PUK will decrement the remaining tries count. Hence, trying to change the PIN with the wrong current PUK too many times (retry count times) will cause the PUK to be blocked.
If the wrong current PUK is provided, and the remaining retries count
is not zero, the method will call the KeyCollector
again with
KeyEntryData.IsRetry
set to true
and
KeyEntryData.RetriesRemaining
set to the number of tries
remaining until the PUK is blocked. The KeyCollector
can try
to collect the PUK again, but will likely report the retries
remaining to the user and offer the option of canceling. If the
KeyCollector
returns false
, this method will call the
KeyCollector
with Release
and return false
.
If the wrong current PUK is provided, and the remaining retries count
is zero, the method will call the KeyCollector
again,
indicating Release
and then throw an exception. That is, once
the remaining retries count goes to zero the PUK is blocked. At this
point, this method will not try to collect the PUK any more and will
throw an exception.
If there is an error during the process, this method will simply call
the KeyCollector
with Release
and throw an exception.
Note that when this method calls the KeyCollector
with
Release
, the return from the KeyCollector
is ignored,
this method will return true
or false
depending on what
happened before the Release
.
Resetting the PIN does not affect the status of the Session's PIN
verification. That is, the PinVerified
property will not change
after this method completes. If the status is false
(unverified), and the PIN is successfully reset, the PIN will still
be unverified and any operation that requires the PIN (such as
signing), will need the PIN verified (with the new PIN). If the
status is true
(verified) and this method succeeds, the PIN will
still be considered verified (the previous PIN), even though there is
a new PIN. If the status is true
(verified) and this method
fails, the PIN will still be considered verified (the current PIN).
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- SecurityException
The remaining retries count indicates the PUK is blocked.
TryResetPin(ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, out int?)
Try to reset the PIN using the PUK (PIN Unblocking Key). This method
will use the puk
and pin
provided.
public bool TryResetPin(ReadOnlyMemory<byte> puk, ReadOnlyMemory<byte> newPin, out int? retriesRemaining)
Parameters
puk
ReadOnlyMemory<byte>The PIN Unblocking Key.
newPin
ReadOnlyMemory<byte>The new PIN, what the PIN will be changed to.
retriesRemaining
int?An output, it will be set to the number of retries remaining if the PUK is not correct. If the PIN is reset, this will be set to null.
Returns
- bool
A boolean,
true
if the PIN is changed,false
if not.
Remarks
Normally, an application would call the TryResetPin()
method
(no arguments) and the SDK would call on the loaded
KeyCollector
to retrieve the PUK and new PIN. With this
method, the caller provides the PUK and new PIN and the
KeyCollector
is never contacted.
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided.
See the TryResetPin() method for further documentation on this method.
If the wrong PUK is provided, this method will return false
.
Changing the PIN does not affect the status of the Session's PIN
verification. That is, the PinVerified
property will not change
after this method completes. If the status is false
(unverified), and the PIN is successfully changed, the PIN will still
be unverified and any operation that requires the PIN (such as
signing), will need the PIN verified (with the new PIN). If the
status is true
(verified) and this method succeeds, the PIN will
still be considered verified (the previous PIN), even though there is
a new PIN. If the status is true
(verified) and this method
fails, the PIN will still be considered verified (the current PIN).
If the PUK is blocked, this method will not execute. Note that if a YubiKey is configured PIN-only, the PUK will be blocked.
Exceptions
- InvalidOperationException
The YubiKey had some error, such as unreliable connection.
- SecurityException
The remaining retries count indicates the PIN is blocked.
TryVerifyPin()
Try to verify the PIN. If the user cancels, return false
public bool TryVerifyPin()
Returns
- bool
A boolean,
true
if the PIN verifies,false
if theKeyCollector
cancels.
Remarks
You need to verify the PIN only once per session. But if you have already verified, and you call this method, it will perform the verification again. If the verification fails the second time, the previous verification will be nullified.
See the PinVerified property for the current state of PIN verification.
This method will collect the PIN using the KeyCollector
delegate. If no such delegate has been set, this method will throw an
exception.
The KeyCollector
has an option to cancel the operation. That
is, this TryVerifyPin
method will call the KeyCollector
requesting the PIN, and it is possible that during the collection
operations, the user cancels. The KeyCollector
will return to
this method noting the cancellation. In that case, this method will
return false
.
Note that this is the only way to get a false
return. Any
other error and this method will throw an exception. In other words,
a false
return from this method means the user canceled.
This method will also set the PinVerified
property of this
class. That property is a boolean. If true
, the PIN has been
verified this session, otherwise it is false
.
If the PIN verifies, the method will return true
. If not, and
the KeyCollector
cancels the process, the method will return
false
and set the PinVerified
property to false
.
If the PIN does not verify, and the remaining retries count is not
zero, the method will call the KeyCollector
again with
KeyEntryData.IsRetry
set to true
and
KeyEntryData.RetriesRemaining
set to the number of tries
remaining until the PIN is blocked. The KeyCollector
can try
to collect the PIN again, but will likely report the retries
remaining to the user and offer the option of canceling. If the
KeyCollector
returns false
, this method will call the
KeyCollector
with Release
and return false
.
If the PIN does not verify, and the remaining retries count is zero,
the method will call the KeyCollector
again, indicating
Release
and then throw an exception. That is, once the
remaining retries count goes to zero the PIN is blocked. At this
point, this method will not try to collect the PIN any more and will
throw an exception.
If there is an error during the process, this method will simply call
the KeyCollector
with Release
, set the
PinVerified
property to false
, and throw an exception.
Note that when this method calls the KeyCollector
with
Release
, the return from the KeyCollector
is ignored,
this method will return true
or false
depending on what
happened before the Release
.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- SecurityException
The remaining retries count indicates the PIN is blocked.
TryVerifyPin(ReadOnlyMemory<byte>, out int?)
Try to verify the PIN. This method will use the PIN provided, rather
than the KeyCollector
.
public bool TryVerifyPin(ReadOnlyMemory<byte> pin, out int? retriesRemaining)
Parameters
pin
ReadOnlyMemory<byte>The PIN to verify.
retriesRemaining
int?An output, it will be set to the number of retries remaining if the PIN is not verified. If the PIN is verified, this will be set to null.
Returns
- bool
A boolean,
true
if the PIN verifies,false
if not.
Remarks
Normally, an application will not call any VerifyPin
method.
Under the covers, the SDK determines when the PIN needs to be
verified and calls the KeyCollector
. It is only at that point
the application needs to supply the PIN. The SDK will call the
application-supplied KeyCollector
, indicating what it needs
(PIN, PUK, management key), and the KeyCollector
does what it
needs to obtain the value requested. This system also contains a
mechanism to report if the previous value was incorrect and how many
retries remain before the value is blocked. If the PIN is never needed,
the PIN is never provided.
See the User's Manual entry on the Key Collector for a more detailed explanation of this process.
With this method, the caller provides the PIN and the
KeyCollector
is never contacted.
Generally, it is necessary to verify a PIN once per session. Once the PIN is verified, any operation that required the PIN in order to execute, called during that session, will work. The exceptions include performing a private key operation using a key that was generated or imported with the PIN policy of always, changing or resetting a PIN, and setting a YubiKey or session to PIN-derived (note that you should never set a YubiKey to PIN-derived, that feature is provided only for backwards compatibility).
Some applications would like to avoid using a KeyCollector
.
For such situations, this method is provided. As long as the
application does not perform an operation that requires the PIN even
if it has been verified in the session, the KeyCollector
is
not needed.
Note that if the PIN is needed during the session even after the PIN
is verified using this method (see exceptions above), and no
KeyCollector
is provided, the SDK will throw an exception.
The PIN is provided to this method as a
ReadOnlyMemory<byte>
. It is possible to pass a
byte[]
, because it will be automatically cast. Most PINs will
be six to eight numbers, but the YubiKey allows any binary data. For
example, if the PIN is "123456" (the default value), what is actually
supplied to the YubiKey are the six bytes 0x31 32 33 34 35 36
,
the ASCII representation of the numerals '1' through '6'. If the PIN
is "ABCDefg", then the value to send to the YubiKey is the byte array
0x41 42 43 44 65 66 67
. But a PIN could also be
0xE7 05 3F 81 1C C9
. Those are not ASCII characters, but a
YubiKey would accept them.
If the wrong PIN is provided, this method will return false
.
Exceptions
- InvalidOperationException
The YubiKey had some error, such as unreliable connection.
- OperationCanceledException
The wrong PIN was provided.
- SecurityException
The remaining retries count indicates the PIN is blocked.
VerifyPin()
Verify the PIN, throw an exception if the user cancels.
public void VerifyPin()
Remarks
This is the same as TryVerifyPin
, except this method will
throw an exception if the KeyCollecter
indicates user
cancellation.
See the TryVerifyPin() method for further documentation on this method.
Exceptions
- InvalidOperationException
There is no
KeyCollector
loaded, or the YubiKey had some other error, such as unreliable connection.- OperationCanceledException
The user canceled PIN collection.
- SecurityException
The remaining retries count indicates the PIN is blocked.
WriteMsroots(ReadOnlySpan<byte>)
Write contents
to the MSROOTS data objects. This will replace
any data already stored in the MSROOTS data objects.
public void WriteMsroots(ReadOnlySpan<byte> contents)
Parameters
contents
ReadOnlySpan<byte>The data to store, represented as a
ReadOnlySpan
(a byte array).
Remarks
The YubiKey PIV application can store data objects. There is a set of data elements defined by the PIV standard. See the User's Manual entry on GET DATA for information on these elements and their tags. The standard also allows for vendor-defined data objects. MSROOTS is one such vendor-defined element.
The intention of the MSROOTS data object is to store (and retrieve) a PKCS 7 constuction containing a set of root certificates. These certificates will make it easier for the SDK to interface with the Microsoft Smart Card Base Crypto Service Provider (CSP).
Very few applications will need to use this feature. If you don't already know what the MSROOTS are, how to use them, and that they are part of your application already, then you almost certainly will never need to use this method.
This method will take whatever data it is given and store it on the YubiKey under the tag "MSROOTS". This method will not verify that the data is a PKCS 7 construction, or that it contains root certificates, it will simply write the bytes given.
Note that in order to store any data on the YubiKey, it must be formatted as a TLV (tag-length-value):
tag || length || value
for example, it might be
53 20 (contents, 32 bytes)
or
7F 61 20 (contents, 32 bytes)
The tag used varies depending on the data being stored. This method
builds the TLV. That is, the caller supplies the contents only, this
method will format it into a construction the YubiKey expects. This
method knows what tag to use for MSROOTS and how to specify the
length.
Note also that there is a limit to the number of bytes that can be stored in a data object. If the contents to store is longer, then this method will break the data into blocks and store each block in a different data object. The caller simply supplies all the data as a single byte array, this method will take care of the bookkeeping of breaking it into blocks and storing them in separate data objects.
There is a limit on the number of data objects, however, so there is indeed a limit on the total size of the data.
There is a limit of 5 MSROOTS data objects
The limit on data length for each data object is
pre 4.0 YubiKeys (e.g. NEO) : 2030 bytes
4.0 and later YubiKeys : 2800 bytes
The total input limit is
pre 4.0 YubiKeys (e.g. NEO) : 2030*5 bytes : 10,150
4.0 and later YubiKeys : 2800*5 bytes : 14,000
If the data passed in is too long, this method will throw an
exception.
Note that the input is a ReadOnlySpan
. If you have the data in
a byte array (byte[]
), just pass it in as the argument, it
will be cast to a ReadOnlySpan
automatically. Also, if you
have no data to store (which is the same as DeleteMsroots
),
you can pass in null
, but the preferred input in this case is
ReadOnlySpan.Empty
.
Input with a length of 0 is equivalent to calling
DeleteMsroots
.
In order to perform this operation, the management key must be
authenticated during this session. If it has not been authenticated,
this method will call AuthenticateManagementKey(bool). That
is, your application does not need to authenticate the management key
separately (i.e., call TryAuthenticateManagementKey
or
AuthenticateManagementKey
), this method will determine if the
management key has been authenticated or not, and if not, it will
make the call to perform mutual authentication.
The authentication method will collect the management key using the
KeyCollector
delegate. If no such delegate has been set, it
will throw an exception.
The KeyCollector
has an option to cancel the operation. That
is, the AuthenticateManagementKey
method will call the
KeyCollector
requesting the management key, and it is possible
that during the collection operations, the user cancels. The
KeyCollector
will return to the authentication method noting
the cancellation. In that case, it will throw an exception. If you
want the authentication to return false
on user cancellation,
you must call TryAuthenticateManagementKey(bool) directly
before calling this method.
Exceptions
- ArgumentOutOfRangeException
The input data was too long.
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
WriteMsrootsStream(Stream)
Write contents
to the MSROOTS data objects. This will replace
any data already stored in the MSROOTS data objects.
public void WriteMsrootsStream(Stream contents)
Parameters
contents
StreamThe data to store, represented as a
Stream
(theCanRead
property istrue
and the data read will be bytes).
Remarks
This is the same as WriteMsroots(ReadOnlySpan<byte>) except the contents are provided as a Stream.
Exceptions
- ArgumentNullException
The
contents
argument is null.- ArgumentException
The
stream
is not readable.- ArgumentOutOfRangeException
The input data was too long.
- InvalidOperationException
There is no
KeyCollector
loaded, the key provided was not a valid Triple-DES key, or the YubiKey had some other error, such as unreliable connection.- MalformedYubiKeyResponseException
The YubiKey returned malformed data and authentication, either single or double, could not be performed.
- OperationCanceledException
The user canceled management key collection.
- SecurityException
Mutual authentication was performed and the YubiKey was not authenticated.
WriteObject(PivDataObject)
Write the contents of the given object to the storage location specified by the DataTag property.
public void WriteObject(PivDataObject pivDataObject)
Parameters
pivDataObject
PivDataObjectThe object containing the data to store (and the definition of its formatting), along with the data tag under which it is to be stored.
Remarks
This method will call on the pivObject
to encode the data
following its definition, then store that data on the YubiKey under
the PivObject.DataTag
storage location.
See also the user's manual entry on PIV data objects.
Note that it is possible to change the DataTag
, and this method
will store the data under whatever DataTag
is set to.
Note also that this method will overwrite any data already on the YubiKey, if there is any. Hence, make sure you know what data is stored there currently, and that it is safe to overwrite, before calling this method.
If the pivDataObject
has no data (the IsEmpty
property
is true
), then this method will "clear" a storage location. If
there was data in the storage location before the call to
WriteObject
, it will be gone after.
Exceptions
- ArgumentNullException
The
pivDataObject
argument is null.- InvalidOperationException
The method was not able to store the data onto the YubiKey.