Add untested Cargo feature for untested functionality
This adds an `untested` feature to any functions which have not yet been tested live against a YubiKey device (which is presently pretty much everything). This sets a clear expectation of what is presently supported, and additionally documents the status in the README (and a series of GitHub issues). Adds a `cargo build --all-features` to GitHub Actions' `test` step in order to make sure that `untested` functionality still compiles.
This commit is contained in:
@@ -59,6 +59,14 @@ jobs:
|
||||
command: test
|
||||
args: --release
|
||||
|
||||
- name: Run cargo build --all-features
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
with:
|
||||
command: build
|
||||
args: --all-features
|
||||
|
||||
test:
|
||||
name: Test Suite
|
||||
strategy:
|
||||
@@ -88,6 +96,14 @@ jobs:
|
||||
command: test
|
||||
args: --release
|
||||
|
||||
- name: Run cargo build --all-features
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
with:
|
||||
command: build
|
||||
args: --all-features
|
||||
|
||||
fmt:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
+13
-5
@@ -7,7 +7,6 @@ application providing general-purpose public-key signing and encryption
|
||||
with hardware-backed private keys for RSA (2048/1024) and ECC (P-256/P-384)
|
||||
algorithms (e.g, PKCS#1v1.5, ECDSA)
|
||||
"""
|
||||
|
||||
authors = ["Tony Arcieri <bascule@gmail.com>", "Yubico AB"]
|
||||
edition = "2018"
|
||||
license = "BSD-2-Clause"
|
||||
@@ -16,16 +15,25 @@ readme = "README.md"
|
||||
categories = ["api-bindings", "cryptography", "hardware-support"]
|
||||
keywords = ["ccid", "ecdsa", "rsa", "piv", "yubikey"]
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
|
||||
[dependencies]
|
||||
des = "0.3"
|
||||
getrandom = "0.1"
|
||||
hmac = "0.7"
|
||||
hmac = { version = "0.7", optional = true }
|
||||
log = "0.4"
|
||||
pbkdf2 = "0.3"
|
||||
pbkdf2 = { version = "0.3", optional = true }
|
||||
pcsc = "2"
|
||||
sha-1 = "0.8"
|
||||
subtle = "2"
|
||||
sha-1 = { version = "0.8", optional = true }
|
||||
subtle = { version = "2", optional = true }
|
||||
zeroize = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.7"
|
||||
|
||||
[features]
|
||||
untested = ["hmac", "pbkdf2", "sha-1", "subtle"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -80,8 +80,11 @@ Legend:
|
||||
| 🚧 | Testing and validation in progress |
|
||||
| ⚠️ | Untested support |
|
||||
|
||||
NOTE: Commands marked ⚠️ have not been properly tested and may contain bugs or
|
||||
not work at all.
|
||||
NOTE: Commands marked ⚠️ are disabled by default as they have have not been properly tested and may contain bugs or
|
||||
not work at all. USE AT YOUR OWN RISK!
|
||||
|
||||
Enable the `untested` feature in your `Cargo.toml` to enable features marked ⚠️
|
||||
above.
|
||||
|
||||
## Testing
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ impl APDU {
|
||||
}
|
||||
|
||||
/// Set this APDU's class
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn cla(&mut self, value: u8) -> &mut Self {
|
||||
self.cla = value;
|
||||
self
|
||||
@@ -83,6 +84,7 @@ impl APDU {
|
||||
}
|
||||
|
||||
/// Set both parameters for this APDU
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn params(&mut self, p1: u8, p2: u8) -> &mut Self {
|
||||
self.p1 = p1;
|
||||
self.p2 = p2;
|
||||
|
||||
+16
-2
@@ -40,7 +40,7 @@
|
||||
//! code from upstream [yubico-piv-tool] has been translated into Rust
|
||||
//! presenting a safe interface, much of it is still untested.
|
||||
//!
|
||||
//! Please see the project's README.md for a complete status.
|
||||
//! Please see the [project's README.md for a complete status][status].
|
||||
//!
|
||||
//! ## History
|
||||
//!
|
||||
@@ -83,6 +83,7 @@
|
||||
//! [YubiKey NEO]: https://support.yubico.com/support/solutions/articles/15000006494-yubikey-neo
|
||||
//! [YubiKey 4]: https://support.yubico.com/support/solutions/articles/15000006486-yubikey-4
|
||||
//! [YubiKey 5]: https://www.yubico.com/products/yubikey-5-overview/
|
||||
//! [status]: https://github.com/tarcieri/yubikey-piv.rs#status
|
||||
//! [yubico-piv-tool]: https://github.com/Yubico/yubico-piv-tool/
|
||||
//! [Corrode]: https://github.com/jameysharp/corrode
|
||||
//! [piv-tool-guide]: https://www.yubico.com/wp-content/uploads/2016/05/Yubico_PIV_Tool_Command_Line_Guide_en.pdf
|
||||
@@ -134,24 +135,37 @@
|
||||
)]
|
||||
|
||||
mod apdu;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod cccid;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod certificate;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod chuid;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod config;
|
||||
pub mod consts;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod container;
|
||||
pub mod error;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod key;
|
||||
#[cfg(feature = "untested")]
|
||||
mod metadata;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod mgm;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod msroots;
|
||||
mod response;
|
||||
#[cfg(feature = "untested")]
|
||||
mod serialization;
|
||||
#[cfg(feature = "untested")]
|
||||
pub mod settings;
|
||||
mod transaction;
|
||||
pub mod yubikey;
|
||||
|
||||
pub use self::{key::Key, mgm::MgmKey, yubikey::YubiKey};
|
||||
#[cfg(feature = "untested")]
|
||||
pub use self::{key::Key, mgm::MgmKey};
|
||||
pub use yubikey::YubiKey;
|
||||
|
||||
/// Algorithm identifiers
|
||||
// TODO(tarcieri): make this an enum
|
||||
|
||||
@@ -64,6 +64,7 @@ impl Response {
|
||||
}
|
||||
|
||||
/// Create a new response from the given status words and buffer
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn new(status_words: StatusWords, buffer: Buffer) -> Response {
|
||||
Response {
|
||||
status_words,
|
||||
@@ -77,6 +78,7 @@ impl Response {
|
||||
}
|
||||
|
||||
/// Get the raw [`StatusWords`] code for this response.
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn code(&self) -> u32 {
|
||||
self.status_words.code()
|
||||
}
|
||||
@@ -92,6 +94,7 @@ impl Response {
|
||||
}
|
||||
|
||||
/// Consume this response, returning its buffer
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn into_buffer(self) -> Buffer {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
+13
-6
@@ -1,17 +1,17 @@
|
||||
//! YubiKey PC/SC transactions
|
||||
|
||||
use crate::{apdu::APDU, consts::*, error::Error, yubikey::*, Buffer};
|
||||
#[cfg(feature = "untested")]
|
||||
use crate::{
|
||||
apdu::APDU,
|
||||
consts::*,
|
||||
error::Error,
|
||||
mgm::MgmKey,
|
||||
response::{Response, StatusWords},
|
||||
serialization::*,
|
||||
yubikey::*,
|
||||
Buffer, ObjectId,
|
||||
ObjectId,
|
||||
};
|
||||
use log::{error, trace};
|
||||
use std::{convert::TryInto, ptr};
|
||||
use std::convert::TryInto;
|
||||
#[cfg(feature = "untested")]
|
||||
use std::ptr;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
/// Exclusive transaction with the YubiKey's PC/SC card.
|
||||
@@ -164,6 +164,7 @@ impl<'tx> Transaction<'tx> {
|
||||
}
|
||||
|
||||
/// Verify device PIN.
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn verify_pin(&self, pin: &[u8]) -> Result<(), Error> {
|
||||
// TODO(tarcieri): allow unpadded (with `0xFF`) PIN shorter than CB_PIN_MAX?
|
||||
if pin.len() != CB_PIN_MAX {
|
||||
@@ -184,6 +185,7 @@ impl<'tx> Transaction<'tx> {
|
||||
}
|
||||
|
||||
/// Change the PIN
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn change_pin(&self, action: i32, current_pin: &[u8], new_pin: &[u8]) -> Result<(), Error> {
|
||||
let mut templ = [0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80];
|
||||
let mut indata = Zeroizing::new([0u8; 16]);
|
||||
@@ -243,6 +245,7 @@ impl<'tx> Transaction<'tx> {
|
||||
}
|
||||
|
||||
/// Set the management key (MGM).
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn set_mgm_key(&self, new_key: &MgmKey, touch: Option<u8>) -> Result<(), Error> {
|
||||
let p2 = match touch.unwrap_or_default() {
|
||||
0 => 0xff,
|
||||
@@ -276,6 +279,7 @@ impl<'tx> Transaction<'tx> {
|
||||
/// This is the common backend for all public key encryption and signing
|
||||
/// operations.
|
||||
// TODO(tarcieri): refactor this to be less gross/coupled.
|
||||
#[cfg(feature = "untested")]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn authenticated_command(
|
||||
&self,
|
||||
@@ -392,6 +396,7 @@ impl<'tx> Transaction<'tx> {
|
||||
/// messages into smaller APDU-sized messages (using the provided APDU
|
||||
/// template to construct them), and then sending those via
|
||||
/// [`Transaction::transmit`].
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn transfer_data(
|
||||
&self,
|
||||
templ: &[u8],
|
||||
@@ -475,6 +480,7 @@ impl<'tx> Transaction<'tx> {
|
||||
}
|
||||
|
||||
/// Fetch an object
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer, Error> {
|
||||
let mut indata = [0u8; 5];
|
||||
let templ = [0, YKPIV_INS_GET_DATA, 0x3f, 0xff];
|
||||
@@ -518,6 +524,7 @@ impl<'tx> Transaction<'tx> {
|
||||
}
|
||||
|
||||
/// Save an object
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn save_object(&self, object_id: ObjectId, indata: &[u8]) -> Result<(), Error> {
|
||||
let templ = [0, YKPIV_INS_PUT_DATA, 0x3f, 0xff];
|
||||
|
||||
|
||||
+78
-49
@@ -33,19 +33,24 @@
|
||||
#![allow(non_snake_case, non_upper_case_globals)]
|
||||
#![allow(clippy::too_many_arguments, clippy::missing_safety_doc)]
|
||||
|
||||
#[cfg(feature = "untested")]
|
||||
use crate::{
|
||||
apdu::APDU, consts::*, error::Error, key::SlotId, metadata, mgm::MgmKey, response::StatusWords,
|
||||
serialization::*, transaction::Transaction, Buffer, ObjectId,
|
||||
apdu::APDU, key::SlotId, metadata, mgm::MgmKey, response::StatusWords, serialization::*,
|
||||
ObjectId,
|
||||
};
|
||||
use crate::{consts::*, error::Error, transaction::Transaction, Buffer};
|
||||
#[cfg(feature = "untested")]
|
||||
use getrandom::getrandom;
|
||||
use log::{error, info, warn};
|
||||
use pcsc::{Card, Context};
|
||||
use std::fmt::{self, Display};
|
||||
#[cfg(feature = "untested")]
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
fmt::{self, Display},
|
||||
ptr, slice,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
#[cfg(feature = "untested")]
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
/// PIV Application ID
|
||||
@@ -96,6 +101,7 @@ pub struct Version {
|
||||
/// Almost all functionality in this library will require an open session
|
||||
/// with a YubiKey which is represented by this type.
|
||||
// TODO(tarcieri): reduce coupling to internal fields via `pub(crate)`
|
||||
#[cfg_attr(not(feature = "untested"), allow(dead_code))]
|
||||
pub struct YubiKey {
|
||||
pub(crate) card: Card,
|
||||
pub(crate) pin: Option<Buffer>,
|
||||
@@ -198,6 +204,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Reconnect to a YubiKey
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn reconnect(&mut self) -> Result<(), Error> {
|
||||
info!("trying to reconnect to current reader");
|
||||
|
||||
@@ -221,12 +228,40 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Begin a transaction.
|
||||
#[cfg(feature = "untested")]
|
||||
pub(crate) fn begin_transaction(&mut self) -> Result<Transaction<'_>, Error> {
|
||||
// TODO(tarcieri): reconnect support
|
||||
Ok(Transaction::new(&mut self.card)?)
|
||||
}
|
||||
|
||||
/// Get the YubiKey's PIV application version.
|
||||
///
|
||||
/// This always uses the cached version queried when the key is initialized.
|
||||
pub fn version(&mut self) -> Version {
|
||||
self.version
|
||||
}
|
||||
|
||||
/// Get YubiKey device serial number.
|
||||
///
|
||||
/// This always uses the cached version queried when the key is initialized.
|
||||
pub fn serial(&mut self) -> Serial {
|
||||
self.serial
|
||||
}
|
||||
|
||||
/// Get YubiKey device model
|
||||
// TODO(tarcieri): use an emum for this
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn device_model(&self) -> u32 {
|
||||
if self.is_neo {
|
||||
DEVTYPE_NEOr3
|
||||
} else {
|
||||
// TODO(tarcieri): YK5?
|
||||
DEVTYPE_YK4
|
||||
}
|
||||
}
|
||||
|
||||
/// Authenticate to the card using the provided management key (MGM).
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn authenticate(&mut self, mgm_key: MgmKey) -> Result<(), Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
|
||||
@@ -280,7 +315,30 @@ impl YubiKey {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deauthenticate
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn deauthenticate(&mut self) -> Result<(), Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
|
||||
let status_words = APDU::new(YKPIV_INS_SELECT_APPLICATION)
|
||||
.p1(0x04)
|
||||
.data(MGMT_AID)
|
||||
.transmit(&txn, 255)?
|
||||
.status_words();
|
||||
|
||||
if !status_words.is_success() {
|
||||
error!(
|
||||
"Failed selecting mgmt application: {:04x}",
|
||||
status_words.code()
|
||||
);
|
||||
return Err(Error::GenericError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sign data using a PIV key
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn sign_data(
|
||||
&mut self,
|
||||
raw_in: &[u8],
|
||||
@@ -296,6 +354,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Decrypt data using a PIV key
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn decrypt_data(
|
||||
&mut self,
|
||||
input: &[u8],
|
||||
@@ -310,21 +369,8 @@ impl YubiKey {
|
||||
txn.authenticated_command(input, out, out_len, algorithm, key, true)
|
||||
}
|
||||
|
||||
/// Get the YubiKey's PIV application version.
|
||||
///
|
||||
/// This always uses the cached version queried when the key is initialized.
|
||||
pub fn version(&mut self) -> Version {
|
||||
self.version
|
||||
}
|
||||
|
||||
/// Get YubiKey device serial number.
|
||||
///
|
||||
/// This always uses the cached version queried when the key is initialized.
|
||||
pub fn serial(&mut self) -> Serial {
|
||||
self.serial
|
||||
}
|
||||
|
||||
/// Verify device PIN.
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn verify_pin(&mut self, pin: &[u8]) -> Result<(), Error> {
|
||||
{
|
||||
let txn = self.begin_transaction()?;
|
||||
@@ -339,6 +385,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Get the number of PIN retries
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn get_pin_retries(&mut self) -> Result<u32, Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
|
||||
@@ -356,6 +403,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Set the number of PIN retries
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn set_pin_retries(&mut self, pin_tries: usize, puk_tries: usize) -> Result<(), Error> {
|
||||
// Special case: if either retry count is 0, it's a successful no-op
|
||||
if pin_tries == 0 || puk_tries == 0 {
|
||||
@@ -388,6 +436,7 @@ impl YubiKey {
|
||||
/// Change the Personal Identification Number (PIN).
|
||||
///
|
||||
/// The default PIN code is 123456
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn change_pin(&mut self, current_pin: &[u8], new_pin: &[u8]) -> Result<(), Error> {
|
||||
{
|
||||
let txn = self.begin_transaction()?;
|
||||
@@ -402,6 +451,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Set PIN last changed
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn set_pin_last_changed(yubikey: &mut YubiKey) -> Result<(), Error> {
|
||||
let mut data = [0u8; CB_BUF_MAX];
|
||||
let max_size = yubikey.obj_size_max();
|
||||
@@ -445,12 +495,14 @@ impl YubiKey {
|
||||
/// The PUK is part of the PIV standard that the YubiKey follows.
|
||||
///
|
||||
/// The default PUK code is 12345678.
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn change_puk(&mut self, current_puk: &[u8], new_puk: &[u8]) -> Result<(), Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
txn.change_pin(CHREF_ACT_CHANGE_PUK, current_puk, new_puk)
|
||||
}
|
||||
|
||||
/// Block PUK: permanently prevent the PIN from becoming unblocked
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn block_puk(yubikey: &mut YubiKey) -> Result<(), Error> {
|
||||
let mut puk = [0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44];
|
||||
let mut tries_remaining: i32 = -1;
|
||||
@@ -519,18 +571,21 @@ impl YubiKey {
|
||||
|
||||
/// Unblock a Personal Identification Number (PIN) using a previously
|
||||
/// configured PIN Unblocking Key (PUK).
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn unblock_pin(&mut self, puk: &[u8], new_pin: &[u8]) -> Result<(), Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
txn.change_pin(CHREF_ACT_UNBLOCK_PIN, puk, new_pin)
|
||||
}
|
||||
|
||||
/// Fetch an object from the YubiKey
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn fetch_object(&mut self, object_id: ObjectId) -> Result<Buffer, Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
txn.fetch_object(object_id)
|
||||
}
|
||||
|
||||
/// Save an object
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn save_object(&mut self, object_id: ObjectId, indata: &mut [u8]) -> Result<(), Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
txn.save_object(object_id, indata)
|
||||
@@ -538,6 +593,7 @@ impl YubiKey {
|
||||
|
||||
/// Import a private encryption or signing key into the YubiKey
|
||||
// TODO(tarcieri): refactor this into separate methods per key type
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn import_private_key(
|
||||
&mut self,
|
||||
key: SlotId,
|
||||
@@ -733,6 +789,7 @@ impl YubiKey {
|
||||
|
||||
/// Generate an attestation certificate for a stored key.
|
||||
/// <https://developers.yubico.com/PIV/Introduction/PIV_attestation.html>
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn attest(&mut self, key: SlotId) -> Result<Buffer, Error> {
|
||||
let templ = [0, YKPIV_INS_ATTEST, key, 0];
|
||||
let txn = self.begin_transaction()?;
|
||||
@@ -754,6 +811,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Get an auth challenge
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn get_auth_challenge(&mut self) -> Result<[u8; 8], Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
|
||||
@@ -770,6 +828,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Verify an auth response
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn verify_auth_response(&mut self, response: [u8; 8]) -> Result<(), Error> {
|
||||
let mut data = [0u8; 12];
|
||||
data[0] = 0x7c;
|
||||
@@ -794,43 +853,12 @@ impl YubiKey {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deauthenticate
|
||||
pub fn deauthenticate(&mut self) -> Result<(), Error> {
|
||||
let txn = self.begin_transaction()?;
|
||||
|
||||
let status_words = APDU::new(YKPIV_INS_SELECT_APPLICATION)
|
||||
.p1(0x04)
|
||||
.data(MGMT_AID)
|
||||
.transmit(&txn, 255)?
|
||||
.status_words();
|
||||
|
||||
if !status_words.is_success() {
|
||||
error!(
|
||||
"Failed selecting mgmt application: {:04x}",
|
||||
status_words.code()
|
||||
);
|
||||
return Err(Error::GenericError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get YubiKey device model
|
||||
// TODO(tarcieri): use an emum for this
|
||||
pub fn device_model(&self) -> u32 {
|
||||
if self.is_neo {
|
||||
DEVTYPE_NEOr3
|
||||
} else {
|
||||
// TODO(tarcieri): YK5?
|
||||
DEVTYPE_YK4
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset YubiKey.
|
||||
///
|
||||
/// WARNING: this is a destructive operation which will destroy all keys!
|
||||
///
|
||||
/// The reset function is only available when both pins are blocked.
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn reset_device(&mut self) -> Result<(), Error> {
|
||||
let templ = [0, YKPIV_INS_RESET, 0, 0];
|
||||
let txn = self.begin_transaction()?;
|
||||
@@ -844,6 +872,7 @@ impl YubiKey {
|
||||
}
|
||||
|
||||
/// Get max object size supported by this device
|
||||
#[cfg(feature = "untested")]
|
||||
pub(crate) fn obj_size_max(&self) -> usize {
|
||||
if self.is_neo {
|
||||
CB_OBJ_MAX_NEO
|
||||
|
||||
Reference in New Issue
Block a user