openpgp-card/openpgp-card-sequoia/src/main.rs
2021-08-18 19:57:54 +02:00

256 lines
7.9 KiB
Rust

// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
// SPDX-License-Identifier: MIT OR Apache-2.0
use anyhow::Result;
use std::env;
use std::error::Error;
use sequoia_openpgp::parse::Parse;
use sequoia_openpgp::Cert;
use openpgp_card::card_app::CardApp;
use openpgp_card::KeyType;
use openpgp_card_pcsc::PcscClient;
// use openpgp_card_scdc::ScdClient;
use openpgp_card_sequoia::CardBase;
// Filename of test key and test message to use:
const TEST_KEY_PATH: &str = "example/test4k.sec";
const TEST_ENC_MSG: &str = "example/encrypted_to_rsa4k.asc";
// const TEST_KEY_PATH: &str = "example/nist521.sec";
// const TEST_ENC_MSG: &str = "example/encrypted_to_nist521.asc";
// const TEST_KEY_PATH: &str = "example/test25519.sec";
// const TEST_ENC_MSG: &str = "example/encrypted_to_25519.asc";
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
// Ident of the OpenPGP Card that will be used for tests.
let test_card_ident = env::var("TEST_CARD_IDENT");
// // "serial" for opening a specific card through scdaemon
// let test_card_serial = env::var("TEST_CARD_SERIAL")?;
if let Ok(test_card_ident) = test_card_ident {
println!("** get card");
let mut oc =
CardBase::open_card(PcscClient::open_by_ident(&test_card_ident)?)?;
// let mut oc = CardBase::open_card(ScdClient::open_by_serial(
// None,
// &test_card_serial,
// )?)?;
// card metadata
println!("** get aid");
let app_id = oc.get_aid()?;
println!("app id: {:x?}\n\n", app_id);
println!(" ident: {:?}\n\n", app_id.ident());
let eli = oc.get_extended_length_information()?;
println!("extended_length_info: {:?}\n\n", eli);
let hist = oc.get_historical()?;
println!("historical {:#x?}", hist);
let ext = oc.get_extended_capabilities()?;
println!("extended_capabilities {:#x?}", ext);
let pws = oc.get_pw_status_bytes()?;
println!("PW Status Bytes {:#x?}", pws);
// cardholder
let ch = oc.get_cardholder_related_data()?;
println!("card holder {:x?}", ch);
// crypto-ish metadata
let fp = oc.get_fingerprints()?;
println!("fp {:#x?}", fp);
let sst = oc.get_security_support_template()?;
println!("sst {:x?}", sst);
let ai = oc.list_supported_algo()?;
println!("ai {:#?}", ai);
let algo = oc.get_algorithm_attributes(KeyType::Signing)?;
println!("algo sig {:?}", algo);
let algo = oc.get_algorithm_attributes(KeyType::Decryption)?;
println!("algo dec {:?}", algo);
let algo = oc.get_algorithm_attributes(KeyType::Authentication)?;
println!("algo aut {:?}", algo);
// ---------------------------------------------
// CAUTION: Write commands ahead!
// Try not to overwrite your production cards.
// ---------------------------------------------
assert_eq!(app_id.ident(), test_card_ident);
let check = oc.check_pw3();
println!("has pw3 been verified yet? {:x?}", check);
oc.factory_reset()?;
match oc.verify_pw3("12345678") {
Ok(mut oc_admin) => {
println!("pw3 verify ok");
let check = oc_admin.check_pw3();
println!("has pw3 been verified yet? {:x?}", check);
let res = oc_admin.set_name("Bar<<Foo")?;
println!("set name {:x?}", res);
res.check_ok()?;
let res =
oc_admin.set_sex(openpgp_card::Sex::NotApplicable)?;
println!("set sex {:x?}", res);
res.check_ok()?;
let res = oc_admin.set_lang("en")?;
println!("set lang {:x?}", res);
res.check_ok()?;
let res = oc_admin.set_url("https://keys.openpgp.org")?;
println!("set url {:x?}", res);
res.check_ok()?;
let cert = Cert::from_file(TEST_KEY_PATH)?;
openpgp_card_sequoia::upload_from_cert_yolo(
&mut oc_admin,
&cert,
KeyType::Decryption,
None,
)?;
openpgp_card_sequoia::upload_from_cert_yolo(
&mut oc_admin,
&cert,
KeyType::Signing,
None,
)?;
// TODO: test keys currently have no auth-capable key
// openpgp_card_sequoia::upload_from_cert(
// &oc_admin,
// &cert,
// KeyType::Authentication,
// None,
// )?;
}
_ => panic!(),
}
// -----------------------------
// Open fresh Card for decrypt
// -----------------------------
let mut oc =
CardBase::open_card(PcscClient::open_by_ident(&test_card_ident)?)?;
// let mut oc = CardBase::open_card(ScdClient::open_by_serial(
// None,
// &test_card_serial,
// )?)?;
let app_id = oc.get_aid()?;
// Check that we're still using the expected card
assert_eq!(app_id.ident(), test_card_ident);
let check = oc.check_pw1();
println!("has pw1/82 been verified yet? {:x?}", check);
match oc.verify_pw1("123456") {
Ok(mut oc_user) => {
println!("pw1 82 verify ok");
let check = oc_user.check_pw1();
println!("has pw1/82 been verified yet? {:x?}", check);
let cert = Cert::from_file(TEST_KEY_PATH)?;
let msg = std::fs::read_to_string(TEST_ENC_MSG)
.expect("Unable to read file");
println!("{:?}", msg);
let res = openpgp_card_sequoia::decrypt(
&mut oc_user.get_card_app(),
&cert,
msg.into_bytes(),
)?;
let plain = String::from_utf8_lossy(&res);
println!("decrypted plaintext: {}", plain);
assert_eq!(plain, "Hello world!\n");
}
_ => panic!("verify pw1 failed"),
}
// -----------------------------
// Open fresh Card for signing
// -----------------------------
let oc =
CardBase::open_card(PcscClient::open_by_ident(&test_card_ident)?)?;
// let oc = CardBase::open_card(ScdClient::open_by_serial(
// None,
// &test_card_serial,
// )?)?;
// Sign
match oc.verify_pw1_for_signing("123456") {
Ok(mut oc_user) => {
println!("pw1 81 verify ok");
let cert = Cert::from_file(TEST_KEY_PATH)?;
let text = "Hello world, I am signed.";
let res = openpgp_card_sequoia::sign(
oc_user.get_card_app(),
&cert,
&mut text.as_bytes(),
);
println!("res sign {:?}", res);
println!("res: {}", res?)
// FIXME: validate sig
}
_ => panic!("verify pw1 failed"),
}
} else {
println!("Please set environment variable TEST_CARD_IDENT.");
println!();
println!("NOTE: the configured card will get overwritten!");
println!("So do NOT use your production card for testing.");
println!();
println!("The following OpenPGP cards are connected to your system:");
let cards = PcscClient::list_cards()?;
for c in cards {
let mut ca = CardApp::new(c);
let ard = ca.get_app_data()?;
let app_id = CardApp::get_aid(&ard)?;
let ident = app_id.ident();
println!(" '{}'", ident);
}
}
Ok(())
}