Merge pull request #44 from str4d/more-enums
Convert SlotId and AlgorithmId into enums
This commit is contained in:
+4
-9
@@ -31,13 +31,8 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::*,
|
consts::*, error::Error, key::SlotId, serialization::*, transaction::Transaction,
|
||||||
error::Error,
|
yubikey::YubiKey, Buffer,
|
||||||
key::{self, SlotId},
|
|
||||||
serialization::*,
|
|
||||||
transaction::Transaction,
|
|
||||||
yubikey::YubiKey,
|
|
||||||
Buffer,
|
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
@@ -100,7 +95,7 @@ impl AsRef<[u8]> for Certificate {
|
|||||||
/// Read certificate
|
/// Read certificate
|
||||||
pub(crate) fn read_certificate(txn: &Transaction<'_>, slot: SlotId) -> Result<Buffer, Error> {
|
pub(crate) fn read_certificate(txn: &Transaction<'_>, slot: SlotId) -> Result<Buffer, Error> {
|
||||||
let mut len: usize = 0;
|
let mut len: usize = 0;
|
||||||
let object_id = key::slot_object(slot)?;
|
let object_id = slot.object_id();
|
||||||
|
|
||||||
let mut buf = match txn.fetch_object(object_id) {
|
let mut buf = match txn.fetch_object(object_id) {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
@@ -141,7 +136,7 @@ pub(crate) fn write_certificate(
|
|||||||
let mut buf = [0u8; CB_OBJ_MAX];
|
let mut buf = [0u8; CB_OBJ_MAX];
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
|
|
||||||
let object_id = key::slot_object(slot)?;
|
let object_id = slot.object_id();
|
||||||
|
|
||||||
if data.is_none() {
|
if data.is_none() {
|
||||||
return txn.save_object(object_id, &[]);
|
return txn.save_object(object_id, &[]);
|
||||||
|
|||||||
@@ -124,10 +124,6 @@ pub const TAG_ECC_POINT: u8 = 0x86;
|
|||||||
|
|
||||||
pub const YKPIV_ALGO_TAG: u8 = 0x80;
|
pub const YKPIV_ALGO_TAG: u8 = 0x80;
|
||||||
pub const YKPIV_ALGO_3DES: u8 = 0x03;
|
pub const YKPIV_ALGO_3DES: u8 = 0x03;
|
||||||
pub const YKPIV_ALGO_RSA1024: u8 = 0x06;
|
|
||||||
pub const YKPIV_ALGO_RSA2048: u8 = 0x07;
|
|
||||||
pub const YKPIV_ALGO_ECCP256: u8 = 0x11;
|
|
||||||
pub const YKPIV_ALGO_ECCP384: u8 = 0x14;
|
|
||||||
|
|
||||||
pub const YKPIV_ATR_NEO_R3: &[u8] = b";\xFC\x13\0\0\x811\xFE\x15YubikeyNEOr3\xE1\0";
|
pub const YKPIV_ATR_NEO_R3: &[u8] = b";\xFC\x13\0\0\x811\xFE\x15YubikeyNEOr3\xE1\0";
|
||||||
|
|
||||||
@@ -141,72 +137,21 @@ pub const YKPIV_CCCID_SIZE: usize = 14;
|
|||||||
pub const YKPIV_CERTINFO_UNCOMPRESSED: u8 = 0;
|
pub const YKPIV_CERTINFO_UNCOMPRESSED: u8 = 0;
|
||||||
pub const YKPIV_CERTINFO_GZIP: u8 = 1;
|
pub const YKPIV_CERTINFO_GZIP: u8 = 1;
|
||||||
|
|
||||||
pub const YKPIV_KEY_AUTHENTICATION: u8 = 0x9a;
|
|
||||||
pub const YKPIV_KEY_CARDMGM: u8 = 0x9b;
|
pub const YKPIV_KEY_CARDMGM: u8 = 0x9b;
|
||||||
pub const YKPIV_KEY_SIGNATURE: u8 = 0x9c;
|
|
||||||
pub const YKPIV_KEY_KEYMGM: u8 = 0x9d;
|
|
||||||
pub const YKPIV_KEY_CARDAUTH: u8 = 0x9e;
|
|
||||||
pub const YKPIV_KEY_RETIRED1: u8 = 0x82;
|
|
||||||
pub const YKPIV_KEY_RETIRED2: u8 = 0x83;
|
|
||||||
pub const YKPIV_KEY_RETIRED3: u8 = 0x84;
|
|
||||||
pub const YKPIV_KEY_RETIRED4: u8 = 0x85;
|
|
||||||
pub const YKPIV_KEY_RETIRED5: u8 = 0x86;
|
|
||||||
pub const YKPIV_KEY_RETIRED6: u8 = 0x87;
|
|
||||||
pub const YKPIV_KEY_RETIRED7: u8 = 0x88;
|
|
||||||
pub const YKPIV_KEY_RETIRED8: u8 = 0x89;
|
|
||||||
pub const YKPIV_KEY_RETIRED9: u8 = 0x8a;
|
|
||||||
pub const YKPIV_KEY_RETIRED10: u8 = 0x8b;
|
|
||||||
pub const YKPIV_KEY_RETIRED11: u8 = 0x8c;
|
|
||||||
pub const YKPIV_KEY_RETIRED12: u8 = 0x8d;
|
|
||||||
pub const YKPIV_KEY_RETIRED13: u8 = 0x8e;
|
|
||||||
pub const YKPIV_KEY_RETIRED14: u8 = 0x8f;
|
|
||||||
pub const YKPIV_KEY_RETIRED15: u8 = 0x90;
|
|
||||||
pub const YKPIV_KEY_RETIRED16: u8 = 0x91;
|
|
||||||
pub const YKPIV_KEY_RETIRED17: u8 = 0x92;
|
|
||||||
pub const YKPIV_KEY_RETIRED18: u8 = 0x93;
|
|
||||||
pub const YKPIV_KEY_RETIRED19: u8 = 0x94;
|
|
||||||
pub const YKPIV_KEY_RETIRED20: u8 = 0x95;
|
|
||||||
pub const YKPIV_KEY_ATTESTATION: u8 = 0xf9;
|
|
||||||
|
|
||||||
pub const YKPIV_OBJ_CAPABILITY: u32 = 0x005f_c107;
|
pub const YKPIV_OBJ_CAPABILITY: u32 = 0x005f_c107;
|
||||||
pub const YKPIV_OBJ_CHUID: u32 = 0x005f_c102;
|
pub const YKPIV_OBJ_CHUID: u32 = 0x005f_c102;
|
||||||
pub const YKPIV_OBJ_AUTHENTICATION: u32 = 0x005f_c105; // cert for 9a key
|
|
||||||
pub const YKPIV_OBJ_FINGERPRINTS: u32 = 0x005f_c103;
|
pub const YKPIV_OBJ_FINGERPRINTS: u32 = 0x005f_c103;
|
||||||
pub const YKPIV_OBJ_SECURITY: u32 = 0x005f_c106;
|
pub const YKPIV_OBJ_SECURITY: u32 = 0x005f_c106;
|
||||||
pub const YKPIV_OBJ_FACIAL: u32 = 0x005f_c108;
|
pub const YKPIV_OBJ_FACIAL: u32 = 0x005f_c108;
|
||||||
pub const YKPIV_OBJ_PRINTED: u32 = 0x005f_c109;
|
pub const YKPIV_OBJ_PRINTED: u32 = 0x005f_c109;
|
||||||
pub const YKPIV_OBJ_SIGNATURE: u32 = 0x005f_c10a; // cert for 9c key
|
|
||||||
pub const YKPIV_OBJ_KEY_MANAGEMENT: u32 = 0x005f_c10b; // cert for 9d key
|
|
||||||
pub const YKPIV_OBJ_CARD_AUTH: u32 = 0x005f_c101; // cert for 9e key
|
|
||||||
pub const YKPIV_OBJ_DISCOVERY: u32 = 0x7e;
|
pub const YKPIV_OBJ_DISCOVERY: u32 = 0x7e;
|
||||||
pub const YKPIV_OBJ_KEY_HISTORY: u32 = 0x005f_c10c;
|
pub const YKPIV_OBJ_KEY_HISTORY: u32 = 0x005f_c10c;
|
||||||
pub const YKPIV_OBJ_IRIS: u32 = 0x005f_c121;
|
pub const YKPIV_OBJ_IRIS: u32 = 0x005f_c121;
|
||||||
|
|
||||||
pub const YKPIV_OBJ_RETIRED1: u32 = 0x005f_c10d;
|
|
||||||
pub const YKPIV_OBJ_RETIRED2: u32 = 0x005f_c10e;
|
|
||||||
pub const YKPIV_OBJ_RETIRED3: u32 = 0x005f_c10f;
|
|
||||||
pub const YKPIV_OBJ_RETIRED4: u32 = 0x005f_c110;
|
|
||||||
pub const YKPIV_OBJ_RETIRED5: u32 = 0x005f_c111;
|
|
||||||
pub const YKPIV_OBJ_RETIRED6: u32 = 0x005f_c112;
|
|
||||||
pub const YKPIV_OBJ_RETIRED7: u32 = 0x005f_c113;
|
|
||||||
pub const YKPIV_OBJ_RETIRED8: u32 = 0x005f_c114;
|
|
||||||
pub const YKPIV_OBJ_RETIRED9: u32 = 0x005f_c115;
|
|
||||||
pub const YKPIV_OBJ_RETIRED10: u32 = 0x005f_c116;
|
|
||||||
pub const YKPIV_OBJ_RETIRED11: u32 = 0x005f_c117;
|
|
||||||
pub const YKPIV_OBJ_RETIRED12: u32 = 0x005f_c118;
|
|
||||||
pub const YKPIV_OBJ_RETIRED13: u32 = 0x005f_c119;
|
|
||||||
pub const YKPIV_OBJ_RETIRED14: u32 = 0x005f_c11a;
|
|
||||||
pub const YKPIV_OBJ_RETIRED15: u32 = 0x005f_c11b;
|
|
||||||
pub const YKPIV_OBJ_RETIRED16: u32 = 0x005f_c11c;
|
|
||||||
pub const YKPIV_OBJ_RETIRED17: u32 = 0x005f_c11d;
|
|
||||||
pub const YKPIV_OBJ_RETIRED18: u32 = 0x005f_c11e;
|
|
||||||
pub const YKPIV_OBJ_RETIRED19: u32 = 0x005f_c11f;
|
|
||||||
pub const YKPIV_OBJ_RETIRED20: u32 = 0x005f_c120;
|
|
||||||
|
|
||||||
// Internal object IDs
|
// Internal object IDs
|
||||||
|
|
||||||
pub const YKPIV_OBJ_ADMIN_DATA: u32 = 0x005f_ff00;
|
pub const YKPIV_OBJ_ADMIN_DATA: u32 = 0x005f_ff00;
|
||||||
pub const YKPIV_OBJ_ATTESTATION: u32 = 0x005f_ff01;
|
|
||||||
pub const YKPIV_OBJ_MSCMAP: u32 = 0x005f_ff10;
|
pub const YKPIV_OBJ_MSCMAP: u32 = 0x005f_ff10;
|
||||||
pub const YKPIV_OBJ_MSROOTS1: u32 = 0x005f_ff11;
|
pub const YKPIV_OBJ_MSROOTS1: u32 = 0x005f_ff11;
|
||||||
pub const YKPIV_OBJ_MSROOTS2: u32 = 0x005f_ff12;
|
pub const YKPIV_OBJ_MSROOTS2: u32 = 0x005f_ff12;
|
||||||
|
|||||||
+3
-3
@@ -158,7 +158,7 @@ impl Container {
|
|||||||
|
|
||||||
Ok(Container {
|
Ok(Container {
|
||||||
name,
|
name,
|
||||||
slot: bytes[name_bytes_len],
|
slot: bytes[name_bytes_len].try_into()?,
|
||||||
key_spec: bytes[name_bytes_len + 1],
|
key_spec: bytes[name_bytes_len + 1],
|
||||||
key_size_bits: u16::from_le_bytes(
|
key_size_bits: u16::from_le_bytes(
|
||||||
bytes[(name_bytes_len + 2)..(name_bytes_len + 4)]
|
bytes[(name_bytes_len + 2)..(name_bytes_len + 4)]
|
||||||
@@ -185,7 +185,7 @@ impl Container {
|
|||||||
bytes.extend_from_slice(&self.name[i].to_le_bytes());
|
bytes.extend_from_slice(&self.name[i].to_le_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes.push(self.slot);
|
bytes.push(self.slot.into());
|
||||||
bytes.push(self.key_spec);
|
bytes.push(self.key_spec);
|
||||||
bytes.extend_from_slice(&self.key_size_bits.to_le_bytes());
|
bytes.extend_from_slice(&self.key_size_bits.to_le_bytes());
|
||||||
bytes.push(self.flags);
|
bytes.push(self.flags);
|
||||||
@@ -204,7 +204,7 @@ impl Debug for Container {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"PivContainer {{ name: {:?}, slot: {}, key_spec: {}, key_size_bits: {}, \
|
"PivContainer {{ name: {:?}, slot: {:?}, key_spec: {}, key_size_bits: {}, \
|
||||||
flags: {}, pin_id: {}, associated_echd_container: {}, cert_fingerprint: {:?} }}",
|
flags: {}, pin_id: {}, associated_echd_container: {}, cert_fingerprint: {:?} }}",
|
||||||
&self.name[..],
|
&self.name[..],
|
||||||
self.slot,
|
self.slot,
|
||||||
|
|||||||
+266
-60
@@ -45,61 +45,272 @@ use crate::{
|
|||||||
serialization::*,
|
serialization::*,
|
||||||
settings,
|
settings,
|
||||||
yubikey::YubiKey,
|
yubikey::YubiKey,
|
||||||
AlgorithmId, Buffer, ObjectId,
|
Buffer, ObjectId,
|
||||||
};
|
};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
/// Slot identifiers.
|
/// Slot identifiers.
|
||||||
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
|
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
|
||||||
// TODO(tarcieri): replace these with enums
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub type SlotId = u8;
|
pub enum SlotId {
|
||||||
|
/// This certificate and its associated private key is used to authenticate the card
|
||||||
|
/// and the cardholder. This slot is used for things like system login. The end user
|
||||||
|
/// PIN is required to perform any private key operations. Once the PIN has been
|
||||||
|
/// provided successfully, multiple private key operations may be performed without
|
||||||
|
/// additional cardholder consent.
|
||||||
|
Authentication,
|
||||||
|
|
||||||
/// Get the [`ObjectId`] that corresponds to a given [`SlotId`]
|
/// This certificate and its associated private key is used for digital signatures for
|
||||||
// TODO(tarcieri): factor this into a slot ID enum
|
/// the purpose of document signing, or signing files and executables. The end user
|
||||||
pub(crate) fn slot_object(slot: SlotId) -> Result<ObjectId, Error> {
|
/// PIN is required to perform any private key operations. The PIN must be submitted
|
||||||
let id = match slot {
|
/// every time immediately before a sign operation, to ensure cardholder participation
|
||||||
YKPIV_KEY_AUTHENTICATION => YKPIV_OBJ_AUTHENTICATION,
|
/// for every digital signature generated.
|
||||||
YKPIV_KEY_SIGNATURE => YKPIV_OBJ_SIGNATURE,
|
Signature,
|
||||||
YKPIV_KEY_KEYMGM => YKPIV_OBJ_KEY_MANAGEMENT,
|
|
||||||
YKPIV_KEY_CARDAUTH => YKPIV_OBJ_CARD_AUTH,
|
/// This certificate and its associated private key is used for encryption for the
|
||||||
YKPIV_KEY_ATTESTATION => YKPIV_OBJ_ATTESTATION,
|
/// purpose of confidentiality. This slot is used for things like encrypting e-mails
|
||||||
slot if slot >= YKPIV_KEY_RETIRED1 && (slot <= YKPIV_KEY_RETIRED20) => {
|
/// or files. The end user PIN is required to perform any private key operations. Once
|
||||||
YKPIV_OBJ_RETIRED1 + (slot - YKPIV_KEY_RETIRED1) as u32
|
/// the PIN has been provided successfully, multiple private key operations may be
|
||||||
|
/// performed without additional cardholder consent.
|
||||||
|
KeyManagement,
|
||||||
|
|
||||||
|
/// This certificate and its associated private key is used to support additional
|
||||||
|
/// physical access applications, such as providing physical access to buildings via
|
||||||
|
/// PIV-enabled door locks. The end user PIN is NOT required to perform private key
|
||||||
|
/// operations for this slot.
|
||||||
|
CardAuthentication,
|
||||||
|
|
||||||
|
/// These slots are only available on the YubiKey 4 & 5. They are meant for previously
|
||||||
|
/// used Key Management keys to be able to decrypt earlier encrypted documents or
|
||||||
|
/// emails. In the YubiKey 4 & 5 all 20 of them are fully available for use.
|
||||||
|
Retired(RetiredSlotId),
|
||||||
|
|
||||||
|
/// This slot is only available on YubiKey version 4.3 and newer. It is only used for
|
||||||
|
/// attestation of other keys generated on device with instruction `f9`. This slot is
|
||||||
|
/// not cleared on reset, but can be overwritten.
|
||||||
|
Attestation,
|
||||||
}
|
}
|
||||||
_ => return Err(Error::InvalidObject),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(id)
|
impl TryFrom<u8> for SlotId {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0x9a => Ok(SlotId::Authentication),
|
||||||
|
0x9c => Ok(SlotId::Signature),
|
||||||
|
0x9d => Ok(SlotId::KeyManagement),
|
||||||
|
0x9e => Ok(SlotId::CardAuthentication),
|
||||||
|
0xf9 => Ok(SlotId::Attestation),
|
||||||
|
_ => RetiredSlotId::try_from(value).map(SlotId::Retired),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SlotId> for u8 {
|
||||||
|
fn from(slot: SlotId) -> u8 {
|
||||||
|
match slot {
|
||||||
|
SlotId::Authentication => 0x9a,
|
||||||
|
SlotId::Signature => 0x9c,
|
||||||
|
SlotId::KeyManagement => 0x9d,
|
||||||
|
SlotId::CardAuthentication => 0x9e,
|
||||||
|
SlotId::Retired(retired) => retired.into(),
|
||||||
|
SlotId::Attestation => 0xf9,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SlotId {
|
||||||
|
/// Returns the [`ObjectId`] that corresponds to a given [`SlotId`].
|
||||||
|
pub(crate) fn object_id(self) -> ObjectId {
|
||||||
|
match self {
|
||||||
|
SlotId::Authentication => 0x005f_c105,
|
||||||
|
SlotId::Signature => 0x005f_c10a,
|
||||||
|
SlotId::KeyManagement => 0x005f_c10b,
|
||||||
|
SlotId::CardAuthentication => 0x005f_c101,
|
||||||
|
SlotId::Retired(retired) => retired.object_id(),
|
||||||
|
SlotId::Attestation => 0x005f_ff01,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retired slot IDs.
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum RetiredSlotId {
|
||||||
|
R1,
|
||||||
|
R2,
|
||||||
|
R3,
|
||||||
|
R4,
|
||||||
|
R5,
|
||||||
|
R6,
|
||||||
|
R7,
|
||||||
|
R8,
|
||||||
|
R9,
|
||||||
|
R10,
|
||||||
|
R11,
|
||||||
|
R12,
|
||||||
|
R13,
|
||||||
|
R14,
|
||||||
|
R15,
|
||||||
|
R16,
|
||||||
|
R17,
|
||||||
|
R18,
|
||||||
|
R19,
|
||||||
|
R20,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for RetiredSlotId {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0x82 => Ok(RetiredSlotId::R1),
|
||||||
|
0x83 => Ok(RetiredSlotId::R2),
|
||||||
|
0x84 => Ok(RetiredSlotId::R3),
|
||||||
|
0x85 => Ok(RetiredSlotId::R4),
|
||||||
|
0x86 => Ok(RetiredSlotId::R5),
|
||||||
|
0x87 => Ok(RetiredSlotId::R6),
|
||||||
|
0x88 => Ok(RetiredSlotId::R7),
|
||||||
|
0x89 => Ok(RetiredSlotId::R8),
|
||||||
|
0x8a => Ok(RetiredSlotId::R9),
|
||||||
|
0x8b => Ok(RetiredSlotId::R10),
|
||||||
|
0x8c => Ok(RetiredSlotId::R11),
|
||||||
|
0x8d => Ok(RetiredSlotId::R12),
|
||||||
|
0x8e => Ok(RetiredSlotId::R13),
|
||||||
|
0x8f => Ok(RetiredSlotId::R14),
|
||||||
|
0x90 => Ok(RetiredSlotId::R15),
|
||||||
|
0x91 => Ok(RetiredSlotId::R16),
|
||||||
|
0x92 => Ok(RetiredSlotId::R17),
|
||||||
|
0x93 => Ok(RetiredSlotId::R18),
|
||||||
|
0x94 => Ok(RetiredSlotId::R19),
|
||||||
|
0x95 => Ok(RetiredSlotId::R20),
|
||||||
|
_ => Err(Error::InvalidObject),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RetiredSlotId> for u8 {
|
||||||
|
fn from(slot: RetiredSlotId) -> u8 {
|
||||||
|
match slot {
|
||||||
|
RetiredSlotId::R1 => 0x82,
|
||||||
|
RetiredSlotId::R2 => 0x83,
|
||||||
|
RetiredSlotId::R3 => 0x84,
|
||||||
|
RetiredSlotId::R4 => 0x85,
|
||||||
|
RetiredSlotId::R5 => 0x86,
|
||||||
|
RetiredSlotId::R6 => 0x87,
|
||||||
|
RetiredSlotId::R7 => 0x88,
|
||||||
|
RetiredSlotId::R8 => 0x89,
|
||||||
|
RetiredSlotId::R9 => 0x8a,
|
||||||
|
RetiredSlotId::R10 => 0x8b,
|
||||||
|
RetiredSlotId::R11 => 0x8c,
|
||||||
|
RetiredSlotId::R12 => 0x8d,
|
||||||
|
RetiredSlotId::R13 => 0x8e,
|
||||||
|
RetiredSlotId::R14 => 0x8f,
|
||||||
|
RetiredSlotId::R15 => 0x90,
|
||||||
|
RetiredSlotId::R16 => 0x91,
|
||||||
|
RetiredSlotId::R17 => 0x92,
|
||||||
|
RetiredSlotId::R18 => 0x93,
|
||||||
|
RetiredSlotId::R19 => 0x94,
|
||||||
|
RetiredSlotId::R20 => 0x95,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RetiredSlotId {
|
||||||
|
/// Returns the [`ObjectId`] that corresponds to a given [`RetiredSlotId`].
|
||||||
|
pub(crate) fn object_id(self) -> ObjectId {
|
||||||
|
match self {
|
||||||
|
RetiredSlotId::R1 => 0x005f_c10d,
|
||||||
|
RetiredSlotId::R2 => 0x005f_c10e,
|
||||||
|
RetiredSlotId::R3 => 0x005f_c10f,
|
||||||
|
RetiredSlotId::R4 => 0x005f_c110,
|
||||||
|
RetiredSlotId::R5 => 0x005f_c111,
|
||||||
|
RetiredSlotId::R6 => 0x005f_c112,
|
||||||
|
RetiredSlotId::R7 => 0x005f_c113,
|
||||||
|
RetiredSlotId::R8 => 0x005f_c114,
|
||||||
|
RetiredSlotId::R9 => 0x005f_c115,
|
||||||
|
RetiredSlotId::R10 => 0x005f_c116,
|
||||||
|
RetiredSlotId::R11 => 0x005f_c117,
|
||||||
|
RetiredSlotId::R12 => 0x005f_c118,
|
||||||
|
RetiredSlotId::R13 => 0x005f_c119,
|
||||||
|
RetiredSlotId::R14 => 0x005f_c11a,
|
||||||
|
RetiredSlotId::R15 => 0x005f_c11b,
|
||||||
|
RetiredSlotId::R16 => 0x005f_c11c,
|
||||||
|
RetiredSlotId::R17 => 0x005f_c11d,
|
||||||
|
RetiredSlotId::R18 => 0x005f_c11e,
|
||||||
|
RetiredSlotId::R19 => 0x005f_c11f,
|
||||||
|
RetiredSlotId::R20 => 0x005f_c120,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Personal Identity Verification (PIV) key slots
|
/// Personal Identity Verification (PIV) key slots
|
||||||
pub const SLOTS: [u8; 24] = [
|
pub const SLOTS: [SlotId; 24] = [
|
||||||
YKPIV_KEY_AUTHENTICATION,
|
SlotId::Authentication,
|
||||||
YKPIV_KEY_SIGNATURE,
|
SlotId::Signature,
|
||||||
YKPIV_KEY_KEYMGM,
|
SlotId::KeyManagement,
|
||||||
YKPIV_KEY_RETIRED1,
|
SlotId::Retired(RetiredSlotId::R1),
|
||||||
YKPIV_KEY_RETIRED2,
|
SlotId::Retired(RetiredSlotId::R2),
|
||||||
YKPIV_KEY_RETIRED3,
|
SlotId::Retired(RetiredSlotId::R3),
|
||||||
YKPIV_KEY_RETIRED4,
|
SlotId::Retired(RetiredSlotId::R4),
|
||||||
YKPIV_KEY_RETIRED5,
|
SlotId::Retired(RetiredSlotId::R5),
|
||||||
YKPIV_KEY_RETIRED6,
|
SlotId::Retired(RetiredSlotId::R6),
|
||||||
YKPIV_KEY_RETIRED7,
|
SlotId::Retired(RetiredSlotId::R7),
|
||||||
YKPIV_KEY_RETIRED8,
|
SlotId::Retired(RetiredSlotId::R8),
|
||||||
YKPIV_KEY_RETIRED9,
|
SlotId::Retired(RetiredSlotId::R9),
|
||||||
YKPIV_KEY_RETIRED10,
|
SlotId::Retired(RetiredSlotId::R10),
|
||||||
YKPIV_KEY_RETIRED11,
|
SlotId::Retired(RetiredSlotId::R11),
|
||||||
YKPIV_KEY_RETIRED12,
|
SlotId::Retired(RetiredSlotId::R12),
|
||||||
YKPIV_KEY_RETIRED13,
|
SlotId::Retired(RetiredSlotId::R13),
|
||||||
YKPIV_KEY_RETIRED14,
|
SlotId::Retired(RetiredSlotId::R14),
|
||||||
YKPIV_KEY_RETIRED15,
|
SlotId::Retired(RetiredSlotId::R15),
|
||||||
YKPIV_KEY_RETIRED16,
|
SlotId::Retired(RetiredSlotId::R16),
|
||||||
YKPIV_KEY_RETIRED17,
|
SlotId::Retired(RetiredSlotId::R17),
|
||||||
YKPIV_KEY_RETIRED18,
|
SlotId::Retired(RetiredSlotId::R18),
|
||||||
YKPIV_KEY_RETIRED19,
|
SlotId::Retired(RetiredSlotId::R19),
|
||||||
YKPIV_KEY_RETIRED20,
|
SlotId::Retired(RetiredSlotId::R20),
|
||||||
YKPIV_KEY_CARDAUTH,
|
SlotId::CardAuthentication,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Algorithm identifiers
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum AlgorithmId {
|
||||||
|
/// 1024-bit RSA.
|
||||||
|
Rsa1024,
|
||||||
|
/// 2048-bit RSA.
|
||||||
|
Rsa2048,
|
||||||
|
/// ECDSA with the NIST P256 curve.
|
||||||
|
EccP256,
|
||||||
|
/// ECDSA with the NIST P384 curve.
|
||||||
|
EccP384,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for AlgorithmId {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0x06 => Ok(AlgorithmId::Rsa1024),
|
||||||
|
0x07 => Ok(AlgorithmId::Rsa2048),
|
||||||
|
0x11 => Ok(AlgorithmId::EccP256),
|
||||||
|
0x14 => Ok(AlgorithmId::EccP384),
|
||||||
|
_ => Err(Error::AlgorithmError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AlgorithmId> for u8 {
|
||||||
|
fn from(id: AlgorithmId) -> u8 {
|
||||||
|
match id {
|
||||||
|
AlgorithmId::Rsa1024 => 0x06,
|
||||||
|
AlgorithmId::Rsa2048 => 0x07,
|
||||||
|
AlgorithmId::EccP256 => 0x11,
|
||||||
|
AlgorithmId::EccP384 => 0x14,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// PIV cryptographic keys stored in a YubiKey
|
/// PIV cryptographic keys stored in a YubiKey
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Key {
|
pub struct Key {
|
||||||
@@ -120,14 +331,16 @@ impl Key {
|
|||||||
let buf = match certificate::read_certificate(&txn, slot) {
|
let buf = match certificate::read_certificate(&txn, slot) {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("error reading certificate in slot {}: {}", slot, e);
|
debug!("error reading certificate in slot {:?}: {}", slot, e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
let cert = Certificate::new(buf)?;
|
let cert = Certificate::new(buf)?;
|
||||||
keys.push(Key { slot, cert });
|
keys.push(Key { slot, cert });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(keys)
|
Ok(keys)
|
||||||
}
|
}
|
||||||
@@ -202,10 +415,12 @@ pub fn generate(
|
|||||||
let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0];
|
let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0];
|
||||||
let setting_roca: settings::BoolValue;
|
let setting_roca: settings::BoolValue;
|
||||||
|
|
||||||
|
match algorithm {
|
||||||
|
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
|
||||||
if yubikey.device_model() == DEVTYPE_YK4
|
if yubikey.device_model() == DEVTYPE_YK4
|
||||||
&& (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048)
|
|
||||||
&& yubikey.version.major == 4
|
&& yubikey.version.major == 4
|
||||||
&& (yubikey.version.minor < 3 || yubikey.version.minor == 3 && (yubikey.version.patch < 5))
|
&& (yubikey.version.minor < 3
|
||||||
|
|| yubikey.version.minor == 3 && (yubikey.version.patch < 5))
|
||||||
{
|
{
|
||||||
setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true);
|
setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true);
|
||||||
|
|
||||||
@@ -239,18 +454,13 @@ pub fn generate(
|
|||||||
return Err(Error::NotSupported);
|
return Err(Error::NotSupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match algorithm {
|
|
||||||
YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 | YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => (),
|
|
||||||
_ => {
|
|
||||||
error!("invalid algorithm specified");
|
|
||||||
return Err(Error::GenericError);
|
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let txn = yubikey.begin_transaction()?;
|
let txn = yubikey.begin_transaction()?;
|
||||||
|
|
||||||
templ[3] = slot;
|
templ[3] = slot.into();
|
||||||
|
|
||||||
let mut offset = 5;
|
let mut offset = 5;
|
||||||
in_data[..offset].copy_from_slice(&[
|
in_data[..offset].copy_from_slice(&[
|
||||||
@@ -258,7 +468,7 @@ pub fn generate(
|
|||||||
3, // length sans this 2-byte header
|
3, // length sans this 2-byte header
|
||||||
YKPIV_ALGO_TAG,
|
YKPIV_ALGO_TAG,
|
||||||
1,
|
1,
|
||||||
algorithm,
|
algorithm.into(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if in_data[4] == 0 {
|
if in_data[4] == 0 {
|
||||||
@@ -312,7 +522,7 @@ pub fn generate(
|
|||||||
let data = Buffer::new(response.data().into());
|
let data = Buffer::new(response.data().into());
|
||||||
|
|
||||||
match algorithm {
|
match algorithm {
|
||||||
YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => {
|
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
|
||||||
let mut offset = 5;
|
let mut offset = 5;
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
|
|
||||||
@@ -340,10 +550,10 @@ pub fn generate(
|
|||||||
exp,
|
exp,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => {
|
AlgorithmId::EccP256 | AlgorithmId::EccP384 => {
|
||||||
let mut offset = 3;
|
let mut offset = 3;
|
||||||
|
|
||||||
let len = if algorithm == YKPIV_ALGO_ECCP256 {
|
let len = if let AlgorithmId::EccP256 = algorithm {
|
||||||
CB_ECC_POINTP256
|
CB_ECC_POINTP256
|
||||||
} else {
|
} else {
|
||||||
CB_ECC_POINTP384
|
CB_ECC_POINTP384
|
||||||
@@ -367,9 +577,5 @@ pub fn generate(
|
|||||||
let point = data[offset..(offset + len)].to_vec();
|
let point = data[offset..(offset + len)].to_vec();
|
||||||
Ok(GeneratedKey::Ecc { algorithm, point })
|
Ok(GeneratedKey::Ecc { algorithm, point })
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
error!("wrong algorithm");
|
|
||||||
Err(Error::AlgorithmError)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,10 +167,6 @@ pub mod yubikey;
|
|||||||
pub use self::{key::Key, mgm::MgmKey};
|
pub use self::{key::Key, mgm::MgmKey};
|
||||||
pub use yubikey::YubiKey;
|
pub use yubikey::YubiKey;
|
||||||
|
|
||||||
/// Algorithm identifiers
|
|
||||||
// TODO(tarcieri): make this an enum
|
|
||||||
pub type AlgorithmId = u8;
|
|
||||||
|
|
||||||
/// Object identifiers
|
/// Object identifiers
|
||||||
pub type ObjectId = u32;
|
pub type ObjectId = u32;
|
||||||
|
|
||||||
|
|||||||
+11
-13
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
apdu::{Response, StatusWords},
|
apdu::{Response, StatusWords},
|
||||||
consts::*,
|
consts::*,
|
||||||
|
key::{AlgorithmId, SlotId},
|
||||||
mgm::MgmKey,
|
mgm::MgmKey,
|
||||||
serialization::*,
|
serialization::*,
|
||||||
Buffer, ObjectId,
|
Buffer, ObjectId,
|
||||||
@@ -266,18 +267,18 @@ impl<'tx> Transaction<'tx> {
|
|||||||
pub(crate) fn authenticated_command(
|
pub(crate) fn authenticated_command(
|
||||||
&self,
|
&self,
|
||||||
sign_in: &[u8],
|
sign_in: &[u8],
|
||||||
algorithm: u8,
|
algorithm: AlgorithmId,
|
||||||
key: u8,
|
key: SlotId,
|
||||||
decipher: bool,
|
decipher: bool,
|
||||||
) -> Result<Buffer, Error> {
|
) -> Result<Buffer, Error> {
|
||||||
let in_len = sign_in.len();
|
let in_len = sign_in.len();
|
||||||
let mut indata = [0u8; 1024];
|
let mut indata = [0u8; 1024];
|
||||||
let templ = [0, Ins::Authenticate.code(), algorithm, key];
|
let templ = [0, Ins::Authenticate.code(), algorithm.into(), key.into()];
|
||||||
let mut len: usize = 0;
|
let mut len: usize = 0;
|
||||||
|
|
||||||
match algorithm {
|
match algorithm {
|
||||||
YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => {
|
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
|
||||||
let key_len = if algorithm == YKPIV_ALGO_RSA1024 {
|
let key_len = if let AlgorithmId::Rsa1024 = algorithm {
|
||||||
128
|
128
|
||||||
} else {
|
} else {
|
||||||
256
|
256
|
||||||
@@ -287,8 +288,8 @@ impl<'tx> Transaction<'tx> {
|
|||||||
return Err(Error::SizeError);
|
return Err(Error::SizeError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => {
|
AlgorithmId::EccP256 | AlgorithmId::EccP384 => {
|
||||||
let key_len = if algorithm == YKPIV_ALGO_ECCP256 {
|
let key_len = if let AlgorithmId::EccP256 = algorithm {
|
||||||
32
|
32
|
||||||
} else {
|
} else {
|
||||||
48
|
48
|
||||||
@@ -299,7 +300,6 @@ impl<'tx> Transaction<'tx> {
|
|||||||
return Err(Error::SizeError);
|
return Err(Error::SizeError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(Error::AlgorithmError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes = if in_len < 0x80 {
|
let bytes = if in_len < 0x80 {
|
||||||
@@ -314,11 +314,9 @@ impl<'tx> Transaction<'tx> {
|
|||||||
let mut offset = 1 + set_length(&mut indata[1..], in_len + bytes + 3);
|
let mut offset = 1 + set_length(&mut indata[1..], in_len + bytes + 3);
|
||||||
indata[offset] = 0x82;
|
indata[offset] = 0x82;
|
||||||
indata[offset + 1] = 0x00;
|
indata[offset + 1] = 0x00;
|
||||||
indata[offset + 2] =
|
indata[offset + 2] = match (algorithm, decipher) {
|
||||||
if (algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) && decipher {
|
(AlgorithmId::EccP256, true) | (AlgorithmId::EccP384, true) => 0x85,
|
||||||
0x85
|
_ => 0x81,
|
||||||
} else {
|
|
||||||
0x81
|
|
||||||
};
|
};
|
||||||
|
|
||||||
offset += 3;
|
offset += 3;
|
||||||
|
|||||||
+12
-21
@@ -36,7 +36,7 @@
|
|||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
use crate::{
|
use crate::{
|
||||||
apdu::{Ins, StatusWords, APDU},
|
apdu::{Ins, StatusWords, APDU},
|
||||||
key::SlotId,
|
key::{AlgorithmId, SlotId},
|
||||||
metadata,
|
metadata,
|
||||||
mgm::MgmKey,
|
mgm::MgmKey,
|
||||||
serialization::*,
|
serialization::*,
|
||||||
@@ -363,7 +363,7 @@ impl YubiKey {
|
|||||||
pub fn sign_data(
|
pub fn sign_data(
|
||||||
&mut self,
|
&mut self,
|
||||||
raw_in: &[u8],
|
raw_in: &[u8],
|
||||||
algorithm: u8,
|
algorithm: AlgorithmId,
|
||||||
key: SlotId,
|
key: SlotId,
|
||||||
) -> Result<Buffer, Error> {
|
) -> Result<Buffer, Error> {
|
||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
@@ -377,7 +377,7 @@ impl YubiKey {
|
|||||||
pub fn decrypt_data(
|
pub fn decrypt_data(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
algorithm: u8,
|
algorithm: AlgorithmId,
|
||||||
key: SlotId,
|
key: SlotId,
|
||||||
) -> Result<Buffer, Error> {
|
) -> Result<Buffer, Error> {
|
||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
@@ -605,7 +605,7 @@ impl YubiKey {
|
|||||||
pub fn import_private_key(
|
pub fn import_private_key(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: SlotId,
|
key: SlotId,
|
||||||
algorithm: u8,
|
algorithm: AlgorithmId,
|
||||||
p: Option<&[u8]>,
|
p: Option<&[u8]>,
|
||||||
q: Option<&[u8]>,
|
q: Option<&[u8]>,
|
||||||
dp: Option<&[u8]>,
|
dp: Option<&[u8]>,
|
||||||
@@ -616,15 +616,7 @@ impl YubiKey {
|
|||||||
touch_policy: u8,
|
touch_policy: u8,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut key_data = Zeroizing::new(vec![0u8; 1024]);
|
let mut key_data = Zeroizing::new(vec![0u8; 1024]);
|
||||||
let templ = [0, Ins::ImportKey.code(), algorithm, key];
|
let templ = [0, Ins::ImportKey.code(), algorithm.into(), key.into()];
|
||||||
|
|
||||||
if key == YKPIV_KEY_CARDMGM
|
|
||||||
|| key < YKPIV_KEY_RETIRED1
|
|
||||||
|| (key > YKPIV_KEY_RETIRED20 && key < YKPIV_KEY_AUTHENTICATION)
|
|
||||||
|| (key > YKPIV_KEY_CARDAUTH && key != YKPIV_KEY_ATTESTATION)
|
|
||||||
{
|
|
||||||
return Err(Error::KeyError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pin_policy != YKPIV_PINPOLICY_DEFAULT
|
if pin_policy != YKPIV_PINPOLICY_DEFAULT
|
||||||
&& pin_policy != YKPIV_PINPOLICY_NEVER
|
&& pin_policy != YKPIV_PINPOLICY_NEVER
|
||||||
@@ -643,7 +635,7 @@ impl YubiKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (elem_len, params, param_tag) = match algorithm {
|
let (elem_len, params, param_tag) = match algorithm {
|
||||||
YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => match (p, q, dp, dq, qinv) {
|
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => match (p, q, dp, dq, qinv) {
|
||||||
(Some(p), Some(q), Some(dp), Some(dq), Some(qinv)) => {
|
(Some(p), Some(q), Some(dp), Some(dq), Some(qinv)) => {
|
||||||
if p.len() + q.len() + dp.len() + dq.len() + qinv.len() >= key_data.len() {
|
if p.len() + q.len() + dp.len() + dq.len() + qinv.len() >= key_data.len() {
|
||||||
return Err(Error::SizeError);
|
return Err(Error::SizeError);
|
||||||
@@ -651,8 +643,8 @@ impl YubiKey {
|
|||||||
|
|
||||||
(
|
(
|
||||||
match algorithm {
|
match algorithm {
|
||||||
YKPIV_ALGO_RSA1024 => 64,
|
AlgorithmId::Rsa1024 => 64,
|
||||||
YKPIV_ALGO_RSA2048 => 128,
|
AlgorithmId::Rsa2048 => 128,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
vec![p, q, dp, dq, qinv],
|
vec![p, q, dp, dq, qinv],
|
||||||
@@ -661,7 +653,7 @@ impl YubiKey {
|
|||||||
}
|
}
|
||||||
_ => return Err(Error::GenericError),
|
_ => return Err(Error::GenericError),
|
||||||
},
|
},
|
||||||
YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => match ec_data {
|
AlgorithmId::EccP256 | AlgorithmId::EccP384 => match ec_data {
|
||||||
Some(ec_data) => {
|
Some(ec_data) => {
|
||||||
if ec_data.len() >= key_data.len() {
|
if ec_data.len() >= key_data.len() {
|
||||||
// This can never be true, but check to be explicit.
|
// This can never be true, but check to be explicit.
|
||||||
@@ -670,8 +662,8 @@ impl YubiKey {
|
|||||||
|
|
||||||
(
|
(
|
||||||
match algorithm {
|
match algorithm {
|
||||||
YKPIV_ALGO_ECCP256 => 32,
|
AlgorithmId::EccP256 => 32,
|
||||||
YKPIV_ALGO_ECCP384 => 48,
|
AlgorithmId::EccP384 => 48,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
vec![ec_data],
|
vec![ec_data],
|
||||||
@@ -680,7 +672,6 @@ impl YubiKey {
|
|||||||
}
|
}
|
||||||
_ => return Err(Error::GenericError),
|
_ => return Err(Error::GenericError),
|
||||||
},
|
},
|
||||||
_ => return Err(Error::AlgorithmError),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
@@ -737,7 +728,7 @@ impl YubiKey {
|
|||||||
/// <https://developers.yubico.com/PIV/Introduction/PIV_attestation.html>
|
/// <https://developers.yubico.com/PIV/Introduction/PIV_attestation.html>
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub fn attest(&mut self, key: SlotId) -> Result<Buffer, Error> {
|
pub fn attest(&mut self, key: SlotId) -> Result<Buffer, Error> {
|
||||||
let templ = [0, Ins::Attest.code(), key, 0];
|
let templ = [0, Ins::Attest.code(), key.into(), 0];
|
||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
let response = txn.transfer_data(&templ, &[], CB_OBJ_MAX)?;
|
let response = txn.transfer_data(&templ, &[], CB_OBJ_MAX)?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user