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:
committed by
GitHub
parent
1051eaf26d
commit
de51b0cc46
Generated
+2
-2
@@ -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
@@ -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()?;
|
||||||
|
|
||||||
|
|||||||
@@ -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()?;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)?)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user