Skip to content

Commit ae28a54

Browse files
authored
Merge pull request #85 from wiktor-k/wiktor/support-certs-everywhere
Add messages with certs
2 parents 47aaa61 + 390ac8b commit ae28a54

16 files changed

Lines changed: 114 additions & 43 deletions

.justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fix:
8383
# try to fix rustc issues
8484
cargo fix --allow-staged
8585
# try to fix clippy issues
86-
cargo clippy --fix --allow-staged
86+
cargo clippy --fix --allow-staged --allow-dirty
8787
8888
# fmt must be last as clippy's changes may break formatting
8989
cargo +nightly fmt --all

examples/agent-socket-info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl Session for AgentSocketInfo {
2727
async fn request_identities(&mut self) -> Result<Vec<Identity>, AgentError> {
2828
Ok(vec![Identity {
2929
// this is just a dummy key, the comment is important
30-
pubkey: KeyData::Ed25519(ssh_key::public::Ed25519PublicKey([0; 32])),
30+
pubkey: KeyData::Ed25519(ssh_key::public::Ed25519PublicKey([0; 32])).into(),
3131
comment: self.comment.clone(),
3232
}])
3333
}

examples/key-storage.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use ssh_agent_lib::agent::{listen, Session};
1212
use ssh_agent_lib::error::AgentError;
1313
use ssh_agent_lib::proto::extension::{QueryResponse, RestrictDestination, SessionBind};
1414
use ssh_agent_lib::proto::{
15-
message, signature, AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained,
16-
Credential, Extension, KeyConstraint, RemoveIdentity, SignRequest, SmartcardKey,
15+
message, signature, AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained, Extension,
16+
KeyConstraint, PrivateCredential, RemoveIdentity, SignRequest, SmartcardKey,
1717
};
1818
use ssh_key::{
1919
private::{KeypairData, PrivateKey},
@@ -74,7 +74,7 @@ impl KeyStorage {
7474
#[crate::async_trait]
7575
impl Session for KeyStorage {
7676
async fn sign(&mut self, sign_request: SignRequest) -> Result<Signature, AgentError> {
77-
let pubkey: PublicKey = sign_request.pubkey.clone().into();
77+
let pubkey: PublicKey = sign_request.pubkey.key_data().clone().into();
7878

7979
if let Some(identity) = self.identity_from_pubkey(&pubkey) {
8080
match identity.privkey.key_data() {
@@ -122,15 +122,15 @@ impl Session for KeyStorage {
122122
let mut identities = vec![];
123123
for identity in self.identities.lock().unwrap().iter() {
124124
identities.push(message::Identity {
125-
pubkey: identity.pubkey.key_data().clone(),
125+
pubkey: identity.pubkey.key_data().clone().into(),
126126
comment: identity.comment.clone(),
127127
})
128128
}
129129
Ok(identities)
130130
}
131131

132132
async fn add_identity(&mut self, identity: AddIdentity) -> Result<(), AgentError> {
133-
if let Credential::Key { privkey, comment } = identity.credential {
133+
if let PrivateCredential::Key { privkey, comment } = identity.credential {
134134
let privkey = PrivateKey::try_from(privkey).map_err(AgentError::other)?;
135135
self.identity_add(Identity {
136136
pubkey: PublicKey::from(&privkey),
@@ -161,7 +161,7 @@ impl Session for KeyStorage {
161161
info!("Destination constraint: {destination:?}");
162162
}
163163

164-
if let Credential::Key { privkey, comment } = identity.credential.clone() {
164+
if let PrivateCredential::Key { privkey, comment } = identity.credential.clone() {
165165
let privkey = PrivateKey::try_from(privkey).map_err(AgentError::other)?;
166166
self.identity_add(Identity {
167167
pubkey: PublicKey::from(&privkey),

examples/random-key.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use sha1::Sha1;
1010
use ssh_agent_lib::agent::NamedPipeListener as Listener;
1111
use ssh_agent_lib::agent::{listen, Session};
1212
use ssh_agent_lib::error::AgentError;
13-
use ssh_agent_lib::proto::{signature, Identity, SignRequest};
13+
use ssh_agent_lib::proto::{signature, Identity, PublicCredential, SignRequest};
1414
use ssh_key::private::RsaKeypair;
1515
use ssh_key::HashAlg;
1616
use ssh_key::{
@@ -41,7 +41,10 @@ impl RandomKey {
4141
impl Session for RandomKey {
4242
async fn sign(&mut self, sign_request: SignRequest) -> Result<Signature, AgentError> {
4343
let private_key = self.private_key.lock().unwrap();
44-
if PublicKey::from(private_key.deref()).key_data() != &sign_request.pubkey {
44+
let PublicCredential::Key(pubkey) = sign_request.pubkey else {
45+
return Err(std::io::Error::other("Key not found").into());
46+
};
47+
if PublicKey::from(private_key.deref()).key_data() != &pubkey {
4548
return Err(std::io::Error::other("Key not found").into());
4649
}
4750

@@ -85,7 +88,7 @@ impl Session for RandomKey {
8588
async fn request_identities(&mut self) -> Result<Vec<Identity>, AgentError> {
8689
let identity = self.private_key.lock().unwrap();
8790
Ok(vec![Identity {
88-
pubkey: PublicKey::from(identity.deref()).into(),
91+
pubkey: PublicCredential::Key(PublicKey::from(identity.deref()).into()),
8992
comment: identity.comment().into(),
9093
}])
9194
}

src/proto/message.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Agent protocol message structures.
22
33
mod add_remove;
4+
mod credential;
45
mod extension;
56
mod identity;
67
mod request;
@@ -9,7 +10,8 @@ mod sign;
910
mod unparsed;
1011

1112
pub use self::{
12-
add_remove::*, extension::*, identity::*, request::*, response::*, sign::*, unparsed::*,
13+
add_remove::*, credential::*, extension::*, identity::*, request::*, response::*, sign::*,
14+
unparsed::*,
1315
};
1416
#[doc(hidden)]
1517
/// For compatibility with pre-0.5.0 type alias in this module

src/proto/message/add_remove.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
//! Add a key to an agent with or without constraints and supporting data types.
22
33
mod constrained;
4-
mod credential;
54

65
pub use constrained::*;
7-
pub use credential::*;
86
use secrecy::ExposeSecret as _;
97
use secrecy::SecretString;
108
use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
119
use ssh_key::public::KeyData;
1210

11+
use super::PrivateCredential;
1312
use crate::proto::{Error, Result};
1413

1514
/// Add a key to an agent.
@@ -20,14 +19,14 @@ use crate::proto::{Error, Result};
2019
#[derive(Clone, PartialEq, Debug)]
2120
pub struct AddIdentity {
2221
/// A credential (private & public key, or private key / certificate) to add to the agent
23-
pub credential: Credential,
22+
pub credential: PrivateCredential,
2423
}
2524

2625
impl Decode for AddIdentity {
2726
type Error = Error;
2827

2928
fn decode(reader: &mut impl Reader) -> Result<Self> {
30-
let credential = Credential::decode(reader)?;
29+
let credential = PrivateCredential::decode(reader)?;
3130

3231
Ok(Self { credential })
3332
}

src/proto/message/add_remove/credential.rs renamed to src/proto/message/credential.rs

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! A container for a public / private key pair, or a certificate / private key.
22
3-
use core::str::FromStr;
3+
use std::str::FromStr as _;
44

55
use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
6+
use ssh_key::public::KeyData;
67
use ssh_key::{certificate::Certificate, private::KeypairData, Algorithm};
78

89
use crate::proto::{Error, PrivateKeyData, Result};
@@ -16,7 +17,7 @@ use crate::proto::{Error, PrivateKeyData, Result};
1617
/// This structure covers both types of identities a user may
1718
/// send to an agent as part of a [`Request::AddIdentity`](crate::proto::Request::AddIdentity) message.
1819
#[derive(Clone, PartialEq, Debug)]
19-
pub enum Credential {
20+
pub enum PrivateCredential {
2021
/// A public/private key pair
2122
Key {
2223
/// Public/private key pair data
@@ -42,37 +43,39 @@ pub enum Credential {
4243
},
4344
}
4445

45-
impl Decode for Credential {
46+
impl Decode for PrivateCredential {
4647
type Error = Error;
4748

4849
fn decode(reader: &mut impl Reader) -> Result<Self> {
4950
let alg = String::decode(reader)?;
5051
let cert_alg = Algorithm::new_certificate(&alg);
5152

5253
if let Ok(algorithm) = cert_alg {
53-
let certificate = reader.read_prefixed(|reader| {
54-
let cert = Certificate::decode(reader)?;
55-
Ok::<_, Error>(cert)
56-
})?;
54+
let certificate = reader
55+
.read_prefixed(|reader| {
56+
let cert = Certificate::decode(reader)?;
57+
Ok::<_, Error>(cert)
58+
})?
59+
.into();
5760
let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?;
5861
let comment = String::decode(reader)?;
5962

60-
Ok(Credential::Cert {
63+
Ok(PrivateCredential::Cert {
6164
algorithm,
62-
certificate: Box::new(certificate),
65+
certificate,
6366
privkey,
6467
comment,
6568
})
6669
} else {
6770
let algorithm = Algorithm::from_str(&alg).map_err(ssh_encoding::Error::from)?;
6871
let privkey = KeypairData::decode_as(reader, algorithm)?;
6972
let comment = String::decode(reader)?;
70-
Ok(Credential::Key { privkey, comment })
73+
Ok(PrivateCredential::Key { privkey, comment })
7174
}
7275
}
7376
}
7477

75-
impl Encode for Credential {
78+
impl Encode for PrivateCredential {
7679
fn encoded_len(&self) -> ssh_encoding::Result<usize> {
7780
match self {
7881
Self::Key { privkey, comment } => {
@@ -113,3 +116,62 @@ impl Encode for Credential {
113116
}
114117
}
115118
}
119+
120+
#[derive(Debug, PartialEq, Eq, Clone)]
121+
/// Represents a public credential.
122+
pub enum PublicCredential {
123+
/// Plain public key.
124+
Key(KeyData),
125+
/// Signed public key.
126+
Cert(Box<Certificate>),
127+
}
128+
129+
impl PublicCredential {
130+
/// Returns a reference to the [KeyData].
131+
pub fn key_data(&self) -> &KeyData {
132+
match self {
133+
Self::Key(key) => key,
134+
Self::Cert(cert) => cert.public_key(),
135+
}
136+
}
137+
}
138+
139+
impl Decode for PublicCredential {
140+
type Error = Error;
141+
142+
fn decode(reader: &mut impl Reader) -> core::result::Result<Self, Self::Error> {
143+
// TODO: implement parsing certificates
144+
Ok(Self::Key(KeyData::decode(reader)?))
145+
}
146+
}
147+
148+
impl Encode for PublicCredential {
149+
fn encoded_len(&self) -> std::result::Result<usize, ssh_encoding::Error> {
150+
match self {
151+
Self::Key(pubkey) => pubkey.encoded_len(),
152+
Self::Cert(certificate) => certificate.encoded_len(),
153+
}
154+
}
155+
156+
fn encode(
157+
&self,
158+
writer: &mut impl ssh_encoding::Writer,
159+
) -> std::result::Result<(), ssh_encoding::Error> {
160+
match self {
161+
Self::Key(pubkey) => pubkey.encode(writer),
162+
Self::Cert(certificate) => certificate.encode(writer),
163+
}
164+
}
165+
}
166+
167+
impl From<KeyData> for PublicCredential {
168+
fn from(value: KeyData) -> Self {
169+
Self::Key(value)
170+
}
171+
}
172+
173+
impl From<Certificate> for PublicCredential {
174+
fn from(value: Certificate) -> Self {
175+
Self::Cert(value.into())
176+
}
177+
}

src/proto/message/identity.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Data returned to the client when listing keys.
22
33
use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
4-
use ssh_key::public::KeyData;
54

5+
use super::PublicCredential;
66
use crate::proto::{Error, Result};
77

88
/// Data returned to the client when listing keys.
@@ -13,7 +13,7 @@ use crate::proto::{Error, Result};
1313
#[derive(Clone, PartialEq, Debug)]
1414
pub struct Identity {
1515
/// A standard public-key encoding of an underlying key.
16-
pub pubkey: KeyData,
16+
pub pubkey: PublicCredential,
1717

1818
/// A human-readable comment
1919
pub comment: String,
@@ -36,7 +36,7 @@ impl Decode for Identity {
3636
type Error = Error;
3737

3838
fn decode(reader: &mut impl Reader) -> Result<Self> {
39-
let pubkey = reader.read_prefixed(KeyData::decode)?;
39+
let pubkey = reader.read_prefixed(PublicCredential::decode)?;
4040
let comment = String::decode(reader)?;
4141

4242
Ok(Self { pubkey, comment })

src/proto/message/sign.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Signature request with data to be signed with a key in an agent.
22
33
use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
4-
use ssh_key::public::KeyData;
54

5+
use super::PublicCredential;
66
use crate::proto::{Error, Result};
77

88
/// Signature request with data to be signed with a key in an agent.
@@ -13,7 +13,7 @@ use crate::proto::{Error, Result};
1313
#[derive(Clone, PartialEq, Debug)]
1414
pub struct SignRequest {
1515
/// The public key portion of the [`Identity`](super::Identity) in the agent to sign the data with
16-
pub pubkey: KeyData,
16+
pub pubkey: PublicCredential,
1717

1818
/// Binary data to be signed
1919
pub data: Vec<u8>,
@@ -27,7 +27,7 @@ impl Decode for SignRequest {
2727
type Error = Error;
2828

2929
fn decode(reader: &mut impl Reader) -> Result<Self> {
30-
let pubkey = reader.read_prefixed(KeyData::decode)?;
30+
let pubkey = reader.read_prefixed(PublicCredential::decode)?;
3131
let data = Vec::decode(reader)?;
3232
let flags = u32::decode(reader)?;
3333

909 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)