From 771cad885a4edfa8d1eeb6efeb15a61401b37d70 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 12 Apr 2021 18:22:54 +1200 Subject: [PATCH 1/3] Always use created date from YubiKey certificate --- Cargo.lock | 1 - Cargo.toml | 1 - src/builder.rs | 7 +++++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbb90d3..1eab04d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,6 @@ dependencies = [ "age-plugin", "base64", "bech32", - "chrono", "console", "dialoguer", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index 67f00e4..0849b1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,6 @@ age-core = "0.5" age-plugin = "0.0" base64 = "0.13" bech32 = "0.8" -chrono = "0.4" console = "0.14" dialoguer = "0.8" env_logger = "0.8" diff --git a/src/builder.rs b/src/builder.rs index 2176fe0..f4aff2d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -123,7 +123,7 @@ impl IdentityBuilder { .name .unwrap_or(format!("age identity {}", hex::encode(stub.tag))); - Certificate::generate_self_signed( + let cert = Certificate::generate_self_signed( yubikey, SlotId::Retired(slot), serial, @@ -140,10 +140,13 @@ impl IdentityBuilder { )], )?; + let (_, cert) = x509_parser::parse_x509_certificate(cert.as_ref()).unwrap(); + let created = cert.validity().not_before.to_rfc2822(); + Ok(( Stub::new(yubikey.serial(), slot, &recipient), recipient, - chrono::Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true), + created, )) } } From 63c8d6c303ee1bb313f3a485914bd83540a93b23 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 12 Apr 2021 22:31:46 +1200 Subject: [PATCH 2/3] Rename PLUGIN_NAME to BINARY_NAME --- src/builder.rs | 4 ++-- src/main.rs | 4 ++-- src/util.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f4aff2d..eab165b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -12,7 +12,7 @@ use crate::{ p256::Recipient, util::POLICY_EXTENSION_OID, yubikey::{self, Stub}, - PLUGIN_NAME, USABLE_SLOTS, + BINARY_NAME, USABLE_SLOTS, }; const DEFAULT_PIN_POLICY: PinPolicy = PinPolicy::Once; @@ -129,7 +129,7 @@ impl IdentityBuilder { serial, None, &[ - RelativeDistinguishedName::organization(PLUGIN_NAME), + RelativeDistinguishedName::organization(BINARY_NAME), RelativeDistinguishedName::organizational_unit(env!("CARGO_PKG_VERSION")), RelativeDistinguishedName::common_name(&name), ], diff --git a/src/main.rs b/src/main.rs index a5fb74c..9d2069c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ mod yubikey; use error::Error; -const PLUGIN_NAME: &str = "age-plugin-yubikey"; +const BINARY_NAME: &str = "age-plugin-yubikey"; const RECIPIENT_PREFIX: &str = "age1yubikey"; const IDENTITY_PREFIX: &str = "age-plugin-yubikey-"; const STANZA_TAG: &str = "piv-p256"; @@ -157,7 +157,7 @@ fn identity(opts: PluginOptions) -> Result<(), Error> { .as_ref() .and_then(|cert| cert.subject().iter_organization().next()) { - Some(org) => org.as_str() == Ok(PLUGIN_NAME), + Some(org) => org.as_str() == Ok(BINARY_NAME), _ => false, } }); diff --git a/src/util.rs b/src/util.rs index 2f7c074..f4e8a82 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,7 +5,7 @@ use yubikey_piv::{ Key, YubiKey, }; -use crate::{error::Error, p256::Recipient, yubikey::Stub, PLUGIN_NAME, USABLE_SLOTS}; +use crate::{error::Error, p256::Recipient, yubikey::Stub, BINARY_NAME, USABLE_SLOTS}; pub(crate) const POLICY_EXTENSION_OID: &[u64] = &[1, 3, 6, 1, 4, 1, 41482, 3, 8]; @@ -63,7 +63,7 @@ pub(crate) fn touch_policy_to_str(policy: Option) -> &'static str { pub(crate) fn extract_name(cert: &X509Certificate, all: bool) -> Option<(String, bool)> { // Look at Subject Organization to determine if we created this. match cert.subject().iter_organization().next() { - Some(org) if org.as_str() == Ok(PLUGIN_NAME) => { + Some(org) if org.as_str() == Ok(BINARY_NAME) => { // We store the identity name as a Common Name attribute. let name = cert .subject() From 33ab75702500848921a1acb929b45adc07335af5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 13 Apr 2021 20:41:34 +1200 Subject: [PATCH 3/3] Migrate to new age-plugin API --- Cargo.lock | 4 +- Cargo.toml | 4 +- src/main.rs | 1 + src/plugin.rs | 138 +++++++++++++++++--------------------------------- 4 files changed, 51 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1eab04d..6e6651f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ dependencies = [ [[package]] name = "age-core" version = "0.5.0" -source = "git+https://github.com/str4d/rage.git?rev=a9b5e88aa5816b284ebea23fc84d0203a3c4fdbb#a9b5e88aa5816b284ebea23fc84d0203a3c4fdbb" +source = "git+https://github.com/str4d/rage.git?rev=4aa52a2dbb5feed86dcafa3afe8d554975ca5518#4aa52a2dbb5feed86dcafa3afe8d554975ca5518" dependencies = [ "base64", "c2-chacha", @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "age-plugin" version = "0.0.0" -source = "git+https://github.com/str4d/rage.git?rev=a9b5e88aa5816b284ebea23fc84d0203a3c4fdbb#a9b5e88aa5816b284ebea23fc84d0203a3c4fdbb" +source = "git+https://github.com/str4d/rage.git?rev=4aa52a2dbb5feed86dcafa3afe8d554975ca5518#4aa52a2dbb5feed86dcafa3afe8d554975ca5518" dependencies = [ "age-core", "bech32", diff --git a/Cargo.toml b/Cargo.toml index 0849b1c..ab6dc84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,5 +45,5 @@ flate2 = "1" man = "0.3" [patch.crates-io] -age-core = { git = "https://github.com/str4d/rage.git", rev = "a9b5e88aa5816b284ebea23fc84d0203a3c4fdbb" } -age-plugin = { git = "https://github.com/str4d/rage.git", rev = "a9b5e88aa5816b284ebea23fc84d0203a3c4fdbb" } +age-core = { git = "https://github.com/str4d/rage.git", rev = "4aa52a2dbb5feed86dcafa3afe8d554975ca5518" } +age-plugin = { git = "https://github.com/str4d/rage.git", rev = "4aa52a2dbb5feed86dcafa3afe8d554975ca5518" } diff --git a/src/main.rs b/src/main.rs index 9d2069c..7080d18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ mod yubikey; use error::Error; +const PLUGIN_NAME: &str = "yubikey"; const BINARY_NAME: &str = "age-plugin-yubikey"; const RECIPIENT_PREFIX: &str = "age1yubikey"; const IDENTITY_PREFIX: &str = "age-plugin-yubikey-"; diff --git a/src/plugin.rs b/src/plugin.rs index 8e76b22..2dc014f 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -4,11 +4,10 @@ use age_plugin::{ recipient::{self, RecipientPluginV1}, Callbacks, }; -use bech32::{FromBase32, Variant}; use std::collections::HashMap; use std::io; -use crate::{format, p256::Recipient, yubikey, IDENTITY_PREFIX, RECIPIENT_PREFIX}; +use crate::{format, p256::Recipient, yubikey, PLUGIN_NAME}; #[derive(Debug, Default)] pub(crate) struct RecipientPlugin { @@ -17,75 +16,45 @@ pub(crate) struct RecipientPlugin { } impl RecipientPluginV1 for RecipientPlugin { - fn add_recipients<'a, I: Iterator>( + fn add_recipient( &mut self, - recipients: I, - ) -> Result<(), Vec> { - let errors: Vec<_> = recipients - .enumerate() - .filter_map(|(index, recipient)| { - if let Some(pk) = bech32::decode(recipient) - .ok() - .and_then(|(hrp, data, variant)| { - if hrp == RECIPIENT_PREFIX && variant == Variant::Bech32 { - Some(data) - } else { - None - } - }) - .and_then(|data| Vec::from_base32(&data).ok()) - .and_then(|bytes| Recipient::from_bytes(&bytes)) - { - self.recipients.push(pk); - None - } else { - Some(recipient::Error::Recipient { - index, - message: "Invalid recipient".to_owned(), - }) - } - }) - .collect(); - if errors.is_empty() { + index: usize, + plugin_name: &str, + bytes: &[u8], + ) -> Result<(), recipient::Error> { + if let Some(pk) = if plugin_name == PLUGIN_NAME { + Recipient::from_bytes(&bytes) + } else { + None + } { + self.recipients.push(pk); Ok(()) } else { - Err(errors) + Err(recipient::Error::Recipient { + index, + message: "Invalid recipient".to_owned(), + }) } } - fn add_identities<'a, I: Iterator>( + fn add_identity( &mut self, - identities: I, - ) -> Result<(), Vec> { - let errors: Vec<_> = identities - .enumerate() - .filter_map(|(index, identity)| { - if let Some(stub) = bech32::decode(identity) - .ok() - .and_then(|(hrp, data, variant)| { - if hrp == IDENTITY_PREFIX.to_lowercase() && variant == Variant::Bech32 { - Some(data) - } else { - None - } - }) - .and_then(|data| Vec::from_base32(&data).ok()) - .and_then(|bytes| yubikey::Stub::from_bytes(&bytes, index)) - { - self.yubikeys.push(stub); - None - } else { - Some(recipient::Error::Identity { - index, - message: "Invalid Yubikey stub".to_owned(), - }) - } - }) - .collect(); - if errors.is_empty() { + index: usize, + plugin_name: &str, + bytes: &[u8], + ) -> Result<(), recipient::Error> { + if let Some(stub) = if plugin_name == PLUGIN_NAME { + yubikey::Stub::from_bytes(&bytes, index) + } else { + None + } { + self.yubikeys.push(stub); Ok(()) } else { - Err(errors) + Err(recipient::Error::Identity { + index, + message: "Invalid Yubikey stub".to_owned(), + }) } } @@ -135,39 +104,24 @@ pub(crate) struct IdentityPlugin { } impl IdentityPluginV1 for IdentityPlugin { - fn add_identities<'a, I: Iterator>( + fn add_identity( &mut self, - identities: I, - ) -> Result<(), Vec> { - let errors: Vec<_> = identities - .enumerate() - .filter_map(|(index, identity)| { - if let Some(stub) = bech32::decode(identity) - .ok() - .and_then(|(hrp, data, variant)| { - if hrp == IDENTITY_PREFIX.to_lowercase() && variant == Variant::Bech32 { - Some(data) - } else { - None - } - }) - .and_then(|data| Vec::from_base32(&data).ok()) - .and_then(|bytes| yubikey::Stub::from_bytes(&bytes, index)) - { - self.yubikeys.push(stub); - None - } else { - Some(identity::Error::Identity { - index, - message: "Invalid Yubikey stub".to_owned(), - }) - } - }) - .collect(); - if errors.is_empty() { + index: usize, + plugin_name: &str, + bytes: &[u8], + ) -> Result<(), identity::Error> { + if let Some(stub) = if plugin_name == PLUGIN_NAME { + yubikey::Stub::from_bytes(&bytes, index) + } else { + None + } { + self.yubikeys.push(stub); Ok(()) } else { - Err(errors) + Err(identity::Error::Identity { + index, + message: "Invalid Yubikey stub".to_owned(), + }) } }