- Implement key generation (without specifying an algorithm so the current algo is used. only supports RSA for now)
- Refactor: rename key_upload.rs -> keys.rs - Fix handling of key timestamps
This commit is contained in:
parent
538bfb51d4
commit
7acc1deb98
7 changed files with 248 additions and 40 deletions
|
@ -26,6 +26,8 @@
|
||||||
//! the command data field").
|
//! the command data field").
|
||||||
|
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::time::SystemTime;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use sequoia_openpgp::parse::Parse;
|
use sequoia_openpgp::parse::Parse;
|
||||||
|
@ -33,7 +35,7 @@ use sequoia_openpgp::Cert;
|
||||||
|
|
||||||
use openpgp_card::card_app::CardApp;
|
use openpgp_card::card_app::CardApp;
|
||||||
use openpgp_card::errors::{OcErrorStatus, OpenpgpCardError};
|
use openpgp_card::errors::{OcErrorStatus, OpenpgpCardError};
|
||||||
use openpgp_card::Sex;
|
use openpgp_card::{KeyType, PublicKeyMaterial, Sex};
|
||||||
|
|
||||||
use crate::cards::{TestCard, TestConfig};
|
use crate::cards::{TestCard, TestConfig};
|
||||||
|
|
||||||
|
@ -203,10 +205,32 @@ fn test_upload_keys(
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_keygen() {
|
/// Generate keys for each of the three KeyTypes
|
||||||
// FIXME
|
fn test_keygen(
|
||||||
// (implementation of this functionality is still missing in openpgp-card)
|
ca: &mut CardApp,
|
||||||
unimplemented!()
|
_param: &[&str],
|
||||||
|
) -> Result<TestOutput, TestError> {
|
||||||
|
let verify = ca.verify_pw3("12345678")?;
|
||||||
|
verify.check_ok()?;
|
||||||
|
|
||||||
|
let fp = |pkm: &PublicKeyMaterial, ts: SystemTime| {
|
||||||
|
// FIXME: store creation timestamp
|
||||||
|
|
||||||
|
let key = openpgp_card_sequoia::public_key_material_to_key(pkm, ts)?;
|
||||||
|
|
||||||
|
let fp = key.fingerprint();
|
||||||
|
let fp = fp.as_bytes();
|
||||||
|
assert_eq!(fp.len(), 20);
|
||||||
|
|
||||||
|
println!("fp {:?}", fp);
|
||||||
|
Ok(fp.try_into().unwrap())
|
||||||
|
};
|
||||||
|
|
||||||
|
ca.generate_key(fp, KeyType::Signing)?;
|
||||||
|
ca.generate_key(fp, KeyType::Decryption)?;
|
||||||
|
ca.generate_key(fp, KeyType::Authentication)?;
|
||||||
|
|
||||||
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_reset(
|
fn test_reset(
|
||||||
|
@ -342,6 +366,11 @@ fn main() -> Result<()> {
|
||||||
println!("Reset");
|
println!("Reset");
|
||||||
let _ = run_test(&mut card, test_reset, &[])?;
|
let _ = run_test(&mut card, test_reset, &[])?;
|
||||||
|
|
||||||
|
println!("Generate key");
|
||||||
|
let _ = run_test(&mut card, test_keygen, &[])?;
|
||||||
|
|
||||||
|
panic!();
|
||||||
|
|
||||||
print!("Verify");
|
print!("Verify");
|
||||||
let verify_out = run_test(&mut card, test_verify, &[])?;
|
let verify_out = run_test(&mut card, test_verify, &[])?;
|
||||||
println!(" {:x?}", verify_out);
|
println!(" {:x?}", verify_out);
|
||||||
|
@ -385,8 +414,6 @@ fn main() -> Result<()> {
|
||||||
println!(" {:x?}", sign_out);
|
println!(" {:x?}", sign_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: generate keys
|
|
||||||
|
|
||||||
// FIXME: upload key with password
|
// FIXME: upload key with password
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
//! This library supports using openpgp-card functionality with
|
//! This library supports using openpgp-card functionality with
|
||||||
//! sequoia_openpgp data structures.
|
//! sequoia_openpgp data structures.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use chrono::prelude::*;
|
|
||||||
use openpgp::armor;
|
use openpgp::armor;
|
||||||
use openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation;
|
use openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation;
|
||||||
use openpgp::crypto::mpi;
|
use openpgp::crypto::mpi;
|
||||||
|
@ -23,8 +24,10 @@ use sequoia_openpgp as openpgp;
|
||||||
use openpgp_card::card_app::CardApp;
|
use openpgp_card::card_app::CardApp;
|
||||||
use openpgp_card::{
|
use openpgp_card::{
|
||||||
errors::OpenpgpCardError, CardAdmin, CardUploadableKey, EccKey, EccType,
|
errors::OpenpgpCardError, CardAdmin, CardUploadableKey, EccKey, EccType,
|
||||||
KeyType, PrivateKeyMaterial, RSAKey,
|
KeyType, PrivateKeyMaterial, PublicKeyMaterial, RSAKey,
|
||||||
};
|
};
|
||||||
|
use sequoia_openpgp::packet::key::{Key4, PublicParts};
|
||||||
|
use sequoia_openpgp::types::Timestamp;
|
||||||
|
|
||||||
mod decryptor;
|
mod decryptor;
|
||||||
mod signer;
|
mod signer;
|
||||||
|
@ -67,6 +70,22 @@ pub fn vka_as_uploadable_key(
|
||||||
Box::new(sqk)
|
Box::new(sqk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper fn: get a Key<PublicParts, UnspecifiedRole> for a PublicKeyMaterial
|
||||||
|
pub fn public_key_material_to_key(
|
||||||
|
pkm: &PublicKeyMaterial,
|
||||||
|
time: SystemTime,
|
||||||
|
) -> Result<Key<PublicParts, UnspecifiedRole>> {
|
||||||
|
match pkm {
|
||||||
|
PublicKeyMaterial::R(rsa) => {
|
||||||
|
let k4: Key4<key::PublicParts, key::UnspecifiedRole> =
|
||||||
|
Key4::import_public_rsa(&rsa.v, &rsa.n, Some(time))?;
|
||||||
|
|
||||||
|
Ok(Key::from(k4))
|
||||||
|
}
|
||||||
|
_ => unimplemented!("ECC not implemented yet"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement the `CardUploadableKey` trait that openpgp-card uses to
|
/// Implement the `CardUploadableKey` trait that openpgp-card uses to
|
||||||
/// upload (sub)keys to a card.
|
/// upload (sub)keys to a card.
|
||||||
impl CardUploadableKey for SequoiaKey {
|
impl CardUploadableKey for SequoiaKey {
|
||||||
|
@ -144,9 +163,12 @@ impl CardUploadableKey for SequoiaKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ts(&self) -> u64 {
|
/// Number of non-leap seconds since January 1, 1970 0:00:00 UTC
|
||||||
let key_creation: DateTime<Utc> = self.key.creation_time().into();
|
/// (aka "UNIX timestamp")
|
||||||
key_creation.timestamp() as u64
|
fn get_ts(&self) -> u32 {
|
||||||
|
let ts: Timestamp = Timestamp::try_from(self.key.creation_time())
|
||||||
|
.expect("Creation time cannot be converted into u32 timestamp");
|
||||||
|
ts.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fp(&self) -> Vec<u8> {
|
fn get_fp(&self) -> Vec<u8> {
|
||||||
|
|
|
@ -126,3 +126,8 @@ pub fn decryption(data: Vec<u8>) -> Command {
|
||||||
pub fn signature(data: Vec<u8>) -> Command {
|
pub fn signature(data: Vec<u8>) -> Command {
|
||||||
Command::new(0x00, 0x2A, 0x9e, 0x9a, data)
|
Command::new(0x00, 0x2A, 0x9e, 0x9a, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates new APDU for "GENERATE ASYMMETRIC KEY PAIR"
|
||||||
|
pub fn gen_key(data: Vec<u8>) -> Command {
|
||||||
|
Command::new(0x00, 0x47, 0x80, 0x00, data)
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
@ -20,13 +21,12 @@ use crate::parse::{
|
||||||
algo_attrs::Algo, algo_info::AlgoInfo, application_id::ApplicationId,
|
algo_attrs::Algo, algo_info::AlgoInfo, application_id::ApplicationId,
|
||||||
cardholder::CardHolder, extended_cap::ExtendedCap,
|
cardholder::CardHolder, extended_cap::ExtendedCap,
|
||||||
extended_length_info::ExtendedLengthInfo, fingerprint,
|
extended_length_info::ExtendedLengthInfo, fingerprint,
|
||||||
historical::Historical, key_generation_times,
|
historical::Historical, key_generation_times, pw_status::PWStatus, KeySet,
|
||||||
key_generation_times::KeyGeneration, pw_status::PWStatus, KeySet,
|
|
||||||
};
|
};
|
||||||
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
|
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
|
||||||
use crate::{
|
use crate::{
|
||||||
apdu, key_upload, CardCaps, CardClientBox, CardUploadableKey, DecryptMe,
|
apdu, keys, CardCaps, CardClientBox, CardUploadableKey, DecryptMe, Hash,
|
||||||
Hash, KeyType, Sex,
|
KeyGeneration, KeyType, PublicKeyMaterial, Sex,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CardApp {
|
pub struct CardApp {
|
||||||
|
@ -524,6 +524,27 @@ impl CardApp {
|
||||||
apdu::send_command(&mut self.card_client, put_url, false)
|
apdu::send_command(&mut self.card_client, put_url, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_creation_time(
|
||||||
|
&mut self,
|
||||||
|
time: u32,
|
||||||
|
key_type: KeyType,
|
||||||
|
) -> Result<Response, OpenpgpCardError> {
|
||||||
|
// Timestamp update
|
||||||
|
let time_value: Vec<u8> = time
|
||||||
|
.to_be_bytes()
|
||||||
|
.iter()
|
||||||
|
.skip_while(|&&e| e == 0)
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let time_cmd = commands::put_data(
|
||||||
|
&[key_type.get_timestamp_put_tag()],
|
||||||
|
time_value,
|
||||||
|
);
|
||||||
|
|
||||||
|
apdu::send_command(&mut self.card_client, time_cmd, false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn upload_key(
|
pub fn upload_key(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: Box<dyn CardUploadableKey>,
|
key: Box<dyn CardUploadableKey>,
|
||||||
|
@ -539,6 +560,16 @@ impl CardApp {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
key_upload::upload_key(self, key, key_type, algo_list)
|
keys::upload_key(self, key, key_type, algo_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: use subset of CardUploadableKey to specify algo?
|
||||||
|
pub fn generate_key(
|
||||||
|
&mut self,
|
||||||
|
fp_from_pub: fn(&PublicKeyMaterial, SystemTime) -> Result<[u8; 20]>,
|
||||||
|
key_type: KeyType,
|
||||||
|
) -> Result<(), OpenpgpCardError> {
|
||||||
|
// FIXME: specify algo; pass in algo list?
|
||||||
|
keys::gen_key_with_metadata(self, fp_from_pub, key_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
|
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
//! Generate and import keys
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use crate::apdu::command::Command;
|
use crate::apdu::command::Command;
|
||||||
use crate::apdu::commands;
|
use crate::apdu::commands;
|
||||||
|
@ -10,12 +13,109 @@ use crate::errors::OpenpgpCardError;
|
||||||
use crate::parse::algo_attrs::{Algo, RsaAttrs};
|
use crate::parse::algo_attrs::{Algo, RsaAttrs};
|
||||||
use crate::parse::algo_info::AlgoInfo;
|
use crate::parse::algo_info::AlgoInfo;
|
||||||
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
|
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
|
||||||
use crate::{apdu, CardClientBox};
|
use crate::{apdu, EccPub, PublicKeyMaterial, RSAPub};
|
||||||
use crate::{
|
use crate::{
|
||||||
tlv, CardUploadableKey, EccKey, EccType, KeyType, PrivateKeyMaterial,
|
tlv, CardUploadableKey, EccKey, EccType, KeyType, PrivateKeyMaterial,
|
||||||
RSAKey,
|
RSAKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// `fp_from_pub` calculates the fingerprint for a public key data object
|
||||||
|
pub(crate) fn gen_key_with_metadata(
|
||||||
|
card_app: &mut CardApp,
|
||||||
|
fp_from_pub: fn(&PublicKeyMaterial, SystemTime) -> Result<[u8; 20]>,
|
||||||
|
key_type: KeyType,
|
||||||
|
) -> Result<(), OpenpgpCardError> {
|
||||||
|
let pubkey = gen_key(card_app, key_type)?;
|
||||||
|
|
||||||
|
// set creation time
|
||||||
|
let time = SystemTime::now();
|
||||||
|
|
||||||
|
// Store creation timestamp (unix time format, limited to u32)
|
||||||
|
let ts = time
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.map_err(|e| OpenpgpCardError::InternalError(anyhow!(e)))?
|
||||||
|
.as_secs() as u32;
|
||||||
|
|
||||||
|
card_app.set_creation_time(ts, key_type)?.check_ok()?;
|
||||||
|
|
||||||
|
// calculate/store fingerprint
|
||||||
|
let fp = fp_from_pub(&pubkey, time)?;
|
||||||
|
let fp_cmd =
|
||||||
|
commands::put_data(&[key_type.get_fingerprint_put_tag()], fp.to_vec());
|
||||||
|
|
||||||
|
apdu::send_command(card_app.card(), fp_cmd, true)?.check_ok()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tlv_to_pubkey(tlv: &Tlv) -> Result<PublicKeyMaterial> {
|
||||||
|
let n = tlv.find(&Tag::new(vec![0x81]));
|
||||||
|
let v = tlv.find(&Tag::new(vec![0x82]));
|
||||||
|
|
||||||
|
let ec = tlv.find(&Tag::new(vec![0x86]));
|
||||||
|
|
||||||
|
match (n, v, ec) {
|
||||||
|
(Some(n), Some(v), None) => {
|
||||||
|
let rsa = RSAPub {
|
||||||
|
n: n.serialize(),
|
||||||
|
v: v.serialize(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(PublicKeyMaterial::R(rsa))
|
||||||
|
}
|
||||||
|
(None, None, Some(ec)) => {
|
||||||
|
let ec = ec.serialize();
|
||||||
|
|
||||||
|
// The public key for ECDSA/DH consists of of two raw
|
||||||
|
// big-endian integers with the same length as a field element
|
||||||
|
// each. In compliance with EN 419212 the format is 04 || x || y
|
||||||
|
// where the first byte (04) indicates an uncompressed raw format.
|
||||||
|
|
||||||
|
assert_eq!(ec[0], 0x4);
|
||||||
|
|
||||||
|
let len = ec.len();
|
||||||
|
assert_eq!(len % 2, 1); // odd number of bytes
|
||||||
|
|
||||||
|
// len 3 -> 4/2 = 2
|
||||||
|
let middle = (len + 1) / 2;
|
||||||
|
let x = ec[1..middle].to_vec();
|
||||||
|
let y = ec[middle..].to_vec();
|
||||||
|
|
||||||
|
let ecc = EccPub { x, y };
|
||||||
|
|
||||||
|
Ok(PublicKeyMaterial::E(ecc))
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, _, _) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn gen_key(
|
||||||
|
card_app: &mut CardApp,
|
||||||
|
key_type: KeyType,
|
||||||
|
) -> Result<PublicKeyMaterial, OpenpgpCardError> {
|
||||||
|
println!("gen key for {:?}", key_type);
|
||||||
|
|
||||||
|
// generate key
|
||||||
|
let crt = get_crt(key_type)?;
|
||||||
|
let gen_key_cmd = commands::gen_key(crt.serialize().to_vec());
|
||||||
|
|
||||||
|
let card_client = card_app.card();
|
||||||
|
|
||||||
|
let resp = apdu::send_command(card_client, gen_key_cmd, true)?;
|
||||||
|
resp.check_ok()?;
|
||||||
|
|
||||||
|
let tlv = Tlv::try_from(resp.data()?)?;
|
||||||
|
|
||||||
|
let pubkey = tlv_to_pubkey(&tlv)?;
|
||||||
|
|
||||||
|
println!("public {:x?}", pubkey);
|
||||||
|
|
||||||
|
Ok(pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
/// Upload an explicitly selected Key to the card as a specific KeyType.
|
/// Upload an explicitly selected Key to the card as a specific KeyType.
|
||||||
///
|
///
|
||||||
/// The client needs to make sure that the key is suitable for `key_type`.
|
/// The client needs to make sure that the key is suitable for `key_type`.
|
||||||
|
@ -87,7 +187,7 @@ pub(crate) fn upload_key(
|
||||||
};
|
};
|
||||||
|
|
||||||
copy_key_to_card(
|
copy_key_to_card(
|
||||||
card_app.card(),
|
card_app,
|
||||||
key_type,
|
key_type,
|
||||||
key.get_ts(),
|
key.get_ts(),
|
||||||
key.get_fp(),
|
key.get_fp(),
|
||||||
|
@ -385,28 +485,17 @@ fn ecc_algo_attrs_cmd(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_key_to_card(
|
fn copy_key_to_card(
|
||||||
card_client: &mut CardClientBox,
|
card_app: &mut CardApp,
|
||||||
key_type: KeyType,
|
key_type: KeyType,
|
||||||
ts: u64,
|
ts: u32,
|
||||||
fp: Vec<u8>,
|
fp: Vec<u8>,
|
||||||
algo_cmd: Command,
|
algo_cmd: Command,
|
||||||
key_cmd: Command,
|
key_cmd: Command,
|
||||||
) -> Result<(), OpenpgpCardError> {
|
) -> Result<(), OpenpgpCardError> {
|
||||||
let fp_cmd = commands::put_data(&[key_type.get_fingerprint_put_tag()], fp);
|
let fp_cmd = commands::put_data(&[key_type.get_fingerprint_put_tag()], fp);
|
||||||
|
|
||||||
// Timestamp update
|
|
||||||
let time_value: Vec<u8> = ts
|
|
||||||
.to_be_bytes()
|
|
||||||
.iter()
|
|
||||||
.skip_while(|&&e| e == 0)
|
|
||||||
.copied()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Generation date/time
|
|
||||||
let time_cmd =
|
|
||||||
commands::put_data(&[key_type.get_timestamp_put_tag()], time_value);
|
|
||||||
|
|
||||||
// Send all the commands
|
// Send all the commands
|
||||||
|
let card_client = card_app.card();
|
||||||
|
|
||||||
// FIXME: Only write algo attributes to the card if "extended
|
// FIXME: Only write algo attributes to the card if "extended
|
||||||
// capabilities" show that they are changeable!
|
// capabilities" show that they are changeable!
|
||||||
|
@ -414,7 +503,8 @@ fn copy_key_to_card(
|
||||||
|
|
||||||
apdu::send_command(card_client, key_cmd, false)?.check_ok()?;
|
apdu::send_command(card_client, key_cmd, false)?.check_ok()?;
|
||||||
apdu::send_command(card_client, fp_cmd, false)?.check_ok()?;
|
apdu::send_command(card_client, fp_cmd, false)?.check_ok()?;
|
||||||
apdu::send_command(card_client, time_cmd, false)?.check_ok()?;
|
|
||||||
|
card_app.set_creation_time(ts, key_type)?.check_ok()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ pub mod apdu;
|
||||||
mod card;
|
mod card;
|
||||||
pub mod card_app;
|
pub mod card_app;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
mod key_upload;
|
mod keys;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod tlv;
|
mod tlv;
|
||||||
|
|
||||||
|
@ -66,6 +66,16 @@ impl CardCaps {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An OpenPGP key generation Time
|
||||||
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
|
pub struct KeyGeneration(u32);
|
||||||
|
|
||||||
|
impl KeyGeneration {
|
||||||
|
pub fn get(&self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Container for a hash value.
|
/// Container for a hash value.
|
||||||
/// These hash values can be signed by the card.
|
/// These hash values can be signed by the card.
|
||||||
pub enum Hash<'a> {
|
pub enum Hash<'a> {
|
||||||
|
@ -111,12 +121,37 @@ pub trait CardUploadableKey {
|
||||||
fn get_key(&self) -> Result<PrivateKeyMaterial>;
|
fn get_key(&self) -> Result<PrivateKeyMaterial>;
|
||||||
|
|
||||||
/// timestamp of (sub)key creation
|
/// timestamp of (sub)key creation
|
||||||
fn get_ts(&self) -> u64;
|
fn get_ts(&self) -> u32;
|
||||||
|
|
||||||
/// fingerprint
|
/// fingerprint
|
||||||
fn get_fp(&self) -> Vec<u8>;
|
fn get_fp(&self) -> Vec<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Algorithm-independent container for public key material retrieved from
|
||||||
|
/// an OpenPGP card
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PublicKeyMaterial {
|
||||||
|
R(RSAPub),
|
||||||
|
E(EccPub),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RSA-specific container for public key material from an OpenPGP card.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RSAPub {
|
||||||
|
/// Modulus (a number denoted as n coded on x bytes)
|
||||||
|
pub n: Vec<u8>,
|
||||||
|
|
||||||
|
/// Public exponent (a number denoted as v, e.g. 65537 dec.)
|
||||||
|
pub v: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ECC-specific container for public key material from an OpenPGP card.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EccPub {
|
||||||
|
pub x: Vec<u8>,
|
||||||
|
pub y: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Algorithm-independent container for private key material to upload to
|
/// Algorithm-independent container for private key material to upload to
|
||||||
/// an OpenPGP card
|
/// an OpenPGP card
|
||||||
pub enum PrivateKeyMaterial {
|
pub enum PrivateKeyMaterial {
|
||||||
|
@ -678,7 +713,7 @@ impl CardAdmin {
|
||||||
) -> Result<(), OpenpgpCardError> {
|
) -> Result<(), OpenpgpCardError> {
|
||||||
let algo_list = self.list_supported_algo()?;
|
let algo_list = self.list_supported_algo()?;
|
||||||
|
|
||||||
key_upload::upload_key(&mut self.card_app, key, key_type, algo_list)
|
keys::upload_key(&mut self.card_app, key, key_type, algo_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,7 @@ use nom::{combinator, number::complete as number, sequence};
|
||||||
|
|
||||||
use crate::errors::OpenpgpCardError;
|
use crate::errors::OpenpgpCardError;
|
||||||
use crate::parse::KeySet;
|
use crate::parse::KeySet;
|
||||||
|
use crate::KeyGeneration;
|
||||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
|
||||||
pub struct KeyGeneration(u32);
|
|
||||||
|
|
||||||
impl From<KeyGeneration> for DateTime<Utc> {
|
impl From<KeyGeneration> for DateTime<Utc> {
|
||||||
fn from(kg: KeyGeneration) -> Self {
|
fn from(kg: KeyGeneration) -> Self {
|
||||||
|
|
Loading…
Reference in a new issue