WIP: more testing in the context of on-card key generation.
In particular, add a decryption test.
This commit is contained in:
parent
6904551c7d
commit
a0370c5c53
7 changed files with 151 additions and 45 deletions
|
@ -46,15 +46,23 @@ fn main() -> Result<()> {
|
||||||
let upload_out = upload_res?;
|
let upload_out = upload_res?;
|
||||||
println!(" {:x?}", upload_out);
|
println!(" {:x?}", upload_out);
|
||||||
|
|
||||||
|
let key = std::fs::read_to_string(key)
|
||||||
|
.expect("Unable to read ciphertext");
|
||||||
|
|
||||||
// decrypt
|
// decrypt
|
||||||
print!(" Decrypt");
|
print!(" Decrypt");
|
||||||
let dec_out =
|
let msg = std::fs::read_to_string(ciphertext).expect(&format![
|
||||||
run_test(&mut card, test_decrypt, &[key, ciphertext])?;
|
"Unable to read ciphertext from file {}",
|
||||||
|
ciphertext
|
||||||
|
]);
|
||||||
|
|
||||||
|
let dec_out = run_test(&mut card, test_decrypt, &[&key, &msg])?;
|
||||||
println!(" {:x?}", dec_out);
|
println!(" {:x?}", dec_out);
|
||||||
|
|
||||||
// sign
|
// sign
|
||||||
print!(" Sign");
|
print!(" Sign");
|
||||||
let sign_out = run_test(&mut card, test_sign, &[key])?;
|
|
||||||
|
let sign_out = run_test(&mut card, test_sign, &[&key])?;
|
||||||
println!(" {:x?}", sign_out);
|
println!(" {:x?}", sign_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use card_functionality::cards::TestConfig;
|
use card_functionality::cards::TestConfig;
|
||||||
use card_functionality::tests::*;
|
use card_functionality::tests::*;
|
||||||
|
use card_functionality::util;
|
||||||
|
use sequoia_openpgp::Cert;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
@ -28,8 +31,8 @@ fn main() -> Result<()> {
|
||||||
println!("Reset");
|
println!("Reset");
|
||||||
let _ = run_test(&mut card, test_reset, &[])?;
|
let _ = run_test(&mut card, test_reset, &[])?;
|
||||||
|
|
||||||
// println!("Algo info");
|
println!("Algo info");
|
||||||
// let _ = run_test(&mut card, test_print_algo_info, &[])?;
|
let _ = run_test(&mut card, test_print_algo_info, &[])?;
|
||||||
|
|
||||||
// Set user data because keygen expects a name (for the user id)
|
// Set user data because keygen expects a name (for the user id)
|
||||||
println!("Set user data");
|
println!("Set user data");
|
||||||
|
@ -39,10 +42,22 @@ fn main() -> Result<()> {
|
||||||
let res = run_test(&mut card, test_keygen, &[])?;
|
let res = run_test(&mut card, test_keygen, &[])?;
|
||||||
|
|
||||||
if let TestResult::Text(cert) = &res[0] {
|
if let TestResult::Text(cert) = &res[0] {
|
||||||
println!("cert\n{}", cert);
|
// sign
|
||||||
};
|
print!(" Sign");
|
||||||
|
let sign_out = run_test(&mut card, test_sign, &[cert])?;
|
||||||
|
println!(" {:x?}", sign_out);
|
||||||
|
|
||||||
// panic!();
|
// decrypt
|
||||||
|
let c = Cert::from_str(cert)?;
|
||||||
|
let ciphertext = util::encrypt_to("Hello world!\n", &c)?;
|
||||||
|
|
||||||
|
print!(" Decrypt");
|
||||||
|
let dec_out =
|
||||||
|
run_test(&mut card, test_decrypt, &[cert, &ciphertext])?;
|
||||||
|
println!(" {:x?}", dec_out);
|
||||||
|
} else {
|
||||||
|
panic!("Didn't get back a Cert from test_keygen");
|
||||||
|
};
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
|
|
||||||
pub mod cards;
|
pub mod cards;
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
mod util;
|
pub mod util;
|
||||||
|
|
|
@ -4,12 +4,17 @@
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::string::FromUtf8Error;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use sequoia_openpgp::packet::key::{KeyRole, PrimaryRole, SubordinateRole};
|
||||||
|
use sequoia_openpgp::packet::signature::SignatureBuilder;
|
||||||
|
use sequoia_openpgp::packet::UserID;
|
||||||
use sequoia_openpgp::parse::Parse;
|
use sequoia_openpgp::parse::Parse;
|
||||||
use sequoia_openpgp::serialize::SerializeInto;
|
use sequoia_openpgp::serialize::SerializeInto;
|
||||||
use sequoia_openpgp::types::{SignatureType, Timestamp};
|
use sequoia_openpgp::types::{KeyFlags, SignatureType, Timestamp};
|
||||||
use sequoia_openpgp::{Cert, Packet};
|
use sequoia_openpgp::{Cert, Packet};
|
||||||
|
|
||||||
use openpgp_card::card_app::CardApp;
|
use openpgp_card::card_app::CardApp;
|
||||||
|
@ -17,14 +22,10 @@ use openpgp_card::errors::{OcErrorStatus, OpenpgpCardError};
|
||||||
use openpgp_card::{
|
use openpgp_card::{
|
||||||
Algo, Curve, EccAttrs, EccType, KeyType, PublicKeyMaterial, RsaAttrs, Sex,
|
Algo, Curve, EccAttrs, EccType, KeyType, PublicKeyMaterial, RsaAttrs, Sex,
|
||||||
};
|
};
|
||||||
|
use openpgp_card_sequoia::signer::CardSigner;
|
||||||
|
|
||||||
use crate::cards::TestCard;
|
use crate::cards::TestCard;
|
||||||
use crate::util;
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum TestResult {
|
pub enum TestResult {
|
||||||
|
@ -63,9 +64,8 @@ pub fn test_decrypt(
|
||||||
"test_decrypt needs filenames for 'cert' and 'encrypted'"
|
"test_decrypt needs filenames for 'cert' and 'encrypted'"
|
||||||
);
|
);
|
||||||
|
|
||||||
let cert = Cert::from_file(param[0])?;
|
let cert = Cert::from_str(param[0])?;
|
||||||
let msg =
|
let msg = param[1].to_string();
|
||||||
std::fs::read_to_string(param[1]).expect("Unable to read ciphertext");
|
|
||||||
|
|
||||||
let res = ca.verify_pw1("123456")?;
|
let res = ca.verify_pw1("123456")?;
|
||||||
res.check_ok()?;
|
res.check_ok()?;
|
||||||
|
@ -88,7 +88,7 @@ pub fn test_sign(
|
||||||
let res = ca.verify_pw1_for_signing("123456")?;
|
let res = ca.verify_pw1_for_signing("123456")?;
|
||||||
res.check_ok()?;
|
res.check_ok()?;
|
||||||
|
|
||||||
let cert = Cert::from_file(param[0])?;
|
let cert = Cert::from_str(param[0])?;
|
||||||
|
|
||||||
let msg = "Hello world, I am signed.";
|
let msg = "Hello world, I am signed.";
|
||||||
let sig = openpgp_card_sequoia::sign(&mut ca, &cert, &mut msg.as_bytes())?;
|
let sig = openpgp_card_sequoia::sign(&mut ca, &cert, &mut msg.as_bytes())?;
|
||||||
|
@ -219,6 +219,8 @@ pub fn test_keygen(
|
||||||
let verify = ca.verify_pw3("12345678")?;
|
let verify = ca.verify_pw3("12345678")?;
|
||||||
verify.check_ok()?;
|
verify.check_ok()?;
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
|
||||||
// RSA 1024, e=17
|
// RSA 1024, e=17
|
||||||
let rsa1k = Algo::Rsa(RsaAttrs {
|
let rsa1k = Algo::Rsa(RsaAttrs {
|
||||||
len_n: 1024,
|
len_n: 1024,
|
||||||
|
@ -227,12 +229,19 @@ pub fn test_keygen(
|
||||||
});
|
});
|
||||||
|
|
||||||
// RSA 2048, e=17
|
// RSA 2048, e=17
|
||||||
let rsa2k = Algo::Rsa(RsaAttrs {
|
let rsa2k_17 = Algo::Rsa(RsaAttrs {
|
||||||
len_n: 2048,
|
len_n: 2048,
|
||||||
len_e: 17,
|
len_e: 17,
|
||||||
import_format: 0,
|
import_format: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// RSA 2048, e=32
|
||||||
|
let rsa2k_32 = Algo::Rsa(RsaAttrs {
|
||||||
|
len_n: 2048,
|
||||||
|
len_e: 32,
|
||||||
|
import_format: 0,
|
||||||
|
});
|
||||||
|
|
||||||
// RSA 3072, e=17
|
// RSA 3072, e=17
|
||||||
let rsa3k = Algo::Rsa(RsaAttrs {
|
let rsa3k = Algo::Rsa(RsaAttrs {
|
||||||
len_n: 3072,
|
len_n: 3072,
|
||||||
|
@ -240,21 +249,28 @@ pub fn test_keygen(
|
||||||
import_format: 0,
|
import_format: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// RSA 4096, e=17
|
||||||
|
let rsa4k_17 = Algo::Rsa(RsaAttrs {
|
||||||
|
len_n: 4096,
|
||||||
|
len_e: 17,
|
||||||
|
import_format: 0,
|
||||||
|
});
|
||||||
|
|
||||||
// RSA 4096, e=32
|
// RSA 4096, e=32
|
||||||
let rsa4k = Algo::Rsa(RsaAttrs {
|
let rsa4k_32 = Algo::Rsa(RsaAttrs {
|
||||||
len_n: 4096,
|
len_n: 4096,
|
||||||
len_e: 32,
|
len_e: 32,
|
||||||
import_format: 0,
|
import_format: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ed25519 sign
|
// ed25519 (sign)
|
||||||
let ed25519 = Algo::Ecc(EccAttrs {
|
let ed25519 = Algo::Ecc(EccAttrs {
|
||||||
ecc_type: EccType::EdDSA,
|
ecc_type: EccType::EdDSA,
|
||||||
curve: Curve::Ed25519,
|
curve: Curve::Ed25519,
|
||||||
import_format: None,
|
import_format: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// cv25519 dec
|
// cv25519 (dec)
|
||||||
let cv25519 = Algo::Ecc(EccAttrs {
|
let cv25519 = Algo::Ecc(EccAttrs {
|
||||||
ecc_type: EccType::ECDH,
|
ecc_type: EccType::ECDH,
|
||||||
curve: Curve::Cv25519,
|
curve: Curve::Cv25519,
|
||||||
|
@ -275,8 +291,33 @@ pub fn test_keygen(
|
||||||
import_format: None,
|
import_format: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let fp =
|
// ---------------
|
||||||
|pkm: &PublicKeyMaterial, ts: SystemTime, kt: KeyType, algo: &Algo| {
|
|
||||||
|
// -- RSA (e=17) [YK4, YK5]
|
||||||
|
// let dec_algo = &rsa2k_17;
|
||||||
|
// let sig_algo = &rsa2k_17;
|
||||||
|
|
||||||
|
// let dec_algo = &rsa4k_17;
|
||||||
|
// let sig_algo = &rsa4k_17;
|
||||||
|
|
||||||
|
// -- RSA (e=32) [YK5, Floss3.4, Gnuk1.2]
|
||||||
|
// let dec_algo = &rsa2k_32;
|
||||||
|
// let sig_algo = &rsa2k_32;
|
||||||
|
|
||||||
|
let dec_algo = &rsa4k_32;
|
||||||
|
let sig_algo = &rsa4k_32;
|
||||||
|
|
||||||
|
// -- NIST 256
|
||||||
|
// let dec_algo = &nist256_ecdh;
|
||||||
|
// let sig_algo = &nist256_ecdsa;
|
||||||
|
|
||||||
|
// -- Curve 25519
|
||||||
|
// let dec_algo = &cv25519;
|
||||||
|
// let sig_algo = &ed25519;
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
|
||||||
|
let fp = |pkm: &PublicKeyMaterial, ts: SystemTime, kt: KeyType| {
|
||||||
// FIXME: store creation timestamp
|
// FIXME: store creation timestamp
|
||||||
|
|
||||||
let key =
|
let key =
|
||||||
|
@ -291,8 +332,7 @@ pub fn test_keygen(
|
||||||
|
|
||||||
// ------
|
// ------
|
||||||
|
|
||||||
let (pkm, ts) =
|
let (pkm, ts) = ca.generate_key(fp, KeyType::Signing, Some(sig_algo))?;
|
||||||
ca.generate_key(fp, KeyType::Signing, Some(&nist256_ecdsa))?;
|
|
||||||
let key_sig = openpgp_card_sequoia::public_key_material_to_key(
|
let key_sig = openpgp_card_sequoia::public_key_material_to_key(
|
||||||
&pkm,
|
&pkm,
|
||||||
KeyType::Signing,
|
KeyType::Signing,
|
||||||
|
@ -302,7 +342,7 @@ pub fn test_keygen(
|
||||||
// ------
|
// ------
|
||||||
|
|
||||||
let (pkm, ts) =
|
let (pkm, ts) =
|
||||||
ca.generate_key(fp, KeyType::Decryption, Some(&nist256_ecdh))?;
|
ca.generate_key(fp, KeyType::Decryption, Some(dec_algo))?;
|
||||||
let key_dec = openpgp_card_sequoia::public_key_material_to_key(
|
let key_dec = openpgp_card_sequoia::public_key_material_to_key(
|
||||||
&pkm,
|
&pkm,
|
||||||
KeyType::Decryption,
|
KeyType::Decryption,
|
||||||
|
@ -312,7 +352,7 @@ pub fn test_keygen(
|
||||||
// ------
|
// ------
|
||||||
|
|
||||||
let (pkm, ts) =
|
let (pkm, ts) =
|
||||||
ca.generate_key(fp, KeyType::Authentication, Some(&nist256_ecdsa))?;
|
ca.generate_key(fp, KeyType::Authentication, Some(sig_algo))?;
|
||||||
let key_aut = openpgp_card_sequoia::public_key_material_to_key(
|
let key_aut = openpgp_card_sequoia::public_key_material_to_key(
|
||||||
&pkm,
|
&pkm,
|
||||||
KeyType::Authentication,
|
KeyType::Authentication,
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use std::io::Write;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use sequoia_openpgp as openpgp;
|
|
||||||
use sequoia_openpgp::cert::amalgamation::key::ValidKeyAmalgamation;
|
use sequoia_openpgp::cert::amalgamation::key::ValidKeyAmalgamation;
|
||||||
use sequoia_openpgp::packet::key::{SecretParts, UnspecifiedRole};
|
use sequoia_openpgp::packet::key::{SecretParts, UnspecifiedRole};
|
||||||
use sequoia_openpgp::parse::stream::{
|
use sequoia_openpgp::parse::stream::{
|
||||||
|
@ -13,6 +13,9 @@ use sequoia_openpgp::parse::stream::{
|
||||||
};
|
};
|
||||||
use sequoia_openpgp::parse::Parse;
|
use sequoia_openpgp::parse::Parse;
|
||||||
use sequoia_openpgp::policy::StandardPolicy;
|
use sequoia_openpgp::policy::StandardPolicy;
|
||||||
|
use sequoia_openpgp::serialize::stream::{
|
||||||
|
Armorer, Encryptor, LiteralWriter, Message,
|
||||||
|
};
|
||||||
use sequoia_openpgp::Cert;
|
use sequoia_openpgp::Cert;
|
||||||
|
|
||||||
use openpgp_card::card_app::CardApp;
|
use openpgp_card::card_app::CardApp;
|
||||||
|
@ -94,20 +97,23 @@ impl<'a> VHelper<'a> {
|
||||||
impl<'a> VerificationHelper for VHelper<'a> {
|
impl<'a> VerificationHelper for VHelper<'a> {
|
||||||
fn get_certs(
|
fn get_certs(
|
||||||
&mut self,
|
&mut self,
|
||||||
_ids: &[openpgp::KeyHandle],
|
_ids: &[sequoia_openpgp::KeyHandle],
|
||||||
) -> openpgp::Result<Vec<openpgp::Cert>> {
|
) -> sequoia_openpgp::Result<Vec<Cert>> {
|
||||||
// Hand out our single Cert
|
// Hand out our single Cert
|
||||||
Ok(vec![self.cert.clone()])
|
Ok(vec![self.cert.clone()])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(&mut self, structure: MessageStructure) -> openpgp::Result<()> {
|
fn check(
|
||||||
|
&mut self,
|
||||||
|
structure: MessageStructure,
|
||||||
|
) -> sequoia_openpgp::Result<()> {
|
||||||
// We are interested in signatures over the data (level 0 signatures)
|
// We are interested in signatures over the data (level 0 signatures)
|
||||||
if let Some(MessageLayer::SignatureGroup { results }) =
|
if let Some(MessageLayer::SignatureGroup { results }) =
|
||||||
structure.into_iter().next()
|
structure.into_iter().next()
|
||||||
{
|
{
|
||||||
match results.into_iter().next() {
|
match results.into_iter().next() {
|
||||||
Some(Ok(_)) => Ok(()), // Good signature.
|
Some(Ok(_)) => Ok(()), // Good signature.
|
||||||
Some(Err(e)) => Err(openpgp::Error::from(e).into()),
|
Some(Err(e)) => Err(sequoia_openpgp::Error::from(e).into()),
|
||||||
None => Err(anyhow::anyhow!("No signature")),
|
None => Err(anyhow::anyhow!("No signature")),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -123,3 +129,42 @@ pub fn verify_sig(cert: &Cert, msg: &[u8], sig: &[u8]) -> Result<bool> {
|
||||||
|
|
||||||
Ok(dv.verify_bytes(msg).is_ok())
|
Ok(dv.verify_bytes(msg).is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encrypt_to(cleartext: &str, cert: &Cert) -> Result<String> {
|
||||||
|
let p = &StandardPolicy::new();
|
||||||
|
|
||||||
|
let mut recipients = Vec::new();
|
||||||
|
|
||||||
|
// Make sure we add at least one subkey from every
|
||||||
|
// certificate.
|
||||||
|
let mut found_one = false;
|
||||||
|
for key in cert
|
||||||
|
.keys()
|
||||||
|
.with_policy(p, None)
|
||||||
|
.supported()
|
||||||
|
.alive()
|
||||||
|
.revoked(false)
|
||||||
|
.for_transport_encryption()
|
||||||
|
{
|
||||||
|
recipients.push(key);
|
||||||
|
found_one = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found_one {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"No suitable encryption subkey for {}",
|
||||||
|
cert
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sink = vec![];
|
||||||
|
|
||||||
|
let message = Message::new(&mut sink);
|
||||||
|
let message = Armorer::new(message).build()?;
|
||||||
|
let message = Encryptor::for_recipients(message, recipients).build()?;
|
||||||
|
let mut w = LiteralWriter::new(message).build()?;
|
||||||
|
w.write_all(cleartext.as_bytes())?;
|
||||||
|
w.finalize()?;
|
||||||
|
|
||||||
|
Ok(String::from_utf8(sink).unwrap())
|
||||||
|
}
|
||||||
|
|
|
@ -643,7 +643,6 @@ impl CardApp {
|
||||||
&PublicKeyMaterial,
|
&PublicKeyMaterial,
|
||||||
SystemTime,
|
SystemTime,
|
||||||
KeyType,
|
KeyType,
|
||||||
&Algo,
|
|
||||||
) -> Result<[u8; 20]>,
|
) -> Result<[u8; 20]>,
|
||||||
key_type: KeyType,
|
key_type: KeyType,
|
||||||
algo: Option<&Algo>,
|
algo: Option<&Algo>,
|
||||||
|
|
|
@ -26,7 +26,6 @@ pub(crate) fn gen_key_with_metadata(
|
||||||
&PublicKeyMaterial,
|
&PublicKeyMaterial,
|
||||||
SystemTime,
|
SystemTime,
|
||||||
KeyType,
|
KeyType,
|
||||||
&Algo,
|
|
||||||
) -> Result<[u8; 20]>,
|
) -> Result<[u8; 20]>,
|
||||||
key_type: KeyType,
|
key_type: KeyType,
|
||||||
algo: Option<&Algo>,
|
algo: Option<&Algo>,
|
||||||
|
@ -62,7 +61,7 @@ pub(crate) fn gen_key_with_metadata(
|
||||||
card_app.set_creation_time(ts, key_type)?.check_ok()?;
|
card_app.set_creation_time(ts, key_type)?.check_ok()?;
|
||||||
|
|
||||||
// calculate/store fingerprint
|
// calculate/store fingerprint
|
||||||
let fp = fp_from_pub(&pubkey, time, key_type, &algo)?;
|
let fp = fp_from_pub(&pubkey, time, key_type)?;
|
||||||
card_app.set_fingerprint(fp, key_type)?.check_ok()?;
|
card_app.set_fingerprint(fp, key_type)?.check_ok()?;
|
||||||
|
|
||||||
Ok((pubkey, ts))
|
Ok((pubkey, ts))
|
||||||
|
|
Loading…
Reference in a new issue