Migrating from SmartCard.NET to the SDK
You might be using a product called the Yubico SmartCard.NET API, a C# library containing classes an application developer can call to get YubiKey functionality.
If you want to migrate to the SDK, you will need to change your code. This document describes what classes and methods to call in the SDK to perform the operations available in the SmartCard.NET API.
Making a connection
When using the SmartCard.NET product, you started with this:
IEnumerable<YkSmartCard> smartCardList = YkSmartCard.GetSmartCards();
At this point you enumerate through the list to find the YubiKey you want to use. It can be something as simple as
YkSmartCard ykSmartCard = smartCardList.First();
You now have the object that you will use to call the YubiKey.
SDK
See the User's Manual entry on making a connection for details.
Note that to make a connection, you must specify which application you want to use. There are six possible applications: OTP, FIDO, FIDO2, OATH, OpenPgpCard, and PIV.
To migrate from the SmartCard.NET API, you will use the PIV application, building a
PivSession
object.
If building a PIV session, your code will likely look something like this.
IEnumerable<IYubiKeyDevice> yubiKeyList = YubiKeyDevice.FindAll();
IYubiKeyDevice yubiKeyToUse = yubiKeyList.First();
using var pivSession = new PivSession(yubiKeyToUse);
Get the firmware version
In the SmartCard.NET API, here is how you get the firmware version.
byte[] versionNumber = ykSmartCard.GetFirmwareVersion();
The result is five bytes. Only the first three bytes make up the actual version number.
byte versionMajor = versionNumber[0];
byte versionMinor = versionNumber[1];
byte versionPatch = versionNumber[2];
SDK
With the SDK, you do not need to perform any operation other than choosing the YubiKey,
because one of the properties in the IYubiKeyDevice
is FirmwareVersion
.
IEnumerable<IYubiKeyDevice> yubiKeyList = YubiKeyDevice.FindAll();
IYubiKeyDevice yubiKeyToUse = yubiKeyList.First();
FirmwareVersion versionNumber = yubiKeyToUse.FirmwareVersion;
Inside the FirmwareVersion
class are
byte versionMajor = versionNumber.Major;
byte versionMinor = versionNumber.Minor;
byte versionPatch = versionNumber.Patch;
Get the serial number
In the SmartCard.NET API, here is how you get the serial number.
string serialNumber = ykSmartCard.GetSerialNumber();
If you want the value as an int, you can use Parse
or TryParse
.
bool isParsed = Int32.TryParse(serialNumber, out int serialNumberAsInt);
SDK
With the SDK, you do not need to perform any operation other than choosing the YubiKey,
because one of the properties in the IYubiKeyDevice
is SerialNumber
.
IEnumerable<IYubiKeyDevice> yubiKeyList = YubiKeyDevice.FindAll();
IYubiKeyDevice yubiKeyToUse = yubiKeyList.First();
int serialNumber = yubiKeyToUse.SerialNumber;
If you want the serial number as a string (as was returned in the SmartCard.NET API), use
the ToString
method. To get the exact same result, set the format.
string serialNumberString = yubiKeyToUse.SerialNumber.ToString("00000000");
Change the management key
In the SmartCard.NET API, here is how you change the management key.
byte[] oldKey = CollectMgmtKey();
byte[] newKey = CollectNewMgmtKey();
ykSmartCard.ChangeManagementKey(oldKey, newKey);
SDK
To change the management key, use the PivSession.TryChangeManagementKey
.
In order to change the management key, the existing key must be authenticated first. There
is a method in the PivSession
class, TryAuthenticateManagementKey
, but it is called
automatically by the TryChangeManagementKey
method if needed. Hence, you can
authenticate the existing key first if you want, but it is not necessary.
The methods that authenticate the current management key and change it will obtain the
keys using the KeyCollector
. see the User's Manual entry on
delegates for a discussion of the KeyCollector
.
using var pivSession = new PivSession(yubiKeyToUse)
{
bool isChanged = pivSession.TryChangeManagementKey();
if (!isChanged)
{
// handle error case.
}
}
Change the PIN
In the SmartCard.NET API, here is how you change the PIN.
string oldPin = CollectPin();
string newPin = CollectNewPin();
ykSmartCard.ChangePin(oldPin, newPin, out int retriesRemaining);
SDK
The method to change the PIN will obtain the current and new PINs using the
KeyCollector
. see the User's Manual entry on delegates for a
discussion of the KeyCollector
.
using var pivSession = new PivSession(yubiKeyToUse)
{
bool isChanged = pivSession.TryChangePin();
if (!isChanged)
{
// handle error case.
}
}
Change the PUK
In the SmartCard.NET API, here is how you change the PUK.
string oldPuk = CollectPuk();
string newPuk = CollectNewPuk();
ykSmartCard.ChangePuk(oldPuk, newPuk, out int retriesRemaining);
SDK
The method to change the PUK will obtain the current and new PUKs using the
KeyCollector
. see the User's Manual entry on delegates for a
discussion of the KeyCollector
.
using var pivSession = new PivSession(yubiKeyToUse)
{
bool isChanged = pivSession.TryChangePuk();
if (!isChanged)
{
// handle error case.
}
}
Unblock the PIN
In the SmartCard.NET API, here is how you use the PUK to unblock the PIN.
string puk = CollectPuk();
string newPin = CollectNewPin();
ykSmartCard.UnblockPin(puk, newPin, out int retriesRemaining);
SDK
The method to change the recover the PIN using the PUK will obtain the PUK and new PIN
using the KeyCollector
. see the User's Manual entry on delegates
for a discussion of the KeyCollector
.
using var pivSession = new PivSession(yubiKeyToUse)
{
bool isChanged = pivSession.TryResetPin();
if (!isChanged)
{
// handle error case.
}
}
Write MSROOTS
In the SmartCard.NET API, here is how you load the MSROOTS data onto the YubiKey.
// Note that there is a limit of 3058 bytes for the data.
byte[] msRootsData = CollectMsRootsData();
string pin = CollectPin();
var memoryStream = new MemoryStream(msRootsData);
ykSmartCard.WriteMsRootsData(pin, memoryStream);
SDK
The method to write the MSROOTS requires management key authentication. The method will
make the appropriate calls to authenticate the management key, if it has not been
authenticated yet, just make sure the KeyCollector
has been loaded. see the User's
Manual entry on delegates for a discussion of the KeyCollector
.
Note that there are two versions of this method, one that takes in a byte array and
another that takes in a Stream
.
using var pivSession = new PivSession(yubiKeyToUse)
{
byte[] msRootsData = CollectMsRootsData();
bool isWritten = pivSession.WriteMsroots(msrootsData);
if (!isWritten)
{
// handle error case.
}
}
using var pivSession = new PivSession(yubiKeyToUse)
{
byte[] msRootsData = CollectMsRootsData();
var memoryStream = new MemoryStream(msRootsData);
bool isWritten = pivSession.WriteMsrootsStream(memoryStream);
if (!isWritten)
{
// handle error case.
}
}
Read MSROOTS
In the SmartCard.NET API, here is how you obtain the MSROOTS data from the YubiKey.
Stream getData = ykSmartCard.ReadMsroots();
SDK
Note that there are two versions of this method, one that returns a byte array and another
that returns a Stream
.
using var pivSession = new PivSession(yubiKeyToUse)
{
byte[] msrootsContents = pivSession.ReadMsroots();
}
using var pivSession = new PivSession(yubiKeyToUse)
{
Stream msrootsContents = pivSession.ReadMsrootsStream();
}
Delete MSROOTS
In the SmartCard.NET API, here is how you delete any MSROOTS data on the YubiKey.
ykSmartCard.DeleteMsroots(pinString);
SDK
The method to delete the MSROOTS requires management key authentication. The method will
make the appropriate calls to authenticate the management key, if it has not been
authenticated yet, just make sure the KeyCollector
has been loaded. see the User's
Manual entry on delegates for a discussion of the KeyCollector
.
using var pivSession = new PivSession(yubiKeyToUse)
{
pivSession.DeleteMsroots();
}
Create attestation statement
You can obtain an attestation statement (which is an X.509 certificate) only for keys generated by the YubiKey itself. You cannot get one from a key imported into the YubiKey.
Suppose you generated a key pair in Slot 9A. Here's how you would get an attestation statement for that key pair.
var cspParams = new CspParameters(1, "Microsoft Base Smart Card Crypto Provider");
var rsaProvider = new RSACryptoServiceProvider(cspParams);
string containerGuid = rsaProvider.CspKeyContainerInfo.UniqueKeyContainerName;
byte[] attestationStatement = ykSmartCard.Attest(containerGuid);
SDK
using var pivSession = new PivSession(yubiKeyToUse)
{
bool isValid = pivSession.TryCreateAttestationStatement(0x9A, out X509Certificate2? attestationStatement);
if (!isValid)
{
// Handle error case.
}
}
Reset the card
In the SmartCard.NET API, here is how you load the MSROOTS data onto the YubiKey.
ykSmartCard.ResetCard();
SDK
To reset the PIV application on the YubiKey, both the PIN and PUK must be blocked. The SDK's reset method will perform the necessary operations needed to block the PIN and PUK. That is, simply call this method to reset, there's no need to do any work yourself to make sure the PIN and PUK are blocked.
using var pivSession = new PivSession(yubiKeyToUse)
{
bool isReset = pivSession.TryResetPiv();
if (!isReset)
{
// handle error case.
}
}