Skip to content

Commit 26df77f

Browse files
committed
Refactor proto::message::AddIdentity etc. to module
Signed-off-by: Ross Williams <ross@ross-williams.net>
1 parent abeb914 commit 26df77f

File tree

2 files changed

+206
-199
lines changed

2 files changed

+206
-199
lines changed

src/proto/message.rs

Lines changed: 6 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -1,215 +1,21 @@
11
//! Agent protocol message structures.
22
3+
pub mod add_identity;
34
pub mod identity;
45
pub mod sign;
56
pub mod unparsed;
67

7-
use core::str::FromStr;
8-
98
use ssh_encoding::{CheckedSum, Decode, Encode, Error as EncodingError, Reader, Writer};
10-
use ssh_key::{
11-
certificate::Certificate, private::KeypairData, public::KeyData, Algorithm, Error, Signature,
12-
};
9+
use ssh_key::{public::KeyData, Error, Signature};
1310

14-
pub use self::{identity::*, sign::*, unparsed::*};
11+
pub use self::{add_identity::*, identity::*, sign::*, unparsed::*};
1512
use super::{
1613
extension::{KeyConstraintExtension, MessageExtension},
17-
PrivateKeyData, ProtoError,
14+
ProtoError,
1815
};
1916

2017
type Result<T> = core::result::Result<T, ProtoError>;
2118

22-
/// A container for a public / private key pair, or a certificate / private key.
23-
///
24-
/// When adding an identity to an agent, a user can provide either:
25-
/// 1. A public / private key pair
26-
/// 2. An OpenSSH [certificate](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys)
27-
///
28-
/// This structure covers both types of identities a user may
29-
/// send to an agent as part of a [`Request::AddIdentity`] message.
30-
#[derive(Clone, PartialEq, Debug)]
31-
pub enum Credential {
32-
/// A public/private key pair
33-
Key {
34-
/// Public/private key pair data
35-
privkey: KeypairData,
36-
37-
/// Key comment, if any.
38-
comment: String,
39-
},
40-
41-
/// An OpenSSH [certificate](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys)
42-
Cert {
43-
/// Certificate algorithm.
44-
algorithm: Algorithm,
45-
46-
/// Certificate data.
47-
certificate: Certificate,
48-
49-
/// Private key data.
50-
privkey: PrivateKeyData,
51-
52-
/// Comment, if any.
53-
comment: String,
54-
},
55-
}
56-
57-
impl Decode for Credential {
58-
type Error = ProtoError;
59-
60-
fn decode(reader: &mut impl Reader) -> Result<Self> {
61-
let alg = String::decode(reader)?;
62-
let cert_alg = Algorithm::new_certificate(&alg);
63-
64-
if let Ok(algorithm) = cert_alg {
65-
let certificate = reader.read_prefixed(|reader| {
66-
let cert = Certificate::decode(reader)?;
67-
Ok::<_, ProtoError>(cert)
68-
})?;
69-
let privkey = PrivateKeyData::decode_as(reader, algorithm.clone())?;
70-
let comment = String::decode(reader)?;
71-
72-
Ok(Credential::Cert {
73-
algorithm,
74-
certificate,
75-
privkey,
76-
comment,
77-
})
78-
} else {
79-
let algorithm = Algorithm::from_str(&alg).map_err(EncodingError::from)?;
80-
let privkey = KeypairData::decode_as(reader, algorithm)?;
81-
let comment = String::decode(reader)?;
82-
Ok(Credential::Key { privkey, comment })
83-
}
84-
}
85-
}
86-
87-
impl Encode for Credential {
88-
fn encoded_len(&self) -> ssh_encoding::Result<usize> {
89-
match self {
90-
Self::Key { privkey, comment } => {
91-
[privkey.encoded_len()?, comment.encoded_len()?].checked_sum()
92-
}
93-
Self::Cert {
94-
algorithm,
95-
certificate,
96-
privkey,
97-
comment,
98-
} => [
99-
algorithm.to_certificate_type().encoded_len()?,
100-
certificate.encoded_len_prefixed()?,
101-
privkey.encoded_len()?,
102-
comment.encoded_len()?,
103-
]
104-
.checked_sum(),
105-
}
106-
}
107-
108-
fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
109-
match self {
110-
Self::Key { privkey, comment } => {
111-
privkey.encode(writer)?;
112-
comment.encode(writer)
113-
}
114-
Self::Cert {
115-
algorithm,
116-
certificate,
117-
privkey,
118-
comment,
119-
} => {
120-
algorithm.to_certificate_type().encode(writer)?;
121-
certificate.encode_prefixed(writer)?;
122-
privkey.encode(writer)?;
123-
comment.encode(writer)
124-
}
125-
}
126-
}
127-
}
128-
129-
/// Add a key to an agent.
130-
///
131-
/// This structure is sent in a [`Request::AddIdentity`] (`SSH_AGENTC_ADD_IDENTITY`) message.
132-
///
133-
/// Described in [draft-miller-ssh-agent-14 § 3.2](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-3.2)
134-
#[derive(Clone, PartialEq, Debug)]
135-
pub struct AddIdentity {
136-
/// A credential (private & public key, or private key / certificate) to add to the agent
137-
pub credential: Credential,
138-
}
139-
140-
impl Decode for AddIdentity {
141-
type Error = ProtoError;
142-
143-
fn decode(reader: &mut impl Reader) -> Result<Self> {
144-
let credential = Credential::decode(reader)?;
145-
146-
Ok(Self { credential })
147-
}
148-
}
149-
150-
impl Encode for AddIdentity {
151-
fn encoded_len(&self) -> ssh_encoding::Result<usize> {
152-
self.credential.encoded_len()
153-
}
154-
155-
fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
156-
self.credential.encode(writer)
157-
}
158-
}
159-
160-
/// Add a key to an agent, with constraints on it's use.
161-
///
162-
/// This structure is sent in a [`Request::AddIdConstrained`] (`SSH_AGENTC_ADD_ID_CONSTRAINED`) message.
163-
///
164-
/// This is a variant of [`Request::AddIdentity`] with a set of [`KeyConstraint`]s attached.
165-
///
166-
/// Described in [draft-miller-ssh-agent-14 § 3.2](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-3.2)
167-
#[derive(Clone, PartialEq, Debug)]
168-
pub struct AddIdentityConstrained {
169-
/// The credential to be added to the agent.
170-
pub identity: AddIdentity,
171-
172-
/// Constraints to be placed on the `identity`.
173-
pub constraints: Vec<KeyConstraint>,
174-
}
175-
176-
impl Decode for AddIdentityConstrained {
177-
type Error = ProtoError;
178-
179-
fn decode(reader: &mut impl Reader) -> Result<Self> {
180-
let identity = AddIdentity::decode(reader)?;
181-
let mut constraints = vec![];
182-
183-
while !reader.is_finished() {
184-
constraints.push(KeyConstraint::decode(reader)?);
185-
}
186-
187-
Ok(Self {
188-
identity,
189-
constraints,
190-
})
191-
}
192-
}
193-
194-
impl Encode for AddIdentityConstrained {
195-
fn encoded_len(&self) -> ssh_encoding::Result<usize> {
196-
self.constraints
197-
.iter()
198-
.try_fold(self.identity.encoded_len()?, |acc, e| {
199-
let constraint_len = e.encoded_len()?;
200-
usize::checked_add(acc, constraint_len).ok_or(EncodingError::Length)
201-
})
202-
}
203-
204-
fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
205-
self.identity.encode(writer)?;
206-
for constraint in &self.constraints {
207-
constraint.encode(writer)?;
208-
}
209-
Ok(())
210-
}
211-
}
212-
21319
/// Remove a key from an agent.
21420
///
21521
/// This structure is sent in a [`Request::RemoveIdentity`] (`SSH_AGENTC_REMOVE_IDENTITY`) message.
@@ -790,10 +596,11 @@ mod tests {
790596
};
791597
use ssh_key::{
792598
private::{EcdsaKeypair, EcdsaPrivateKey, KeypairData, RsaPrivateKey},
793-
Mpint,
599+
Algorithm, Certificate, Mpint,
794600
};
795601

796602
use super::*;
603+
use crate::proto::PrivateKeyData;
797604

798605
fn demo_key() -> EcdsaKeypair {
799606
EcdsaKeypair::NistP256 {

0 commit comments

Comments
 (0)