How to set, reset, remove, and use slot access codes
The YubiKey's OTP application slots can be protected by a six-byte access code. Once a slot is configured with an access code, that slot cannot be reconfigured in any way unless the correct access code in provided during the reconfiguration operation.
Note
Attempting to perform an OTP application configuration operation without providing the correct access code will result in the following exception:
System.InvalidOperationException has been thrown.
YubiKey Operation Failed. [Warning, state of non-volatile memory is unchanged.]
So for example, let's say that the short press slot of a key was configured with a Yubico OTP credential and a slot
access code. If you want to reconfigure the slot with an OATH HOTP credential, you will have to provide the slot's
access code when calling ConfigureHotp()
.
Access codes can only be set, reset, or removed during another slot configuration operation:
- ConfigureYubicoOtp()
- ConfigureHotp()
- ConfigureChallengeResponse()
- ConfigureStaticPassword()
- UpdateSlot()
Note
If a slot is configured with an access code,
calling ConfigureNdef() will fail,
even
if the correct access code is provided during the operation. Similarly, if a slot is not configured with an access
code,
you cannot set one when calling ConfigureNdef()
.
Slot access code properties
Access codes must be exactly six bytes (MaxAccessCodeLength). The SlotAccessCode container class pads the code with zeros (0x00) if less than six bytes are provided and throws an exception if more than six bytes are provided.
If a slot is configured with an access code, that code must be specified during any reconfiguration operation. In addition, if you don’t also resupply the same (or any) code as a "new" access code, an access code will not be carried over to the new slot configuration, and the slot will no longer be protected after reconfiguration.
Example code
Before running any of the code provided below, make sure you have already connected to a particular YubiKey on your host device via the YubiKeyDevice class.
To select the first available YubiKey connected to your host, use:
IEnumerable<IYubiKeyDevice> yubiKeyList = YubiKeyDevice.FindAll();
var yubiKey = yubiKeyList.First();
Exampe: set a slot access code
To set a slot's access code when no access code is present,
call SetNewAccessCode()
during a slot configuration operation, and provide the access code as a SlotAccessCode
object. Prior to the
configuration operation, initialize the SlotAccessCode
object by passing it the access code
in ReadOnlyMemory<byte>
form.
using (OtpSession otp = new OtpSession(yubiKey))
{
ReadOnlyMemory<byte> hmacKey = new byte[ConfigureHotp.HmacKeySize] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
ReadOnlyMemory<byte> accessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, };
SlotAccessCode accessCode = new SlotAccessCode(accessCodeBytes);
otp.ConfigureHotp(Slot.LongPress)
.UseKey(hmacKey)
.SetNewAccessCode(accessCode)
.Execute();
}
Example: reset a slot access code
To reset a slot's access code, you must provide the current access code
with UseCurrentAccessCode()
followed by the new access code with SetNewAccessCode()
:
using (OtpSession otp = new OtpSession(yubiKey))
{
ReadOnlyMemory<byte> hmacKey = new byte[ConfigureHotp.HmacKeySize] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
ReadOnlyMemory<byte> currentAccessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, };
SlotAccessCode currentAccessCode = new SlotAccessCode(currentAccessCodeBytes);
ReadOnlyMemory<byte> newAccessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, };
SlotAccessCode newAccessCode = new SlotAccessCode(newAccessCodeBytes);
otp.ConfigureHotp(Slot.LongPress)
.UseKey(hmacKey)
.UseCurrentAccessCode(currentAccessCode)
.SetNewAccessCode(newAccessCode)
.Execute();
}
Example: remove a slot access code
If you want to remove a slot's access code, you must either:
- provide a new access code of all zeros, or
- only call
UseCurrentAccessCode()
during the reconfiguration operation. The slot's access code will be removed if a code is not provided viaSetNewAccessCode()
after callingUseCurrentAccessCode()
.
Note
A 6-byte access code of zeros (0x00) is considered no access code. The factory default state of the access code for each OTP slot is all zeros.
Once the access code is removed, you do not need to call UseCurrentAccessCode()
with subsequent configuration
operations.
Note
Technically, if a slot does not have an access code, you could provide any 6-byte code
with UseCurrentAccessCode()
, and the operation would succeed.
using (OtpSession otp = new OtpSession(yubiKey))
{
ReadOnlyMemory<byte> hmacKey = new byte[ConfigureHotp.HmacKeySize] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
ReadOnlyMemory<byte> currentAccessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, };
SlotAccessCode currentAccessCode = new SlotAccessCode(currentAccessCodeBytes);
// New access code of all zeros.
ReadOnlyMemory<byte> newAccessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
SlotAccessCode newAccessCode = new SlotAccessCode(newAccessCodeBytes);
otp.ConfigureHotp(Slot.LongPress)
.UseKey(hmacKey)
.UseCurrentAccessCode(currentAccessCode)
.SetNewAccessCode(newAccessCode)
.Execute();
}
Example: provide a slot access code during a configuration operation
Once a slot has been configured with an access code, you must provide that access code with UseCurrentAccessCode()
when performing a configuration operation on that slot. To retain the access code, you must also
call SetNewAccessCode()
. If you do not call SetNewAccessCode()
, the access code will be removed.
using (OtpSession otp = new OtpSession(yubiKey))
{
ReadOnlyMemory<byte> currentAccessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, };
SlotAccessCode currentAccessCode = new SlotAccessCode(currentAccessCodeBytes);
Memory<byte> privateId = new byte[ConfigureYubicoOtp.PrivateIdentifierSize];
Memory<byte> aesKey = new byte[ConfigureYubicoOtp.KeySize];
otp.ConfigureYubicoOtp(Slot.LongPress)
.UseCurrentAccessCode(currentAccessCode)
.SetNewAccessCode(currentAccessCode)
.UseSerialNumberAsPublicId()
.GeneratePrivateId(privateId)
.GenerateKey(aesKey)
.Execute();
}
In this example, the slot is now configured with a Yubico OTP credential and is still protected by the same access
code (currentAccessCode
).
Deleting a slot configuration when an access code is present
To delete a slot configuration that is protected with an access code, you must
call DeleteSlotConfiguration
and provide the current access code with UseCurrentAccessCode()
. You cannot set a new access code during this
operation--calling SetNewAccessCode()
will succeed, but the operation will not be applied.
using (OtpSession otp = new OtpSession(yubiKey))
{
ReadOnlyMemory<byte> currentAccessCodeBytes = new byte[SlotAccessCode.MaxAccessCodeLength] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, };
SlotAccessCode currentAccessCode = new SlotAccessCode(currentAccessCodeBytes);
otp.DeleteSlotConfiguration(Slot.LongPress)
.UseCurrentAccessCode(currentAccessCode)
.Execute();
}
To delete a slot configuration that is not protected with an access code, use DeleteSlot().