// SPDX-FileCopyrightText: 2021 Heiko Schaefer // 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::policy::StandardPolicy; use sequoia_openpgp::Cert; use openpgp_card::card_do::Sex; use openpgp_card::{CardApp, KeyType}; use openpgp_card_pcsc::PcscClient; // use openpgp_card_scdc::ScdClient; use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::sq_util::{decryption_helper, sign_helper}; // 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> { 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 = Open::open_card(PcscClient::open_by_ident(&test_card_ident)?)?; println!(); // let mut oc = CardBase::open_card(ScdClient::open_by_serial( // None, // &test_card_serial, // )?)?; // card metadata println!("** get aid"); let app_id = oc.get_application_id()?; println!("app id: {:x?}", app_id); println!(); let eli = oc.get_extended_length_information()?; println!("extended_length_info: {:?}", eli); println!(); let hist = oc.get_historical()?; println!("{:#x?}", hist); println!(); let ext = oc.get_extended_capabilities()?; println!("{:#x?}", ext); println!(); let pws = oc.get_pw_status_bytes()?; println!("{:#x?}", pws); println!(); // cardholder let ch = oc.get_cardholder_related_data()?; println!("{:#x?}", ch); println!(); // crypto-ish metadata let fp = oc.get_fingerprints()?; println!("Fingerprint {:#x?}", fp); println!(); match oc.list_supported_algo() { Ok(Some(ai)) => println!("Algorithm information:\n{}", ai), Ok(None) => println!("No Algorithm information found"), Err(e) => println!("Error getting Algorithm information: {:?}", e), } let algo = oc.get_algorithm_attributes(KeyType::Signing)?; println!("Sig: {}", algo); let algo = oc.get_algorithm_attributes(KeyType::Decryption)?; println!("Dec: {}", algo); let algo = oc.get_algorithm_attributes(KeyType::Authentication)?; println!("Aut: {}", algo); println!(); // --------------------------------------------- // 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?}\n", check); println!("factory reset"); 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< panic!(), } // ----------------------------- // Open fresh Card for decrypt // ----------------------------- let mut oc = Open::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_application_id()?; // 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 sp = StandardPolicy::new(); let d = oc_user.decryptor(&cert, &sp)?; let res = decryption_helper(d, msg.into_bytes(), &sp)?; 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 = Open::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_sign) => { println!("pw1 81 verify ok"); let cert = Cert::from_file(TEST_KEY_PATH)?; let text = "Hello world, I am signed."; let signer = oc_sign.signer(&cert, &StandardPolicy::new())?; let res = sign_helper(signer, &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::cards()?; for c in cards { let mut ca = CardApp::from(c); let ard = ca.get_application_related_data()?; let app_id = ard.get_application_id()?; let ident = app_id.ident(); println!(" '{}'", ident); } } Ok(()) }