diff --git a/openpgp-card-sequoia/src/lib.rs b/openpgp-card-sequoia/src/lib.rs index e23c5db..55c5126 100644 --- a/openpgp-card-sequoia/src/lib.rs +++ b/openpgp-card-sequoia/src/lib.rs @@ -32,7 +32,7 @@ use openpgp_card::{ use sequoia_openpgp::types::PublicKeyAlgorithm; mod decryptor; -mod signer; +pub mod signer; /// Shorthand for public key data pub(crate) type PublicKey = Key; @@ -88,6 +88,15 @@ pub fn public_key_material_to_key( PublicKeyMaterial::E(ecc) => { let algo = ecc.algo.clone(); // FIXME? if let Algo::Ecc(algo_ecc) = algo { + let curve = match algo_ecc.curve { + Curve::NistP256r1 => openpgp::types::Curve::NistP256, + Curve::NistP384r1 => openpgp::types::Curve::NistP384, + Curve::NistP521r1 => openpgp::types::Curve::NistP521, + Curve::Ed25519 => openpgp::types::Curve::Ed25519, + Curve::Cv25519 => openpgp::types::Curve::Cv25519, + c => unimplemented!("unhandled curve: {:?}", c), + }; + match key_type { KeyType::Authentication | KeyType::Signing => { if algo_ecc.curve == Curve::Ed25519 { @@ -102,41 +111,12 @@ pub fn public_key_material_to_key( Ok(Key::from(k4)) } else { // ECDSA - - // The public key for ECDSA/DH consists of of two raw - // big-endian integers with the same length as a field element - // each. In compliance with EN 419212 the format is 04 || x || y - // where the first byte (04) indicates an uncompressed raw format. - - let ec = &ecc.data; - - assert_eq!(ec[0], 0x4); - - let len = ec.len(); - assert_eq!(len % 2, 1); // odd number of bytes - - // --- - - let curve = match algo_ecc.curve { - Curve::NistP256r1 => { - openpgp::types::Curve::NistP256 - } - Curve::NistP384r1 => { - openpgp::types::Curve::NistP384 - } - Curve::NistP521r1 => { - openpgp::types::Curve::NistP521 - } - _ => unimplemented!(), - }; - - // NIST let k4 = Key4::new( time, PublicKeyAlgorithm::ECDSA, mpi::PublicKey::ECDSA { curve, - q: mpi::MPI::new(&ec), + q: mpi::MPI::new(&ecc.data), }, )?; @@ -144,7 +124,36 @@ pub fn public_key_material_to_key( } } KeyType::Decryption => { - unimplemented!("Decryption keys not implemented yet") + if algo_ecc.curve == Curve::Cv25519 { + // EdDSA + let k4: Key4< + key::PublicParts, + key::UnspecifiedRole, + > = Key4::import_public_cv25519( + &ecc.data, None, None, time, + )?; + + println!("k4 {:?}", k4); + + Ok(Key::from(k4)) + } else { + // FIXME: just defining `hash` and `sym` is not + // ok when a cert already exists + + // ECDH + let k4 = Key4::new( + time, + PublicKeyAlgorithm::ECDH, + mpi::PublicKey::ECDH { + curve, + q: mpi::MPI::new(&ecc.data), + hash: Default::default(), + sym: Default::default(), + }, + )?; + + Ok(Key::from(k4)) + } } _ => unimplemented!("Unsupported KeyType"), } diff --git a/openpgp-card-sequoia/src/signer.rs b/openpgp-card-sequoia/src/signer.rs index e9a16d3..4b2d02b 100644 --- a/openpgp-card-sequoia/src/signer.rs +++ b/openpgp-card-sequoia/src/signer.rs @@ -16,7 +16,7 @@ use openpgp_card::Hash; use crate::PublicKey; -pub(crate) struct CardSigner<'a> { +pub struct CardSigner<'a> { /// The OpenPGP card (authenticated to allow signing operations) ca: &'a mut CardApp, @@ -58,10 +58,7 @@ impl<'a> CardSigner<'a> { if keys.len() == 1 { let public = keys[0].clone(); - Ok(CardSigner { - ca, - public: public.role_as_unspecified().clone(), - }) + Ok(Self::with_pubkey(ca, public)) } else { Err(OpenpgpCardError::InternalError(anyhow!( "Failed to find a matching (sub)key in cert" @@ -74,6 +71,13 @@ impl<'a> CardSigner<'a> { ))) } } + + pub fn with_pubkey( + ca: &'a mut CardApp, + public: PublicKey, + ) -> CardSigner<'a> { + CardSigner { ca, public } + } } impl<'a> crypto::Signer for CardSigner<'a> {