ssh_agent_lib/proto/message/
add_remove.rs

1//! Add a key to an agent with or without constraints and supporting data types.
2
3mod constrained;
4mod credential;
5
6pub use constrained::*;
7pub use credential::*;
8use secrecy::ExposeSecret as _;
9use secrecy::SecretString;
10use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
11use ssh_key::public::KeyData;
12
13use crate::proto::{Error, Result};
14
15/// Add a key to an agent.
16///
17/// This structure is sent in a [`Request::AddIdentity`](super::Request::AddIdentity) (`SSH_AGENTC_ADD_IDENTITY`) message.
18///
19/// Described in [draft-miller-ssh-agent-14 § 3.2](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-3.2)
20#[derive(Clone, PartialEq, Debug)]
21pub struct AddIdentity {
22    /// A credential (private & public key, or private key / certificate) to add to the agent
23    pub credential: Credential,
24}
25
26impl Decode for AddIdentity {
27    type Error = Error;
28
29    fn decode(reader: &mut impl Reader) -> Result<Self> {
30        let credential = Credential::decode(reader)?;
31
32        Ok(Self { credential })
33    }
34}
35
36impl Encode for AddIdentity {
37    fn encoded_len(&self) -> ssh_encoding::Result<usize> {
38        self.credential.encoded_len()
39    }
40
41    fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
42        self.credential.encode(writer)
43    }
44}
45
46/// Pointer to a key in a hardware token, along with an optional PIN.
47///
48/// This structure is sent in a [`Request::AddSmartcardKey`](super::Request::AddSmartcardKey) (`SSH_AGENTC_ADD_SMARTCARD_KEY`) message.
49///
50/// Described in [draft-miller-ssh-agent-14 § 3.2](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-3.2)
51#[derive(Clone, Debug)]
52pub struct SmartcardKey {
53    /// An opaque identifier for the hardware token
54    ///
55    /// Note: the interpretation of "id" is not defined by the protocol,
56    /// but is left solely up to the agent.
57    pub id: String,
58
59    /// An optional password to unlock the key
60    pub pin: SecretString,
61}
62
63impl Decode for SmartcardKey {
64    type Error = Error;
65
66    fn decode(reader: &mut impl Reader) -> Result<Self> {
67        let id = String::decode(reader)?;
68        let pin = String::decode(reader)?.into();
69
70        Ok(Self { id, pin })
71    }
72}
73
74impl Encode for SmartcardKey {
75    fn encoded_len(&self) -> ssh_encoding::Result<usize> {
76        [
77            self.id.encoded_len()?,
78            self.pin.expose_secret().encoded_len()?,
79        ]
80        .checked_sum()
81    }
82
83    fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
84        self.id.encode(writer)?;
85        self.pin.expose_secret().encode(writer)?;
86
87        Ok(())
88    }
89}
90
91impl PartialEq for SmartcardKey {
92    fn eq(&self, other: &Self) -> bool {
93        self.id == other.id && self.pin.expose_secret() == other.pin.expose_secret()
94    }
95}
96
97/// Remove a key from an agent.
98///
99/// This structure is sent in a [`Request::RemoveIdentity`](super::Request::RemoveIdentity) (`SSH_AGENTC_REMOVE_IDENTITY`) message.
100///
101/// Described in [draft-miller-ssh-agent-14 § 3.4](https://www.ietf.org/archive/id/draft-miller-ssh-agent-14.html#section-3.4)
102#[derive(Clone, PartialEq, Debug)]
103pub struct RemoveIdentity {
104    /// The public key portion of the [`Identity`](super::Identity) to be removed
105    pub pubkey: KeyData,
106}
107
108impl Decode for RemoveIdentity {
109    type Error = Error;
110
111    fn decode(reader: &mut impl Reader) -> Result<Self> {
112        let pubkey = reader.read_prefixed(KeyData::decode)?;
113
114        Ok(Self { pubkey })
115    }
116}
117
118impl Encode for RemoveIdentity {
119    fn encoded_len(&self) -> ssh_encoding::Result<usize> {
120        self.pubkey.encoded_len_prefixed()
121    }
122
123    fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
124        self.pubkey.encode_prefixed(writer)
125    }
126}