PutDataCommand Class
Namespace: Yubico.YubiKey.Piv.Commands Assembly: Yubico.YubiKey.dllPut a Data Object onto the YubiKey in a storage location.
public sealed class PutDataCommand : Object, IYubiKeyCommand<PutDataResponse>
Implements
Remarks
The partner Response class is PutDataResponse.
See also the User's Manual entries on Get and Put Data and PIV objects.
A Data Object is a DataTag/Data pair. Think of it as a "key-value pair", with the DataTag a key and the Data a value. The DataTag is simply a number and associated with each is a definition of data elements and how they are encoded.
The PIV standard specifies a set of Data Objects. See a description of each DataTag and the associated Data in the User's Manual entry on the GET DATA command. Yubico specifies some non-standard DataTags as well. See descriptions in the User's Manual entry on Get and Put vendor data. The YubiKey also allows an application to use undefined DataTags as well. See the See the User's Manual entry on Data Objects for a table describing the undefined DataTags.
The caller supplies the DataTag and the data, this command will store that data on the YubiKey under the DataTag. If the YubiKey already contains information under the given DataTag, this command replaces it.
Note that for some Data Objects there are higher-level APIs that are easier to use. An application that needs to store information often will not need to use this command. For example, if you want to put a certificate onto a YubiKey, use ImportCertificate(Byte, X509Certificate2). Or if you want to store/retrieve Key History, use ReadObject<T>() and WriteObject(PivDataObject) along with the KeyHistory class. Under the covers, these APIs will ultimately call this command. But the application that uses the SDK can simply make the specific API calls, rather than use Put Data.
There are a number of ways to use this command. The old, obsolete way is
to provide the DataTag using the PivDataTag
enum, along with data
encoded as defined by PIV. The constructor
PutDataCommand(PivDataTag, ReadOnlyMemory<byte>)
and the
properties Tag
and EncodedData
require using PIV-defined
DataTags with PIV-defined encoded data only. This constructor and these
properties are marked "Obsolete" and will be removed from the SDK in the
future. However, it will still be possible to get the same functionality
using the updated API.
The API you should use are the constructors PutDataCommand()
, and
PutDataCommand(int, ReadOnlyMemory<byte>)
c>, along with the
properties DataTag
and Data
. Using these will allow you to
use any DataTag (not just those defined by PIV) and any data (not just
the data and encoding specified by PIV). There are two restrictions on
the data. One, each storage area on the YubiKey can only store up to
2,800 bytes, and two, the data must be encoded as
53 length
data
For example, to store 04 02 55 44 02 01 7F
the data must be provided as
53 07
04 02 55 44 02 01 7F
While you can store any data under a PIV-defined DataTag, if you want to
use only PIV-defined DataTags, and want to verify that the encoding
follows the PIV standard (as happens using the old, obsolete API), you
can use the PivDataTag
class. For example,
// Store IrisImages
if (PivDataTag.IrisImages.IsValidEncodingForPut(encodedDataToStore))
{
var putCmd = new PutDataCommand(
(int)PivDataTag.IrisImages, encodedDataToStore);
}
Note that even though it is possible, using this command, to store any
data under a PIV-defined DataTag, it is not recommended. If you have some
other data you would like to store, you can use an "undefined" DataTag.
For example, the YubiKey will store data under the number
0x005F0101
. That is a number not used by PIV and not used by
Yubico. But the YubiKey will accept it. So if you have non-PIV data you
want to store, rather than use a PIV-defined number, just use one of the
undefined values. See the User's Manual entry on
Data Objects
for tables describing possible DataTags.
There is probably only one reason to store non-PIV data under a PIV-defined DataTag, and that is to require the PIN to retrieve. There are four PIV-defined DataTags for which the PIN is required to retrieve the data: Printed, Iris, FacialImages, and Fingerprints. Data stored under any other DataTag can be retrieved by anyone with access to the YubiKey. If you want to store some data and want it to be accessible only with PIN verification, then you must store it under one of those DataTags. However, Yubico already stores data under the Printed DataTag. That data is needed to configure the YubiKey in "PIN-Protected mode". Hence, it would be a good idea to stay away from that DataTag.
This command will not allow putting data for all PIV data tags. The Discovery and BITGT DataTags will not be accepted. The Discovery Data object is fixed data and it would inhibit the YubiKey's ability to operate if that value were changed from what was installed at manufacture. In virtually all real-world applications, this will likely not be a problem.
Note that when you set an object with the DataTag or Data using either the old constructor/properties or the new versions, when you get it (using either old or new), you are getting the same thing. For example,
// Use the old, obsolete API to set the tag and data.
var putCmd = new PutDataCommand()
{
Tag = PivDataTag.KeyHistory,
EncodedData = encodedKeyHistory,
}
PivDataTag pivDataTag = putCmd.Tag;
int dataTag = putCmd.DataTag;
// At this point pivDataTag will equal PivDataTag.KeyHistory = 0x005FC10C
// dataTag will equal 0x005FC10C
// Even though the code used the old API to set the Tag property
// the new API DataTag property will return the same value.
This class will copy a reference to the data to put, so you should not
clear or alter that input data until this class is done with it, which is
after the call to SendCommand
.
Example:
/* This example assumes there is some code that will build an encoded
certificate from an X509Certificate2 object. */
byte[] encodedCertificate = PivPutDataEncodeCertificate(certObject);
IYubiKeyConnection connection = key.Connect(YubiKeyApplication.Piv);
PutDataCommand putDataCommand = new PutDataCommand(
(int)PivDataTag.Authentication, encodedCertificate);
PutDataResponse putDataResponse = connection.SendCommand(putDataCommand);
if (getDataResponse.StatusWord != SWConstants.Success)
{
/* handle case where the the PUT did not work. */
}
Constructors
Name | Description |
---|---|
PutDataCommand() | Initializes a new instance of the |
PutDataCommand(Int32, ReadOnlyMemory<Byte>) | Initializes a new instance of the |
PutDataCommand(PivDataTag, ReadOnlyMemory<Byte>) | WarningThis constructor is obsolete, use Initializes a new instance of the |
Properties
Name | Description |
---|---|
Application | Gets the YubiKeyApplication to which this command belongs. For this command it's PIV. |
Data | The data that will be put onto the YubiKey. |
DataTag | The tag specifying where the data will be put. |
EncodedData | WarningThis property is obsolete, use The data that will be put onto the YubiKey. |
Tag | WarningThis property is obsolete, use The tag specifying where the data will be put. |
Methods
Name | Description |
---|---|
CreateCommandApdu() | Creates a well-formed CommandApdu to send to the YubiKey. |
CreateResponseForApdu(ResponseApdu) | Creates the corresponding IYubiKeyResponse implementation for the current command. |