Generated
+272
-389
File diff suppressed because it is too large
Load Diff
+9
-10
@@ -22,25 +22,24 @@ assets = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
age-core = "0.6"
|
age-core = "0.7"
|
||||||
age-plugin = "0.1"
|
age-plugin = "0.2"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
bech32 = "0.8"
|
bech32 = "0.8"
|
||||||
console = "0.14"
|
console = { version = "0.15", default-features = false }
|
||||||
dialoguer = "0.8"
|
dialoguer = { version = "0.9", default-features = false, features = ["password"] }
|
||||||
env_logger = "0.8"
|
env_logger = "0.9"
|
||||||
gumdrop = "0.8"
|
gumdrop = "0.8"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
p256 = { version = "0.7", features = ["ecdh"] }
|
p256 = { version = "0.9", features = ["ecdh"] }
|
||||||
pcsc = "2.4"
|
pcsc = "2.4"
|
||||||
rand = "0.7"
|
rand = "0.8"
|
||||||
secrecy = "0.7"
|
|
||||||
sha2 = "0.9"
|
sha2 = "0.9"
|
||||||
which = "4.1"
|
which = "4.1"
|
||||||
x509 = "0.2"
|
x509 = "0.2"
|
||||||
x509-parser = "0.9"
|
x509-parser = "0.12"
|
||||||
yubikey-piv = { version = "0.3", features = ["untested"] }
|
yubikey = { version = "0.5", features = ["untested"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
1.51.0
|
||||||
+5
-6
@@ -1,17 +1,16 @@
|
|||||||
use rand::{rngs::OsRng, RngCore};
|
use rand::{rngs::OsRng, RngCore};
|
||||||
use x509::RelativeDistinguishedName;
|
use x509::RelativeDistinguishedName;
|
||||||
use yubikey_piv::{
|
use yubikey::{
|
||||||
certificate::{Certificate, PublicKeyInfo},
|
certificate::{Certificate, PublicKeyInfo},
|
||||||
key::{generate as yubikey_generate, AlgorithmId, RetiredSlotId, SlotId},
|
piv::{generate as yubikey_generate, AlgorithmId, RetiredSlotId, SlotId},
|
||||||
policy::{PinPolicy, TouchPolicy},
|
Key, PinPolicy, TouchPolicy, YubiKey,
|
||||||
Key, YubiKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
|
key::{self, Stub},
|
||||||
p256::Recipient,
|
p256::Recipient,
|
||||||
util::{Metadata, POLICY_EXTENSION_OID},
|
util::{Metadata, POLICY_EXTENSION_OID},
|
||||||
yubikey::{self, Stub},
|
|
||||||
BINARY_NAME, USABLE_SLOTS,
|
BINARY_NAME, USABLE_SLOTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,7 +89,7 @@ impl IdentityBuilder {
|
|||||||
// No need to ask for users to enter their PIN if the PIN policy requires it,
|
// No need to ask for users to enter their PIN if the PIN policy requires it,
|
||||||
// because here we _always_ require them to enter their PIN in order to access the
|
// because here we _always_ require them to enter their PIN in order to access the
|
||||||
// protected management key (which is necessary in order to generate identities).
|
// protected management key (which is necessary in order to generate identities).
|
||||||
yubikey::manage(yubikey)?;
|
key::manage(yubikey)?;
|
||||||
|
|
||||||
if let TouchPolicy::Never = touch_policy {
|
if let TouchPolicy::Never = touch_policy {
|
||||||
// No need to touch YubiKey
|
// No need to touch YubiKey
|
||||||
|
|||||||
+6
-6
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use yubikey_piv::{key::RetiredSlotId, Serial};
|
use yubikey::{piv::RetiredSlotId, Serial};
|
||||||
|
|
||||||
use crate::util::slot_to_ui;
|
use crate::util::slot_to_ui;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ pub enum Error {
|
|||||||
SlotIsNotEmpty(RetiredSlotId),
|
SlotIsNotEmpty(RetiredSlotId),
|
||||||
TimedOut,
|
TimedOut,
|
||||||
UseListForSingleSlot,
|
UseListForSingleSlot,
|
||||||
YubiKey(yubikey_piv::Error),
|
YubiKey(yubikey::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
@@ -30,8 +30,8 @@ impl From<io::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<yubikey_piv::error::Error> for Error {
|
impl From<yubikey::Error> for Error {
|
||||||
fn from(e: yubikey_piv::error::Error) -> Self {
|
fn from(e: yubikey::Error) -> Self {
|
||||||
Error::YubiKey(e)
|
Error::YubiKey(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,10 +100,10 @@ impl fmt::Debug for Error {
|
|||||||
writeln!(f, "Use --list to print the recipient for a single slot.")?
|
writeln!(f, "Use --list to print the recipient for a single slot.")?
|
||||||
}
|
}
|
||||||
Error::YubiKey(e) => match e {
|
Error::YubiKey(e) => match e {
|
||||||
yubikey_piv::error::Error::NotFound => {
|
yubikey::Error::NotFound => {
|
||||||
writeln!(f, "Please insert the YubiKey you want to set up")?
|
writeln!(f, "Please insert the YubiKey you want to set up")?
|
||||||
}
|
}
|
||||||
yubikey_piv::error::Error::WrongPin { tries } => writeln!(
|
yubikey::Error::WrongPin { tries } => writeln!(
|
||||||
f,
|
f,
|
||||||
"Invalid PIN ({} tries remaining before it is blocked)",
|
"Invalid PIN ({} tries remaining before it is blocked)",
|
||||||
tries
|
tries
|
||||||
|
|||||||
+1
-1
@@ -1,10 +1,10 @@
|
|||||||
use age_core::{
|
use age_core::{
|
||||||
format::{FileKey, Stanza},
|
format::{FileKey, Stanza},
|
||||||
primitives::{aead_encrypt, hkdf},
|
primitives::{aead_encrypt, hkdf},
|
||||||
|
secrecy::ExposeSecret,
|
||||||
};
|
};
|
||||||
use p256::{ecdh::EphemeralSecret, elliptic_curve::sec1::ToEncodedPoint};
|
use p256::{ecdh::EphemeralSecret, elliptic_curve::sec1::ToEncodedPoint};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use secrecy::ExposeSecret;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use crate::{p256::Recipient, STANZA_TAG};
|
use crate::{p256::Recipient, STANZA_TAG};
|
||||||
|
|||||||
+12
-14
@@ -3,25 +3,23 @@
|
|||||||
use age_core::{
|
use age_core::{
|
||||||
format::{FileKey, FILE_KEY_BYTES},
|
format::{FileKey, FILE_KEY_BYTES},
|
||||||
primitives::{aead_decrypt, hkdf},
|
primitives::{aead_decrypt, hkdf},
|
||||||
|
secrecy::ExposeSecret,
|
||||||
};
|
};
|
||||||
use age_plugin::{identity, Callbacks};
|
use age_plugin::{identity, Callbacks};
|
||||||
use bech32::{ToBase32, Variant};
|
use bech32::{ToBase32, Variant};
|
||||||
use dialoguer::Password;
|
use dialoguer::Password;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use secrecy::ExposeSecret;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use yubikey_piv::{
|
use yubikey::{
|
||||||
certificate::{Certificate, PublicKeyInfo},
|
certificate::{Certificate, PublicKeyInfo},
|
||||||
key::{decrypt_data, AlgorithmId, RetiredSlotId, SlotId},
|
piv::{decrypt_data, AlgorithmId, RetiredSlotId, SlotId},
|
||||||
policy::PinPolicy,
|
reader::{Context, Reader},
|
||||||
readers::Reader,
|
MgmKey, PinPolicy, Serial, YubiKey,
|
||||||
yubikey::Serial,
|
|
||||||
MgmKey, Readers, YubiKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -56,11 +54,11 @@ pub(crate) fn filter_connected(reader: &Reader) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn wait_for_readers() -> Result<Readers, Error> {
|
pub(crate) fn wait_for_readers() -> Result<Context, Error> {
|
||||||
// Start a 15-second timer waiting for a YubiKey to be inserted (if necessary).
|
// Start a 15-second timer waiting for a YubiKey to be inserted (if necessary).
|
||||||
let start = SystemTime::now();
|
let start = SystemTime::now();
|
||||||
loop {
|
loop {
|
||||||
let mut readers = Readers::open()?;
|
let mut readers = Context::open()?;
|
||||||
if readers.iter()?.any(is_connected) {
|
if readers.iter()?.any(is_connected) {
|
||||||
break Ok(readers);
|
break Ok(readers);
|
||||||
}
|
}
|
||||||
@@ -73,7 +71,7 @@ pub(crate) fn wait_for_readers() -> Result<Readers, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn open(serial: Option<Serial>) -> Result<YubiKey, Error> {
|
pub(crate) fn open(serial: Option<Serial>) -> Result<YubiKey, Error> {
|
||||||
if !Readers::open()?.iter()?.any(is_connected) {
|
if !Context::open()?.iter()?.any(is_connected) {
|
||||||
if let Some(serial) = serial {
|
if let Some(serial) = serial {
|
||||||
eprintln!("⏳ Please insert the YubiKey with serial {}.", serial);
|
eprintln!("⏳ Please insert the YubiKey with serial {}.", serial);
|
||||||
} else {
|
} else {
|
||||||
@@ -157,7 +155,7 @@ pub(crate) fn manage(yubikey: &mut YubiKey) -> Result<(), Error> {
|
|||||||
.map_err(|_| Error::CustomManagementKey)?;
|
.map_err(|_| Error::CustomManagementKey)?;
|
||||||
|
|
||||||
// Migrate to a PIN-protected management key.
|
// Migrate to a PIN-protected management key.
|
||||||
let mgm_key = MgmKey::generate()?;
|
let mgm_key = MgmKey::generate();
|
||||||
eprintln!();
|
eprintln!();
|
||||||
eprintln!("✨ Your YubiKey is using the default management key.");
|
eprintln!("✨ Your YubiKey is using the default management key.");
|
||||||
eprintln!("✨ We'll migrate it to a PIN-protected management key.");
|
eprintln!("✨ We'll migrate it to a PIN-protected management key.");
|
||||||
@@ -247,7 +245,7 @@ impl Stub {
|
|||||||
) -> io::Result<Result<Connection, identity::Error>> {
|
) -> io::Result<Result<Connection, identity::Error>> {
|
||||||
let mut yubikey = match YubiKey::open_by_serial(self.serial) {
|
let mut yubikey = match YubiKey::open_by_serial(self.serial) {
|
||||||
Ok(yk) => yk,
|
Ok(yk) => yk,
|
||||||
Err(yubikey_piv::Error::NotFound) => {
|
Err(yubikey::Error::NotFound) => {
|
||||||
if callbacks
|
if callbacks
|
||||||
.message(&format!(
|
.message(&format!(
|
||||||
"Please insert YubiKey with serial {}",
|
"Please insert YubiKey with serial {}",
|
||||||
@@ -266,7 +264,7 @@ impl Stub {
|
|||||||
loop {
|
loop {
|
||||||
match YubiKey::open_by_serial(self.serial) {
|
match YubiKey::open_by_serial(self.serial) {
|
||||||
Ok(yubikey) => break yubikey,
|
Ok(yubikey) => break yubikey,
|
||||||
Err(yubikey_piv::Error::NotFound) => (),
|
Err(yubikey::Error::NotFound) => (),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Ok(Err(identity::Error::Identity {
|
return Ok(Err(identity::Error::Identity {
|
||||||
index: self.identity_index,
|
index: self.identity_index,
|
||||||
@@ -425,7 +423,7 @@ impl Connection {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use yubikey_piv::{key::RetiredSlotId, Serial};
|
use yubikey::{piv::RetiredSlotId, Serial};
|
||||||
|
|
||||||
use super::Stub;
|
use super::Stub;
|
||||||
|
|
||||||
+18
-18
@@ -5,20 +5,20 @@ use std::io::{self, Write};
|
|||||||
use age_plugin::run_state_machine;
|
use age_plugin::run_state_machine;
|
||||||
use dialoguer::{Confirm, Input, Select};
|
use dialoguer::{Confirm, Input, Select};
|
||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use yubikey_piv::{
|
use yubikey::{
|
||||||
certificate::PublicKeyInfo,
|
certificate::PublicKeyInfo,
|
||||||
key::{RetiredSlotId, SlotId},
|
piv::{RetiredSlotId, SlotId},
|
||||||
policy::{PinPolicy, TouchPolicy},
|
reader::Context,
|
||||||
Key, Readers, Serial,
|
Key, PinPolicy, Serial, TouchPolicy,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod builder;
|
mod builder;
|
||||||
mod error;
|
mod error;
|
||||||
mod format;
|
mod format;
|
||||||
|
mod key;
|
||||||
mod p256;
|
mod p256;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
mod util;
|
mod util;
|
||||||
mod yubikey;
|
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ impl TryFrom<PluginOptions> for PluginFlags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate(flags: PluginFlags) -> Result<(), Error> {
|
fn generate(flags: PluginFlags) -> Result<(), Error> {
|
||||||
let mut yubikey = yubikey::open(flags.serial)?;
|
let mut yubikey = key::open(flags.serial)?;
|
||||||
|
|
||||||
let (stub, recipient, metadata) = builder::IdentityBuilder::new(flags.slot)
|
let (stub, recipient, metadata) = builder::IdentityBuilder::new(flags.slot)
|
||||||
.with_name(flags.name)
|
.with_name(flags.name)
|
||||||
@@ -165,9 +165,9 @@ fn generate(flags: PluginFlags) -> Result<(), Error> {
|
|||||||
fn print_single(
|
fn print_single(
|
||||||
serial: Option<Serial>,
|
serial: Option<Serial>,
|
||||||
slot: RetiredSlotId,
|
slot: RetiredSlotId,
|
||||||
printer: impl Fn(yubikey::Stub, p256::Recipient, util::Metadata),
|
printer: impl Fn(key::Stub, p256::Recipient, util::Metadata),
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut yubikey = yubikey::open(serial)?;
|
let mut yubikey = key::open(serial)?;
|
||||||
|
|
||||||
let mut keys = Key::list(&mut yubikey)?.into_iter().filter_map(|key| {
|
let mut keys = Key::list(&mut yubikey)?.into_iter().filter_map(|key| {
|
||||||
// - We only use the retired slots.
|
// - We only use the retired slots.
|
||||||
@@ -184,7 +184,7 @@ fn print_single(
|
|||||||
.find(|(_, s, _)| s == &slot)
|
.find(|(_, s, _)| s == &slot)
|
||||||
.ok_or(Error::SlotHasNoIdentity(slot))?;
|
.ok_or(Error::SlotHasNoIdentity(slot))?;
|
||||||
|
|
||||||
let stub = yubikey::Stub::new(yubikey.serial(), slot, &recipient);
|
let stub = key::Stub::new(yubikey.serial(), slot, &recipient);
|
||||||
let metadata = x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
let metadata = x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|(_, cert)| util::Metadata::extract(&mut yubikey, slot, &cert, true))
|
.and_then(|(_, cert)| util::Metadata::extract(&mut yubikey, slot, &cert, true))
|
||||||
@@ -199,12 +199,12 @@ fn print_multiple(
|
|||||||
kind: &str,
|
kind: &str,
|
||||||
serial: Option<Serial>,
|
serial: Option<Serial>,
|
||||||
all: bool,
|
all: bool,
|
||||||
printer: impl Fn(yubikey::Stub, p256::Recipient, util::Metadata),
|
printer: impl Fn(key::Stub, p256::Recipient, util::Metadata),
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut readers = Readers::open()?;
|
let mut readers = Context::open()?;
|
||||||
|
|
||||||
let mut printed = 0;
|
let mut printed = 0;
|
||||||
for reader in readers.iter()?.filter(yubikey::filter_connected) {
|
for reader in readers.iter()?.filter(key::filter_connected) {
|
||||||
let mut yubikey = reader.open()?;
|
let mut yubikey = reader.open()?;
|
||||||
if let Some(serial) = serial {
|
if let Some(serial) = serial {
|
||||||
if yubikey.serial() != serial {
|
if yubikey.serial() != serial {
|
||||||
@@ -228,7 +228,7 @@ fn print_multiple(
|
|||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let stub = yubikey::Stub::new(yubikey.serial(), slot, &recipient);
|
let stub = key::Stub::new(yubikey.serial(), slot, &recipient);
|
||||||
let metadata = match x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
let metadata = match x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|(_, cert)| util::Metadata::extract(&mut yubikey, slot, &cert, all))
|
.and_then(|(_, cert)| util::Metadata::extract(&mut yubikey, slot, &cert, all))
|
||||||
@@ -257,7 +257,7 @@ fn print_details(
|
|||||||
kind: &str,
|
kind: &str,
|
||||||
flags: PluginFlags,
|
flags: PluginFlags,
|
||||||
all: bool,
|
all: bool,
|
||||||
printer: impl Fn(yubikey::Stub, p256::Recipient, util::Metadata),
|
printer: impl Fn(key::Stub, p256::Recipient, util::Metadata),
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(slot) = flags.slot {
|
if let Some(slot) = flags.slot {
|
||||||
print_single(flags.serial, slot, printer)
|
print_single(flags.serial, slot, printer)
|
||||||
@@ -350,13 +350,13 @@ fn main() -> Result<(), Error> {
|
|||||||
eprintln!("make your choice, or press [Esc] or [q] to quit.");
|
eprintln!("make your choice, or press [Esc] or [q] to quit.");
|
||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
||||||
if !Readers::open()?.iter()?.any(yubikey::is_connected) {
|
if !Context::open()?.iter()?.any(key::is_connected) {
|
||||||
eprintln!("⏳ Please insert the YubiKey you want to set up.");
|
eprintln!("⏳ Please insert the YubiKey you want to set up.");
|
||||||
};
|
};
|
||||||
let mut readers = yubikey::wait_for_readers()?;
|
let mut readers = key::wait_for_readers()?;
|
||||||
|
|
||||||
// Filter out readers we can't connect to.
|
// Filter out readers we can't connect to.
|
||||||
let readers_list: Vec<_> = readers.iter()?.filter(yubikey::filter_connected).collect();
|
let readers_list: Vec<_> = readers.iter()?.filter(key::filter_connected).collect();
|
||||||
|
|
||||||
let reader_names = readers_list
|
let reader_names = readers_list
|
||||||
.iter()
|
.iter()
|
||||||
@@ -447,7 +447,7 @@ fn main() -> Result<(), Error> {
|
|||||||
.with_prompt(&format!("Use existing identity in slot {}?", slot_index))
|
.with_prompt(&format!("Use existing identity in slot {}?", slot_index))
|
||||||
.interact()?
|
.interact()?
|
||||||
{
|
{
|
||||||
let stub = yubikey::Stub::new(yubikey.serial(), slot, &recipient);
|
let stub = key::Stub::new(yubikey.serial(), slot, &recipient);
|
||||||
let (_, cert) =
|
let (_, cert) =
|
||||||
x509_parser::parse_x509_certificate(key.certificate().as_ref()).unwrap();
|
x509_parser::parse_x509_certificate(key.certificate().as_ref()).unwrap();
|
||||||
let metadata =
|
let metadata =
|
||||||
|
|||||||
+10
-13
@@ -7,12 +7,12 @@ use age_plugin::{
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use crate::{format, p256::Recipient, yubikey, PLUGIN_NAME};
|
use crate::{format, key, p256::Recipient, PLUGIN_NAME};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct RecipientPlugin {
|
pub(crate) struct RecipientPlugin {
|
||||||
recipients: Vec<Recipient>,
|
recipients: Vec<Recipient>,
|
||||||
yubikeys: Vec<yubikey::Stub>,
|
yubikeys: Vec<key::Stub>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecipientPluginV1 for RecipientPlugin {
|
impl RecipientPluginV1 for RecipientPlugin {
|
||||||
@@ -44,7 +44,7 @@ impl RecipientPluginV1 for RecipientPlugin {
|
|||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Result<(), recipient::Error> {
|
) -> Result<(), recipient::Error> {
|
||||||
if let Some(stub) = if plugin_name == PLUGIN_NAME {
|
if let Some(stub) = if plugin_name == PLUGIN_NAME {
|
||||||
yubikey::Stub::from_bytes(bytes, index)
|
key::Stub::from_bytes(bytes, index)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
} {
|
} {
|
||||||
@@ -100,7 +100,7 @@ impl RecipientPluginV1 for RecipientPlugin {
|
|||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct IdentityPlugin {
|
pub(crate) struct IdentityPlugin {
|
||||||
yubikeys: Vec<yubikey::Stub>,
|
yubikeys: Vec<key::Stub>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdentityPluginV1 for IdentityPlugin {
|
impl IdentityPluginV1 for IdentityPlugin {
|
||||||
@@ -111,7 +111,7 @@ impl IdentityPluginV1 for IdentityPlugin {
|
|||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Result<(), identity::Error> {
|
) -> Result<(), identity::Error> {
|
||||||
if let Some(stub) = if plugin_name == PLUGIN_NAME {
|
if let Some(stub) = if plugin_name == PLUGIN_NAME {
|
||||||
yubikey::Stub::from_bytes(bytes, index)
|
key::Stub::from_bytes(bytes, index)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
} {
|
} {
|
||||||
@@ -133,14 +133,11 @@ impl IdentityPluginV1 for IdentityPlugin {
|
|||||||
let mut file_keys = HashMap::with_capacity(files.len());
|
let mut file_keys = HashMap::with_capacity(files.len());
|
||||||
|
|
||||||
// Filter to files / stanzas for which we have matching YubiKeys
|
// Filter to files / stanzas for which we have matching YubiKeys
|
||||||
let mut candidate_stanzas: Vec<(
|
let mut candidate_stanzas: Vec<(&key::Stub, HashMap<usize, Vec<format::RecipientLine>>)> =
|
||||||
&yubikey::Stub,
|
self.yubikeys
|
||||||
HashMap<usize, Vec<format::RecipientLine>>,
|
.iter()
|
||||||
)> = self
|
.map(|stub| (stub, HashMap::new()))
|
||||||
.yubikeys
|
.collect();
|
||||||
.iter()
|
|
||||||
.map(|stub| (stub, HashMap::new()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
for (file, stanzas) in files.iter().enumerate() {
|
for (file, stanzas) in files.iter().enumerate() {
|
||||||
for (stanza_index, stanza) in stanzas.iter().enumerate() {
|
for (stanza_index, stanza) in stanzas.iter().enumerate() {
|
||||||
|
|||||||
+7
-8
@@ -1,13 +1,12 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use x509_parser::{certificate::X509Certificate, der_parser::oid::Oid};
|
use x509_parser::{certificate::X509Certificate, der_parser::oid::Oid};
|
||||||
use yubikey_piv::{
|
use yubikey::{
|
||||||
key::{RetiredSlotId, SlotId},
|
piv::{RetiredSlotId, SlotId},
|
||||||
policy::{PinPolicy, TouchPolicy},
|
PinPolicy, Serial, TouchPolicy, YubiKey,
|
||||||
Serial, YubiKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{error::Error, p256::Recipient, yubikey::Stub, BINARY_NAME, USABLE_SLOTS};
|
use crate::{error::Error, key::Stub, p256::Recipient, BINARY_NAME, USABLE_SLOTS};
|
||||||
|
|
||||||
pub(crate) const POLICY_EXTENSION_OID: &[u64] = &[1, 3, 6, 1, 4, 1, 41482, 3, 8];
|
pub(crate) const POLICY_EXTENSION_OID: &[u64] = &[1, 3, 6, 1, 4, 1, 41482, 3, 8];
|
||||||
|
|
||||||
@@ -111,8 +110,8 @@ impl Metadata {
|
|||||||
// using the same certificate extension as PIV attestations.
|
// using the same certificate extension as PIV attestations.
|
||||||
// https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
|
// https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
|
||||||
let policies = |c: &X509Certificate| {
|
let policies = |c: &X509Certificate| {
|
||||||
c.extensions()
|
c.tbs_certificate
|
||||||
.get(&Oid::from(POLICY_EXTENSION_OID).unwrap())
|
.find_extension(&Oid::from(POLICY_EXTENSION_OID).unwrap())
|
||||||
// If the encoded extension doesn't have 2 bytes, we assume it is invalid.
|
// If the encoded extension doesn't have 2 bytes, we assume it is invalid.
|
||||||
.filter(|policy| policy.value.len() >= 2)
|
.filter(|policy| policy.value.len() >= 2)
|
||||||
.map(|policy| {
|
.map(|policy| {
|
||||||
@@ -144,7 +143,7 @@ impl Metadata {
|
|||||||
// We can extract the PIN and touch policies via an attestation. This
|
// We can extract the PIN and touch policies via an attestation. This
|
||||||
// is slow, but the user has asked for all compatible keys, so...
|
// is slow, but the user has asked for all compatible keys, so...
|
||||||
let (pin_policy, touch_policy) =
|
let (pin_policy, touch_policy) =
|
||||||
yubikey_piv::key::attest(yubikey, SlotId::Retired(slot))
|
yubikey::piv::attest(yubikey, SlotId::Retired(slot))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|buf| {
|
.and_then(|buf| {
|
||||||
x509_parser::parse_x509_certificate(&buf)
|
x509_parser::parse_x509_certificate(&buf)
|
||||||
|
|||||||
Reference in New Issue
Block a user