From 486792b3de1f0d19a1f32fd876a1e7b9021cc7a5 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Mon, 8 Jul 2024 13:43:09 +0200 Subject: [PATCH 1/8] Add messages with certs Signed-off-by: Wiktor Kwapisiewicz --- tests/messages/req-sign-with-cert.bin | Bin 0 -> 909 bytes tests/messages/resp-identities-with-cert.bin | Bin 0 -> 1761 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/messages/req-sign-with-cert.bin create mode 100644 tests/messages/resp-identities-with-cert.bin diff --git a/tests/messages/req-sign-with-cert.bin b/tests/messages/req-sign-with-cert.bin new file mode 100644 index 0000000000000000000000000000000000000000..76fff0a8d947a68c2e8c531238b8663b4d7f4d9b GIT binary patch literal 909 zcmd;OU|?2YU|^6bF3!*`Do)f*PAw|YEi*85$S+9E0}ART=jQ_D6%LE7e7sWc@xe_? zi&D?sPv4rm?~RzJ+r9#QvHoH~(=KVC8fHcYMg|7PMur!E-hB;<@TkfAQ8J}q|BdIl zvWwWGZR5Ww&9~X$?A`=4n<9R4z1n9kc~MS(wnA^a;G`uBl6BcT88=5> zO@1~(IeOQbP1Y;*%h#5#oB8oXV7=4tX`fFNE!LKa{^$8x+V$0qBlF%pSny$|_@`Iz z?rgA6lYJu`B6QuRV<)F`@zUVrDg3?f1B{oJ9IAF+Ssa~~S+(L_2v;`;v zq%YqC(Lm4y#G(bMMY)+Jx)Fwkx@q}E<%vZpnR)48X$A&ysAOV#YF-JZv=~&nARm~F zFf?<)WJ@Zc#_>T#N{dsAbc>Rqq9Do`h`B+jGBw4>)YQ-t$WvaH<_=^`g(#;r|`8#Sb2y05p*yAvoA0*wY=z zVoA%)Nd*Z30b6lKqN$+~kmbO9>-zj%j?-R#KP<0puM{__bn0uqdr3NzuP05MeJD9Q qS9i_7sccJDguLLM*|Gk};;@VEySiRaYwKATzjJ%2&yg~q87u%H&uSw8 literal 0 HcmV?d00001 diff --git a/tests/messages/resp-identities-with-cert.bin b/tests/messages/resp-identities-with-cert.bin new file mode 100644 index 0000000000000000000000000000000000000000..258e382c211b073e3fd6fdc532076629030d7800 GIT binary patch literal 1761 zcmd;KU|?WjU|8M;Nqi9jYZBLgE)l#$`W{uIwG*{hdax^_x&^S2}G;*Tvj z8(-5aTlOCOF+bkaXZho% zX|EpLJ125yL4;7|)FR0}ojJ+>uW*aMd^+7LV*2Yu@BJ6bTlUZT|8~0Of%q3Q^s6(@ zDlJQpb3Vc%vHgK$p4l6gTmSY>5@*`~NS5h`$dx%K{wL`F(C9y7n_zW(ODr@0#N3FR z<(`NQrz&i%VN@x(Muhe>iS0qT5T<}{q2^ywJCv$1;jbd^(O6Ezr2E;-jpMdfmx zV0@es!?FHolJ<1Z)zv?;7g>u7u%|Mg2lg>Y$?Rz5duP)D>{kG;4 zNOCsgbf9v~$ZuqL@#o#wpa_qeydNb~3ijW4o-4bEJ=!+@o6>xn4bI-Z5)TjWEPKP6 zXt^okC)cZe=8_lX^k*ydwhK;LvLIQPy_0csuccjI-8eGu-Gc=mc8Y&`_3q9F`!v}%!XZM}Z8~;xIu|buPM*Tw z`#!*UY005#=at3LX_-|k-Zj3OAv^nn(cS31zSHOFYIa;`{kOI&ZT^BU@8$pRT$R-Q z;n-b?$txt?3ia6N$Zw(yq(6g zDk5(EJUQXB`hmtxg=SNxzX>*WWVkl z^~H`K@v>{*CH87g&$fnt@l&k1i=sFKjlWF$7Ws3Ev}5m_M|VHSv81vym1?UdZ$}srB3+I##O{$s!@rVzmDM#i^VK)&Gh}w(nZ4(WUpnWMgP&|K zdjq3|r#v&eB)`a^C^02J5120%fMPPxe5#wAT2!K2W?<-$Uyzyy6x2)3&jrdW92Q&o zc%|OsgPWEXrJlQ=zBPB>8!=C}eFger{l$W&UD7}`&C5*(G!Qfav1mbRQEq05ZiJzsZd!g(d16sYW?nj2nt?$a zDw&v`npc7;Ee4e?$Ok4P49#3H*^)}AaePpb(&E%2-J)cuD2Or!Vs22XOieK|H8r#Z zauo_B9p^-4-0Ph4YkAJ=nrr9WCU*FIo3>_RMx6MCrKfCbfNFvp!1s`gj0RV~u?!y28 literal 0 HcmV?d00001 From 5d5fb38aec62c9577706b179ba276c424330291d Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 9 Jul 2024 15:07:31 +0200 Subject: [PATCH 2/8] Add `CertKeyData` structure See: https://github.com/RustCrypto/SSH/pull/233 Signed-off-by: Wiktor Kwapisiewicz --- examples/openpgp-card-agent.rs | 6 +- examples/pgp-wrapper.rs | 19 ++++-- src/proto/message.rs | 4 +- src/proto/message/cert_key_data.rs | 61 +++++++++++++++++++ src/proto/message/identity.rs | 5 +- src/proto/message/sign.rs | 5 +- .../expected/resp_parse_identities.rs | 2 +- 7 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 src/proto/message/cert_key_data.rs diff --git a/examples/openpgp-card-agent.rs b/examples/openpgp-card-agent.rs index 0f952d2..4b3b0f5 100644 --- a/examples/openpgp-card-agent.rs +++ b/examples/openpgp-card-agent.rs @@ -173,7 +173,8 @@ impl Session for CardSession { return Ok::<_, Box>(Some(Identity { pubkey: KeyData::Ed25519(Ed25519PublicKey( e.data().try_into()?, - )), + )) + .into(), comment: ident, })); } @@ -231,7 +232,8 @@ impl Session for CardSession { return Ok::<_, Box>(Some(Identity { pubkey: KeyData::Ed25519(Ed25519PublicKey( e.data().try_into()?, - )), + )) + .into(), comment: ident, })); } diff --git a/examples/pgp-wrapper.rs b/examples/pgp-wrapper.rs index 61af481..bc83d67 100644 --- a/examples/pgp-wrapper.rs +++ b/examples/pgp-wrapper.rs @@ -64,7 +64,7 @@ use service_binding::Binding; use ssh_agent_lib::{ agent::Session, client::connect, - proto::{Extension, SignRequest}, + proto::{CertKeyData, Extension, SignRequest}, }; use ssh_key::public::KeyData; use tokio::runtime::Runtime; @@ -372,7 +372,10 @@ fn main() -> testresult::TestResult { let mut keyflags = KeyFlags::default(); keyflags.set_encrypt_comms(true); keyflags.set_encrypt_storage(true); - let pk = ssh_to_pgp(decryption_id.pubkey.clone(), KeyRole::Decryption); + let CertKeyData::Key(pubkey) = &decryption_id.pubkey else { + panic!("Only pubkeys are supported."); + }; + let pk = ssh_to_pgp(pubkey.clone(), KeyRole::Decryption); vec![pgp::PublicSubkey::new( pgp::packet::PublicSubkey::new( pk.packet_version(), @@ -388,6 +391,9 @@ fn main() -> testresult::TestResult { vec![] }; + let CertKeyData::Key(pubkey) = pubkey else { + panic!("Only pubkeys are supported."); + }; let signer = WrappedKey::new(pubkey.clone(), client, KeyRole::Signing); let mut keyflags = KeyFlags::default(); keyflags.set_sign(true); @@ -411,6 +417,9 @@ fn main() -> testresult::TestResult { signed_pk.to_writer(&mut std::io::stdout())?; } Args::Sign => { + let CertKeyData::Key(pubkey) = pubkey else { + panic!("Only pubkeys are supported."); + }; let signer = WrappedKey::new(pubkey.clone(), client, KeyRole::Signing); let signature = SignatureConfig::new_v4( SignatureVersion::V4, @@ -445,8 +454,10 @@ fn main() -> testresult::TestResult { pgp::packet::write_packet(&mut std::io::stdout(), &signature)?; } Args::Decrypt => { - let decryptor = - WrappedKey::new(decrypt_ids[0].pubkey.clone(), client, KeyRole::Decryption); + let CertKeyData::Key(pubkey) = decrypt_ids[0].pubkey else { + panic!("Only pubkeys are supported"); + }; + let decryptor = WrappedKey::new(pubkey.clone(), client, KeyRole::Decryption); let message = Message::from_bytes(std::io::stdin())?; let Message::Encrypted { esk, edata } = message else { diff --git a/src/proto/message.rs b/src/proto/message.rs index c5b7a83..d2444ec 100644 --- a/src/proto/message.rs +++ b/src/proto/message.rs @@ -1,6 +1,7 @@ //! Agent protocol message structures. mod add_remove; +mod cert_key_data; mod extension; mod identity; mod request; @@ -9,7 +10,8 @@ mod sign; mod unparsed; pub use self::{ - add_remove::*, extension::*, identity::*, request::*, response::*, sign::*, unparsed::*, + add_remove::*, cert_key_data::*, extension::*, identity::*, request::*, response::*, sign::*, + unparsed::*, }; #[doc(hidden)] /// For compatibility with pre-0.5.0 type alias in this module diff --git a/src/proto/message/cert_key_data.rs b/src/proto/message/cert_key_data.rs new file mode 100644 index 0000000..b7d1d99 --- /dev/null +++ b/src/proto/message/cert_key_data.rs @@ -0,0 +1,61 @@ +use std::str::FromStr as _; + +use ssh_encoding::{CheckedSum as _, Decode, Encode, Reader}; +use ssh_key::{public::KeyData, Algorithm, Certificate, PublicKey}; + +use crate::proto::{Error, Result}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum CertKeyData { + Key(KeyData), + Cert(Certificate), +} + +impl Decode for CertKeyData { + type Error = Error; + + fn decode(reader: &mut impl Reader) -> core::result::Result { + let alg = String::decode(reader)?; + let cert_alg = Algorithm::new_certificate(&alg); + + if let Ok(algorithm) = cert_alg { + let certificate = Certificate::decode_as(algorithm.clone(), reader)?; + Ok(Self::Cert(certificate)) + } else { + let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?; + let pubkey = KeyData::decode_as(reader, algorithm)?; + Ok(Self::Key(pubkey)) + } + } +} + +impl Encode for CertKeyData { + fn encoded_len(&self) -> std::result::Result { + match self { + Self::Key(pubkey) => pubkey.encoded_len(), + Self::Cert(certificate) => certificate.encoded_len(), + } + } + + fn encode( + &self, + writer: &mut impl ssh_encoding::Writer, + ) -> std::result::Result<(), ssh_encoding::Error> { + match self { + Self::Key(pubkey) => pubkey.encode(writer), + Self::Cert(certificate) => certificate.encode(writer), + } + } +} + +impl From for CertKeyData { + fn from(value: KeyData) -> Self { + Self::Key(value) + } +} + +impl From for CertKeyData { + fn from(value: Certificate) -> Self { + Self::Cert(value) + } +} diff --git a/src/proto/message/identity.rs b/src/proto/message/identity.rs index bf56403..c1710a4 100644 --- a/src/proto/message/identity.rs +++ b/src/proto/message/identity.rs @@ -3,6 +3,7 @@ use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; use ssh_key::public::KeyData; +use super::cert_key_data::CertKeyData; use crate::proto::{Error, Result}; /// Data returned to the client when listing keys. @@ -13,7 +14,7 @@ use crate::proto::{Error, Result}; #[derive(Clone, PartialEq, Debug)] pub struct Identity { /// A standard public-key encoding of an underlying key. - pub pubkey: KeyData, + pub pubkey: CertKeyData, /// A human-readable comment pub comment: String, @@ -36,7 +37,7 @@ impl Decode for Identity { type Error = Error; fn decode(reader: &mut impl Reader) -> Result { - let pubkey = reader.read_prefixed(KeyData::decode)?; + let pubkey = reader.read_prefixed(CertKeyData::decode)?; let comment = String::decode(reader)?; Ok(Self { pubkey, comment }) diff --git a/src/proto/message/sign.rs b/src/proto/message/sign.rs index b32f0bc..5b804fd 100644 --- a/src/proto/message/sign.rs +++ b/src/proto/message/sign.rs @@ -3,6 +3,7 @@ use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; use ssh_key::public::KeyData; +use super::cert_key_data::CertKeyData; use crate::proto::{Error, Result}; /// Signature request with data to be signed with a key in an agent. @@ -13,7 +14,7 @@ use crate::proto::{Error, Result}; #[derive(Clone, PartialEq, Debug)] pub struct SignRequest { /// The public key portion of the [`Identity`](super::Identity) in the agent to sign the data with - pub pubkey: KeyData, + pub pubkey: CertKeyData, /// Binary data to be signed pub data: Vec, @@ -27,7 +28,7 @@ impl Decode for SignRequest { type Error = Error; fn decode(reader: &mut impl Reader) -> Result { - let pubkey = reader.read_prefixed(KeyData::decode)?; + let pubkey = reader.read_prefixed(CertKeyData::decode)?; let data = Vec::decode(reader)?; let flags = u32::decode(reader)?; diff --git a/tests/roundtrip/expected/resp_parse_identities.rs b/tests/roundtrip/expected/resp_parse_identities.rs index 63b5d13..ec22774 100644 --- a/tests/roundtrip/expected/resp_parse_identities.rs +++ b/tests/roundtrip/expected/resp_parse_identities.rs @@ -5,7 +5,7 @@ use super::fixtures; pub fn expected() -> Response { Response::IdentitiesAnswer(vec![Identity { - pubkey: KeyData::Ecdsa(fixtures::demo_key().into()), + pubkey: KeyData::Ecdsa(fixtures::demo_key().into()).into(), comment: "baloo@angela".to_string(), }]) } From e3e51a8262ee08c3185399c2dcbf83f0fba31b1a Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 11:54:33 +0200 Subject: [PATCH 3/8] Fix build by removing code that does not compile Signed-off-by: Wiktor Kwapisiewicz --- .justfile | 2 +- examples/agent-socket-info.rs | 2 +- examples/key-storage.rs | 4 +-- examples/openpgp-card-agent.rs | 2 +- examples/pgp-wrapper.rs | 6 ++-- src/proto/message/cert_key_data.rs | 34 +++++++++--------- src/proto/message/identity.rs | 1 - src/proto/message/sign.rs | 1 - ...ert.bin => req-sign-with-cert.bin.ignored} | Bin ... => resp-identities-with-cert.bin.ignored} | Bin 10 files changed, 25 insertions(+), 27 deletions(-) rename tests/messages/{req-sign-with-cert.bin => req-sign-with-cert.bin.ignored} (100%) rename tests/messages/{resp-identities-with-cert.bin => resp-identities-with-cert.bin.ignored} (100%) diff --git a/.justfile b/.justfile index 323e1a7..86ff694 100755 --- a/.justfile +++ b/.justfile @@ -83,7 +83,7 @@ fix: # try to fix rustc issues cargo fix --allow-staged # try to fix clippy issues - cargo clippy --fix --allow-staged + cargo clippy --fix --allow-staged --allow-dirty # fmt must be last as clippy's changes may break formatting cargo +nightly fmt --all diff --git a/examples/agent-socket-info.rs b/examples/agent-socket-info.rs index f819b6c..1dc075e 100644 --- a/examples/agent-socket-info.rs +++ b/examples/agent-socket-info.rs @@ -27,7 +27,7 @@ impl Session for AgentSocketInfo { async fn request_identities(&mut self) -> Result, AgentError> { Ok(vec![Identity { // this is just a dummy key, the comment is important - pubkey: KeyData::Ed25519(ssh_key::public::Ed25519PublicKey([0; 32])), + pubkey: KeyData::Ed25519(ssh_key::public::Ed25519PublicKey([0; 32])).into(), comment: self.comment.clone(), }]) } diff --git a/examples/key-storage.rs b/examples/key-storage.rs index 934f35a..576c6a6 100644 --- a/examples/key-storage.rs +++ b/examples/key-storage.rs @@ -74,7 +74,7 @@ impl KeyStorage { #[crate::async_trait] impl Session for KeyStorage { async fn sign(&mut self, sign_request: SignRequest) -> Result { - let pubkey: PublicKey = sign_request.pubkey.clone().into(); + let pubkey: PublicKey = sign_request.pubkey.key_data().clone().into(); if let Some(identity) = self.identity_from_pubkey(&pubkey) { match identity.privkey.key_data() { @@ -113,7 +113,7 @@ impl Session for KeyStorage { let mut identities = vec![]; for identity in self.identities.lock().unwrap().iter() { identities.push(message::Identity { - pubkey: identity.pubkey.key_data().clone(), + pubkey: identity.pubkey.key_data().clone().into(), comment: identity.comment.clone(), }) } diff --git a/examples/openpgp-card-agent.rs b/examples/openpgp-card-agent.rs index 4b3b0f5..5935105 100644 --- a/examples/openpgp-card-agent.rs +++ b/examples/openpgp-card-agent.rs @@ -71,7 +71,7 @@ impl CardSession { if let AlgorithmAttributes::Ecc(ecc) = e.algo() { if ecc.ecc_type() == EccType::EdDSA { let pubkey = KeyData::Ed25519(Ed25519PublicKey(e.data().try_into()?)); - if pubkey == request.pubkey { + if pubkey == *request.pubkey.key_data() { let pin = self.pwds.get(&ident).await; return if let Some(pin) = pin { let str = pin.expose_secret().as_bytes().to_vec(); diff --git a/examples/pgp-wrapper.rs b/examples/pgp-wrapper.rs index bc83d67..f05d41b 100644 --- a/examples/pgp-wrapper.rs +++ b/examples/pgp-wrapper.rs @@ -295,7 +295,7 @@ impl SecretKeyTrait for WrappedKey { .block_on(async { let mut client = self.client.lock().await; let result = client.sign(SignRequest { - pubkey: self.pubkey.clone(), + pubkey: self.pubkey.clone().into(), data: data.to_vec(), flags: 0, }); @@ -454,9 +454,7 @@ fn main() -> testresult::TestResult { pgp::packet::write_packet(&mut std::io::stdout(), &signature)?; } Args::Decrypt => { - let CertKeyData::Key(pubkey) = decrypt_ids[0].pubkey else { - panic!("Only pubkeys are supported"); - }; + let pubkey = decrypt_ids[0].pubkey.key_data(); let decryptor = WrappedKey::new(pubkey.clone(), client, KeyRole::Decryption); let message = Message::from_bytes(std::io::stdin())?; diff --git a/src/proto/message/cert_key_data.rs b/src/proto/message/cert_key_data.rs index b7d1d99..eb531cd 100644 --- a/src/proto/message/cert_key_data.rs +++ b/src/proto/message/cert_key_data.rs @@ -1,31 +1,33 @@ -use std::str::FromStr as _; +use ssh_encoding::{Decode, Encode, Reader}; +use ssh_key::{public::KeyData, Certificate}; -use ssh_encoding::{CheckedSum as _, Decode, Encode, Reader}; -use ssh_key::{public::KeyData, Algorithm, Certificate, PublicKey}; - -use crate::proto::{Error, Result}; +use crate::proto::Error; #[derive(Debug, PartialEq, Eq, Clone)] +/// Represents a public credential. pub enum CertKeyData { + /// Plain public key. Key(KeyData), + /// Signed public key. Cert(Certificate), } +impl CertKeyData { + /// Returns a reference to the [KeyData]. + pub fn key_data(&self) -> &KeyData { + match self { + Self::Key(key) => key, + Self::Cert(cert) => cert.public_key(), + } + } +} + impl Decode for CertKeyData { type Error = Error; fn decode(reader: &mut impl Reader) -> core::result::Result { - let alg = String::decode(reader)?; - let cert_alg = Algorithm::new_certificate(&alg); - - if let Ok(algorithm) = cert_alg { - let certificate = Certificate::decode_as(algorithm.clone(), reader)?; - Ok(Self::Cert(certificate)) - } else { - let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?; - let pubkey = KeyData::decode_as(reader, algorithm)?; - Ok(Self::Key(pubkey)) - } + // TODO: implement parsing certificates + Ok(Self::Key(KeyData::decode(reader)?)) } } diff --git a/src/proto/message/identity.rs b/src/proto/message/identity.rs index c1710a4..f17607a 100644 --- a/src/proto/message/identity.rs +++ b/src/proto/message/identity.rs @@ -1,7 +1,6 @@ //! Data returned to the client when listing keys. use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; -use ssh_key::public::KeyData; use super::cert_key_data::CertKeyData; use crate::proto::{Error, Result}; diff --git a/src/proto/message/sign.rs b/src/proto/message/sign.rs index 5b804fd..41339f9 100644 --- a/src/proto/message/sign.rs +++ b/src/proto/message/sign.rs @@ -1,7 +1,6 @@ //! Signature request with data to be signed with a key in an agent. use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; -use ssh_key::public::KeyData; use super::cert_key_data::CertKeyData; use crate::proto::{Error, Result}; diff --git a/tests/messages/req-sign-with-cert.bin b/tests/messages/req-sign-with-cert.bin.ignored similarity index 100% rename from tests/messages/req-sign-with-cert.bin rename to tests/messages/req-sign-with-cert.bin.ignored diff --git a/tests/messages/resp-identities-with-cert.bin b/tests/messages/resp-identities-with-cert.bin.ignored similarity index 100% rename from tests/messages/resp-identities-with-cert.bin rename to tests/messages/resp-identities-with-cert.bin.ignored From b56ab4e193c00cfd10d25ddc6ea27246ce9d6e37 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 11:54:51 +0200 Subject: [PATCH 4/8] Update `bytes` to avoid using yanked version Signed-off-by: Wiktor Kwapisiewicz --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9d4970..09d7ee7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,9 +295,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" [[package]] name = "camellia" From 8aa6bf90d9e23c6bdc432df78a1c378d43fb81e1 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 11:58:09 +0200 Subject: [PATCH 5/8] Rename `CertKeyData` to `PublicCredential` Signed-off-by: Wiktor Kwapisiewicz --- examples/pgp-wrapper.rs | 8 ++++---- src/proto/message.rs | 4 ++-- .../message/{cert_key_data.rs => credential.rs} | 12 ++++++------ src/proto/message/identity.rs | 6 +++--- src/proto/message/sign.rs | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) rename src/proto/message/{cert_key_data.rs => credential.rs} (86%) diff --git a/examples/pgp-wrapper.rs b/examples/pgp-wrapper.rs index f05d41b..680ea75 100644 --- a/examples/pgp-wrapper.rs +++ b/examples/pgp-wrapper.rs @@ -64,7 +64,7 @@ use service_binding::Binding; use ssh_agent_lib::{ agent::Session, client::connect, - proto::{CertKeyData, Extension, SignRequest}, + proto::{Extension, PublicCredential, SignRequest}, }; use ssh_key::public::KeyData; use tokio::runtime::Runtime; @@ -372,7 +372,7 @@ fn main() -> testresult::TestResult { let mut keyflags = KeyFlags::default(); keyflags.set_encrypt_comms(true); keyflags.set_encrypt_storage(true); - let CertKeyData::Key(pubkey) = &decryption_id.pubkey else { + let PublicCredential::Key(pubkey) = &decryption_id.pubkey else { panic!("Only pubkeys are supported."); }; let pk = ssh_to_pgp(pubkey.clone(), KeyRole::Decryption); @@ -391,7 +391,7 @@ fn main() -> testresult::TestResult { vec![] }; - let CertKeyData::Key(pubkey) = pubkey else { + let PublicCredential::Key(pubkey) = pubkey else { panic!("Only pubkeys are supported."); }; let signer = WrappedKey::new(pubkey.clone(), client, KeyRole::Signing); @@ -417,7 +417,7 @@ fn main() -> testresult::TestResult { signed_pk.to_writer(&mut std::io::stdout())?; } Args::Sign => { - let CertKeyData::Key(pubkey) = pubkey else { + let PublicCredential::Key(pubkey) = pubkey else { panic!("Only pubkeys are supported."); }; let signer = WrappedKey::new(pubkey.clone(), client, KeyRole::Signing); diff --git a/src/proto/message.rs b/src/proto/message.rs index d2444ec..11c3031 100644 --- a/src/proto/message.rs +++ b/src/proto/message.rs @@ -1,7 +1,7 @@ //! Agent protocol message structures. mod add_remove; -mod cert_key_data; +mod credential; mod extension; mod identity; mod request; @@ -10,7 +10,7 @@ mod sign; mod unparsed; pub use self::{ - add_remove::*, cert_key_data::*, extension::*, identity::*, request::*, response::*, sign::*, + add_remove::*, credential::*, extension::*, identity::*, request::*, response::*, sign::*, unparsed::*, }; #[doc(hidden)] diff --git a/src/proto/message/cert_key_data.rs b/src/proto/message/credential.rs similarity index 86% rename from src/proto/message/cert_key_data.rs rename to src/proto/message/credential.rs index eb531cd..06c9d95 100644 --- a/src/proto/message/cert_key_data.rs +++ b/src/proto/message/credential.rs @@ -5,14 +5,14 @@ use crate::proto::Error; #[derive(Debug, PartialEq, Eq, Clone)] /// Represents a public credential. -pub enum CertKeyData { +pub enum PublicCredential { /// Plain public key. Key(KeyData), /// Signed public key. Cert(Certificate), } -impl CertKeyData { +impl PublicCredential { /// Returns a reference to the [KeyData]. pub fn key_data(&self) -> &KeyData { match self { @@ -22,7 +22,7 @@ impl CertKeyData { } } -impl Decode for CertKeyData { +impl Decode for PublicCredential { type Error = Error; fn decode(reader: &mut impl Reader) -> core::result::Result { @@ -31,7 +31,7 @@ impl Decode for CertKeyData { } } -impl Encode for CertKeyData { +impl Encode for PublicCredential { fn encoded_len(&self) -> std::result::Result { match self { Self::Key(pubkey) => pubkey.encoded_len(), @@ -50,13 +50,13 @@ impl Encode for CertKeyData { } } -impl From for CertKeyData { +impl From for PublicCredential { fn from(value: KeyData) -> Self { Self::Key(value) } } -impl From for CertKeyData { +impl From for PublicCredential { fn from(value: Certificate) -> Self { Self::Cert(value) } diff --git a/src/proto/message/identity.rs b/src/proto/message/identity.rs index f17607a..24080a4 100644 --- a/src/proto/message/identity.rs +++ b/src/proto/message/identity.rs @@ -2,7 +2,7 @@ use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; -use super::cert_key_data::CertKeyData; +use super::PublicCredential; use crate::proto::{Error, Result}; /// Data returned to the client when listing keys. @@ -13,7 +13,7 @@ use crate::proto::{Error, Result}; #[derive(Clone, PartialEq, Debug)] pub struct Identity { /// A standard public-key encoding of an underlying key. - pub pubkey: CertKeyData, + pub pubkey: PublicCredential, /// A human-readable comment pub comment: String, @@ -36,7 +36,7 @@ impl Decode for Identity { type Error = Error; fn decode(reader: &mut impl Reader) -> Result { - let pubkey = reader.read_prefixed(CertKeyData::decode)?; + let pubkey = reader.read_prefixed(PublicCredential::decode)?; let comment = String::decode(reader)?; Ok(Self { pubkey, comment }) diff --git a/src/proto/message/sign.rs b/src/proto/message/sign.rs index 41339f9..d243753 100644 --- a/src/proto/message/sign.rs +++ b/src/proto/message/sign.rs @@ -2,7 +2,7 @@ use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; -use super::cert_key_data::CertKeyData; +use super::PublicCredential; use crate::proto::{Error, Result}; /// Signature request with data to be signed with a key in an agent. @@ -13,7 +13,7 @@ use crate::proto::{Error, Result}; #[derive(Clone, PartialEq, Debug)] pub struct SignRequest { /// The public key portion of the [`Identity`](super::Identity) in the agent to sign the data with - pub pubkey: CertKeyData, + pub pubkey: PublicCredential, /// Binary data to be signed pub data: Vec, @@ -27,7 +27,7 @@ impl Decode for SignRequest { type Error = Error; fn decode(reader: &mut impl Reader) -> Result { - let pubkey = reader.read_prefixed(CertKeyData::decode)?; + let pubkey = reader.read_prefixed(PublicCredential::decode)?; let data = Vec::decode(reader)?; let flags = u32::decode(reader)?; From ae7d5a5119f6565a6b2a87b3620690afecba9d66 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 12:00:42 +0200 Subject: [PATCH 6/8] Rename `Credential` to `PrivateCredential` Signed-off-by: Wiktor Kwapisiewicz --- examples/key-storage.rs | 8 ++++---- src/proto/message/add_remove.rs | 4 ++-- src/proto/message/add_remove/credential.rs | 10 +++++----- ...ntity_constrained_extension_restrict_destination.rs | 7 +++++-- .../expected/req_add_identity_constrained_lifetime.rs | 6 ++++-- tests/roundtrip/expected/req_add_identity_ecdsa.rs | 6 +++--- tests/roundtrip/expected/req_parse_certificates.rs | 8 ++++---- 7 files changed, 27 insertions(+), 22 deletions(-) diff --git a/examples/key-storage.rs b/examples/key-storage.rs index 576c6a6..fba18bf 100644 --- a/examples/key-storage.rs +++ b/examples/key-storage.rs @@ -12,8 +12,8 @@ use ssh_agent_lib::agent::{listen, Session}; use ssh_agent_lib::error::AgentError; use ssh_agent_lib::proto::extension::{QueryResponse, RestrictDestination, SessionBind}; use ssh_agent_lib::proto::{ - message, signature, AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained, - Credential, Extension, KeyConstraint, RemoveIdentity, SignRequest, SmartcardKey, + message, signature, AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained, Extension, + KeyConstraint, PrivateCredential, RemoveIdentity, SignRequest, SmartcardKey, }; use ssh_key::{ private::{KeypairData, PrivateKey}, @@ -121,7 +121,7 @@ impl Session for KeyStorage { } async fn add_identity(&mut self, identity: AddIdentity) -> Result<(), AgentError> { - if let Credential::Key { privkey, comment } = identity.credential { + if let PrivateCredential::Key { privkey, comment } = identity.credential { let privkey = PrivateKey::try_from(privkey).map_err(AgentError::other)?; self.identity_add(Identity { pubkey: PublicKey::from(&privkey), @@ -152,7 +152,7 @@ impl Session for KeyStorage { info!("Destination constraint: {destination:?}"); } - if let Credential::Key { privkey, comment } = identity.credential.clone() { + if let PrivateCredential::Key { privkey, comment } = identity.credential.clone() { let privkey = PrivateKey::try_from(privkey).map_err(AgentError::other)?; self.identity_add(Identity { pubkey: PublicKey::from(&privkey), diff --git a/src/proto/message/add_remove.rs b/src/proto/message/add_remove.rs index 1b29d8d..68aec17 100644 --- a/src/proto/message/add_remove.rs +++ b/src/proto/message/add_remove.rs @@ -20,14 +20,14 @@ use crate::proto::{Error, Result}; #[derive(Clone, PartialEq, Debug)] pub struct AddIdentity { /// A credential (private & public key, or private key / certificate) to add to the agent - pub credential: Credential, + pub credential: PrivateCredential, } impl Decode for AddIdentity { type Error = Error; fn decode(reader: &mut impl Reader) -> Result { - let credential = Credential::decode(reader)?; + let credential = PrivateCredential::decode(reader)?; Ok(Self { credential }) } diff --git a/src/proto/message/add_remove/credential.rs b/src/proto/message/add_remove/credential.rs index 22efdc5..95060dd 100644 --- a/src/proto/message/add_remove/credential.rs +++ b/src/proto/message/add_remove/credential.rs @@ -16,7 +16,7 @@ use crate::proto::{Error, PrivateKeyData, Result}; /// This structure covers both types of identities a user may /// send to an agent as part of a [`Request::AddIdentity`](crate::proto::Request::AddIdentity) message. #[derive(Clone, PartialEq, Debug)] -pub enum Credential { +pub enum PrivateCredential { /// A public/private key pair Key { /// Public/private key pair data @@ -42,7 +42,7 @@ pub enum Credential { }, } -impl Decode for Credential { +impl Decode for PrivateCredential { type Error = Error; fn decode(reader: &mut impl Reader) -> Result { @@ -57,7 +57,7 @@ impl Decode for Credential { let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?; let comment = String::decode(reader)?; - Ok(Credential::Cert { + Ok(PrivateCredential::Cert { algorithm, certificate, privkey, @@ -67,12 +67,12 @@ impl Decode for Credential { let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?; let privkey = KeypairData::decode_as(reader, algorithm)?; let comment = String::decode(reader)?; - Ok(Credential::Key { privkey, comment }) + Ok(PrivateCredential::Key { privkey, comment }) } } } -impl Encode for Credential { +impl Encode for PrivateCredential { fn encoded_len(&self) -> ssh_encoding::Result { match self { Self::Key { privkey, comment } => { diff --git a/tests/roundtrip/expected/req_add_identity_constrained_extension_restrict_destination.rs b/tests/roundtrip/expected/req_add_identity_constrained_extension_restrict_destination.rs index 83ed194..9f9c509 100644 --- a/tests/roundtrip/expected/req_add_identity_constrained_extension_restrict_destination.rs +++ b/tests/roundtrip/expected/req_add_identity_constrained_extension_restrict_destination.rs @@ -1,5 +1,8 @@ use hex_literal::hex; -use ssh_agent_lib::proto::{AddIdentity, AddIdentityConstrained, Credential, Extension, KeyConstraint, Request, Unparsed}; +use ssh_agent_lib::proto::{ + AddIdentity, AddIdentityConstrained, Extension, KeyConstraint, PrivateCredential, Request, + Unparsed, +}; use ssh_key::private::KeypairData; use super::fixtures; @@ -7,7 +10,7 @@ use super::fixtures; pub fn expected() -> Request { Request::AddIdConstrained(AddIdentityConstrained { identity: AddIdentity { - credential: Credential::Key { + credential: PrivateCredential::Key { privkey: KeypairData::Ecdsa(fixtures::demo_key()), comment: "baloo@angela".to_string(), }, diff --git a/tests/roundtrip/expected/req_add_identity_constrained_lifetime.rs b/tests/roundtrip/expected/req_add_identity_constrained_lifetime.rs index 203a388..7c6c233 100644 --- a/tests/roundtrip/expected/req_add_identity_constrained_lifetime.rs +++ b/tests/roundtrip/expected/req_add_identity_constrained_lifetime.rs @@ -1,4 +1,6 @@ -use ssh_agent_lib::proto::{AddIdentity, AddIdentityConstrained, Credential, KeyConstraint, Request}; +use ssh_agent_lib::proto::{ + AddIdentity, AddIdentityConstrained, KeyConstraint, PrivateCredential, Request, +}; use ssh_key::private::KeypairData; use super::fixtures; @@ -6,7 +8,7 @@ use super::fixtures; pub fn expected() -> Request { Request::AddIdConstrained(AddIdentityConstrained { identity: AddIdentity { - credential: Credential::Key { + credential: PrivateCredential::Key { privkey: KeypairData::Ecdsa(fixtures::demo_key()), comment: "baloo@angela".to_string(), }, diff --git a/tests/roundtrip/expected/req_add_identity_ecdsa.rs b/tests/roundtrip/expected/req_add_identity_ecdsa.rs index b79aab9..bd2d231 100644 --- a/tests/roundtrip/expected/req_add_identity_ecdsa.rs +++ b/tests/roundtrip/expected/req_add_identity_ecdsa.rs @@ -1,13 +1,13 @@ -use ssh_agent_lib::proto::{AddIdentity, Credential, Request}; +use ssh_agent_lib::proto::{AddIdentity, PrivateCredential, Request}; use ssh_key::private::KeypairData; use super::fixtures; pub fn expected() -> Request { Request::AddIdentity(AddIdentity { - credential: Credential::Key { + credential: PrivateCredential::Key { privkey: KeypairData::Ecdsa(fixtures::demo_key()), comment: "baloo@angela".to_string(), - } + }, }) } diff --git a/tests/roundtrip/expected/req_parse_certificates.rs b/tests/roundtrip/expected/req_parse_certificates.rs index b7913ad..2ec4796 100644 --- a/tests/roundtrip/expected/req_parse_certificates.rs +++ b/tests/roundtrip/expected/req_parse_certificates.rs @@ -1,15 +1,15 @@ use hex_literal::hex; -use ssh_agent_lib::proto::{AddIdentity, AddIdentityConstrained, Credential, KeyConstraint, PrivateKeyData, Request,}; -use ssh_key::{ - private::RsaPrivateKey, Algorithm, Mpint +use ssh_agent_lib::proto::{ + AddIdentity, AddIdentityConstrained, KeyConstraint, PrivateCredential, PrivateKeyData, Request, }; +use ssh_key::{private::RsaPrivateKey, Algorithm, Mpint}; use super::fixtures; pub fn expected() -> Request { Request::AddIdConstrained(AddIdentityConstrained { identity: AddIdentity { - credential: Credential::Cert { + credential: PrivateCredential::Cert { algorithm: Algorithm::new("ssh-rsa").unwrap(), certificate: fixtures::demo_certificate(), privkey: PrivateKeyData::Rsa(RsaPrivateKey { From dcec785680dc5b165b5f195d540a7070d859f1d1 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 12:05:04 +0200 Subject: [PATCH 7/8] Move `PrivateCredential` to the `credential` module Signed-off-by: Wiktor Kwapisiewicz --- src/proto/message/add_remove.rs | 3 +- src/proto/message/add_remove/credential.rs | 115 -------------------- src/proto/message/credential.rs | 118 ++++++++++++++++++++- 3 files changed, 116 insertions(+), 120 deletions(-) delete mode 100644 src/proto/message/add_remove/credential.rs diff --git a/src/proto/message/add_remove.rs b/src/proto/message/add_remove.rs index 68aec17..3f843a5 100644 --- a/src/proto/message/add_remove.rs +++ b/src/proto/message/add_remove.rs @@ -1,15 +1,14 @@ //! Add a key to an agent with or without constraints and supporting data types. mod constrained; -mod credential; pub use constrained::*; -pub use credential::*; use secrecy::ExposeSecret as _; use secrecy::SecretString; use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; use ssh_key::public::KeyData; +use super::PrivateCredential; use crate::proto::{Error, Result}; /// Add a key to an agent. diff --git a/src/proto/message/add_remove/credential.rs b/src/proto/message/add_remove/credential.rs deleted file mode 100644 index 95060dd..0000000 --- a/src/proto/message/add_remove/credential.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! A container for a public / private key pair, or a certificate / private key. - -use core::str::FromStr; - -use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; -use ssh_key::{certificate::Certificate, private::KeypairData, Algorithm}; - -use crate::proto::{Error, PrivateKeyData, Result}; - -/// A container for a public / private key pair, or a certificate / private key. -/// -/// When adding an identity to an agent, a user can provide either: -/// 1. A public / private key pair -/// 2. An OpenSSH [certificate](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys) -/// -/// This structure covers both types of identities a user may -/// send to an agent as part of a [`Request::AddIdentity`](crate::proto::Request::AddIdentity) message. -#[derive(Clone, PartialEq, Debug)] -pub enum PrivateCredential { - /// A public/private key pair - Key { - /// Public/private key pair data - privkey: KeypairData, - - /// Key comment, if any. - comment: String, - }, - - /// An OpenSSH [certificate](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys) - Cert { - /// Certificate algorithm. - algorithm: Algorithm, - - /// Certificate data. - certificate: Certificate, - - /// Private key data. - privkey: PrivateKeyData, - - /// Comment, if any. - comment: String, - }, -} - -impl Decode for PrivateCredential { - type Error = Error; - - fn decode(reader: &mut impl Reader) -> Result { - let alg = String::decode(reader)?; - let cert_alg = Algorithm::new_certificate(&alg); - - if let Ok(algorithm) = cert_alg { - let certificate = reader.read_prefixed(|reader| { - let cert = Certificate::decode(reader)?; - Ok::<_, Error>(cert) - })?; - let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?; - let comment = String::decode(reader)?; - - Ok(PrivateCredential::Cert { - algorithm, - certificate, - privkey, - comment, - }) - } else { - let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?; - let privkey = KeypairData::decode_as(reader, algorithm)?; - let comment = String::decode(reader)?; - Ok(PrivateCredential::Key { privkey, comment }) - } - } -} - -impl Encode for PrivateCredential { - fn encoded_len(&self) -> ssh_encoding::Result { - match self { - Self::Key { privkey, comment } => { - [privkey.encoded_len()?, comment.encoded_len()?].checked_sum() - } - Self::Cert { - algorithm, - certificate, - privkey, - comment, - } => [ - algorithm.to_certificate_type().encoded_len()?, - certificate.encoded_len_prefixed()?, - privkey.encoded_len()?, - comment.encoded_len()?, - ] - .checked_sum(), - } - } - - fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> { - match self { - Self::Key { privkey, comment } => { - privkey.encode(writer)?; - comment.encode(writer) - } - Self::Cert { - algorithm, - certificate, - privkey, - comment, - } => { - algorithm.to_certificate_type().encode(writer)?; - certificate.encode_prefixed(writer)?; - privkey.encode(writer)?; - comment.encode(writer) - } - } - } -} diff --git a/src/proto/message/credential.rs b/src/proto/message/credential.rs index 06c9d95..d85b373 100644 --- a/src/proto/message/credential.rs +++ b/src/proto/message/credential.rs @@ -1,7 +1,119 @@ -use ssh_encoding::{Decode, Encode, Reader}; -use ssh_key::{public::KeyData, Certificate}; +//! A container for a public / private key pair, or a certificate / private key. -use crate::proto::Error; +use std::str::FromStr as _; + +use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer}; +use ssh_key::public::KeyData; +use ssh_key::{certificate::Certificate, private::KeypairData, Algorithm}; + +use crate::proto::{Error, PrivateKeyData, Result}; + +/// A container for a public / private key pair, or a certificate / private key. +/// +/// When adding an identity to an agent, a user can provide either: +/// 1. A public / private key pair +/// 2. An OpenSSH [certificate](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys) +/// +/// This structure covers both types of identities a user may +/// send to an agent as part of a [`Request::AddIdentity`](crate::proto::Request::AddIdentity) message. +#[derive(Clone, PartialEq, Debug)] +pub enum PrivateCredential { + /// A public/private key pair + Key { + /// Public/private key pair data + privkey: KeypairData, + + /// Key comment, if any. + comment: String, + }, + + /// An OpenSSH [certificate](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys) + Cert { + /// Certificate algorithm. + algorithm: Algorithm, + + /// Certificate data. + certificate: Certificate, + + /// Private key data. + privkey: PrivateKeyData, + + /// Comment, if any. + comment: String, + }, +} + +impl Decode for PrivateCredential { + type Error = Error; + + fn decode(reader: &mut impl Reader) -> Result { + let alg = String::decode(reader)?; + let cert_alg = Algorithm::new_certificate(&alg); + + if let Ok(algorithm) = cert_alg { + let certificate = reader.read_prefixed(|reader| { + let cert = Certificate::decode(reader)?; + Ok::<_, Error>(cert) + })?; + let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?; + let comment = String::decode(reader)?; + + Ok(PrivateCredential::Cert { + algorithm, + certificate, + privkey, + comment, + }) + } else { + let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?; + let privkey = KeypairData::decode_as(reader, algorithm)?; + let comment = String::decode(reader)?; + Ok(PrivateCredential::Key { privkey, comment }) + } + } +} + +impl Encode for PrivateCredential { + fn encoded_len(&self) -> ssh_encoding::Result { + match self { + Self::Key { privkey, comment } => { + [privkey.encoded_len()?, comment.encoded_len()?].checked_sum() + } + Self::Cert { + algorithm, + certificate, + privkey, + comment, + } => [ + algorithm.to_certificate_type().encoded_len()?, + certificate.encoded_len_prefixed()?, + privkey.encoded_len()?, + comment.encoded_len()?, + ] + .checked_sum(), + } + } + + fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> { + match self { + Self::Key { privkey, comment } => { + privkey.encode(writer)?; + comment.encode(writer) + } + Self::Cert { + algorithm, + certificate, + privkey, + comment, + } => { + algorithm.to_certificate_type().encode(writer)?; + certificate.encode_prefixed(writer)?; + privkey.encode(writer)?; + comment.encode(writer) + } + } + } +} #[derive(Debug, PartialEq, Eq, Clone)] /// Represents a public credential. From 936a1b72e9019e0376d2a23c84f71348f8110753 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 12:29:14 +0200 Subject: [PATCH 8/8] Use `key_data` to simplify code Signed-off-by: Wiktor Kwapisiewicz --- examples/pgp-wrapper.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/pgp-wrapper.rs b/examples/pgp-wrapper.rs index 680ea75..d52c4b0 100644 --- a/examples/pgp-wrapper.rs +++ b/examples/pgp-wrapper.rs @@ -372,9 +372,7 @@ fn main() -> testresult::TestResult { let mut keyflags = KeyFlags::default(); keyflags.set_encrypt_comms(true); keyflags.set_encrypt_storage(true); - let PublicCredential::Key(pubkey) = &decryption_id.pubkey else { - panic!("Only pubkeys are supported."); - }; + let pubkey = decryption_id.pubkey.key_data(); let pk = ssh_to_pgp(pubkey.clone(), KeyRole::Decryption); vec![pgp::PublicSubkey::new( pgp::packet::PublicSubkey::new(