diff --git a/README.md b/README.md index b493cea..09c0860 100644 --- a/README.md +++ b/README.md @@ -66,12 +66,12 @@ functions of the YubiKey: |----|---------------|-------|-------------| | 🚧 | `yubikey` | [#20] | Core functionality: auth, keys, PIN/PUK, encrypt, sign, attest | | ⚠️ | `cccid` | [#21] | Cardholder Capability Container (CCC) IDs | -| ⚠️ | `certificate` | [#22] | Certificates for stored keys | +| 🚧️ | `certificate` | [#22] | Certificates for stored keys | | ⚠️ | `chuid` | [#23] | Cardholder Unique Identifier (CHUID) | | ⚠️ | `config` | [#24] | Support for reading on-key configuration | | ⚠️ | `container` | [#25] | MS Container Map Records | -| ⚠️ | `key` | [#26] | Crypto key management: list, generate, import | -| ⚠️ | `mgm` | [#26] | Management Key (MGM) support: set, get, derive +| 🚧 | `key` | [#26] | Crypto key management: list, generate, import | +| ⚠️ | `mgm` | [#26] | Management Key (MGM) support: set, get, derive | | ⚠️ | `msroots` | [#28] | `msroots` file: PKCS#7 formatted certificate store for enterprise trusted roots | Legend: diff --git a/src/apdu.rs b/src/apdu.rs index d7b4dbf..beb9c69 100644 --- a/src/apdu.rs +++ b/src/apdu.rs @@ -71,7 +71,6 @@ impl APDU { } /// Set this APDU's class - #[cfg(feature = "untested")] pub fn cla(&mut self, value: u8) -> &mut Self { self.cla = value; self @@ -267,7 +266,6 @@ pub(crate) struct Response { impl Response { /// Create a new response from the given status words and buffer - #[cfg(feature = "untested")] pub fn new(status_words: StatusWords, data: Vec) -> Response { Response { status_words, data } } diff --git a/src/certificate.rs b/src/certificate.rs index d8c8f3d..ebb09df 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -143,6 +143,7 @@ impl Certificate { } /// Write this certificate into the YubiKey in the given slot + #[cfg(feature = "untested")] pub fn write(&self, yubikey: &mut YubiKey, slot: SlotId, certinfo: u8) -> Result<(), Error> { let max_size = yubikey.obj_size_max(); let txn = yubikey.begin_transaction()?; @@ -150,6 +151,7 @@ impl Certificate { } /// Delete a certificate located at the given slot of the given YubiKey + #[cfg(feature = "untested")] pub fn delete(yubikey: &mut YubiKey, slot: SlotId) -> Result<(), Error> { let max_size = yubikey.obj_size_max(); let txn = yubikey.begin_transaction()?; @@ -236,6 +238,7 @@ pub(crate) fn read_certificate(txn: &Transaction<'_>, slot: SlotId) -> Result, slot: SlotId, diff --git a/src/key.rs b/src/key.rs index 11ac520..76c9c94 100644 --- a/src/key.rs +++ b/src/key.rs @@ -38,18 +38,24 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - apdu::{Ins, StatusWords}, certificate::{self, Certificate}, - consts::*, error::Error, + yubikey::YubiKey, + ObjectId, +}; +use log::debug; +use std::convert::TryFrom; + +#[cfg(feature = "untested")] +use crate::{ + apdu::{Ins, StatusWords}, + consts::*, policy::{PinPolicy, TouchPolicy}, serialization::*, - settings, - yubikey::YubiKey, - Buffer, ObjectId, + settings, Buffer, }; -use log::{debug, error, warn}; -use std::convert::TryFrom; +#[cfg(feature = "untested")] +use log::{error, warn}; /// Slot identifiers. /// @@ -312,6 +318,7 @@ impl From for u8 { } } +#[cfg(feature = "untested")] impl AlgorithmId { /// Writes the `AlgorithmId` in the format the YubiKey expects during key generation. pub(crate) fn write(self, buf: &mut [u8]) -> usize { @@ -367,19 +374,9 @@ impl Key { } } -// Keygen messages -// TODO(tarcieri): extract these into an I18N-handling type? -const SZ_SETTING_ROCA: &str = "Enable_Unsafe_Keygen_ROCA"; -const SZ_ROCA_ALLOW_USER: &str = - "was permitted by an end-user configuration setting, but is not recommended."; -const SZ_ROCA_ALLOW_ADMIN: &str = - "was permitted by an administrator configuration setting, but is not recommended."; -const SZ_ROCA_BLOCK_USER: &str = "was blocked due to an end-user configuration setting."; -const SZ_ROCA_BLOCK_ADMIN: &str = "was blocked due to an administrator configuration setting."; -const SZ_ROCA_DEFAULT: &str = "was permitted by default, but is not recommended. The default behavior will change in a future Yubico release."; - /// Information about a generated key // TODO(tarcieri): this could use some more work +#[cfg(feature = "untested")] #[derive(Clone, Debug, Eq, PartialEq)] pub enum GeneratedKey { /// RSA keys @@ -403,6 +400,7 @@ pub enum GeneratedKey { }, } +#[cfg(feature = "untested")] impl GeneratedKey { /// Get the algorithm pub fn algorithm(&self) -> AlgorithmId { @@ -414,6 +412,7 @@ impl GeneratedKey { } /// Generate key +#[cfg(feature = "untested")] #[allow(clippy::cognitive_complexity)] pub fn generate( yubikey: &mut YubiKey, @@ -422,6 +421,17 @@ pub fn generate( pin_policy: PinPolicy, touch_policy: TouchPolicy, ) -> Result { + // Keygen messages + // TODO(tarcieri): extract these into an I18N-handling type? + const SZ_SETTING_ROCA: &str = "Enable_Unsafe_Keygen_ROCA"; + const SZ_ROCA_ALLOW_USER: &str = + "was permitted by an end-user configuration setting, but is not recommended."; + const SZ_ROCA_ALLOW_ADMIN: &str = + "was permitted by an administrator configuration setting, but is not recommended."; + const SZ_ROCA_BLOCK_USER: &str = "was blocked due to an end-user configuration setting."; + const SZ_ROCA_BLOCK_ADMIN: &str = "was blocked due to an administrator configuration setting."; + const SZ_ROCA_DEFAULT: &str = "was permitted by default, but is not recommended. The default behavior will change in a future Yubico release."; + let setting_roca: settings::BoolValue; match algorithm { diff --git a/src/lib.rs b/src/lib.rs index 04c022b..90a48d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,7 +138,6 @@ mod apdu; #[cfg(feature = "untested")] pub mod cccid; -#[cfg(feature = "untested")] pub mod certificate; #[cfg(feature = "untested")] pub mod chuid; @@ -148,7 +147,6 @@ pub mod consts; #[cfg(feature = "untested")] pub mod container; pub mod error; -#[cfg(feature = "untested")] pub mod key; #[cfg(feature = "untested")] mod metadata; @@ -156,10 +154,8 @@ mod metadata; pub mod mgm; #[cfg(feature = "untested")] pub mod msroots; -#[cfg(feature = "untested")] pub mod policy; pub mod readers; -#[cfg(feature = "untested")] mod serialization; #[cfg(feature = "untested")] pub mod settings; diff --git a/src/policy.rs b/src/policy.rs index a9650ab..e82c180 100644 --- a/src/policy.rs +++ b/src/policy.rs @@ -35,6 +35,7 @@ impl From for u8 { impl PinPolicy { /// Writes the `PinPolicy` in the format the YubiKey expects during key generation or /// importation. + #[cfg(feature = "untested")] pub(crate) fn write(self, buf: &mut [u8]) -> usize { match self { PinPolicy::Default => 0, @@ -84,6 +85,7 @@ impl From for u8 { impl TouchPolicy { /// Writes the `TouchPolicy` in the format the YubiKey expects during key generation /// or importation. + #[cfg(feature = "untested")] pub(crate) fn write(self, buf: &mut [u8]) -> usize { match self { TouchPolicy::Default => 0, diff --git a/src/serialization.rs b/src/serialization.rs index 614f97d..25a28ca 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -35,6 +35,7 @@ use crate::{consts::*, ObjectId}; // TODO(tarcieri): refactor these into better serializers/message builders /// Set length +#[cfg(feature = "untested")] pub(crate) fn set_length(buffer: &mut [u8], length: usize) -> usize { if length < 0x80 { buffer[0] = length as u8; diff --git a/src/transaction.rs b/src/transaction.rs index 970ce26..eb0dbb3 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,23 +1,24 @@ //! YubiKey PC/SC transactions -#[cfg(feature = "untested")] use crate::{ apdu::Response, - key::{AlgorithmId, SlotId}, - mgm::MgmKey, - serialization::*, - Buffer, ObjectId, -}; -use crate::{ apdu::{Ins, StatusWords, APDU}, consts::*, error::Error, + serialization::*, yubikey::*, + Buffer, ObjectId, }; use log::{error, trace}; use std::convert::TryInto; use zeroize::Zeroizing; +#[cfg(feature = "untested")] +use crate::{ + key::{AlgorithmId, SlotId}, + mgm::MgmKey, +}; + /// Exclusive transaction with the YubiKey's PC/SC card. pub(crate) struct Transaction<'tx> { inner: pcsc::Transaction<'tx>, @@ -364,7 +365,6 @@ 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], @@ -448,7 +448,6 @@ impl<'tx> Transaction<'tx> { } /// Fetch an object. - #[cfg(feature = "untested")] pub fn fetch_object(&self, object_id: ObjectId) -> Result { let mut indata = [0u8; 5]; let templ = [0, Ins::GetData.code(), 0x3f, 0xff]; diff --git a/tests/integration.rs b/tests/integration.rs index 6980220..b0407b3 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -5,7 +5,7 @@ use lazy_static::lazy_static; use std::{env, sync::Mutex}; -use yubikey_piv::YubiKey; +use yubikey_piv::{key::Key, YubiKey}; lazy_static! { /// Provide thread-safe access to a YubiKey @@ -29,3 +29,12 @@ fn test_verify_pin() { assert!(yubikey.verify_pin(b"000000").is_err()); assert!(yubikey.verify_pin(b"123456").is_ok()); } + +#[test] +#[ignore] +fn test_list_keys() { + let mut yubikey = YUBIKEY.lock().unwrap(); + let keys_result = Key::list(&mut yubikey); + assert!(keys_result.is_ok()); + dbg!(keys_result.unwrap()); +}