Add Result alias (#271)

Adds a `yubikey::Result` alias with `yubikey::Error` as the error type.

Since we only have one `Error` type, this simplifies the return types
where a `Result` is returned.
This commit is contained in:
Tony Arcieri (iqlusion)
2021-07-11 09:44:08 -07:00
committed by GitHub
parent 1051eaf26d
commit de51b0cc46
23 changed files with 210 additions and 223 deletions
Generated
+2 -2
View File
@@ -820,9 +820,9 @@ dependencies = [
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.12.4" version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
+1 -1
View File
@@ -36,7 +36,7 @@ pub struct YubiKeyCli {
impl YubiKeyCli { impl YubiKeyCli {
/// Print usage information /// Print usage information
pub fn print_usage() -> Result<(), io::Error> { pub fn print_usage() -> io::Result<()> {
let mut stdout = STDOUT.lock(); let mut stdout = STDOUT.lock();
stdout.reset()?; stdout.reset()?;
+1 -1
View File
@@ -53,7 +53,7 @@ impl ReadersCmd {
index: usize, index: usize,
name: &str, name: &str,
serial: Serial, serial: Serial,
) -> Result<(), io::Error> { ) -> io::Result<()> {
stream.set_color(ColorSpec::new().set_bold(true))?; stream.set_color(ColorSpec::new().set_bold(true))?;
write!(stream, "{:>3}:", index)?; write!(stream, "{:>3}:", index)?;
stream.reset()?; stream.reset()?;
+1 -1
View File
@@ -51,7 +51,7 @@ impl StatusCmd {
stream: &mut StandardStreamLock<'_>, stream: &mut StandardStreamLock<'_>,
name: &str, name: &str,
value: impl ToString, value: impl ToString,
) -> Result<(), io::Error> { ) -> io::Result<()> {
stream.set_color(ColorSpec::new().set_bold(true))?; stream.set_color(ColorSpec::new().set_bold(true))?;
write!(stream, "{:>12}:", name)?; write!(stream, "{:>12}:", name)?;
stream.reset()?; stream.reset()?;
+2 -2
View File
@@ -27,7 +27,7 @@ pub fn print_cert_info(
yubikey: &mut YubiKey, yubikey: &mut YubiKey,
slot: SlotId, slot: SlotId,
stream: &mut StandardStreamLock<'_>, stream: &mut StandardStreamLock<'_>,
) -> Result<(), io::Error> { ) -> io::Result<()> {
let cert = match Certificate::read(yubikey, slot) { let cert = match Certificate::read(yubikey, slot) {
Ok(c) => c, Ok(c) => c,
Err(e) => { Err(e) => {
@@ -82,7 +82,7 @@ fn print_cert_attr(
stream: &mut StandardStreamLock<'_>, stream: &mut StandardStreamLock<'_>,
name: &str, name: &str,
value: impl ToString, value: impl ToString,
) -> Result<(), io::Error> { ) -> io::Result<()> {
stream.set_color(ColorSpec::new().set_bold(true))?; stream.set_color(ColorSpec::new().set_bold(true))?;
write!(stream, "{:>12}:", name)?; write!(stream, "{:>12}:", name)?;
stream.reset()?; stream.reset()?;
+1 -1
View File
@@ -143,7 +143,7 @@ impl Status {
} }
/// Print the given message /// Print the given message
fn print(self, stream: &StandardStream, msg: impl AsRef<str>) -> Result<(), io::Error> { fn print(self, stream: &StandardStream, msg: impl AsRef<str>) -> io::Result<()> {
let mut s = stream.lock(); let mut s = stream.lock();
s.reset()?; s.reset()?;
s.set_color(ColorSpec::new().set_fg(self.color).set_bold(self.bold))?; s.set_color(ColorSpec::new().set_fg(self.color).set_bold(self.bold))?;
+2 -2
View File
@@ -30,7 +30,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::{error::Error, transaction::Transaction, Buffer}; use crate::{transaction::Transaction, Buffer, Result};
use log::trace; use log::trace;
use zeroize::{Zeroize, Zeroizing}; use zeroize::{Zeroize, Zeroizing};
@@ -109,7 +109,7 @@ impl Apdu {
} }
/// Transmit this APDU using the given card transaction /// Transmit this APDU using the given card transaction
pub fn transmit(&self, txn: &Transaction<'_>, recv_len: usize) -> Result<Response, Error> { pub fn transmit(&self, txn: &Transaction<'_>, recv_len: usize) -> Result<Response> {
trace!(">>> {:?}", self); trace!(">>> {:?}", self);
let response = Response::from(txn.transmit(&self.to_bytes(), recv_len)?); let response = Response::from(txn.transmit(&self.to_bytes(), recv_len)?);
trace!("<<< {:?}", &response); trace!("<<< {:?}", &response);
+5 -5
View File
@@ -30,7 +30,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::{error::Error, yubikey::YubiKey}; use crate::{Error, Result, YubiKey};
use getrandom::getrandom; use getrandom::getrandom;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};
use subtle_encoding::hex; use subtle_encoding::hex;
@@ -68,7 +68,7 @@ pub struct CardId(pub [u8; CCCID_SIZE]);
impl CardId { impl CardId {
/// Generate a random CCC Card ID /// Generate a random CCC Card ID
pub fn generate() -> Result<Self, Error> { pub fn generate() -> Result<Self> {
let mut id = [0u8; CCCID_SIZE]; let mut id = [0u8; CCCID_SIZE];
getrandom(&mut id).map_err(|_| Error::RandomnessError)?; getrandom(&mut id).map_err(|_| Error::RandomnessError)?;
Ok(Self(id)) Ok(Self(id))
@@ -81,14 +81,14 @@ pub struct Ccc(pub [u8; CCC_SIZE]);
impl Ccc { impl Ccc {
/// Return CardId component of CCC /// Return CardId component of CCC
pub fn card_id(&self) -> Result<CardId, Error> { pub fn card_id(&self) -> Result<CardId> {
let mut cccid = [0u8; CCCID_SIZE]; let mut cccid = [0u8; CCCID_SIZE];
cccid.copy_from_slice(&self.0[CCC_ID_OFFS..(CCC_ID_OFFS + CCCID_SIZE)]); cccid.copy_from_slice(&self.0[CCC_ID_OFFS..(CCC_ID_OFFS + CCCID_SIZE)]);
Ok(CardId(cccid)) Ok(CardId(cccid))
} }
/// Get Cardholder Capability Container (CCC) ID /// Get Cardholder Capability Container (CCC) ID
pub fn get(yubikey: &mut YubiKey) -> Result<Self, Error> { pub fn get(yubikey: &mut YubiKey) -> Result<Self> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let response = txn.fetch_object(OBJ_CAPABILITY)?; let response = txn.fetch_object(OBJ_CAPABILITY)?;
@@ -103,7 +103,7 @@ impl Ccc {
/// Set Cardholder Capability Container (CCC) ID /// Set Cardholder Capability Container (CCC) ID
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set(&self, yubikey: &mut YubiKey) -> Result<(), Error> { pub fn set(&self, yubikey: &mut YubiKey) -> Result<()> {
let mut buf = CCC_TMPL.to_vec(); let mut buf = CCC_TMPL.to_vec();
buf[0..self.0.len()].copy_from_slice(&self.0); buf[0..self.0.len()].copy_from_slice(&self.0);
+17 -22
View File
@@ -31,7 +31,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::{
error::Error, error::{Error, Result},
key::{sign_data, AlgorithmId, SlotId}, key::{sign_data, AlgorithmId, SlotId},
serialization::*, serialization::*,
transaction::Transaction, transaction::Transaction,
@@ -82,13 +82,13 @@ impl From<[u8; 20]> for Serial {
} }
impl TryFrom<&[u8]> for Serial { impl TryFrom<&[u8]> for Serial {
type Error = (); type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Serial, ()> { fn try_from(bytes: &[u8]) -> Result<Serial> {
if bytes.len() <= 20 { if bytes.len() <= 20 {
Ok(Serial(BigUint::from_bytes_be(&bytes))) Ok(Serial(BigUint::from_bytes_be(&bytes)))
} else { } else {
Err(()) Err(Error::ParseError)
} }
} }
} }
@@ -112,7 +112,7 @@ pub enum CertInfo {
impl TryFrom<u8> for CertInfo { impl TryFrom<u8> for CertInfo {
type Error = Error; type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self> {
match value { match value {
0x00 => Ok(CertInfo::Uncompressed), 0x00 => Ok(CertInfo::Uncompressed),
0x01 => Ok(CertInfo::Gzip), 0x01 => Ok(CertInfo::Gzip),
@@ -190,7 +190,7 @@ impl fmt::Debug for PublicKeyInfo {
} }
impl PublicKeyInfo { impl PublicKeyInfo {
fn parse(subject_pki: &SubjectPublicKeyInfo<'_>) -> Result<Self, Error> { fn parse(subject_pki: &SubjectPublicKeyInfo<'_>) -> Result<Self> {
match subject_pki.algorithm.algorithm.to_string().as_str() { match subject_pki.algorithm.algorithm.to_string().as_str() {
OID_RSA_ENCRYPTION => { OID_RSA_ENCRYPTION => {
let pubkey = read_pki::rsa_pubkey(subject_pki.subject_public_key.data)?; let pubkey = read_pki::rsa_pubkey(subject_pki.subject_public_key.data)?;
@@ -330,7 +330,7 @@ pub struct Certificate {
impl<'a> TryFrom<&'a [u8]> for Certificate { impl<'a> TryFrom<&'a [u8]> for Certificate {
type Error = Error; type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self, Error> { fn try_from(bytes: &'a [u8]) -> Result<Self> {
Self::from_bytes(bytes.to_vec()) Self::from_bytes(bytes.to_vec())
} }
} }
@@ -350,7 +350,7 @@ impl Certificate {
subject: &[RelativeDistinguishedName<'_>], subject: &[RelativeDistinguishedName<'_>],
subject_pki: PublicKeyInfo, subject_pki: PublicKeyInfo,
extensions: &[x509::Extension<'_, O>], extensions: &[x509::Extension<'_, O>],
) -> Result<Self, Error> { ) -> Result<Self> {
let serial = serial.into(); let serial = serial.into();
let mut tbs_cert = Buffer::new(Vec::with_capacity(CB_OBJ_MAX)); let mut tbs_cert = Buffer::new(Vec::with_capacity(CB_OBJ_MAX));
@@ -453,7 +453,7 @@ impl Certificate {
} }
/// Read a certificate from the given slot in the YubiKey /// Read a certificate from the given slot in the YubiKey
pub fn read(yubikey: &mut YubiKey, slot: SlotId) -> Result<Self, Error> { pub fn read(yubikey: &mut YubiKey, slot: SlotId) -> Result<Self> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let buf = read_certificate(&txn, slot)?; let buf = read_certificate(&txn, slot)?;
@@ -465,25 +465,20 @@ impl Certificate {
} }
/// Write this certificate into the YubiKey in the given slot /// Write this certificate into the YubiKey in the given slot
pub fn write( pub fn write(&self, yubikey: &mut YubiKey, slot: SlotId, certinfo: CertInfo) -> Result<()> {
&self,
yubikey: &mut YubiKey,
slot: SlotId,
certinfo: CertInfo,
) -> Result<(), Error> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
write_certificate(&txn, slot, Some(&self.data), certinfo) write_certificate(&txn, slot, Some(&self.data), certinfo)
} }
/// Delete a certificate located at the given slot of the given YubiKey /// Delete a certificate located at the given slot of the given YubiKey
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn delete(yubikey: &mut YubiKey, slot: SlotId) -> Result<(), Error> { pub fn delete(yubikey: &mut YubiKey, slot: SlotId) -> Result<()> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
write_certificate(&txn, slot, None, CertInfo::Uncompressed) write_certificate(&txn, slot, None, CertInfo::Uncompressed)
} }
/// Initialize a local certificate struct from the given bytebuffer /// Initialize a local certificate struct from the given bytebuffer
pub fn from_bytes(cert: impl Into<Buffer>) -> Result<Self, Error> { pub fn from_bytes(cert: impl Into<Buffer>) -> Result<Self> {
let cert = cert.into(); let cert = cert.into();
if cert.is_empty() { if cert.is_empty() {
@@ -544,7 +539,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> {
let object_id = slot.object_id(); let object_id = slot.object_id();
let buf = match txn.fetch_object(object_id) { let buf = match txn.fetch_object(object_id) {
@@ -572,7 +567,7 @@ pub(crate) fn write_certificate(
slot: SlotId, slot: SlotId,
data: Option<&[u8]>, data: Option<&[u8]>,
certinfo: CertInfo, certinfo: CertInfo,
) -> Result<(), Error> { ) -> Result<()> {
let object_id = slot.object_id(); let object_id = slot.object_id();
if data.is_none() { if data.is_none() {
@@ -602,7 +597,7 @@ mod read_pki {
use rsa::{BigUint, RSAPublicKey}; use rsa::{BigUint, RSAPublicKey};
use super::{OID_NIST_P256, OID_NIST_P384}; use super::{OID_NIST_P256, OID_NIST_P384};
use crate::{error::Error, key::AlgorithmId}; use crate::{key::AlgorithmId, Error, Result};
/// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1): /// From [RFC 8017](https://tools.ietf.org/html/rfc8017#appendix-A.1.1):
/// ```text /// ```text
@@ -611,7 +606,7 @@ mod read_pki {
/// publicExponent INTEGER -- e /// publicExponent INTEGER -- e
/// } /// }
/// ``` /// ```
pub(super) fn rsa_pubkey(encoded: &[u8]) -> Result<RSAPublicKey, Error> { pub(super) fn rsa_pubkey(encoded: &[u8]) -> Result<RSAPublicKey> {
fn parse_rsa_pubkey(i: &[u8]) -> IResult<&[u8], DerObject<'_>, BerError> { fn parse_rsa_pubkey(i: &[u8]) -> IResult<&[u8], DerObject<'_>, BerError> {
parse_der_sequence_defined!(i, parse_der_integer >> parse_der_integer) parse_der_sequence_defined!(i, parse_der_integer >> parse_der_integer)
} }
@@ -650,7 +645,7 @@ mod read_pki {
/// -- specifiedCurve SpecifiedECDomain /// -- specifiedCurve SpecifiedECDomain
/// } /// }
/// ``` /// ```
pub(super) fn ec_parameters(parameters: &DerObject<'_>) -> Result<AlgorithmId, Error> { pub(super) fn ec_parameters(parameters: &DerObject<'_>) -> Result<AlgorithmId> {
let curve_oid = parameters.as_oid_val().map_err(|_| Error::InvalidObject)?; let curve_oid = parameters.as_oid_val().map_err(|_| Error::InvalidObject)?;
match curve_oid.to_string().as_str() { match curve_oid.to_string().as_str() {
+7 -7
View File
@@ -30,7 +30,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::{error::Error, yubikey::YubiKey}; use crate::{Error, Result, YubiKey};
use getrandom::getrandom; use getrandom::getrandom;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};
use subtle_encoding::hex; use subtle_encoding::hex;
@@ -87,7 +87,7 @@ pub struct Uuid(pub [u8; CARDID_SIZE]);
impl Uuid { impl Uuid {
/// Generate a random Cardholder Unique Identifier (CHUID) UUID /// Generate a random Cardholder Unique Identifier (CHUID) UUID
pub fn generate() -> Result<Self, Error> { pub fn generate() -> Result<Self> {
let mut id = [0u8; CARDID_SIZE]; let mut id = [0u8; CARDID_SIZE];
getrandom(&mut id).map_err(|_| Error::RandomnessError)?; getrandom(&mut id).map_err(|_| Error::RandomnessError)?;
Ok(Self(id)) Ok(Self(id))
@@ -100,14 +100,14 @@ pub struct ChuId(pub [u8; CHUID_SIZE]);
impl ChuId { impl ChuId {
/// Return FASC-N component of CHUID /// Return FASC-N component of CHUID
pub fn fascn(&self) -> Result<[u8; FASCN_SIZE], Error> { pub fn fascn(&self) -> Result<[u8; FASCN_SIZE]> {
let mut fascn = [0u8; FASCN_SIZE]; let mut fascn = [0u8; FASCN_SIZE];
fascn.copy_from_slice(&self.0[CHUID_FASCN_OFFS..(CHUID_FASCN_OFFS + FASCN_SIZE)]); fascn.copy_from_slice(&self.0[CHUID_FASCN_OFFS..(CHUID_FASCN_OFFS + FASCN_SIZE)]);
Ok(fascn) Ok(fascn)
} }
/// Return Card UUID/GUID component of CHUID /// Return Card UUID/GUID component of CHUID
pub fn uuid(&self) -> Result<[u8; CARDID_SIZE], Error> { pub fn uuid(&self) -> Result<[u8; CARDID_SIZE]> {
let mut uuid = [0u8; CARDID_SIZE]; let mut uuid = [0u8; CARDID_SIZE];
uuid.copy_from_slice(&self.0[CHUID_GUID_OFFS..(CHUID_GUID_OFFS + CARDID_SIZE)]); uuid.copy_from_slice(&self.0[CHUID_GUID_OFFS..(CHUID_GUID_OFFS + CARDID_SIZE)]);
Ok(uuid) Ok(uuid)
@@ -115,7 +115,7 @@ impl ChuId {
/// Return expiration date component of CHUID /// Return expiration date component of CHUID
// TODO(tarcieri): parse expiration? // TODO(tarcieri): parse expiration?
pub fn expiration(&self) -> Result<[u8; EXPIRATION_SIZE], Error> { pub fn expiration(&self) -> Result<[u8; EXPIRATION_SIZE]> {
let mut expiration = [0u8; EXPIRATION_SIZE]; let mut expiration = [0u8; EXPIRATION_SIZE];
expiration.copy_from_slice( expiration.copy_from_slice(
&self.0[CHUID_EXPIRATION_OFFS..(CHUID_EXPIRATION_OFFS + EXPIRATION_SIZE)], &self.0[CHUID_EXPIRATION_OFFS..(CHUID_EXPIRATION_OFFS + EXPIRATION_SIZE)],
@@ -124,7 +124,7 @@ impl ChuId {
} }
/// Get Cardholder Unique Identifier (CHUID) /// Get Cardholder Unique Identifier (CHUID)
pub fn get(yubikey: &mut YubiKey) -> Result<ChuId, Error> { pub fn get(yubikey: &mut YubiKey) -> Result<ChuId> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let response = txn.fetch_object(OBJ_CHUID)?; let response = txn.fetch_object(OBJ_CHUID)?;
@@ -140,7 +140,7 @@ impl ChuId {
/// Set Cardholder Unique Identifier (CHUID) /// Set Cardholder Unique Identifier (CHUID)
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set(&self, yubikey: &mut YubiKey) -> Result<(), Error> { pub fn set(&self, yubikey: &mut YubiKey) -> Result<()> {
let mut buf = CHUID_TMPL.to_vec(); let mut buf = CHUID_TMPL.to_vec();
buf[0..self.0.len()].copy_from_slice(&self.0); buf[0..self.0.len()].copy_from_slice(&self.0);
+2 -3
View File
@@ -31,11 +31,10 @@
// 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::{
error::Error,
metadata::{AdminData, ProtectedData}, metadata::{AdminData, ProtectedData},
mgm::{MgmType, ADMIN_FLAGS_1_PROTECTED_MGM}, mgm::{MgmType, ADMIN_FLAGS_1_PROTECTED_MGM},
yubikey::{YubiKey, ADMIN_FLAGS_1_PUK_BLOCKED}, yubikey::{YubiKey, ADMIN_FLAGS_1_PUK_BLOCKED},
TAG_ADMIN_FLAGS_1, TAG_ADMIN_SALT, TAG_ADMIN_TIMESTAMP, TAG_PROTECTED_FLAGS_1, Result, TAG_ADMIN_FLAGS_1, TAG_ADMIN_SALT, TAG_ADMIN_TIMESTAMP, TAG_PROTECTED_FLAGS_1,
TAG_PROTECTED_MGM, TAG_PROTECTED_MGM,
}; };
use log::error; use log::error;
@@ -68,7 +67,7 @@ pub struct Config {
impl Config { impl Config {
/// Get YubiKey config /// Get YubiKey config
pub fn get(yubikey: &mut YubiKey) -> Result<Config, Error> { pub fn get(yubikey: &mut YubiKey) -> Result<Config> {
let mut config = Config { let mut config = Config {
protected_data_available: false, protected_data_available: false,
puk_blocked: false, puk_blocked: false,
+72 -70
View File
@@ -32,65 +32,69 @@
use std::fmt::{self, Display}; use std::fmt::{self, Display};
/// Result type with [`Error`].
pub type Result<T> = core::result::Result<T, Error>;
/// Kinds of errors /// Kinds of errors
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error { pub enum Error {
/// Algorithm error
AlgorithmError,
/// Applet error
AppletError,
/// Argument error
ArgumentError,
/// Authentication error
AuthenticationError,
/// Generic error
GenericError,
/// Invalid object
InvalidObject,
/// Key error
KeyError,
/// Memory error /// Memory error
MemoryError, MemoryError,
/// Not supported
NotSupported,
/// Not found
NotFound,
/// Parse error
ParseError,
/// PCSC error /// PCSC error
PcscError { PcscError {
/// Original PC/SC error /// Original PC/SC error
inner: Option<pcsc::Error>, inner: Option<pcsc::Error>,
}, },
/// Size error /// PIN locked
SizeError, PinLocked,
/// Applet error
AppletError,
/// Authentication error
AuthenticationError,
/// Randomness error /// Randomness error
RandomnessError, RandomnessError,
/// Generic error /// Range error
GenericError, RangeError,
/// Key error /// Size error
KeyError, SizeError,
/// Parse error
ParseError,
/// Wrong PIN /// Wrong PIN
WrongPin { WrongPin {
/// Number of tries remaining /// Number of tries remaining
tries: u8, tries: u8,
}, },
/// Invalid object
InvalidObject,
/// Algorithm error
AlgorithmError,
/// PIN locked
PinLocked,
/// Argument error
ArgumentError,
/// Range error
RangeError,
/// Not supported
NotSupported,
/// Not found
NotFound,
} }
impl Error { impl Error {
@@ -98,48 +102,48 @@ impl Error {
/// ///
/// These names map to the legacy names from the Yubico C library, to /// These names map to the legacy names from the Yubico C library, to
/// assist in web searches for relevant information for these errors. /// assist in web searches for relevant information for these errors.
pub fn name(self) -> &'static str { pub fn name(self) -> Option<&'static str> {
match self { Some(match self {
Error::MemoryError => "YKPIV_MEMORY_ERROR",
Error::PcscError { .. } => "YKPIV_PCSC_ERROR",
Error::SizeError => "YKPIV_SIZE_ERROR",
Error::AppletError => "YKPIV_APPLET_ERROR",
Error::AuthenticationError => "YKPIV_AUTHENTICATION_ERROR",
Error::RandomnessError => "YKPIV_RANDOMNESS_ERROR",
Error::GenericError => "YKPIV_GENERIC_ERROR",
Error::KeyError => "YKPIV_KEY_ERROR",
Error::ParseError => "YKPIV_PARSE_ERROR",
Error::WrongPin { .. } => "YKPIV_WRONG_PIN",
Error::InvalidObject => "YKPIV_INVALID_OBJECT",
Error::AlgorithmError => "YKPIV_ALGORITHM_ERROR", Error::AlgorithmError => "YKPIV_ALGORITHM_ERROR",
Error::PinLocked => "YKPIV_PIN_LOCKED", Error::AppletError => "YKPIV_APPLET_ERROR",
Error::ArgumentError => "YKPIV_ARGUMENT_ERROR", Error::ArgumentError => "YKPIV_ARGUMENT_ERROR",
Error::RangeError => "YKPIV_RANGE_ERROR", Error::AuthenticationError => "YKPIV_AUTHENTICATION_ERROR",
Error::GenericError => "YKPIV_GENERIC_ERROR",
Error::InvalidObject => "YKPIV_INVALID_OBJECT",
Error::KeyError => "YKPIV_KEY_ERROR",
Error::MemoryError => "YKPIV_MEMORY_ERROR",
Error::NotSupported => "YKPIV_NOT_SUPPORTED", Error::NotSupported => "YKPIV_NOT_SUPPORTED",
Error::NotFound => "<not found>", Error::ParseError => "YKPIV_PARSE_ERROR",
} Error::PcscError { .. } => "YKPIV_PCSC_ERROR",
Error::PinLocked => "YKPIV_PIN_LOCKED",
Error::RandomnessError => "YKPIV_RANDOMNESS_ERROR",
Error::RangeError => "YKPIV_RANGE_ERROR",
Error::SizeError => "YKPIV_SIZE_ERROR",
Error::WrongPin { .. } => "YKPIV_WRONG_PIN",
_ => return None,
})
} }
/// Error message /// Error message
pub fn msg(self) -> &'static str { pub fn msg(self) -> &'static str {
match self { match self {
Error::MemoryError => "memory error",
Error::PcscError { .. } => "PCSC error",
Error::SizeError => "size error",
Error::AppletError => "applet error",
Error::AuthenticationError => "authentication error",
Error::RandomnessError => "randomness error",
Error::GenericError => "generic error",
Error::KeyError => "key error",
Error::ParseError => "parse error",
Error::WrongPin { .. } => "wrong pin",
Error::InvalidObject => "invalid object",
Error::AlgorithmError => "algorithm error", Error::AlgorithmError => "algorithm error",
Error::PinLocked => "PIN locked", Error::AppletError => "applet error",
Error::ArgumentError => "argument error", Error::ArgumentError => "argument error",
Error::RangeError => "range error", Error::AuthenticationError => "authentication error",
Error::GenericError => "generic error",
Error::InvalidObject => "invalid object",
Error::KeyError => "key error",
Error::MemoryError => "memory error",
Error::NotSupported => "not supported", Error::NotSupported => "not supported",
Error::NotFound => "not found", Error::NotFound => "not found",
Error::ParseError => "parse error",
Error::PcscError { .. } => "PC/SC error",
Error::PinLocked => "PIN locked",
Error::RandomnessError => "randomness error",
Error::RangeError => "range error",
Error::SizeError => "size error",
Error::WrongPin { .. } => "wrong pin",
} }
} }
} }
@@ -159,10 +163,8 @@ impl From<pcsc::Error> for Error {
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self { match self {
#[allow(trivial_casts)] // why doesn't this work without the cast??? #[allow(trivial_casts)]
Error::PcscError { inner } => inner Error::PcscError { inner } => inner.as_ref().map(|err| err as &_),
.as_ref()
.map(|err| err as &(dyn std::error::Error + 'static)),
_ => None, _ => None,
} }
} }
+18 -22
View File
@@ -39,23 +39,19 @@
use crate::{ use crate::{
apdu::{Ins, StatusWords}, apdu::{Ins, StatusWords},
certificate::{self, Certificate}, certificate::{self, Certificate, PublicKeyInfo},
error::Error, error::{Error, Result},
policy::{PinPolicy, TouchPolicy},
serialization::*, serialization::*,
settings, settings,
yubikey::YubiKey, yubikey::YubiKey,
ObjectId, Buffer, ObjectId,
}; };
use log::debug; use log::debug;
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
use crate::CB_OBJ_MAX; use crate::CB_OBJ_MAX;
use crate::{
certificate::PublicKeyInfo,
policy::{PinPolicy, TouchPolicy},
Buffer,
};
use elliptic_curve::sec1::EncodedPoint as EcPublicKey; use elliptic_curve::sec1::EncodedPoint as EcPublicKey;
use log::{error, warn}; use log::{error, warn};
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
@@ -126,7 +122,7 @@ pub enum SlotId {
impl TryFrom<u8> for SlotId { impl TryFrom<u8> for SlotId {
type Error = Error; type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self> {
match value { match value {
0x9a => Ok(SlotId::Authentication), 0x9a => Ok(SlotId::Authentication),
0x9c => Ok(SlotId::Signature), 0x9c => Ok(SlotId::Signature),
@@ -154,7 +150,7 @@ impl From<SlotId> for u8 {
impl TryFrom<String> for SlotId { impl TryFrom<String> for SlotId {
type Error = Error; type Error = Error;
fn try_from(s: String) -> Result<SlotId, Error> { fn try_from(s: String) -> Result<SlotId> {
match s.as_ref() { match s.as_ref() {
"9a" => Ok(SlotId::Authentication), "9a" => Ok(SlotId::Authentication),
"9c" => Ok(SlotId::Signature), "9c" => Ok(SlotId::Signature),
@@ -209,7 +205,7 @@ pub enum RetiredSlotId {
impl TryFrom<u8> for RetiredSlotId { impl TryFrom<u8> for RetiredSlotId {
type Error = Error; type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self> {
match value { match value {
0x82 => Ok(RetiredSlotId::R1), 0x82 => Ok(RetiredSlotId::R1),
0x83 => Ok(RetiredSlotId::R2), 0x83 => Ok(RetiredSlotId::R2),
@@ -239,7 +235,7 @@ impl TryFrom<u8> for RetiredSlotId {
impl TryFrom<String> for RetiredSlotId { impl TryFrom<String> for RetiredSlotId {
type Error = Error; type Error = Error;
fn try_from(value: String) -> Result<Self, Self::Error> { fn try_from(value: String) -> Result<Self> {
match value.as_ref() { match value.as_ref() {
"82" => Ok(RetiredSlotId::R1), "82" => Ok(RetiredSlotId::R1),
"83" => Ok(RetiredSlotId::R2), "83" => Ok(RetiredSlotId::R2),
@@ -365,7 +361,7 @@ pub enum AlgorithmId {
impl TryFrom<u8> for AlgorithmId { impl TryFrom<u8> for AlgorithmId {
type Error = Error; type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self> {
match value { match value {
0x06 => Ok(AlgorithmId::Rsa1024), 0x06 => Ok(AlgorithmId::Rsa1024),
0x07 => Ok(AlgorithmId::Rsa2048), 0x07 => Ok(AlgorithmId::Rsa2048),
@@ -389,7 +385,7 @@ impl From<AlgorithmId> for u8 {
impl AlgorithmId { impl AlgorithmId {
/// Writes the `AlgorithmId` in the format the YubiKey expects during key generation. /// Writes the `AlgorithmId` in the format the YubiKey expects during key generation.
pub(crate) fn write(self, buf: &mut [u8]) -> Result<usize, Error> { pub(crate) fn write(self, buf: &mut [u8]) -> Result<usize> {
Tlv::write(buf, 0x80, &[self.into()]) Tlv::write(buf, 0x80, &[self.into()])
} }
@@ -424,7 +420,7 @@ pub struct Key {
impl Key { impl Key {
/// List Personal Identity Verification (PIV) keys stored in a YubiKey /// List Personal Identity Verification (PIV) keys stored in a YubiKey
pub fn list(yubikey: &mut YubiKey) -> Result<Vec<Self>, Error> { pub fn list(yubikey: &mut YubiKey) -> Result<Vec<Self>> {
let mut keys = vec![]; let mut keys = vec![];
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
@@ -465,7 +461,7 @@ pub fn generate(
algorithm: AlgorithmId, algorithm: AlgorithmId,
pin_policy: PinPolicy, pin_policy: PinPolicy,
touch_policy: TouchPolicy, touch_policy: TouchPolicy,
) -> Result<PublicKeyInfo, Error> { ) -> Result<PublicKeyInfo> {
// Keygen messages // Keygen messages
// TODO(tarcieri): extract these into an I18N-handling type? // TODO(tarcieri): extract these into an I18N-handling type?
const SZ_SETTING_ROCA: &str = "Enable_Unsafe_Keygen_ROCA"; const SZ_SETTING_ROCA: &str = "Enable_Unsafe_Keygen_ROCA";
@@ -671,7 +667,7 @@ fn write_key(
pin_policy: PinPolicy, pin_policy: PinPolicy,
touch_policy: TouchPolicy, touch_policy: TouchPolicy,
algorithm: AlgorithmId, algorithm: AlgorithmId,
) -> Result<(), Error> { ) -> Result<()> {
let mut key_data = Buffer::new(vec![0u8; KEYDATA_LEN]); let mut key_data = Buffer::new(vec![0u8; KEYDATA_LEN]);
let templ = [0, Ins::ImportKey.code(), algorithm.into(), slot.into()]; let templ = [0, Ins::ImportKey.code(), algorithm.into(), slot.into()];
let mut offset = 0; let mut offset = 0;
@@ -780,7 +776,7 @@ pub fn import_rsa_key(
key_data: RsaKeyData, key_data: RsaKeyData,
touch_policy: TouchPolicy, touch_policy: TouchPolicy,
pin_policy: PinPolicy, pin_policy: PinPolicy,
) -> Result<(), Error> { ) -> Result<()> {
match algorithm { match algorithm {
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => (), AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => (),
_ => return Err(Error::AlgorithmError), _ => return Err(Error::AlgorithmError),
@@ -814,7 +810,7 @@ pub fn import_ecc_key(
key_data: &[u8], key_data: &[u8],
touch_policy: TouchPolicy, touch_policy: TouchPolicy,
pin_policy: PinPolicy, pin_policy: PinPolicy,
) -> Result<(), Error> { ) -> Result<()> {
match algorithm { match algorithm {
AlgorithmId::EccP256 | AlgorithmId::EccP384 => (), AlgorithmId::EccP256 | AlgorithmId::EccP384 => (),
_ => return Err(Error::AlgorithmError), _ => return Err(Error::AlgorithmError),
@@ -834,7 +830,7 @@ pub fn import_ecc_key(
/// Generate an attestation certificate for a stored key. /// Generate an attestation certificate for a stored key.
/// <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(yubikey: &mut YubiKey, key: SlotId) -> Result<Buffer, Error> { pub fn attest(yubikey: &mut YubiKey, key: SlotId) -> Result<Buffer> {
let templ = [0, Ins::Attest.code(), key.into(), 0]; let templ = [0, Ins::Attest.code(), key.into(), 0];
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let response = txn.transfer_data(&templ, &[], CB_OBJ_MAX)?; let response = txn.transfer_data(&templ, &[], CB_OBJ_MAX)?;
@@ -860,7 +856,7 @@ pub fn sign_data(
raw_in: &[u8], raw_in: &[u8],
algorithm: AlgorithmId, algorithm: AlgorithmId,
key: SlotId, key: SlotId,
) -> Result<Buffer, Error> { ) -> Result<Buffer> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
// don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS // don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS
@@ -874,7 +870,7 @@ pub fn decrypt_data(
input: &[u8], input: &[u8],
algorithm: AlgorithmId, algorithm: AlgorithmId,
key: SlotId, key: SlotId,
) -> Result<Buffer, Error> { ) -> Result<Buffer> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
// don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS // don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS
+1 -1
View File
@@ -149,7 +149,7 @@ mod transaction;
pub mod yubikey; pub mod yubikey;
pub use self::{ pub use self::{
error::Error, error::{Error, Result},
key::Key, key::Key,
mgm::MgmKey, mgm::MgmKey,
readers::Readers, readers::Readers,
+6 -6
View File
@@ -33,7 +33,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use zeroize::Zeroizing; use zeroize::Zeroizing;
use crate::{error::Error, serialization::*, transaction::Transaction, Buffer}; use crate::{serialization::*, transaction::Transaction, Buffer, Error, Result};
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
use crate::{CB_OBJ_MAX, CB_OBJ_TAG_MAX}; use crate::{CB_OBJ_MAX, CB_OBJ_TAG_MAX};
@@ -78,7 +78,7 @@ impl<T: MetadataType> Default for Metadata<T> {
impl<T: MetadataType> Metadata<T> { impl<T: MetadataType> Metadata<T> {
/// Read metadata /// Read metadata
pub(crate) fn read(txn: &Transaction<'_>) -> Result<Self, Error> { pub(crate) fn read(txn: &Transaction<'_>) -> Result<Self> {
let data = txn.fetch_object(T::obj_id())?; let data = txn.fetch_object(T::obj_id())?;
Ok(Metadata { Ok(Metadata {
inner: Tlv::parse_single(data, T::tag())?, inner: Tlv::parse_single(data, T::tag())?,
@@ -88,7 +88,7 @@ impl<T: MetadataType> Metadata<T> {
/// Write metadata /// Write metadata
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub(crate) fn write(&self, txn: &Transaction<'_>) -> Result<(), Error> { pub(crate) fn write(&self, txn: &Transaction<'_>) -> Result<()> {
if self.inner.len() > CB_OBJ_MAX - CB_OBJ_TAG_MAX { if self.inner.len() > CB_OBJ_MAX - CB_OBJ_TAG_MAX {
return Err(Error::GenericError); return Err(Error::GenericError);
} }
@@ -105,12 +105,12 @@ impl<T: MetadataType> Metadata<T> {
/// Delete metadata /// Delete metadata
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub(crate) fn delete(txn: &Transaction<'_>) -> Result<(), Error> { pub(crate) fn delete(txn: &Transaction<'_>) -> Result<()> {
txn.save_object(T::obj_id(), &[]) txn.save_object(T::obj_id(), &[])
} }
/// Get metadata item /// Get metadata item
pub(crate) fn get_item(&self, tag: u8) -> Result<&[u8], Error> { pub(crate) fn get_item(&self, tag: u8) -> Result<&[u8]> {
let mut data = &self.inner[..]; let mut data = &self.inner[..];
while !data.is_empty() { while !data.is_empty() {
@@ -128,7 +128,7 @@ impl<T: MetadataType> Metadata<T> {
/// Set metadata item /// Set metadata item
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub(crate) fn set_item(&mut self, tag: u8, item: &[u8]) -> Result<(), Error> { pub(crate) fn set_item(&mut self, tag: u8, item: &[u8]) -> Result<()> {
let mut cb_temp: usize = 0; let mut cb_temp: usize = 0;
let mut tag_temp: u8 = 0; let mut tag_temp: u8 = 0;
let mut cb_len: usize = 0; let mut cb_len: usize = 0;
+10 -10
View File
@@ -30,7 +30,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::error::Error; use crate::{Error, Result};
use getrandom::getrandom; use getrandom::getrandom;
use log::error; use log::error;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
@@ -97,7 +97,7 @@ pub struct MgmKey([u8; DES_LEN_3DES]);
impl MgmKey { impl MgmKey {
/// Generate a random MGM key /// Generate a random MGM key
pub fn generate() -> Result<Self, Error> { pub fn generate() -> Result<Self> {
let mut key_bytes = [0u8; DES_LEN_3DES]; let mut key_bytes = [0u8; DES_LEN_3DES];
if getrandom(&mut key_bytes).is_err() { if getrandom(&mut key_bytes).is_err() {
@@ -110,14 +110,14 @@ impl MgmKey {
/// Create an MGM key from byte slice. /// Create an MGM key from byte slice.
/// ///
/// Returns an error if the slice is the wrong size or the key is weak. /// Returns an error if the slice is the wrong size or the key is weak.
pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> { pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self> {
bytes.as_ref().try_into() bytes.as_ref().try_into()
} }
/// Create an MGM key from the given byte array. /// Create an MGM key from the given byte array.
/// ///
/// Returns an error if the key is weak. /// Returns an error if the key is weak.
pub fn new(key_bytes: [u8; DES_LEN_3DES]) -> Result<Self, Error> { pub fn new(key_bytes: [u8; DES_LEN_3DES]) -> Result<Self> {
if is_weak_key(&key_bytes) { if is_weak_key(&key_bytes) {
error!( error!(
"blacklisting key '{:?}' since it's weak (with odd parity)", "blacklisting key '{:?}' since it's weak (with odd parity)",
@@ -132,7 +132,7 @@ impl MgmKey {
/// Get derived management key (MGM) /// Get derived management key (MGM)
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn get_derived(yubikey: &mut YubiKey, pin: &[u8]) -> Result<Self, Error> { pub fn get_derived(yubikey: &mut YubiKey, pin: &[u8]) -> Result<Self> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
// recover management key // recover management key
@@ -157,7 +157,7 @@ impl MgmKey {
/// Get protected management key (MGM) /// Get protected management key (MGM)
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn get_protected(yubikey: &mut YubiKey) -> Result<Self, Error> { pub fn get_protected(yubikey: &mut YubiKey) -> Result<Self> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let protected_data = ProtectedData::read(&txn).map_err(|e| { let protected_data = ProtectedData::read(&txn).map_err(|e| {
@@ -187,7 +187,7 @@ impl MgmKey {
/// ///
/// This will wipe any metadata related to derived and PIN-protected management keys. /// This will wipe any metadata related to derived and PIN-protected management keys.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_default(yubikey: &mut YubiKey) -> Result<(), Error> { pub fn set_default(yubikey: &mut YubiKey) -> Result<()> {
MgmKey::default().set_manual(yubikey, false) MgmKey::default().set_manual(yubikey, false)
} }
@@ -198,7 +198,7 @@ impl MgmKey {
/// ///
/// This will wipe any metadata related to derived and PIN-protected management keys. /// This will wipe any metadata related to derived and PIN-protected management keys.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_manual(&self, yubikey: &mut YubiKey, require_touch: bool) -> Result<(), Error> { pub fn set_manual(&self, yubikey: &mut YubiKey, require_touch: bool) -> Result<()> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
txn.set_mgm_key(&self, require_touch).map_err(|e| { txn.set_mgm_key(&self, require_touch).map_err(|e| {
@@ -257,7 +257,7 @@ impl MgmKey {
/// ///
/// This enables key management operations to be performed with access to the PIN. /// This enables key management operations to be performed with access to the PIN.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_protected(&self, yubikey: &mut YubiKey) -> Result<(), Error> { pub fn set_protected(&self, yubikey: &mut YubiKey) -> Result<()> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
txn.set_mgm_key(self, false).map_err(|e| { txn.set_mgm_key(self, false).map_err(|e| {
@@ -364,7 +364,7 @@ impl Drop for MgmKey {
impl<'a> TryFrom<&'a [u8]> for MgmKey { impl<'a> TryFrom<&'a [u8]> for MgmKey {
type Error = Error; type Error = Error;
fn try_from(key_bytes: &'a [u8]) -> Result<Self, Error> { fn try_from(key_bytes: &'a [u8]) -> Result<Self> {
Self::new(key_bytes.try_into().map_err(|_| Error::SizeError)?) Self::new(key_bytes.try_into().map_err(|_| Error::SizeError)?)
} }
} }
+6 -6
View File
@@ -33,7 +33,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::{error::Error, key::SlotId, serialization::*, yubikey::YubiKey, CB_OBJ_MAX}; use crate::{key::SlotId, serialization::*, Error, Result, YubiKey, CB_OBJ_MAX};
use log::error; use log::error;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
@@ -77,7 +77,7 @@ pub struct Container {
impl Container { impl Container {
/// Read MS Container Map records /// Read MS Container Map records
pub fn read_mscmap(yubikey: &mut YubiKey) -> Result<Vec<Self>, Error> { pub fn read_mscmap(yubikey: &mut YubiKey) -> Result<Vec<Self>> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let response = txn.fetch_object(OBJ_MSCMAP)?; let response = txn.fetch_object(OBJ_MSCMAP)?;
let mut containers = vec![]; let mut containers = vec![];
@@ -103,7 +103,7 @@ impl Container {
} }
/// Write MS Container Map records. /// Write MS Container Map records.
pub fn write_mscmap(yubikey: &mut YubiKey, containers: &[Self]) -> Result<(), Error> { pub fn write_mscmap(yubikey: &mut YubiKey, containers: &[Self]) -> Result<()> {
let n_containers = containers.len(); let n_containers = containers.len();
let data_len = n_containers * CONTAINER_REC_LEN; let data_len = n_containers * CONTAINER_REC_LEN;
@@ -124,7 +124,7 @@ impl Container {
} }
/// Parse a container record from a byte slice /// Parse a container record from a byte slice
pub fn new(bytes: &[u8]) -> Result<Self, Error> { pub fn new(bytes: &[u8]) -> Result<Self> {
if bytes.len() != CONTAINER_REC_LEN { if bytes.len() != CONTAINER_REC_LEN {
error!( error!(
"couldn't parse PIV container: expected {}-bytes, got {}-bytes", "couldn't parse PIV container: expected {}-bytes, got {}-bytes",
@@ -161,7 +161,7 @@ impl Container {
} }
/// Parse the container name as a UTF-16 string /// Parse the container name as a UTF-16 string
pub fn parse_name(&self) -> Result<String, Error> { pub fn parse_name(&self) -> Result<String> {
String::from_utf16(&self.name).map_err(|_| Error::ParseError) String::from_utf16(&self.name).map_err(|_| Error::ParseError)
} }
@@ -188,7 +188,7 @@ impl Container {
impl<'a> TryFrom<&'a [u8]> for Container { impl<'a> TryFrom<&'a [u8]> for Container {
type Error = Error; type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self, Error> { fn try_from(bytes: &'a [u8]) -> Result<Self> {
Self::new(bytes) Self::new(bytes)
} }
} }
+4 -4
View File
@@ -37,7 +37,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::{error::Error, serialization::*, yubikey::YubiKey}; use crate::{serialization::*, Error, Result, YubiKey};
use crate::{CB_OBJ_MAX, CB_OBJ_TAG_MAX}; use crate::{CB_OBJ_MAX, CB_OBJ_TAG_MAX};
use log::error; use log::error;
@@ -58,12 +58,12 @@ pub struct MsRoots(Vec<u8>);
impl MsRoots { impl MsRoots {
/// Initialize a local certificate struct from the given bytebuffer /// Initialize a local certificate struct from the given bytebuffer
pub fn new(msroots: impl AsRef<[u8]>) -> Result<Self, Error> { pub fn new(msroots: impl AsRef<[u8]>) -> Result<Self> {
Ok(MsRoots(msroots.as_ref().into())) Ok(MsRoots(msroots.as_ref().into()))
} }
/// Read `msroots` file from YubiKey /// Read `msroots` file from YubiKey
pub fn read(yubikey: &mut YubiKey) -> Result<Option<Self>, Error> { pub fn read(yubikey: &mut YubiKey) -> Result<Option<Self>> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
// allocate first page // allocate first page
@@ -100,7 +100,7 @@ impl MsRoots {
} }
/// Write `msroots` file to YubiKey /// Write `msroots` file to YubiKey
pub fn write(&self, yubikey: &mut YubiKey) -> Result<(), Error> { pub fn write(&self, yubikey: &mut YubiKey) -> Result<()> {
let mut buf = [0u8; CB_OBJ_MAX]; let mut buf = [0u8; CB_OBJ_MAX];
let mut offset: usize; let mut offset: usize;
let mut data_offset: usize = 0; let mut data_offset: usize = 0;
+3 -3
View File
@@ -1,6 +1,6 @@
//! Enums representing key policies. //! Enums representing key policies.
use crate::{error::Error, serialization::Tlv}; use crate::{serialization::Tlv, Result};
/// Specifies how often the PIN needs to be entered for access to the credential in a /// Specifies how often the PIN needs to be entered for access to the credential in a
/// given slot. This policy must be set upon key generation or importation, and cannot be /// given slot. This policy must be set upon key generation or importation, and cannot be
@@ -37,7 +37,7 @@ impl From<PinPolicy> for u8 {
impl PinPolicy { impl PinPolicy {
/// Writes the `PinPolicy` in the format the YubiKey expects during key generation or /// Writes the `PinPolicy` in the format the YubiKey expects during key generation or
/// importation. /// importation.
pub(crate) fn write(self, buf: &mut [u8]) -> Result<usize, Error> { pub(crate) fn write(self, buf: &mut [u8]) -> Result<usize> {
match self { match self {
PinPolicy::Default => Ok(0), PinPolicy::Default => Ok(0),
_ => Tlv::write(buf, 0xaa, &[self.into()]), _ => Tlv::write(buf, 0xaa, &[self.into()]),
@@ -81,7 +81,7 @@ impl From<TouchPolicy> for u8 {
impl TouchPolicy { impl TouchPolicy {
/// Writes the `TouchPolicy` in the format the YubiKey expects during key generation /// Writes the `TouchPolicy` in the format the YubiKey expects during key generation
/// or importation. /// or importation.
pub(crate) fn write(self, buf: &mut [u8]) -> Result<usize, Error> { pub(crate) fn write(self, buf: &mut [u8]) -> Result<usize> {
match self { match self {
TouchPolicy::Default => Ok(0), TouchPolicy::Default => Ok(0),
_ => Tlv::write(buf, 0xab, &[self.into()]), _ => Tlv::write(buf, 0xab, &[self.into()]),
+5 -5
View File
@@ -1,6 +1,6 @@
//! Support for enumerating available readers //! Support for enumerating available readers
use crate::{error::Error, yubikey::YubiKey}; use crate::{Result, YubiKey};
use std::{ use std::{
borrow::Cow, borrow::Cow,
convert::TryInto, convert::TryInto,
@@ -23,7 +23,7 @@ pub struct Readers {
impl Readers { impl Readers {
/// Open a PC/SC context, which can be used to enumerate available PC/SC /// Open a PC/SC context, which can be used to enumerate available PC/SC
/// readers (which can be used to connect to YubiKeys). /// readers (which can be used to connect to YubiKeys).
pub fn open() -> Result<Self, Error> { pub fn open() -> Result<Self> {
let ctx = pcsc::Context::establish(pcsc::Scope::System)?; let ctx = pcsc::Context::establish(pcsc::Scope::System)?;
let reader_names = vec![0u8; ctx.list_readers_len()?]; let reader_names = vec![0u8; ctx.list_readers_len()?];
Ok(Self { Ok(Self {
@@ -33,7 +33,7 @@ impl Readers {
} }
/// Iterate over the available readers /// Iterate over the available readers
pub fn iter(&mut self) -> Result<Iter<'_>, Error> { pub fn iter(&mut self) -> Result<Iter<'_>> {
let Self { ctx, reader_names } = self; let Self { ctx, reader_names } = self;
let reader_cstrs: Vec<_> = { let reader_cstrs: Vec<_> = {
@@ -77,12 +77,12 @@ impl<'ctx> Reader<'ctx> {
} }
/// Open a connection to this reader, returning a `YubiKey` if successful /// Open a connection to this reader, returning a `YubiKey` if successful
pub fn open(&self) -> Result<YubiKey, Error> { pub fn open(&self) -> Result<YubiKey> {
self.try_into() self.try_into()
} }
/// Connect to this reader, returning its `pcsc::Card` /// Connect to this reader, returning its `pcsc::Card`
pub(crate) fn connect(&self) -> Result<pcsc::Card, Error> { pub(crate) fn connect(&self) -> Result<pcsc::Card> {
let ctx = self.ctx.lock().unwrap(); let ctx = self.ctx.lock().unwrap();
Ok(ctx.connect(self.name, pcsc::ShareMode::Shared, pcsc::Protocols::T1)?) Ok(ctx.connect(self.name, pcsc::ShareMode::Shared, pcsc::Protocols::T1)?)
} }
+6 -6
View File
@@ -30,7 +30,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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::{error::Error, Buffer, ObjectId, CB_OBJ_TAG_MIN}; use crate::{Buffer, Error, ObjectId, Result, CB_OBJ_TAG_MIN};
pub const OBJ_DISCOVERY: u32 = 0x7e; pub const OBJ_DISCOVERY: u32 = 0x7e;
@@ -44,7 +44,7 @@ pub(crate) struct Tlv<'a> {
impl<'a> Tlv<'a> { impl<'a> Tlv<'a> {
/// Parses a `Tlv` from a buffer, returning the remainder of the buffer. /// Parses a `Tlv` from a buffer, returning the remainder of the buffer.
pub(crate) fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], Self), Error> { pub(crate) fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], Self)> {
if buffer.len() < CB_OBJ_TAG_MIN || !has_valid_length(&buffer[1..], buffer.len() - 1) { if buffer.len() < CB_OBJ_TAG_MIN || !has_valid_length(&buffer[1..], buffer.len() - 1) {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
@@ -61,7 +61,7 @@ impl<'a> Tlv<'a> {
/// Takes a [`Buffer`] containing a single `Tlv` with the given tag, and returns a /// Takes a [`Buffer`] containing a single `Tlv` with the given tag, and returns a
/// `Buffer` containing only the value part of the `Tlv`. /// `Buffer` containing only the value part of the `Tlv`.
pub(crate) fn parse_single(mut buffer: Buffer, tag: u8) -> Result<Buffer, Error> { pub(crate) fn parse_single(mut buffer: Buffer, tag: u8) -> Result<Buffer> {
if buffer.len() < CB_OBJ_TAG_MIN || !has_valid_length(&buffer[1..], buffer.len() - 1) { if buffer.len() < CB_OBJ_TAG_MIN || !has_valid_length(&buffer[1..], buffer.len() - 1) {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
@@ -79,7 +79,7 @@ impl<'a> Tlv<'a> {
} }
/// Writes a TLV to the given buffer. /// Writes a TLV to the given buffer.
pub(crate) fn write(buffer: &mut [u8], tag: u8, value: &[u8]) -> Result<usize, Error> { pub(crate) fn write(buffer: &mut [u8], tag: u8, value: &[u8]) -> Result<usize> {
if buffer.len() < CB_OBJ_TAG_MIN { if buffer.len() < CB_OBJ_TAG_MIN {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
@@ -103,7 +103,7 @@ impl<'a> Tlv<'a> {
tag: u8, tag: u8,
length: usize, length: usize,
value: Gen, value: Gen,
) -> Result<usize, Error> ) -> Result<usize>
where where
Gen: FnOnce(&mut [u8]), Gen: FnOnce(&mut [u8]),
{ {
@@ -124,7 +124,7 @@ impl<'a> Tlv<'a> {
} }
/// Set length /// Set length
pub(crate) fn set_length(buffer: &mut [u8], length: usize) -> Result<usize, Error> { pub(crate) fn set_length(buffer: &mut [u8], length: usize) -> Result<usize> {
if length < 0x80 { if length < 0x80 {
if buffer.is_empty() { if buffer.is_empty() {
Err(Error::SizeError) Err(Error::SizeError)
+13 -18
View File
@@ -3,7 +3,7 @@
use crate::{ use crate::{
apdu::Response, apdu::Response,
apdu::{Apdu, Ins, StatusWords}, apdu::{Apdu, Ins, StatusWords},
error::Error, error::{Error, Result},
key::{AlgorithmId, SlotId}, key::{AlgorithmId, SlotId},
serialization::*, serialization::*,
yubikey::*, yubikey::*,
@@ -32,7 +32,7 @@ pub(crate) struct Transaction<'tx> {
impl<'tx> Transaction<'tx> { impl<'tx> Transaction<'tx> {
/// Create a new transaction with the given card. /// Create a new transaction with the given card.
pub fn new(card: &'tx mut pcsc::Card) -> Result<Self, Error> { pub fn new(card: &'tx mut pcsc::Card) -> Result<Self> {
Ok(Transaction { Ok(Transaction {
inner: card.transaction()?, inner: card.transaction()?,
}) })
@@ -45,7 +45,7 @@ impl<'tx> Transaction<'tx> {
/// single APDU messages at a time. For larger messages that need to be /// single APDU messages at a time. For larger messages that need to be
/// split into multiple APDUs, use the [`Transaction::transfer_data`] /// split into multiple APDUs, use the [`Transaction::transfer_data`]
/// method instead. /// method instead.
pub fn transmit(&self, send_buffer: &[u8], recv_len: usize) -> Result<Vec<u8>, Error> { pub fn transmit(&self, send_buffer: &[u8], recv_len: usize) -> Result<Vec<u8>> {
trace!(">>> {:?}", send_buffer); trace!(">>> {:?}", send_buffer);
let mut recv_buffer = vec![0u8; recv_len]; let mut recv_buffer = vec![0u8; recv_len];
@@ -60,7 +60,7 @@ impl<'tx> Transaction<'tx> {
} }
/// Select application. /// Select application.
pub fn select_application(&self) -> Result<(), Error> { pub fn select_application(&self) -> Result<()> {
let response = Apdu::new(Ins::SelectApplication) let response = Apdu::new(Ins::SelectApplication)
.p1(0x04) .p1(0x04)
.data(&PIV_AID) .data(&PIV_AID)
@@ -82,7 +82,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> {
// get version from device // get version from device
let response = Apdu::new(Ins::GetVersion).transmit(self, 261)?; let response = Apdu::new(Ins::GetVersion).transmit(self, 261)?;
@@ -98,7 +98,7 @@ impl<'tx> Transaction<'tx> {
} }
/// Get YubiKey device serial number. /// Get YubiKey device serial number.
pub fn get_serial(&self, version: Version) -> Result<Serial, Error> { pub fn get_serial(&self, version: Version) -> Result<Serial> {
let response = if version.major < 5 { let response = if version.major < 5 {
// YK4 requires switching to the yk applet to retrieve the serial // YK4 requires switching to the yk applet to retrieve the serial
let sw = Apdu::new(Ins::SelectApplication) let sw = Apdu::new(Ins::SelectApplication)
@@ -157,7 +157,7 @@ impl<'tx> Transaction<'tx> {
} }
/// Verify device PIN. /// Verify device PIN.
pub fn verify_pin(&self, pin: &[u8]) -> Result<(), Error> { pub fn verify_pin(&self, pin: &[u8]) -> Result<()> {
if pin.len() > CB_PIN_MAX { if pin.len() > CB_PIN_MAX {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
@@ -191,7 +191,7 @@ impl<'tx> Transaction<'tx> {
action: ChangeRefAction, action: ChangeRefAction,
current_pin: &[u8], current_pin: &[u8],
new_pin: &[u8], new_pin: &[u8],
) -> Result<(), Error> { ) -> Result<()> {
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 {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
@@ -229,7 +229,7 @@ impl<'tx> Transaction<'tx> {
/// Set the management key (MGM). /// Set the management key (MGM).
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_mgm_key(&self, new_key: &MgmKey, require_touch: bool) -> Result<(), Error> { pub fn set_mgm_key(&self, new_key: &MgmKey, require_touch: bool) -> Result<()> {
let p2 = if require_touch { 0xfe } else { 0xff }; let p2 = if require_touch { 0xfe } else { 0xff };
let mut data = [0u8; DES_LEN_3DES + 3]; let mut data = [0u8; DES_LEN_3DES + 3];
@@ -263,7 +263,7 @@ impl<'tx> Transaction<'tx> {
algorithm: AlgorithmId, algorithm: AlgorithmId,
key: SlotId, key: SlotId,
decipher: bool, decipher: bool,
) -> Result<Buffer, Error> { ) -> Result<Buffer> {
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.into(), key.into()]; let templ = [0, Ins::Authenticate.code(), algorithm.into(), key.into()];
@@ -358,12 +358,7 @@ impl<'tx> Transaction<'tx> {
/// messages into smaller APDU-sized messages (using the provided APDU /// messages into smaller APDU-sized messages (using the provided APDU
/// template to construct them), and then sending those via /// template to construct them), and then sending those via
/// [`Transaction::transmit`]. /// [`Transaction::transmit`].
pub fn transfer_data( pub fn transfer_data(&self, templ: &[u8], in_data: &[u8], max_out: usize) -> Result<Response> {
&self,
templ: &[u8],
in_data: &[u8],
max_out: usize,
) -> Result<Response, Error> {
let mut in_offset = 0; let mut in_offset = 0;
let mut out_data = vec![]; let mut out_data = vec![];
let mut sw; let mut sw;
@@ -441,7 +436,7 @@ impl<'tx> Transaction<'tx> {
} }
/// Fetch an object. /// Fetch an object.
pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer, Error> { pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer> {
let mut indata = [0u8; 5]; let mut indata = [0u8; 5];
let templ = [0, Ins::GetData.code(), 0x3f, 0xff]; let templ = [0, Ins::GetData.code(), 0x3f, 0xff];
@@ -475,7 +470,7 @@ impl<'tx> Transaction<'tx> {
} }
/// Save an object. /// Save an object.
pub fn save_object(&self, object_id: ObjectId, indata: &[u8]) -> Result<(), Error> { pub fn save_object(&self, object_id: ObjectId, indata: &[u8]) -> Result<()> {
let templ = [0, Ins::PutData.code(), 0x3f, 0xff]; let templ = [0, Ins::PutData.code(), 0x3f, 0xff];
// TODO(tarcieri): replace with vector // TODO(tarcieri): replace with vector
+25 -25
View File
@@ -35,7 +35,7 @@ use crate::{
cccid::Ccc, cccid::Ccc,
chuid::ChuId, chuid::ChuId,
config::Config, config::Config,
error::Error, error::{Error, Result},
mgm::MgmKey, mgm::MgmKey,
readers::{Reader, Readers}, readers::{Reader, Readers},
transaction::Transaction, transaction::Transaction,
@@ -92,7 +92,7 @@ impl From<Serial> for u32 {
impl FromStr for Serial { impl FromStr for Serial {
type Err = Error; type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> { fn from_str(s: &str) -> Result<Self> {
u32::from_str(s).map(Serial).map_err(|_| Error::ParseError) u32::from_str(s).map(Serial).map_err(|_| Error::ParseError)
} }
} }
@@ -157,7 +157,7 @@ impl YubiKey {
/// attached to the same system, use [`YubiKey::open_by_serial`] or /// attached to the same system, use [`YubiKey::open_by_serial`] or
/// [`yubikey::Readers`][`Readers`] to select from the available /// [`yubikey::Readers`][`Readers`] to select from the available
/// PC/SC readers. /// PC/SC readers.
pub fn open() -> Result<Self, Error> { pub fn open() -> Result<Self> {
let mut readers = Readers::open().map_err(|e| match e { let mut readers = Readers::open().map_err(|e| match e {
Error::PcscError { Error::PcscError {
inner: Some(pcsc::Error::NoReadersAvailable), inner: Some(pcsc::Error::NoReadersAvailable),
@@ -180,7 +180,7 @@ impl YubiKey {
} }
/// Open a YubiKey with a specific serial number. /// Open a YubiKey with a specific serial number.
pub fn open_by_serial(serial: Serial) -> Result<Self, Error> { pub fn open_by_serial(serial: Serial) -> Result<Self> {
let mut readers = Readers::open().map_err(|e| match e { let mut readers = Readers::open().map_err(|e| match e {
Error::PcscError { Error::PcscError {
inner: Some(pcsc::Error::NoReadersAvailable), inner: Some(pcsc::Error::NoReadersAvailable),
@@ -205,7 +205,7 @@ impl YubiKey {
/// Reconnect to a YubiKey /// Reconnect to a YubiKey
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn reconnect(&mut self) -> Result<(), Error> { pub fn reconnect(&mut self) -> Result<()> {
info!("trying to reconnect to current reader"); info!("trying to reconnect to current reader");
self.card.reconnect( self.card.reconnect(
@@ -230,7 +230,7 @@ impl YubiKey {
} }
/// Begin a transaction. /// Begin a transaction.
pub(crate) fn begin_transaction(&mut self) -> Result<Transaction<'_>, Error> { pub(crate) fn begin_transaction(&mut self) -> Result<Transaction<'_>> {
// TODO(tarcieri): reconnect support // TODO(tarcieri): reconnect support
Transaction::new(&mut self.card) Transaction::new(&mut self.card)
} }
@@ -255,22 +255,22 @@ impl YubiKey {
} }
/// Get device configuration. /// Get device configuration.
pub fn config(&mut self) -> Result<Config, Error> { pub fn config(&mut self) -> Result<Config> {
Config::get(self) Config::get(self)
} }
/// Get CHUID /// Get CHUID
pub fn chuid(&mut self) -> Result<ChuId, Error> { pub fn chuid(&mut self) -> Result<ChuId> {
ChuId::get(self) ChuId::get(self)
} }
/// Get CCCID /// Get CCCID
pub fn cccid(&mut self) -> Result<Ccc, Error> { pub fn cccid(&mut self) -> Result<Ccc> {
Ccc::get(self) Ccc::get(self)
} }
/// Authenticate to the card using the provided management key (MGM). /// Authenticate to the card using the provided management key (MGM).
pub fn authenticate(&mut self, mgm_key: MgmKey) -> Result<(), Error> { pub fn authenticate(&mut self, mgm_key: MgmKey) -> Result<()> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
// get a challenge from the card // get a challenge from the card
@@ -325,7 +325,7 @@ impl YubiKey {
/// Deauthenticate /// Deauthenticate
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn deauthenticate(&mut self) -> Result<(), Error> { pub fn deauthenticate(&mut self) -> Result<()> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
let status_words = Apdu::new(Ins::SelectApplication) let status_words = Apdu::new(Ins::SelectApplication)
@@ -346,7 +346,7 @@ impl YubiKey {
} }
/// Verify device PIN. /// Verify device PIN.
pub fn verify_pin(&mut self, pin: &[u8]) -> Result<(), Error> { pub fn verify_pin(&mut self, pin: &[u8]) -> Result<()> {
{ {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
txn.verify_pin(pin)?; txn.verify_pin(pin)?;
@@ -360,7 +360,7 @@ impl YubiKey {
} }
/// Get the number of PIN retries /// Get the number of PIN retries
pub fn get_pin_retries(&mut self) -> Result<u8, Error> { pub fn get_pin_retries(&mut self) -> Result<u8> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
// Force a re-select to unverify, because once verified the spec dictates that // Force a re-select to unverify, because once verified the spec dictates that
@@ -378,7 +378,7 @@ impl YubiKey {
/// Set the number of PIN retries /// Set the number of PIN retries
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_pin_retries(&mut self, pin_tries: u8, puk_tries: u8) -> Result<(), Error> { pub fn set_pin_retries(&mut self, pin_tries: u8, puk_tries: u8) -> Result<()> {
// Special case: if either retry count is 0, it's a successful no-op // Special case: if either retry count is 0, it's a successful no-op
if pin_tries == 0 || puk_tries == 0 { if pin_tries == 0 || puk_tries == 0 {
return Ok(()); return Ok(());
@@ -402,7 +402,7 @@ impl YubiKey {
/// ///
/// The default PIN code is 123456 /// The default PIN code is 123456
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn change_pin(&mut self, current_pin: &[u8], new_pin: &[u8]) -> Result<(), Error> { pub fn change_pin(&mut self, current_pin: &[u8], new_pin: &[u8]) -> Result<()> {
{ {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
txn.change_ref(ChangeRefAction::ChangePin, current_pin, new_pin)?; txn.change_ref(ChangeRefAction::ChangePin, current_pin, new_pin)?;
@@ -417,7 +417,7 @@ impl YubiKey {
/// Set PIN last changed /// Set PIN last changed
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn set_pin_last_changed(yubikey: &mut YubiKey) -> Result<(), Error> { pub fn set_pin_last_changed(yubikey: &mut YubiKey) -> Result<()> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
let mut admin_data = AdminData::read(&txn)?; let mut admin_data = AdminData::read(&txn)?;
@@ -452,14 +452,14 @@ impl YubiKey {
/// ///
/// The default PUK code is 12345678. /// The default PUK code is 12345678.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn change_puk(&mut self, current_puk: &[u8], new_puk: &[u8]) -> Result<(), Error> { pub fn change_puk(&mut self, current_puk: &[u8], new_puk: &[u8]) -> Result<()> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
txn.change_ref(ChangeRefAction::ChangePuk, current_puk, new_puk) txn.change_ref(ChangeRefAction::ChangePuk, current_puk, new_puk)
} }
/// Block PUK: permanently prevent the PIN from becoming unblocked /// Block PUK: permanently prevent the PIN from becoming unblocked
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn block_puk(yubikey: &mut YubiKey) -> Result<(), Error> { pub fn block_puk(yubikey: &mut YubiKey) -> Result<()> {
let mut puk = [0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44]; let mut puk = [0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44];
let mut tries_remaining: i32 = -1; let mut tries_remaining: i32 = -1;
let mut flags = [0]; let mut flags = [0];
@@ -523,28 +523,28 @@ impl YubiKey {
/// Unblock a Personal Identification Number (PIN) using a previously /// Unblock a Personal Identification Number (PIN) using a previously
/// configured PIN Unblocking Key (PUK). /// configured PIN Unblocking Key (PUK).
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn unblock_pin(&mut self, puk: &[u8], new_pin: &[u8]) -> Result<(), Error> { pub fn unblock_pin(&mut self, puk: &[u8], new_pin: &[u8]) -> Result<()> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
txn.change_ref(ChangeRefAction::UnblockPin, puk, new_pin) txn.change_ref(ChangeRefAction::UnblockPin, puk, new_pin)
} }
/// Fetch an object from the YubiKey /// Fetch an object from the YubiKey
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn fetch_object(&mut self, object_id: ObjectId) -> Result<Buffer, Error> { pub fn fetch_object(&mut self, object_id: ObjectId) -> Result<Buffer> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
txn.fetch_object(object_id) txn.fetch_object(object_id)
} }
/// Save an object /// Save an object
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn save_object(&mut self, object_id: ObjectId, indata: &mut [u8]) -> Result<(), Error> { pub fn save_object(&mut self, object_id: ObjectId, indata: &mut [u8]) -> Result<()> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
txn.save_object(object_id, indata) txn.save_object(object_id, indata)
} }
/// Get an auth challenge /// Get an auth challenge
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn get_auth_challenge(&mut self) -> Result<[u8; 8], Error> { pub fn get_auth_challenge(&mut self) -> Result<[u8; 8]> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
let response = Apdu::new(Ins::Authenticate) let response = Apdu::new(Ins::Authenticate)
@@ -561,7 +561,7 @@ impl YubiKey {
/// Verify an auth response /// Verify an auth response
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub fn verify_auth_response(&mut self, response: [u8; 8]) -> Result<(), Error> { pub fn verify_auth_response(&mut self, response: [u8; 8]) -> Result<()> {
let mut data = [0u8; 12]; let mut data = [0u8; 12];
data[0] = 0x7c; data[0] = 0x7c;
data[1] = 0x0a; data[1] = 0x0a;
@@ -591,7 +591,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<()> {
let templ = [0, Ins::Reset.code(), 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();
@@ -607,7 +607,7 @@ impl YubiKey {
impl<'a> TryFrom<&'a Reader<'_>> for YubiKey { impl<'a> TryFrom<&'a Reader<'_>> for YubiKey {
type Error = Error; type Error = Error;
fn try_from(reader: &'a Reader<'_>) -> Result<Self, Error> { fn try_from(reader: &'a Reader<'_>) -> Result<Self> {
let mut card = reader.connect().map_err(|e| { let mut card = reader.connect().map_err(|e| {
error!("error connecting to reader '{}': {}", reader.name(), e); error!("error connecting to reader '{}': {}", reader.name(), e);
e e