Show / Hide Table of Contents

PutDataCommand Class

Namespace: Yubico.YubiKey.Piv.Commands Assembly: Yubico.YubiKey.dll

Put a Data Object onto the YubiKey in a storage location.

C#
public sealed class PutDataCommand : IYubiKeyCommand<PutDataResponse>
Inheritance object PutDataCommand
Implements
IYubiKeyCommand<PutDataResponse>

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 class.

PutDataCommand(int, ReadOnlyMemory<byte>)

Initializes a new instance of the PutDataCommand class.

PutDataCommand(PivDataTag, ReadOnlyMemory<byte>)
Warning

This constructor is obsolete, use PutDataCommand() or PutDataCommand(int, ReadOnlyMemory<byte>) instead.

Initializes a new instance of the PutDataCommand class. This command takes in a tag indicating which data element to put, and the encoded data to load onto the YubiKey.

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
Warning

This property is obsolete, use Data instead.

The data that will be put onto the YubiKey.

Tag
Warning

This property is obsolete, use DataTag instead.

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.

In this article
Back to top Generated by DocFX