// SPDX-FileCopyrightText: 2021-2023 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 use std::env; use std::error::Error; use anyhow::Result; use card_backend_pcsc::PcscBackend; use openpgp_card::card_do::Sex; use openpgp_card::KeyType; use openpgp_card_sequoia::sq_util; use openpgp_card_sequoia::{state::Open, Card}; use sequoia_openpgp::parse::Parse; use sequoia_openpgp::policy::StandardPolicy; use sequoia_openpgp::Cert; // 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_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 an OpenPGP card to use for these tests let test_card_ident = env::var("TEST_CARD_IDENT"); if let Ok(test_card_ident) = test_card_ident { let cards = PcscBackend::card_backends(None)?; let mut card = Card::::open_by_ident(cards, &test_card_ident)?; { let mut transaction = card.transaction()?; // card metadata let app_id = transaction.application_identifier()?; println!("{app_id:x?}\n"); let eli = transaction.extended_length_information()?; println!("extended_length_info: {eli:?}\n"); let hist = transaction.historical_bytes()?; println!("{hist:#x?}\n"); let ext = transaction.extended_capabilities()?; println!("{ext:#x?}\n"); let pws = transaction.pw_status_bytes()?; println!("{pws:#x?}\n"); // cardholder let ch = transaction.cardholder_related_data()?; println!("{ch:#x?}\n"); // crypto-ish metadata let fp = transaction.fingerprints()?; println!("Fingerprint {fp:#x?}\n"); match transaction.algorithm_information() { Ok(Some(ai)) => println!("Algorithm information:\n{ai}"), Ok(None) => println!("No Algorithm information found"), Err(e) => println!("Error getting Algorithm information: {e:?}"), } println!("Current algorithm attributes on card:"); let algo = transaction.algorithm_attributes(KeyType::Signing)?; println!("Sig: {algo}"); let algo = transaction.algorithm_attributes(KeyType::Decryption)?; println!("Dec: {algo}"); let algo = transaction.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.to_ascii_uppercase()); let check = transaction.check_admin_verified(); println!("has admin (pw3) been verified yet?\n{check:x?}\n"); println!("factory reset\n"); transaction.factory_reset()?; transaction.verify_admin_pin("12345678")?; println!("verify for admin ok"); let check = transaction.check_user_verified(); println!("has user (pw1/82) been verified yet? {check:x?}"); // Use Admin access to card let mut admin = transaction.to_admin_card(None).expect("just verified"); println!(); admin.set_cardholder_name("Bar<::open_by_ident(cards, &test_card_ident)?; { let mut transaction = card.transaction()?; // Check that we're still using the expected card let app_id = transaction.application_identifier()?; assert_eq!(app_id.ident(), test_card_ident.to_ascii_uppercase()); let check = transaction.check_user_verified(); println!("has user (pw1/82) been verified yet?\n{check:x?}\n"); transaction.verify_user_pin("123456")?; println!("verify for user (pw1/82) ok"); let check = transaction.check_user_verified(); println!("has user (pw1/82) been verified yet?\n{check:x?}\n"); // Use User access to card let mut user = transaction .to_user_card(None) .expect("We just validated, this should not fail"); let _cert = Cert::from_file(TEST_KEY_PATH)?; let msg = std::fs::read_to_string(TEST_ENC_MSG).expect("Unable to read file"); println!("Encrypted message:\n{msg}"); let sp = StandardPolicy::new(); let d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?; let res = sq_util::decryption_helper(d, msg.into_bytes(), &sp)?; let plain = String::from_utf8_lossy(&res); println!("Decrypted plaintext: {plain}"); assert_eq!(plain, "Hello world!\n"); } // ----------------------------- // Open fresh Card for signing // ----------------------------- let cards = PcscBackend::card_backends(None)?; let mut card = Card::::open_by_ident(cards, &test_card_ident)?; let mut transaction = card.transaction()?; // Sign transaction.verify_user_signing_pin("123456")?; println!("verify for sign (pw1/81) ok\n"); // Use Sign access to card let mut sign = transaction.to_signing_card(None).expect("just verified"); let _cert = Cert::from_file(TEST_KEY_PATH)?; let text = "Hello world, I am signed."; let signer = sign.signer(&|| {})?; let sig = sq_util::sign_helper(signer, &mut text.as_bytes())?; println!("Signature from card:\n{sig}") // FIXME: validate sig } 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:"); for backend in PcscBackend::cards(None)? { let mut card: Card = Card::::new(backend?)?; let open = card.transaction()?; println!(" {}", open.application_identifier()?.ident()); } } Ok(()) }