Merge pull request #33 from tarcieri/ins-enum
`Ins` (APDU instruction codes) enum
This commit is contained in:
@@ -112,15 +112,16 @@ To trace every message sent to/from the card i.e. the raw
|
|||||||
Application Protocol Data Unit (APDU) messages, use the `trace` log level:
|
Application Protocol Data Unit (APDU) messages, use the `trace` log level:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
running 1 test
|
||||||
[INFO yubikey_piv::yubikey] trying to connect to reader 'Yubico YubiKey OTP+FIDO+CCID'
|
[INFO yubikey_piv::yubikey] trying to connect to reader 'Yubico YubiKey OTP+FIDO+CCID'
|
||||||
[INFO yubikey_piv::yubikey] connected to 'Yubico YubiKey OTP+FIDO+CCID' successfully
|
[INFO yubikey_piv::yubikey] connected to 'Yubico YubiKey OTP+FIDO+CCID' successfully
|
||||||
[TRACE yubikey_piv::apdu] >>> APDU { cla: 0, ins: 164, p1: 4, p2: 0, lc: 5, data: [160, 0, 0, 3, 8] }
|
[TRACE yubikey_piv::apdu] >>> APDU { cla: 0, ins: SelectApplication, p1: 4, p2: 0, data: [160, 0, 0, 3, 8] }
|
||||||
[TRACE yubikey_piv::transaction] >>> [0, 164, 4, 0, 5, 160, 0, 0, 3, 8]
|
[TRACE yubikey_piv::transaction] >>> [0, 164, 4, 0, 5, 160, 0, 0, 3, 8]
|
||||||
[TRACE yubikey_piv::apdu] <<< Response { status_words: Success, data: [97, 17, 79, 6, 0, 0, 16, 0, 1, 0, 121, 7, 79, 5, 160, 0, 0, 3, 8] }
|
[TRACE yubikey_piv::apdu] <<< Response { status_words: Success, data: [97, 17, 79, 6, 0, 0, 16, 0, 1, 0, 121, 7, 79, 5, 160, 0, 0, 3, 8] }
|
||||||
[TRACE yubikey_piv::apdu] >>> APDU { cla: 0, ins: 253, p1: 0, p2: 0, lc: 0, data: [] }
|
[TRACE yubikey_piv::apdu] >>> APDU { cla: 0, ins: GetVersion, p1: 0, p2: 0, data: [] }
|
||||||
[TRACE yubikey_piv::transaction] >>> [0, 253, 0, 0, 0]
|
[TRACE yubikey_piv::transaction] >>> [0, 253, 0, 0, 0]
|
||||||
[TRACE yubikey_piv::apdu] <<< Response { status_words: Success, data: [5, 1, 2] }
|
[TRACE yubikey_piv::apdu] <<< Response { status_words: Success, data: [5, 1, 2] }
|
||||||
[TRACE yubikey_piv::apdu] >>> APDU { cla: 0, ins: 248, p1: 0, p2: 0, lc: 0, data: [] }
|
[TRACE yubikey_piv::apdu] >>> APDU { cla: 0, ins: GetSerial, p1: 0, p2: 0, data: [] }
|
||||||
[TRACE yubikey_piv::transaction] >>> [0, 248, 0, 0, 0]
|
[TRACE yubikey_piv::transaction] >>> [0, 248, 0, 0, 0]
|
||||||
[TRACE yubikey_piv::apdu] <<< Response { status_words: Success, data: [0, 115, 0, 178] }
|
[TRACE yubikey_piv::apdu] <<< Response { status_words: Success, data: [0, 115, 0, 178] }
|
||||||
test connect ... ok
|
test connect ... ok
|
||||||
|
|||||||
+120
-26
@@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
use crate::{error::Error, transaction::Transaction, Buffer};
|
use crate::{error::Error, transaction::Transaction, Buffer};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
use zeroize::{Zeroize, Zeroizing};
|
use zeroize::{Zeroize, Zeroizing};
|
||||||
|
|
||||||
/// Maximum amount of command data that can be included in an APDU
|
/// Maximum amount of command data that can be included in an APDU
|
||||||
@@ -41,13 +40,13 @@ const APDU_DATA_MAX: usize = 0xFF;
|
|||||||
/// Application Protocol Data Unit (APDU).
|
/// Application Protocol Data Unit (APDU).
|
||||||
///
|
///
|
||||||
/// These messages are packets used to communicate with the YubiKey.
|
/// These messages are packets used to communicate with the YubiKey.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) struct APDU {
|
pub(crate) struct APDU {
|
||||||
/// Instruction class: indicates the type of command (e.g. inter-industry or proprietary)
|
/// Instruction class: indicates the type of command (e.g. inter-industry or proprietary)
|
||||||
cla: u8,
|
cla: u8,
|
||||||
|
|
||||||
/// Instruction code: indicates the specific command (e.g. "write data")
|
/// Instruction code: indicates the specific command (e.g. "write data")
|
||||||
ins: u8,
|
ins: Ins,
|
||||||
|
|
||||||
/// Instruction parameter 1 for the command (e.g. offset into file at which to write the data)
|
/// Instruction parameter 1 for the command (e.g. offset into file at which to write the data)
|
||||||
p1: u8,
|
p1: u8,
|
||||||
@@ -61,10 +60,10 @@ pub(crate) struct APDU {
|
|||||||
|
|
||||||
impl APDU {
|
impl APDU {
|
||||||
/// Create a new APDU with the given instruction code
|
/// Create a new APDU with the given instruction code
|
||||||
pub fn new(ins: u8) -> Self {
|
pub fn new(ins: impl Into<Ins>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cla: 0,
|
cla: 0,
|
||||||
ins,
|
ins: ins.into(),
|
||||||
p1: 0,
|
p1: 0,
|
||||||
p2: 0,
|
p2: 0,
|
||||||
data: vec![],
|
data: vec![],
|
||||||
@@ -123,7 +122,7 @@ impl APDU {
|
|||||||
pub fn to_bytes(&self) -> Buffer {
|
pub fn to_bytes(&self) -> Buffer {
|
||||||
let mut bytes = Vec::with_capacity(5 + self.data.len());
|
let mut bytes = Vec::with_capacity(5 + self.data.len());
|
||||||
bytes.push(self.cla);
|
bytes.push(self.cla);
|
||||||
bytes.push(self.ins);
|
bytes.push(self.ins.code());
|
||||||
bytes.push(self.p1);
|
bytes.push(self.p1);
|
||||||
bytes.push(self.p2);
|
bytes.push(self.p2);
|
||||||
bytes.push(self.data.len() as u8);
|
bytes.push(self.data.len() as u8);
|
||||||
@@ -132,21 +131,6 @@ impl APDU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for APDU {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"APDU {{ cla: {}, ins: {}, p1: {}, p2: {}, lc: {}, data: {:?} }}",
|
|
||||||
self.cla,
|
|
||||||
self.ins,
|
|
||||||
self.p1,
|
|
||||||
self.p2,
|
|
||||||
self.data.len(),
|
|
||||||
self.data.as_slice()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for APDU {
|
impl Drop for APDU {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.zeroize();
|
self.zeroize();
|
||||||
@@ -155,16 +139,125 @@ impl Drop for APDU {
|
|||||||
|
|
||||||
impl Zeroize for APDU {
|
impl Zeroize for APDU {
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
self.cla.zeroize();
|
// Only `data` may contain secrets
|
||||||
self.ins.zeroize();
|
|
||||||
self.p1.zeroize();
|
|
||||||
self.p2.zeroize();
|
|
||||||
self.data.zeroize();
|
self.data.zeroize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// APDU instruction codes
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Ins {
|
||||||
|
/// Verify
|
||||||
|
Verify,
|
||||||
|
|
||||||
|
/// Change reference
|
||||||
|
ChangeReference,
|
||||||
|
|
||||||
|
/// Reset retry
|
||||||
|
ResetRetry,
|
||||||
|
|
||||||
|
/// Generate asymmetric
|
||||||
|
GenerateAsymmetric,
|
||||||
|
|
||||||
|
/// Authenticate
|
||||||
|
Authenticate,
|
||||||
|
|
||||||
|
/// Get data
|
||||||
|
GetData,
|
||||||
|
|
||||||
|
/// Put data
|
||||||
|
PutData,
|
||||||
|
|
||||||
|
/// Select application
|
||||||
|
SelectApplication,
|
||||||
|
|
||||||
|
/// Get response APDU
|
||||||
|
GetResponseApdu,
|
||||||
|
|
||||||
|
// Yubico vendor specific instructions
|
||||||
|
// <https://developers.yubico.com/PIV/Introduction/Yubico_extensions.html>
|
||||||
|
/// Set MGM key
|
||||||
|
SetMgmKey,
|
||||||
|
|
||||||
|
/// Import key
|
||||||
|
ImportKey,
|
||||||
|
|
||||||
|
/// Get version
|
||||||
|
GetVersion,
|
||||||
|
|
||||||
|
/// Reset device
|
||||||
|
Reset,
|
||||||
|
|
||||||
|
/// Set PIN retries
|
||||||
|
SetPinRetries,
|
||||||
|
|
||||||
|
/// Generate attestation certificate for asymmetric key
|
||||||
|
Attest,
|
||||||
|
|
||||||
|
/// Get device serial
|
||||||
|
GetSerial,
|
||||||
|
|
||||||
|
/// Other/unrecognized instruction codes
|
||||||
|
Other(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ins {
|
||||||
|
/// Get the code that corresponds to this instruction
|
||||||
|
pub fn code(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Ins::Verify => 0x20,
|
||||||
|
Ins::ChangeReference => 0x24,
|
||||||
|
Ins::ResetRetry => 0x2c,
|
||||||
|
Ins::GenerateAsymmetric => 0x47,
|
||||||
|
Ins::Authenticate => 0x87,
|
||||||
|
Ins::GetData => 0xcb,
|
||||||
|
Ins::PutData => 0xdb,
|
||||||
|
Ins::SelectApplication => 0xa4,
|
||||||
|
Ins::GetResponseApdu => 0xc0,
|
||||||
|
Ins::SetMgmKey => 0xff,
|
||||||
|
Ins::ImportKey => 0xfe,
|
||||||
|
Ins::GetVersion => 0xfd,
|
||||||
|
Ins::Reset => 0xfb,
|
||||||
|
Ins::SetPinRetries => 0xfa,
|
||||||
|
Ins::Attest => 0xf9,
|
||||||
|
Ins::GetSerial => 0xf8,
|
||||||
|
Ins::Other(code) => code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for Ins {
|
||||||
|
fn from(code: u8) -> Self {
|
||||||
|
match code {
|
||||||
|
0x20 => Ins::Verify,
|
||||||
|
0x24 => Ins::ChangeReference,
|
||||||
|
0x2c => Ins::ResetRetry,
|
||||||
|
0x47 => Ins::GenerateAsymmetric,
|
||||||
|
0x87 => Ins::Authenticate,
|
||||||
|
0xcb => Ins::GetData,
|
||||||
|
0xdb => Ins::PutData,
|
||||||
|
0xa4 => Ins::SelectApplication,
|
||||||
|
0xc0 => Ins::GetResponseApdu,
|
||||||
|
0xff => Ins::SetMgmKey,
|
||||||
|
0xfe => Ins::ImportKey,
|
||||||
|
0xfd => Ins::GetVersion,
|
||||||
|
0xfb => Ins::Reset,
|
||||||
|
0xfa => Ins::SetPinRetries,
|
||||||
|
0xf9 => Ins::Attest,
|
||||||
|
0xf8 => Ins::GetSerial,
|
||||||
|
code => Ins::Other(code),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ins> for u8 {
|
||||||
|
fn from(ins: Ins) -> u8 {
|
||||||
|
ins.code()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// APDU responses
|
/// APDU responses
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) struct Response {
|
pub(crate) struct Response {
|
||||||
/// Status words
|
/// Status words
|
||||||
status_words: StatusWords,
|
status_words: StatusWords,
|
||||||
@@ -239,6 +332,7 @@ impl From<Vec<u8>> for Response {
|
|||||||
|
|
||||||
impl Zeroize for Response {
|
impl Zeroize for Response {
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
|
// Only `data` may contain secrets
|
||||||
self.data.zeroize();
|
self.data.zeroize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,26 +136,6 @@ 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_INS_VERIFY: u8 = 0x20;
|
|
||||||
pub const YKPIV_INS_CHANGE_REFERENCE: u8 = 0x24;
|
|
||||||
pub const YKPIV_INS_RESET_RETRY: u8 = 0x2c;
|
|
||||||
pub const YKPIV_INS_GENERATE_ASYMMETRIC: u8 = 0x47;
|
|
||||||
pub const YKPIV_INS_AUTHENTICATE: u8 = 0x87;
|
|
||||||
pub const YKPIV_INS_GET_DATA: u8 = 0xcb;
|
|
||||||
pub const YKPIV_INS_PUT_DATA: u8 = 0xdb;
|
|
||||||
pub const YKPIV_INS_SELECT_APPLICATION: u8 = 0xa4;
|
|
||||||
pub const YKPIV_INS_GET_RESPONSE_APDU: u8 = 0xc0;
|
|
||||||
|
|
||||||
// Yubico vendor specific instructions
|
|
||||||
// <https://developers.yubico.com/PIV/Introduction/Yubico_extensions.html>
|
|
||||||
pub const YKPIV_INS_SET_MGMKEY: u8 = 0xff;
|
|
||||||
pub const YKPIV_INS_IMPORT_KEY: u8 = 0xfe;
|
|
||||||
pub const YKPIV_INS_GET_VERSION: u8 = 0xfd;
|
|
||||||
pub const YKPIV_INS_RESET: u8 = 0xfb;
|
|
||||||
pub const YKPIV_INS_SET_PIN_RETRIES: u8 = 0xfa;
|
|
||||||
pub const YKPIV_INS_ATTEST: u8 = 0xf9;
|
|
||||||
pub const YKPIV_INS_GET_SERIAL: u8 = 0xf8;
|
|
||||||
|
|
||||||
pub const YKPIV_KEY_AUTHENTICATION: u8 = 0x9a;
|
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_SIGNATURE: u8 = 0x9c;
|
||||||
|
|||||||
+2
-2
@@ -38,7 +38,7 @@
|
|||||||
// 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::{
|
||||||
apdu::StatusWords,
|
apdu::{Ins, StatusWords},
|
||||||
certificate::{self, Certificate},
|
certificate::{self, Certificate},
|
||||||
consts::*,
|
consts::*,
|
||||||
error::Error,
|
error::Error,
|
||||||
@@ -199,7 +199,7 @@ pub fn generate(
|
|||||||
touch_policy: u8,
|
touch_policy: u8,
|
||||||
) -> Result<GeneratedKey, Error> {
|
) -> Result<GeneratedKey, Error> {
|
||||||
let mut in_data = [0u8; 11];
|
let mut in_data = [0u8; 11];
|
||||||
let mut templ = [0, YKPIV_INS_GENERATE_ASYMMETRIC, 0, 0];
|
let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0];
|
||||||
let setting_roca: settings::BoolValue;
|
let setting_roca: settings::BoolValue;
|
||||||
|
|
||||||
if yubikey.device_model() == DEVTYPE_YK4
|
if yubikey.device_model() == DEVTYPE_YK4
|
||||||
|
|||||||
+20
-19
@@ -1,9 +1,14 @@
|
|||||||
//! YubiKey PC/SC transactions
|
//! YubiKey PC/SC transactions
|
||||||
|
|
||||||
use crate::{apdu::APDU, consts::*, error::Error, yubikey::*};
|
use crate::{
|
||||||
|
apdu::{Ins, APDU},
|
||||||
|
error::Error,
|
||||||
|
yubikey::*,
|
||||||
|
};
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
use crate::{
|
use crate::{
|
||||||
apdu::{Response, StatusWords},
|
apdu::{Response, StatusWords},
|
||||||
|
consts::*,
|
||||||
mgm::MgmKey,
|
mgm::MgmKey,
|
||||||
serialization::*,
|
serialization::*,
|
||||||
Buffer, ObjectId,
|
Buffer, ObjectId,
|
||||||
@@ -60,7 +65,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
|
|
||||||
/// Select application.
|
/// Select application.
|
||||||
pub fn select_application(&self) -> Result<(), Error> {
|
pub fn select_application(&self) -> Result<(), Error> {
|
||||||
let response = APDU::new(YKPIV_INS_SELECT_APPLICATION)
|
let response = APDU::new(Ins::SelectApplication)
|
||||||
.p1(0x04)
|
.p1(0x04)
|
||||||
.data(&AID)
|
.data(&AID)
|
||||||
.transmit(self, 0xFF)
|
.transmit(self, 0xFF)
|
||||||
@@ -83,7 +88,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
/// Get the version of the PIV application installed on the YubiKey
|
/// Get the version of the PIV application installed on the YubiKey
|
||||||
pub fn get_version(&self) -> Result<Version, Error> {
|
pub fn get_version(&self) -> Result<Version, Error> {
|
||||||
// get version from device
|
// get version from device
|
||||||
let response = APDU::new(YKPIV_INS_GET_VERSION).transmit(self, 261)?;
|
let response = APDU::new(Ins::GetVersion).transmit(self, 261)?;
|
||||||
|
|
||||||
if !response.is_success() {
|
if !response.is_success() {
|
||||||
return Err(Error::GenericError);
|
return Err(Error::GenericError);
|
||||||
@@ -93,11 +98,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
return Err(Error::SizeError);
|
return Err(Error::SizeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Version {
|
Ok(Version::new(response.data()[..3].try_into().unwrap()))
|
||||||
major: response.data()[0],
|
|
||||||
minor: response.data()[1],
|
|
||||||
patch: response.data()[2],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get YubiKey device serial number
|
/// Get YubiKey device serial number
|
||||||
@@ -106,7 +107,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
|
|
||||||
let response = if version.major < 5 {
|
let response = if version.major < 5 {
|
||||||
// get serial from neo/yk4 devices using the otp applet
|
// get serial from neo/yk4 devices using the otp applet
|
||||||
let sw = APDU::new(YKPIV_INS_SELECT_APPLICATION)
|
let sw = APDU::new(Ins::SelectApplication)
|
||||||
.p1(0x04)
|
.p1(0x04)
|
||||||
.data(&yk_applet)
|
.data(&yk_applet)
|
||||||
.transmit(self, 0xFF)?
|
.transmit(self, 0xFF)?
|
||||||
@@ -128,7 +129,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reselect the PIV applet
|
// reselect the PIV applet
|
||||||
let sw = APDU::new(YKPIV_INS_SELECT_APPLICATION)
|
let sw = APDU::new(Ins::SelectApplication)
|
||||||
.p1(0x04)
|
.p1(0x04)
|
||||||
.data(&AID)
|
.data(&AID)
|
||||||
.transmit(self, 0xFF)?
|
.transmit(self, 0xFF)?
|
||||||
@@ -142,7 +143,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
resp
|
resp
|
||||||
} else {
|
} else {
|
||||||
// get serial from yk5 and later devices using the f8 command
|
// get serial from yk5 and later devices using the f8 command
|
||||||
let resp = APDU::new(YKPIV_INS_GET_SERIAL).transmit(self, 0xFF)?;
|
let resp = APDU::new(Ins::GetSerial).transmit(self, 0xFF)?;
|
||||||
|
|
||||||
if !resp.is_success() {
|
if !resp.is_success() {
|
||||||
error!(
|
error!(
|
||||||
@@ -169,7 +170,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
return Err(Error::SizeError);
|
return Err(Error::SizeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = APDU::new(YKPIV_INS_VERIFY)
|
let response = APDU::new(Ins::Verify)
|
||||||
.params(0x00, 0x80)
|
.params(0x00, 0x80)
|
||||||
.data(pin)
|
.data(pin)
|
||||||
.transmit(self, 261)?;
|
.transmit(self, 261)?;
|
||||||
@@ -185,7 +186,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
/// Change the PIN
|
/// Change the PIN
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub fn change_pin(&self, action: i32, current_pin: &[u8], new_pin: &[u8]) -> Result<(), Error> {
|
pub fn change_pin(&self, action: i32, current_pin: &[u8], new_pin: &[u8]) -> Result<(), Error> {
|
||||||
let mut templ = [0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80];
|
let mut templ = [0, Ins::ChangeReference.code(), 0, 0x80];
|
||||||
let mut indata = Zeroizing::new([0u8; 16]);
|
let mut indata = Zeroizing::new([0u8; 16]);
|
||||||
|
|
||||||
if current_pin.len() > CB_PIN_MAX || new_pin.len() > CB_PIN_MAX {
|
if current_pin.len() > CB_PIN_MAX || new_pin.len() > CB_PIN_MAX {
|
||||||
@@ -193,7 +194,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if action == CHREF_ACT_UNBLOCK_PIN {
|
if action == CHREF_ACT_UNBLOCK_PIN {
|
||||||
templ[1] = YKPIV_INS_RESET_RETRY;
|
templ[1] = Ins::ResetRetry.code();
|
||||||
} else if action == CHREF_ACT_CHANGE_PUK {
|
} else if action == CHREF_ACT_CHANGE_PUK {
|
||||||
templ[3] = 0x81;
|
templ[3] = 0x81;
|
||||||
}
|
}
|
||||||
@@ -259,7 +260,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
data[2] = DES_LEN_3DES as u8;
|
data[2] = DES_LEN_3DES as u8;
|
||||||
data[3..3 + DES_LEN_3DES].copy_from_slice(new_key.as_ref());
|
data[3..3 + DES_LEN_3DES].copy_from_slice(new_key.as_ref());
|
||||||
|
|
||||||
let status_words = APDU::new(YKPIV_INS_SET_MGMKEY)
|
let status_words = APDU::new(Ins::SetMgmKey)
|
||||||
.params(0xff, p2)
|
.params(0xff, p2)
|
||||||
.data(&data)
|
.data(&data)
|
||||||
.transmit(self, 261)?
|
.transmit(self, 261)?
|
||||||
@@ -290,7 +291,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), 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, YKPIV_INS_AUTHENTICATE, algorithm, key];
|
let templ = [0, Ins::Authenticate.code(), algorithm, key];
|
||||||
let mut len: usize = 0;
|
let mut len: usize = 0;
|
||||||
|
|
||||||
match algorithm {
|
match algorithm {
|
||||||
@@ -454,7 +455,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
sw & 0xff
|
sw & 0xff
|
||||||
);
|
);
|
||||||
|
|
||||||
let response = APDU::new(YKPIV_INS_GET_RESPONSE_APDU).transmit(self, 261)?;
|
let response = APDU::new(Ins::GetResponseApdu).transmit(self, 261)?;
|
||||||
sw = response.status_words().code();
|
sw = response.status_words().code();
|
||||||
|
|
||||||
if sw != StatusWords::Success.code() && (sw >> 8 != 0x61) {
|
if sw != StatusWords::Success.code() && (sw >> 8 != 0x61) {
|
||||||
@@ -481,7 +482,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer, Error> {
|
pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer, Error> {
|
||||||
let mut indata = [0u8; 5];
|
let mut indata = [0u8; 5];
|
||||||
let templ = [0, YKPIV_INS_GET_DATA, 0x3f, 0xff];
|
let templ = [0, Ins::GetData.code(), 0x3f, 0xff];
|
||||||
|
|
||||||
let mut inlen = indata.len();
|
let mut inlen = indata.len();
|
||||||
let indata_remaining = set_object(object_id, &mut indata);
|
let indata_remaining = set_object(object_id, &mut indata);
|
||||||
@@ -524,7 +525,7 @@ impl<'tx> Transaction<'tx> {
|
|||||||
/// Save an object
|
/// Save an object
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub fn save_object(&self, object_id: ObjectId, indata: &[u8]) -> Result<(), Error> {
|
pub fn save_object(&self, object_id: ObjectId, indata: &[u8]) -> Result<(), Error> {
|
||||||
let templ = [0, YKPIV_INS_PUT_DATA, 0x3f, 0xff];
|
let templ = [0, Ins::PutData.code(), 0x3f, 0xff];
|
||||||
|
|
||||||
// TODO(tarcieri): replace with vector
|
// TODO(tarcieri): replace with vector
|
||||||
let mut data = [0u8; CB_BUF_MAX];
|
let mut data = [0u8; CB_BUF_MAX];
|
||||||
|
|||||||
+21
-10
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
use crate::{
|
use crate::{
|
||||||
apdu::{StatusWords, APDU},
|
apdu::{Ins, StatusWords, APDU},
|
||||||
key::SlotId,
|
key::SlotId,
|
||||||
metadata,
|
metadata,
|
||||||
mgm::MgmKey,
|
mgm::MgmKey,
|
||||||
@@ -99,6 +99,17 @@ pub struct Version {
|
|||||||
pub patch: u8,
|
pub patch: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Version {
|
||||||
|
/// Parse a version from bytes
|
||||||
|
pub fn new(bytes: [u8; 3]) -> Version {
|
||||||
|
Version {
|
||||||
|
major: bytes[0],
|
||||||
|
minor: bytes[1],
|
||||||
|
patch: bytes[2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// YubiKey Device: this is the primary API for opening a session and
|
/// YubiKey Device: this is the primary API for opening a session and
|
||||||
/// performing various operations.
|
/// performing various operations.
|
||||||
///
|
///
|
||||||
@@ -270,7 +281,7 @@ impl YubiKey {
|
|||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
|
|
||||||
// get a challenge from the card
|
// get a challenge from the card
|
||||||
let challenge = APDU::new(YKPIV_INS_AUTHENTICATE)
|
let challenge = APDU::new(Ins::Authenticate)
|
||||||
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
||||||
.data(&[0x7c, 0x02, 0x80, 0x00])
|
.data(&[0x7c, 0x02, 0x80, 0x00])
|
||||||
.transmit(&txn, 261)?;
|
.transmit(&txn, 261)?;
|
||||||
@@ -299,7 +310,7 @@ impl YubiKey {
|
|||||||
let mut challenge = [0u8; 8];
|
let mut challenge = [0u8; 8];
|
||||||
challenge.copy_from_slice(&data[14..22]);
|
challenge.copy_from_slice(&data[14..22]);
|
||||||
|
|
||||||
let authentication = APDU::new(YKPIV_INS_AUTHENTICATE)
|
let authentication = APDU::new(Ins::Authenticate)
|
||||||
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
||||||
.data(&data)
|
.data(&data)
|
||||||
.transmit(&txn, 261)?;
|
.transmit(&txn, 261)?;
|
||||||
@@ -324,7 +335,7 @@ impl YubiKey {
|
|||||||
pub fn deauthenticate(&mut self) -> Result<(), Error> {
|
pub fn deauthenticate(&mut self) -> Result<(), Error> {
|
||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
|
|
||||||
let status_words = APDU::new(YKPIV_INS_SELECT_APPLICATION)
|
let status_words = APDU::new(Ins::SelectApplication)
|
||||||
.p1(0x04)
|
.p1(0x04)
|
||||||
.data(MGMT_AID)
|
.data(MGMT_AID)
|
||||||
.transmit(&txn, 255)?
|
.transmit(&txn, 255)?
|
||||||
@@ -422,7 +433,7 @@ impl YubiKey {
|
|||||||
|
|
||||||
let templ = [
|
let templ = [
|
||||||
0,
|
0,
|
||||||
YKPIV_INS_SET_PIN_RETRIES,
|
Ins::SetPinRetries.code(),
|
||||||
pin_tries as u8,
|
pin_tries as u8,
|
||||||
puk_tries as u8,
|
puk_tries as u8,
|
||||||
];
|
];
|
||||||
@@ -644,7 +655,7 @@ impl YubiKey {
|
|||||||
|
|
||||||
let mut key_data = Zeroizing::new(vec![0u8; 1024]);
|
let mut key_data = Zeroizing::new(vec![0u8; 1024]);
|
||||||
let mut in_ptr: *mut u8 = key_data.as_mut_ptr();
|
let mut in_ptr: *mut u8 = key_data.as_mut_ptr();
|
||||||
let templ = [0, YKPIV_INS_IMPORT_KEY, algorithm, key];
|
let templ = [0, Ins::ImportKey.code(), algorithm, key];
|
||||||
let mut elem_len: u32 = 0;
|
let mut elem_len: u32 = 0;
|
||||||
let mut params: [*const u8; 5] = [ptr::null(); 5];
|
let mut params: [*const u8; 5] = [ptr::null(); 5];
|
||||||
let mut lens = [0usize; 5];
|
let mut lens = [0usize; 5];
|
||||||
@@ -795,7 +806,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, YKPIV_INS_ATTEST, key, 0];
|
let templ = [0, Ins::Attest.code(), key, 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)?;
|
||||||
|
|
||||||
@@ -819,7 +830,7 @@ impl YubiKey {
|
|||||||
pub fn get_auth_challenge(&mut self) -> Result<[u8; 8], Error> {
|
pub fn get_auth_challenge(&mut self) -> Result<[u8; 8], Error> {
|
||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
|
|
||||||
let response = APDU::new(YKPIV_INS_AUTHENTICATE)
|
let response = APDU::new(Ins::Authenticate)
|
||||||
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
||||||
.data(&[0x7c, 0x02, 0x81, 0x00])
|
.data(&[0x7c, 0x02, 0x81, 0x00])
|
||||||
.transmit(&txn, 261)?;
|
.transmit(&txn, 261)?;
|
||||||
@@ -844,7 +855,7 @@ impl YubiKey {
|
|||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
|
|
||||||
// send the response to the card and a challenge of our own.
|
// send the response to the card and a challenge of our own.
|
||||||
let status_words = APDU::new(YKPIV_INS_AUTHENTICATE)
|
let status_words = APDU::new(Ins::Authenticate)
|
||||||
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
.params(YKPIV_ALGO_3DES, YKPIV_KEY_CARDMGM)
|
||||||
.data(&data)
|
.data(&data)
|
||||||
.transmit(&txn, 261)?
|
.transmit(&txn, 261)?
|
||||||
@@ -864,7 +875,7 @@ impl YubiKey {
|
|||||||
/// The reset function is only available when both pins are blocked.
|
/// The reset function is only available when both pins are blocked.
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub fn reset_device(&mut self) -> Result<(), Error> {
|
pub fn reset_device(&mut self) -> Result<(), Error> {
|
||||||
let templ = [0, YKPIV_INS_RESET, 0, 0];
|
let templ = [0, Ins::Reset.code(), 0, 0];
|
||||||
let txn = self.begin_transaction()?;
|
let txn = self.begin_transaction()?;
|
||||||
let status_words = txn.transfer_data(&templ, &[], 255)?.status_words();
|
let status_words = txn.transfer_data(&templ, &[], 255)?.status_words();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user