Skip to main content

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