From ca5dd610014dda5a866972843a058aca4a763690 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Wed, 11 Aug 2021 14:33:20 +0200 Subject: [PATCH] Assemble information from the card into a Cert. Still a WIP (this code serves in part to explore handling of Certs for cards). --- card-functionality/src/keygen.rs | 10 ++- card-functionality/src/tests.rs | 119 ++++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 12 deletions(-) diff --git a/card-functionality/src/keygen.rs b/card-functionality/src/keygen.rs index 88fa1fd..18a8544 100644 --- a/card-functionality/src/keygen.rs +++ b/card-functionality/src/keygen.rs @@ -31,8 +31,16 @@ fn main() -> Result<()> { // println!("Algo info"); // let _ = run_test(&mut card, test_print_algo_info, &[])?; + // Set user data because keygen expects a name (for the user id) + println!("Set user data"); + let _ = run_test(&mut card, test_set_user_data, &[])?; + println!("Generate key"); - let _ = run_test(&mut card, test_keygen, &[])?; + let res = run_test(&mut card, test_keygen, &[])?; + + if let TestResult::Text(cert) = &res[0] { + println!("cert\n{}", cert); + }; // panic!(); diff --git a/card-functionality/src/tests.rs b/card-functionality/src/tests.rs index 57aa0ae..dba8ae5 100644 --- a/card-functionality/src/tests.rs +++ b/card-functionality/src/tests.rs @@ -2,13 +2,15 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use anyhow::{Error, Result}; +use std::convert::TryFrom; use std::convert::TryInto; use std::time::SystemTime; use thiserror::Error; use sequoia_openpgp::parse::Parse; -use sequoia_openpgp::types::Timestamp; -use sequoia_openpgp::Cert; +use sequoia_openpgp::serialize::SerializeInto; +use sequoia_openpgp::types::{SignatureType, Timestamp}; +use sequoia_openpgp::{Cert, Packet}; use openpgp_card::card_app::CardApp; use openpgp_card::errors::{OcErrorStatus, OpenpgpCardError}; @@ -16,8 +18,13 @@ use openpgp_card::{ Algo, Curve, EccAttrs, EccType, KeyType, PublicKeyMaterial, RsaAttrs, Sex, }; -use crate::cards::{TestCard, TestConfig}; +use crate::cards::TestCard; use crate::util; +use openpgp_card_sequoia::signer::CardSigner; +use sequoia_openpgp::packet::key::{KeyRole, PrimaryRole, SubordinateRole}; +use sequoia_openpgp::packet::signature::SignatureBuilder; +use sequoia_openpgp::packet::UserID; +use std::string::FromUtf8Error; #[derive(Debug)] pub enum TestResult { @@ -40,6 +47,9 @@ pub enum TestError { #[error(transparent)] Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error + + #[error(transparent)] + Utf8Error(#[from] FromUtf8Error), } /// Run after each "upload keys", if key *was* uploaded (?) @@ -289,8 +299,6 @@ pub fn test_keygen( SystemTime::from(Timestamp::from(ts)), )?; - println!("key sig: {:?}", key_sig); - // ------ let (pkm, ts) = @@ -301,8 +309,6 @@ pub fn test_keygen( SystemTime::from(Timestamp::from(ts)), )?; - println!("key dec: {:?}", key_dec); - // ------ let (pkm, ts) = @@ -313,13 +319,104 @@ pub fn test_keygen( SystemTime::from(Timestamp::from(ts)), )?; - println!("key auth: {:?}", key_aut); - // ---- make cert - unimplemented!("return Cert as text"); + let mut pp = vec![]; - Ok(vec![]) + // 1) use the signing key as primary key + let pri = PrimaryRole::convert_key(key_sig.clone()); + pp.push(Packet::from(pri)); + + // 2) add decryption key as subkey + let sub_dec = SubordinateRole::convert_key(key_dec); + pp.push(Packet::from(sub_dec.clone())); + + // Temporary version of the cert + let cert = Cert::try_from(pp.clone())?; + + // 3) make binding, sign with card -> add + { + let signing_builder = + SignatureBuilder::new(SignatureType::SubkeyBinding) + .set_signature_creation_time(SystemTime::now())? + .set_key_validity_period(std::time::Duration::new(0, 0))?; + + // Allow signing on the card + let res = ca.verify_pw1_for_signing("123456")?; + res.check_ok()?; + + // Card-backed signer for bindings + let mut card_signer = CardSigner::with_pubkey(ca, key_sig.clone()); + + let signing_bsig: Packet = sub_dec + .bind(&mut card_signer, &cert, signing_builder)? + .into(); + + pp.push(signing_bsig); + } + + // 4) add auth subkey + let sub_aut = SubordinateRole::convert_key(key_aut); + pp.push(Packet::from(sub_aut.clone())); + + // 5) make, sign binding -> add + { + let signing_builder = + SignatureBuilder::new(SignatureType::SubkeyBinding) + .set_signature_creation_time(SystemTime::now())? + .set_key_validity_period(std::time::Duration::new(0, 0))?; + + // Allow signing on the card + let res = ca.verify_pw1_for_signing("123456")?; + res.check_ok()?; + + // Card-backed signer for bindings + let mut card_signer = CardSigner::with_pubkey(ca, key_sig.clone()); + + let signing_bsig: Packet = sub_aut + .bind(&mut card_signer, &cert, signing_builder)? + .into(); + + pp.push(signing_bsig); + } + + // 6) add user id from name / email + let cardholder = ca.get_cardholder_related_data()?; + + // FIXME: process name field? accept email as argument?! + let uid: UserID = cardholder.name.expect("expecting name on card").into(); + + pp.push(uid.clone().into()); + + // 7) make, sign binding -> add + { + let signing_builder = + SignatureBuilder::new(SignatureType::PositiveCertification) + .set_signature_creation_time(SystemTime::now())? + .set_key_validity_period(std::time::Duration::new(0, 0))?; + + // Allow signing on the card + let res = ca.verify_pw1_for_signing("123456")?; + res.check_ok()?; + + // Card-backed signer for bindings + let mut card_signer = CardSigner::with_pubkey(ca, key_sig); + + let signing_bsig: Packet = + uid.bind(&mut card_signer, &cert, signing_builder)?.into(); + + pp.push(signing_bsig); + } + + // -- process resulting Vec as a Cert + + let cert = Cert::try_from(pp)?; + + let armored = String::from_utf8(cert.armored().to_vec()?)?; + + let res = TestResult::Text(armored); + + Ok(vec![res]) } /// Construct public key based on data from the card