Merge pull request #61 from iqlusioninc/test-listing-keys
Test `Key::list`
This commit is contained in:
@@ -66,12 +66,12 @@ functions of the YubiKey:
|
|||||||
|----|---------------|-------|-------------|
|
|----|---------------|-------|-------------|
|
||||||
| 🚧 | `yubikey` | [#20] | Core functionality: auth, keys, PIN/PUK, encrypt, sign, attest |
|
| 🚧 | `yubikey` | [#20] | Core functionality: auth, keys, PIN/PUK, encrypt, sign, attest |
|
||||||
| ⚠️ | `cccid` | [#21] | Cardholder Capability Container (CCC) IDs |
|
| ⚠️ | `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) |
|
| ⚠️ | `chuid` | [#23] | Cardholder Unique Identifier (CHUID) |
|
||||||
| ⚠️ | `config` | [#24] | Support for reading on-key configuration |
|
| ⚠️ | `config` | [#24] | Support for reading on-key configuration |
|
||||||
| ⚠️ | `container` | [#25] | MS Container Map Records |
|
| ⚠️ | `container` | [#25] | MS Container Map Records |
|
||||||
| ⚠️ | `key` | [#26] | Crypto key management: list, generate, import |
|
| 🚧 | `key` | [#26] | Crypto key management: list, generate, import |
|
||||||
| ⚠️ | `mgm` | [#26] | Management Key (MGM) support: set, get, derive
|
| ⚠️ | `mgm` | [#26] | Management Key (MGM) support: set, get, derive |
|
||||||
| ⚠️ | `msroots` | [#28] | `msroots` file: PKCS#7 formatted certificate store for enterprise trusted roots |
|
| ⚠️ | `msroots` | [#28] | `msroots` file: PKCS#7 formatted certificate store for enterprise trusted roots |
|
||||||
|
|
||||||
Legend:
|
Legend:
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ impl APDU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set this APDU's class
|
/// Set this APDU's class
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub fn cla(&mut self, value: u8) -> &mut Self {
|
pub fn cla(&mut self, value: u8) -> &mut Self {
|
||||||
self.cla = value;
|
self.cla = value;
|
||||||
self
|
self
|
||||||
@@ -267,7 +266,6 @@ pub(crate) struct Response {
|
|||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
/// Create a new response from the given status words and buffer
|
/// Create a new response from the given status words and buffer
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub fn new(status_words: StatusWords, data: Vec<u8>) -> Response {
|
pub fn new(status_words: StatusWords, data: Vec<u8>) -> Response {
|
||||||
Response { status_words, data }
|
Response { status_words, data }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ impl Certificate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write this certificate into the YubiKey in the given slot
|
/// 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> {
|
pub fn write(&self, yubikey: &mut YubiKey, slot: SlotId, certinfo: u8) -> Result<(), Error> {
|
||||||
let max_size = yubikey.obj_size_max();
|
let max_size = yubikey.obj_size_max();
|
||||||
let txn = yubikey.begin_transaction()?;
|
let txn = yubikey.begin_transaction()?;
|
||||||
@@ -150,6 +151,7 @@ impl Certificate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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")]
|
||||||
pub fn delete(yubikey: &mut YubiKey, slot: SlotId) -> Result<(), Error> {
|
pub fn delete(yubikey: &mut YubiKey, slot: SlotId) -> Result<(), Error> {
|
||||||
let max_size = yubikey.obj_size_max();
|
let max_size = yubikey.obj_size_max();
|
||||||
let txn = yubikey.begin_transaction()?;
|
let txn = yubikey.begin_transaction()?;
|
||||||
@@ -236,6 +238,7 @@ pub(crate) fn read_certificate(txn: &Transaction<'_>, slot: SlotId) -> Result<Bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write certificate
|
/// Write certificate
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
pub(crate) fn write_certificate(
|
pub(crate) fn write_certificate(
|
||||||
txn: &Transaction<'_>,
|
txn: &Transaction<'_>,
|
||||||
slot: SlotId,
|
slot: SlotId,
|
||||||
|
|||||||
+28
-18
@@ -38,18 +38,24 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
apdu::{Ins, StatusWords},
|
|
||||||
certificate::{self, Certificate},
|
certificate::{self, Certificate},
|
||||||
consts::*,
|
|
||||||
error::Error,
|
error::Error,
|
||||||
|
yubikey::YubiKey,
|
||||||
|
ObjectId,
|
||||||
|
};
|
||||||
|
use log::debug;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
|
use crate::{
|
||||||
|
apdu::{Ins, StatusWords},
|
||||||
|
consts::*,
|
||||||
policy::{PinPolicy, TouchPolicy},
|
policy::{PinPolicy, TouchPolicy},
|
||||||
serialization::*,
|
serialization::*,
|
||||||
settings,
|
settings, Buffer,
|
||||||
yubikey::YubiKey,
|
|
||||||
Buffer, ObjectId,
|
|
||||||
};
|
};
|
||||||
use log::{debug, error, warn};
|
#[cfg(feature = "untested")]
|
||||||
use std::convert::TryFrom;
|
use log::{error, warn};
|
||||||
|
|
||||||
/// Slot identifiers.
|
/// Slot identifiers.
|
||||||
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
|
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
|
||||||
@@ -312,6 +318,7 @@ impl From<AlgorithmId> for u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
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]) -> usize {
|
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
|
/// Information about a generated key
|
||||||
// TODO(tarcieri): this could use some more work
|
// TODO(tarcieri): this could use some more work
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum GeneratedKey {
|
pub enum GeneratedKey {
|
||||||
/// RSA keys
|
/// RSA keys
|
||||||
@@ -403,6 +400,7 @@ pub enum GeneratedKey {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
impl GeneratedKey {
|
impl GeneratedKey {
|
||||||
/// Get the algorithm
|
/// Get the algorithm
|
||||||
pub fn algorithm(&self) -> AlgorithmId {
|
pub fn algorithm(&self) -> AlgorithmId {
|
||||||
@@ -414,6 +412,7 @@ impl GeneratedKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate key
|
/// Generate key
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
pub fn generate(
|
pub fn generate(
|
||||||
yubikey: &mut YubiKey,
|
yubikey: &mut YubiKey,
|
||||||
@@ -422,6 +421,17 @@ pub fn generate(
|
|||||||
pin_policy: PinPolicy,
|
pin_policy: PinPolicy,
|
||||||
touch_policy: TouchPolicy,
|
touch_policy: TouchPolicy,
|
||||||
) -> Result<GeneratedKey, Error> {
|
) -> Result<GeneratedKey, Error> {
|
||||||
|
// 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;
|
let setting_roca: settings::BoolValue;
|
||||||
|
|
||||||
match algorithm {
|
match algorithm {
|
||||||
|
|||||||
@@ -138,7 +138,6 @@
|
|||||||
mod apdu;
|
mod apdu;
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub mod cccid;
|
pub mod cccid;
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub mod certificate;
|
pub mod certificate;
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub mod chuid;
|
pub mod chuid;
|
||||||
@@ -148,7 +147,6 @@ pub mod consts;
|
|||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub mod container;
|
pub mod container;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub mod key;
|
pub mod key;
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
mod metadata;
|
mod metadata;
|
||||||
@@ -156,10 +154,8 @@ mod metadata;
|
|||||||
pub mod mgm;
|
pub mod mgm;
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub mod msroots;
|
pub mod msroots;
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub mod policy;
|
pub mod policy;
|
||||||
pub mod readers;
|
pub mod readers;
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
mod serialization;
|
mod serialization;
|
||||||
#[cfg(feature = "untested")]
|
#[cfg(feature = "untested")]
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|||||||
@@ -35,6 +35,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.
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
pub(crate) fn write(self, buf: &mut [u8]) -> usize {
|
pub(crate) fn write(self, buf: &mut [u8]) -> usize {
|
||||||
match self {
|
match self {
|
||||||
PinPolicy::Default => 0,
|
PinPolicy::Default => 0,
|
||||||
@@ -84,6 +85,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.
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
pub(crate) fn write(self, buf: &mut [u8]) -> usize {
|
pub(crate) fn write(self, buf: &mut [u8]) -> usize {
|
||||||
match self {
|
match self {
|
||||||
TouchPolicy::Default => 0,
|
TouchPolicy::Default => 0,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ use crate::{consts::*, ObjectId};
|
|||||||
// TODO(tarcieri): refactor these into better serializers/message builders
|
// TODO(tarcieri): refactor these into better serializers/message builders
|
||||||
|
|
||||||
/// Set length
|
/// Set length
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
pub(crate) fn set_length(buffer: &mut [u8], length: usize) -> usize {
|
pub(crate) fn set_length(buffer: &mut [u8], length: usize) -> usize {
|
||||||
if length < 0x80 {
|
if length < 0x80 {
|
||||||
buffer[0] = length as u8;
|
buffer[0] = length as u8;
|
||||||
|
|||||||
+8
-9
@@ -1,23 +1,24 @@
|
|||||||
//! YubiKey PC/SC transactions
|
//! YubiKey PC/SC transactions
|
||||||
|
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
use crate::{
|
use crate::{
|
||||||
apdu::Response,
|
apdu::Response,
|
||||||
key::{AlgorithmId, SlotId},
|
|
||||||
mgm::MgmKey,
|
|
||||||
serialization::*,
|
|
||||||
Buffer, ObjectId,
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
apdu::{Ins, StatusWords, APDU},
|
apdu::{Ins, StatusWords, APDU},
|
||||||
consts::*,
|
consts::*,
|
||||||
error::Error,
|
error::Error,
|
||||||
|
serialization::*,
|
||||||
yubikey::*,
|
yubikey::*,
|
||||||
|
Buffer, ObjectId,
|
||||||
};
|
};
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
#[cfg(feature = "untested")]
|
||||||
|
use crate::{
|
||||||
|
key::{AlgorithmId, SlotId},
|
||||||
|
mgm::MgmKey,
|
||||||
|
};
|
||||||
|
|
||||||
/// Exclusive transaction with the YubiKey's PC/SC card.
|
/// Exclusive transaction with the YubiKey's PC/SC card.
|
||||||
pub(crate) struct Transaction<'tx> {
|
pub(crate) struct Transaction<'tx> {
|
||||||
inner: pcsc::Transaction<'tx>,
|
inner: pcsc::Transaction<'tx>,
|
||||||
@@ -364,7 +365,6 @@ 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`].
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub fn transfer_data(
|
pub fn transfer_data(
|
||||||
&self,
|
&self,
|
||||||
templ: &[u8],
|
templ: &[u8],
|
||||||
@@ -448,7 +448,6 @@ impl<'tx> Transaction<'tx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch an object.
|
/// Fetch an object.
|
||||||
#[cfg(feature = "untested")]
|
|
||||||
pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer, Error> {
|
pub fn fetch_object(&self, object_id: ObjectId) -> Result<Buffer, Error> {
|
||||||
let mut indata = [0u8; 5];
|
let mut indata = [0u8; 5];
|
||||||
let templ = [0, Ins::GetData.code(), 0x3f, 0xff];
|
let templ = [0, Ins::GetData.code(), 0x3f, 0xff];
|
||||||
|
|||||||
+10
-1
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::{env, sync::Mutex};
|
use std::{env, sync::Mutex};
|
||||||
use yubikey_piv::YubiKey;
|
use yubikey_piv::{key::Key, YubiKey};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Provide thread-safe access to a YubiKey
|
/// 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"000000").is_err());
|
||||||
assert!(yubikey.verify_pin(b"123456").is_ok());
|
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());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user