ssh_agent_lib/proto/message/
response.rs

1//! SSH agent protocol response messages.
2use ssh_encoding::{CheckedSum, Decode, Encode, Reader, Writer};
3use ssh_key::Signature;
4
5use super::{Extension, Identity};
6use crate::proto::{Error, Result};
7
8/// SSH agent protocol response messages.
9///
10/// These message types are sent to a client *from* an agent (in response to a [`Request`](super::Request) message).
11///
12/// Described in [draft-miller-ssh-agent-14 § 3](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-3).
13#[derive(Clone, PartialEq, Debug)]
14pub enum Response {
15    /// Indicates generic agent failure
16    Failure,
17
18    /// Indicates generic agent success
19    Success,
20
21    /// A list of identities, sent in response to
22    /// a [`Request::RequestIdentities`](super::Request::RequestIdentities) message.
23    IdentitiesAnswer(Vec<Identity>),
24
25    /// A signature, sent in response to
26    /// a [`Request::SignRequest`](super::Request::SignRequest) message.
27    SignResponse(Signature),
28
29    /// Indicates generic extension failure
30    ExtensionFailure,
31
32    /// Send a vendor-specific response message via the agent protocol,
33    /// identified by an *extension type*.
34    ExtensionResponse(Extension),
35}
36
37impl Response {
38    /// The protocol message identifier for a given [`Response`](super::Response) message type.
39    ///
40    /// Described in [draft-miller-ssh-agent-14 § 6.1](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-6.1).
41    pub fn message_id(&self) -> u8 {
42        match self {
43            Self::Failure => 5,
44            Self::Success => 6,
45            Self::IdentitiesAnswer(_) => 12,
46            Self::SignResponse(_) => 14,
47            Self::ExtensionFailure => 28,
48            Self::ExtensionResponse(_) => 29,
49        }
50    }
51}
52
53impl Decode for Response {
54    type Error = Error;
55
56    fn decode(reader: &mut impl Reader) -> Result<Self> {
57        let message_type = u8::decode(reader)?;
58
59        match message_type {
60            5 => Ok(Self::Failure),
61            6 => Ok(Self::Success),
62            12 => Identity::decode_vec(reader).map(Self::IdentitiesAnswer),
63            14 => {
64                Ok(reader
65                    .read_prefixed(|reader| Signature::decode(reader).map(Self::SignResponse))?)
66            }
67            28 => Ok(Self::ExtensionFailure),
68            29 => Extension::decode(reader).map(Self::ExtensionResponse),
69            command => Err(Error::UnsupportedCommand { command }),
70        }
71    }
72}
73
74impl Encode for Response {
75    fn encoded_len(&self) -> ssh_encoding::Result<usize> {
76        let message_id_len = 1;
77        let payload_len = match self {
78            Self::Failure => 0,
79            Self::Success => 0,
80            Self::IdentitiesAnswer(ids) => {
81                let mut lengths = Vec::with_capacity(1 + ids.len());
82                // Prefixed length
83                lengths.push(4);
84
85                for id in ids {
86                    lengths.push(id.encoded_len()?);
87                }
88
89                lengths.checked_sum()?
90            }
91            Self::SignResponse(response) => response.encoded_len_prefixed()?,
92            Self::ExtensionFailure => 0,
93            Self::ExtensionResponse(extension) => extension.encoded_len()?,
94        };
95
96        [message_id_len, payload_len].checked_sum()
97    }
98
99    fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
100        let message_id: u8 = self.message_id();
101        message_id.encode(writer)?;
102
103        match self {
104            Self::Failure => {}
105            Self::Success => {}
106            Self::IdentitiesAnswer(ids) => {
107                (ids.len() as u32).encode(writer)?;
108                for id in ids {
109                    id.encode(writer)?;
110                }
111            }
112            Self::SignResponse(response) => response.encode_prefixed(writer)?,
113            Self::ExtensionFailure => {}
114            Self::ExtensionResponse(extension) => extension.encode(writer)?,
115        };
116
117        Ok(())
118    }
119}