|
1 | 1 | //! Agent protocol message structures.
|
2 | 2 |
|
| 3 | +pub mod add_identity; |
3 | 4 | pub mod identity;
|
4 | 5 | pub mod sign;
|
5 | 6 | pub mod unparsed;
|
6 | 7 |
|
7 |
| -use core::str::FromStr; |
8 |
| - |
9 | 8 | 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}; |
13 | 10 |
|
14 |
| -pub use self::{identity::*, sign::*, unparsed::*}; |
| 11 | +pub use self::{add_identity::*, identity::*, sign::*, unparsed::*}; |
15 | 12 | use super::{
|
16 | 13 | extension::{KeyConstraintExtension, MessageExtension},
|
17 |
| - PrivateKeyData, ProtoError, |
| 14 | + ProtoError, |
18 | 15 | };
|
19 | 16 |
|
20 | 17 | type Result<T> = core::result::Result<T, ProtoError>;
|
21 | 18 |
|
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 |
| - |
213 | 19 | /// Remove a key from an agent.
|
214 | 20 | ///
|
215 | 21 | /// This structure is sent in a [`Request::RemoveIdentity`] (`SSH_AGENTC_REMOVE_IDENTITY`) message.
|
@@ -790,10 +596,11 @@ mod tests {
|
790 | 596 | };
|
791 | 597 | use ssh_key::{
|
792 | 598 | private::{EcdsaKeypair, EcdsaPrivateKey, KeypairData, RsaPrivateKey},
|
793 |
| - Mpint, |
| 599 | + Algorithm, Certificate, Mpint, |
794 | 600 | };
|
795 | 601 |
|
796 | 602 | use super::*;
|
| 603 | + use crate::proto::PrivateKeyData; |
797 | 604 |
|
798 | 605 | fn demo_key() -> EcdsaKeypair {
|
799 | 606 | EcdsaKeypair::NistP256 {
|
|
0 commit comments