Add functionality for cli tools.
This commit is contained in:
parent
1d4f058858
commit
aa7528ec9a
4 changed files with 81 additions and 9 deletions
|
@ -454,7 +454,7 @@ pub fn test_pw_status(
|
||||||
|
|
||||||
ca.verify_pw3("12345678")?;
|
ca.verify_pw3("12345678")?;
|
||||||
|
|
||||||
pws.set_pw1_cds_multi(true);
|
pws.set_pw1_cds_valid_once(false);
|
||||||
pws.set_pw1_pin_block(true);
|
pws.set_pw1_pin_block(true);
|
||||||
|
|
||||||
ca.set_pw_status_bytes(&pws, false)?;
|
ca.set_pw_status_bytes(&pws, false)?;
|
||||||
|
|
|
@ -18,7 +18,7 @@ use openpgp::parse::{
|
||||||
};
|
};
|
||||||
use openpgp::policy::Policy;
|
use openpgp::policy::Policy;
|
||||||
use openpgp::serialize::stream::{Message, Signer};
|
use openpgp::serialize::stream::{Message, Signer};
|
||||||
use openpgp::Cert;
|
use openpgp::{Cert, Fingerprint};
|
||||||
use sequoia_openpgp as openpgp;
|
use sequoia_openpgp as openpgp;
|
||||||
|
|
||||||
use openpgp_card::KeyType;
|
use openpgp_card::KeyType;
|
||||||
|
@ -60,6 +60,36 @@ pub fn get_subkey<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve a (sub)key from a Cert, with a specified fingerprint.
|
||||||
|
pub fn get_subkey_by_fingerprint<'a>(
|
||||||
|
cert: &'a Cert,
|
||||||
|
policy: &'a dyn Policy,
|
||||||
|
fingerprint: &str,
|
||||||
|
) -> Result<Option<ValidErasedKeyAmalgamation<'a, SecretParts>>> {
|
||||||
|
let fp = Fingerprint::from_hex(fingerprint)?;
|
||||||
|
|
||||||
|
// Find usable (sub)key with Fingerprint fp.
|
||||||
|
let mut vkas: Vec<_> = cert
|
||||||
|
.keys()
|
||||||
|
.with_policy(policy, None)
|
||||||
|
.secret()
|
||||||
|
.alive()
|
||||||
|
.revoked(false)
|
||||||
|
.filter(|vka| vka.fingerprint() == fp)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if vkas.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else if vkas.len() == 1 {
|
||||||
|
Ok(Some(vkas.pop().unwrap()))
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Unexpected number of suitable (sub)key found: {}",
|
||||||
|
vkas.len()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Produce an armored signature from `input` and a Signer `s`.
|
/// Produce an armored signature from `input` and a Signer `s`.
|
||||||
pub fn sign_helper<S>(s: S, input: &mut dyn io::Read) -> Result<String>
|
pub fn sign_helper<S>(s: S, input: &mut dyn io::Read) -> Result<String>
|
||||||
where
|
where
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
//! OpenPGP card data objects (DO)
|
//! OpenPGP card data objects (DO)
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
|
|
||||||
use crate::{algorithm::Algo, tlv::Tlv, Error, KeySet, KeyType};
|
use crate::{algorithm::Algo, tlv::Tlv, Error, KeySet, KeyType};
|
||||||
|
|
||||||
|
@ -193,6 +195,13 @@ impl KeyGenerationTime {
|
||||||
pub fn get(&self) -> u32 {
|
pub fn get(&self) -> u32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn formatted(&self) -> String {
|
||||||
|
let d = UNIX_EPOCH + Duration::from_secs(self.get() as u64);
|
||||||
|
let datetime = DateTime::<Utc>::from(d);
|
||||||
|
|
||||||
|
datetime.format("%Y-%m-%d %H:%M:%S").to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 4.2.1 Application Identifier (AID)
|
/// 4.2.1 Application Identifier (AID)
|
||||||
|
@ -312,7 +321,7 @@ impl From<u8> for Sex {
|
||||||
/// PW status Bytes (see spec page 23)
|
/// PW status Bytes (see spec page 23)
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PWStatusBytes {
|
pub struct PWStatusBytes {
|
||||||
pub(crate) pw1_cds_multi: bool,
|
pub(crate) pw1_cds_valid_once: bool,
|
||||||
pub(crate) pw1_pin_block: bool,
|
pub(crate) pw1_pin_block: bool,
|
||||||
pub(crate) pw1_len: u8,
|
pub(crate) pw1_len: u8,
|
||||||
pub(crate) rc_len: u8,
|
pub(crate) rc_len: u8,
|
||||||
|
@ -324,8 +333,8 @@ pub struct PWStatusBytes {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PWStatusBytes {
|
impl PWStatusBytes {
|
||||||
pub fn set_pw1_cds_multi(&mut self, val: bool) {
|
pub fn set_pw1_cds_valid_once(&mut self, val: bool) {
|
||||||
self.pw1_cds_multi = val;
|
self.pw1_cds_valid_once = val;
|
||||||
}
|
}
|
||||||
pub fn set_pw1_pin_block(&mut self, val: bool) {
|
pub fn set_pw1_pin_block(&mut self, val: bool) {
|
||||||
self.pw1_pin_block = val;
|
self.pw1_pin_block = val;
|
||||||
|
@ -333,12 +342,45 @@ impl PWStatusBytes {
|
||||||
pub fn set_pw3_pin_block(&mut self, val: bool) {
|
pub fn set_pw3_pin_block(&mut self, val: bool) {
|
||||||
self.pw3_pin_block = val;
|
self.pw3_pin_block = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_pw1_cds_valid_once(&self) -> bool {
|
||||||
|
self.pw1_cds_valid_once
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_err_count_pw1(&self) -> u8 {
|
||||||
|
self.err_count_pw1
|
||||||
|
}
|
||||||
|
pub fn get_err_count_rst(&self) -> u8 {
|
||||||
|
self.err_count_rst
|
||||||
|
}
|
||||||
|
pub fn get_err_count_pw3(&self) -> u8 {
|
||||||
|
self.err_count_pw3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fingerprint (see spec pg. 23)
|
/// Fingerprint (see spec pg. 23)
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct Fingerprint([u8; 20]);
|
pub struct Fingerprint([u8; 20]);
|
||||||
|
|
||||||
|
impl Fingerprint {
|
||||||
|
pub fn to_spaced_hex(&self) -> String {
|
||||||
|
let mut fp = String::new();
|
||||||
|
|
||||||
|
for i in 0..20 {
|
||||||
|
fp.push_str(&format!("{:02X}", self.0[i]));
|
||||||
|
|
||||||
|
if i < 19 && (i % 2 == 1) {
|
||||||
|
fp.push(' ');
|
||||||
|
}
|
||||||
|
if i == 9 {
|
||||||
|
fp.push(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper fn for nom parsing
|
/// Helper fn for nom parsing
|
||||||
pub(crate) fn complete<O>(
|
pub(crate) fn complete<O>(
|
||||||
result: nom::IResult<&[u8], O>,
|
result: nom::IResult<&[u8], O>,
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl PWStatusBytes {
|
||||||
pub(crate) fn serialize_for_put(&self, long: bool) -> Vec<u8> {
|
pub(crate) fn serialize_for_put(&self, long: bool) -> Vec<u8> {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
|
|
||||||
data.push(if !self.pw1_cds_multi { 0 } else { 1 });
|
data.push(if self.pw1_cds_valid_once { 0 } else { 1 });
|
||||||
|
|
||||||
if long {
|
if long {
|
||||||
let mut b2 = self.pw1_len;
|
let mut b2 = self.pw1_len;
|
||||||
|
@ -45,7 +45,7 @@ impl TryFrom<&[u8]> for PWStatusBytes {
|
||||||
|
|
||||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||||
if input.len() == 7 {
|
if input.len() == 7 {
|
||||||
let pw1_cds_multi = input[0] == 0x01;
|
let pw1_cds_valid_once = input[0] == 0x00;
|
||||||
let pw1_pin_block = input[1] & 0x80 != 0;
|
let pw1_pin_block = input[1] & 0x80 != 0;
|
||||||
let pw1_len = input[1] & 0x7f;
|
let pw1_len = input[1] & 0x7f;
|
||||||
let rc_len = input[2];
|
let rc_len = input[2];
|
||||||
|
@ -56,7 +56,7 @@ impl TryFrom<&[u8]> for PWStatusBytes {
|
||||||
let err_count_pw3 = input[6];
|
let err_count_pw3 = input[6];
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
pw1_cds_multi,
|
pw1_cds_valid_once,
|
||||||
pw1_pin_block,
|
pw1_pin_block,
|
||||||
pw1_len,
|
pw1_len,
|
||||||
rc_len,
|
rc_len,
|
||||||
|
@ -90,7 +90,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pws,
|
pws,
|
||||||
PWStatusBytes {
|
PWStatusBytes {
|
||||||
pw1_cds_multi: false,
|
pw1_cds_valid_once: true,
|
||||||
pw1_pin_block: false,
|
pw1_pin_block: false,
|
||||||
pw1_len: 0x40,
|
pw1_len: 0x40,
|
||||||
rc_len: 0x40,
|
rc_len: 0x40,
|
||||||
|
|
Loading…
Reference in a new issue