opgpcard: DRY make_cert().
This commit is contained in:
parent
1b483b5c09
commit
4557c40bda
1 changed files with 67 additions and 102 deletions
|
@ -6,13 +6,13 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
|
||||||
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;
|
||||||
|
use openpgp::packet::Signature;
|
||||||
use openpgp::packet::{
|
use openpgp::packet::{
|
||||||
key::{Key4, KeyRole, PrimaryRole, SecretParts, SubordinateRole},
|
key::{Key4, KeyRole, PrimaryRole, SecretParts, SubordinateRole},
|
||||||
signature::SignatureBuilder,
|
signature::SignatureBuilder,
|
||||||
|
@ -21,10 +21,11 @@ use openpgp::packet::{
|
||||||
use openpgp::parse::{stream::DecryptorBuilder, Parse};
|
use openpgp::parse::{stream::DecryptorBuilder, Parse};
|
||||||
use openpgp::policy::Policy;
|
use openpgp::policy::Policy;
|
||||||
use openpgp::serialize::stream::{Message, Signer};
|
use openpgp::serialize::stream::{Message, Signer};
|
||||||
use openpgp::types::{KeyFlags, PublicKeyAlgorithm, SignatureType, Timestamp};
|
use openpgp::types::{
|
||||||
|
HashAlgorithm, KeyFlags, PublicKeyAlgorithm, SignatureType, SymmetricAlgorithm, Timestamp,
|
||||||
|
};
|
||||||
use openpgp::{Cert, Packet};
|
use openpgp::{Cert, Packet};
|
||||||
use sequoia_openpgp as openpgp;
|
use sequoia_openpgp as openpgp;
|
||||||
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
|
|
||||||
|
|
||||||
use openpgp_card::algorithm::{Algo, Curve};
|
use openpgp_card::algorithm::{Algo, Curve};
|
||||||
use openpgp_card::card_do::{Fingerprint, KeyGenerationTime};
|
use openpgp_card::card_do::{Fingerprint, KeyGenerationTime};
|
||||||
|
@ -58,26 +59,39 @@ pub fn make_cert<'app>(
|
||||||
) -> Result<Cert> {
|
) -> Result<Cert> {
|
||||||
let mut pp = vec![];
|
let mut pp = vec![];
|
||||||
|
|
||||||
|
let cardholder = open.cardholder_related_data()?;
|
||||||
|
|
||||||
|
// helper: use the card to perform a signing operation
|
||||||
|
let mut sign_on_card =
|
||||||
|
|op: &mut dyn Fn(&mut dyn sequoia_openpgp::crypto::Signer) -> Result<Signature>| {
|
||||||
|
// Allow signing on the card
|
||||||
|
if let Some(pw1) = pw1 {
|
||||||
|
open.verify_user_for_signing(pw1)?;
|
||||||
|
} else {
|
||||||
|
open.verify_user_for_signing_pinpad(pinpad_prompt)?;
|
||||||
|
}
|
||||||
|
if let Some(mut sign) = open.signing_card() {
|
||||||
|
// Card-backed signer for bindings
|
||||||
|
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
||||||
|
|
||||||
|
// Make signature, return it
|
||||||
|
let s = op(&mut card_signer)?;
|
||||||
|
Ok(s)
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Failed to open card for signing"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 1) use the signing key as primary key
|
// 1) use the signing key as primary key
|
||||||
let pri = PrimaryRole::convert_key(key_sig.clone());
|
let pri = PrimaryRole::convert_key(key_sig.clone());
|
||||||
pp.push(Packet::from(pri));
|
pp.push(Packet::from(pri));
|
||||||
|
|
||||||
// 1a) add a direct key signature
|
// 1a) add a direct key signature
|
||||||
// Allow signing on the card
|
let s = sign_on_card(&mut |signer| {
|
||||||
if let Some(pw1) = pw1 {
|
SignatureBuilder::new(SignatureType::DirectKey)
|
||||||
open.verify_user_for_signing(pw1)?;
|
.sign_direct_key(signer, key_sig.role_as_primary())
|
||||||
} else {
|
})?;
|
||||||
open.verify_user_for_signing_pinpad(pinpad_prompt)?;
|
pp.push(s.into());
|
||||||
}
|
|
||||||
if let Some(mut sign) = open.signing_card() {
|
|
||||||
// Card-backed signer for bindings
|
|
||||||
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
|
||||||
|
|
||||||
let dks = SignatureBuilder::new(SignatureType::DirectKey)
|
|
||||||
.sign_direct_key(&mut card_signer, key_sig.role_as_primary())?;
|
|
||||||
|
|
||||||
pp.push(dks.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(key_dec) = key_dec {
|
if let Some(key_dec) = key_dec {
|
||||||
// 2) add decryption key as subkey
|
// 2) add decryption key as subkey
|
||||||
|
@ -88,33 +102,18 @@ pub fn make_cert<'app>(
|
||||||
let cert = Cert::try_from(pp.clone())?;
|
let cert = Cert::try_from(pp.clone())?;
|
||||||
|
|
||||||
// 3) make binding, sign with card -> add
|
// 3) make binding, sign with card -> add
|
||||||
{
|
let s = sign_on_card(&mut |signer| {
|
||||||
let signing_builder = SignatureBuilder::new(SignatureType::SubkeyBinding)
|
sub_dec.bind(
|
||||||
.set_signature_creation_time(SystemTime::now())?
|
signer,
|
||||||
.set_key_validity_period(std::time::Duration::new(0, 0))?
|
&cert,
|
||||||
.set_key_flags(
|
SignatureBuilder::new(SignatureType::SubkeyBinding).set_key_flags(
|
||||||
KeyFlags::empty()
|
KeyFlags::empty()
|
||||||
.set_storage_encryption()
|
.set_storage_encryption()
|
||||||
.set_transport_encryption(),
|
.set_transport_encryption(),
|
||||||
)?;
|
)?,
|
||||||
|
)
|
||||||
// Allow signing on the card
|
})?;
|
||||||
if let Some(pw1) = pw1 {
|
pp.push(s.into());
|
||||||
open.verify_user_for_signing(pw1)?;
|
|
||||||
} else {
|
|
||||||
open.verify_user_for_signing_pinpad(pinpad_prompt)?;
|
|
||||||
}
|
|
||||||
if let Some(mut sign) = open.signing_card() {
|
|
||||||
// Card-backed signer for bindings
|
|
||||||
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
|
||||||
|
|
||||||
let signing_bsig: Packet = sub_dec
|
|
||||||
.bind(&mut card_signer, &cert, signing_builder)?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
pp.push(signing_bsig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(key_aut) = key_aut {
|
if let Some(key_aut) = key_aut {
|
||||||
|
@ -122,77 +121,43 @@ pub fn make_cert<'app>(
|
||||||
let sub_aut = SubordinateRole::convert_key(key_aut);
|
let sub_aut = SubordinateRole::convert_key(key_aut);
|
||||||
pp.push(Packet::from(sub_aut.clone()));
|
pp.push(Packet::from(sub_aut.clone()));
|
||||||
|
|
||||||
|
// Temporary version of the cert
|
||||||
|
let cert = Cert::try_from(pp.clone())?;
|
||||||
|
|
||||||
// 5) make, sign binding -> add
|
// 5) make, sign binding -> add
|
||||||
{
|
let s = sign_on_card(&mut |signer| {
|
||||||
let signing_builder = SignatureBuilder::new(SignatureType::SubkeyBinding)
|
sub_aut.bind(
|
||||||
.set_signature_creation_time(SystemTime::now())?
|
signer,
|
||||||
.set_key_validity_period(std::time::Duration::new(0, 0))?
|
&cert,
|
||||||
.set_key_flags(KeyFlags::empty().set_authentication())?;
|
SignatureBuilder::new(SignatureType::SubkeyBinding)
|
||||||
|
.set_key_flags(KeyFlags::empty().set_authentication())?,
|
||||||
// Allow signing on the card
|
)
|
||||||
if let Some(pw1) = pw1 {
|
})?;
|
||||||
open.verify_user_for_signing(pw1)?;
|
pp.push(s.into());
|
||||||
} else {
|
|
||||||
open.verify_user_for_signing_pinpad(pinpad_prompt)?;
|
|
||||||
}
|
|
||||||
if let Some(mut sign) = open.signing_card() {
|
|
||||||
// Card-backed signer for bindings
|
|
||||||
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
|
||||||
|
|
||||||
// Temporary version of the cert
|
|
||||||
let cert = Cert::try_from(pp.clone())?;
|
|
||||||
|
|
||||||
let signing_bsig: Packet = sub_aut
|
|
||||||
.bind(&mut card_signer, &cert, signing_builder)?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
pp.push(signing_bsig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) add user id from cardholder name (if a name is set)
|
// 6) add user id from cardholder name (if a name is set on the card), plus any User IDs that
|
||||||
let cardholder = open.cardholder_related_data()?;
|
// were explicitly passed as a parameter.
|
||||||
|
|
||||||
for uid in user_ids
|
for uid in user_ids
|
||||||
.iter()
|
.iter()
|
||||||
.map(|uid| uid.as_bytes())
|
.map(|uid| uid.as_bytes())
|
||||||
.chain(cardholder.name())
|
.chain(cardholder.name())
|
||||||
{
|
{
|
||||||
let uid: UserID = uid.into();
|
let uid: UserID = uid.into();
|
||||||
|
|
||||||
pp.push(uid.clone().into());
|
pp.push(uid.clone().into());
|
||||||
|
|
||||||
|
// Temporary version of the cert
|
||||||
|
let cert = Cert::try_from(pp.clone())?;
|
||||||
|
|
||||||
// 7) make, sign binding -> add
|
// 7) make, sign binding -> add
|
||||||
{
|
let s = sign_on_card(&mut |signer| {
|
||||||
let signing_builder = SignatureBuilder::new(SignatureType::PositiveCertification)
|
uid.bind(
|
||||||
.set_signature_creation_time(SystemTime::now())?
|
signer,
|
||||||
.set_key_validity_period(std::time::Duration::new(0, 0))?
|
&cert,
|
||||||
.set_key_flags(
|
SignatureBuilder::new(SignatureType::PositiveCertification),
|
||||||
// Flags for primary key
|
)
|
||||||
KeyFlags::empty().set_signing().set_certification(),
|
})?;
|
||||||
)?;
|
pp.push(s.into());
|
||||||
|
|
||||||
// Allow signing on the card
|
|
||||||
if let Some(pw1) = pw1 {
|
|
||||||
open.verify_user_for_signing(pw1)?;
|
|
||||||
} else {
|
|
||||||
open.verify_user_for_signing_pinpad(pinpad_prompt)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mut sign) = open.signing_card() {
|
|
||||||
// Card-backed signer for bindings
|
|
||||||
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
|
||||||
|
|
||||||
// Temporary version of the cert
|
|
||||||
let cert = Cert::try_from(pp.clone())?;
|
|
||||||
|
|
||||||
let signing_bsig: Packet =
|
|
||||||
uid.bind(&mut card_signer, &cert, signing_builder)?.into();
|
|
||||||
|
|
||||||
pp.push(signing_bsig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cert::try_from(pp)
|
Cert::try_from(pp)
|
||||||
|
|
Loading…
Reference in a new issue