Skip to content

Commit

Permalink
Add CertKeyData structure
Browse files Browse the repository at this point in the history
See: RustCrypto/SSH#233
Signed-off-by: Wiktor Kwapisiewicz <wiktor@metacode.biz>
  • Loading branch information
wiktor-k committed Jul 9, 2024
1 parent 486792b commit 5d5fb38
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 12 deletions.
6 changes: 4 additions & 2 deletions examples/openpgp-card-agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ impl Session for CardSession {
return Ok::<_, Box<dyn std::error::Error>>(Some(Identity {
pubkey: KeyData::Ed25519(Ed25519PublicKey(
e.data().try_into()?,
)),
))
.into(),
comment: ident,
}));
}
Expand Down Expand Up @@ -231,7 +232,8 @@ impl Session for CardSession {
return Ok::<_, Box<dyn std::error::Error>>(Some(Identity {
pubkey: KeyData::Ed25519(Ed25519PublicKey(
e.data().try_into()?,
)),
))
.into(),
comment: ident,
}));
}
Expand Down
19 changes: 15 additions & 4 deletions examples/pgp-wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand All @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion src/proto/message.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Agent protocol message structures.
mod add_remove;
mod cert_key_data;
mod extension;
mod identity;
mod request;
Expand All @@ -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
Expand Down
61 changes: 61 additions & 0 deletions src/proto/message/cert_key_data.rs
Original file line number Diff line number Diff line change
@@ -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<Self, Self::Error> {
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<usize, ssh_encoding::Error> {
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<KeyData> for CertKeyData {
fn from(value: KeyData) -> Self {
Self::Key(value)
}
}

impl From<Certificate> for CertKeyData {
fn from(value: Certificate) -> Self {
Self::Cert(value)
}
}
5 changes: 3 additions & 2 deletions src/proto/message/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -36,7 +37,7 @@ impl Decode for Identity {
type Error = Error;

fn decode(reader: &mut impl Reader) -> Result<Self> {
let pubkey = reader.read_prefixed(KeyData::decode)?;
let pubkey = reader.read_prefixed(CertKeyData::decode)?;
let comment = String::decode(reader)?;

Ok(Self { pubkey, comment })
Expand Down
5 changes: 3 additions & 2 deletions src/proto/message/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<u8>,
Expand All @@ -27,7 +28,7 @@ impl Decode for SignRequest {
type Error = Error;

fn decode(reader: &mut impl Reader) -> Result<Self> {
let pubkey = reader.read_prefixed(KeyData::decode)?;
let pubkey = reader.read_prefixed(CertKeyData::decode)?;
let data = Vec::decode(reader)?;
let flags = u32::decode(reader)?;

Expand Down
2 changes: 1 addition & 1 deletion tests/roundtrip/expected/resp_parse_identities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}])
}

0 comments on commit 5d5fb38

Please sign in to comment.