ssh_agent_lib/proto/message/add_remove/
constrained.rs1use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
2use ssh_key::Error as KeyError;
3
4use crate::proto::{AddIdentity, Error, Extension, Result, SmartcardKey, Unparsed};
5
6#[derive(Clone, PartialEq, Debug)]
14pub enum KeyConstraint {
15 Lifetime(u32),
17
18 Confirm,
20
21 Extension(Extension),
31}
32
33impl Decode for KeyConstraint {
34 type Error = Error;
35
36 fn decode(reader: &mut impl Reader) -> Result<Self> {
37 let constraint_type = u8::decode(reader)?;
38 Ok(match constraint_type {
40 1 => KeyConstraint::Lifetime(u32::decode(reader)?),
41 2 => KeyConstraint::Confirm,
42 255 => {
43 let name = String::decode(reader)?;
44 let details: Vec<u8> = Vec::decode(reader)?;
45 KeyConstraint::Extension(Extension {
46 name,
47 details: Unparsed::from(details),
48 })
49 }
50 _ => return Err(KeyError::AlgorithmUnknown)?, })
52 }
53}
54
55impl Encode for KeyConstraint {
56 fn encoded_len(&self) -> ssh_encoding::Result<usize> {
57 let base = u8::MAX.encoded_len()?;
58
59 match self {
60 Self::Lifetime(lifetime) => base
61 .checked_add(lifetime.encoded_len()?)
62 .ok_or(ssh_encoding::Error::Length),
63 Self::Confirm => Ok(base),
64 Self::Extension(extension) => [
65 base,
66 extension.name.encoded_len()?,
67 extension.details.encoded_len_prefixed()?,
68 ]
69 .checked_sum(),
70 }
71 }
72
73 fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
74 match self {
75 Self::Lifetime(lifetime) => {
76 1u8.encode(writer)?;
77 lifetime.encode(writer)
78 }
79 Self::Confirm => 2u8.encode(writer),
80 Self::Extension(extension) => {
81 255u8.encode(writer)?;
82 extension.name.encode(writer)?;
83 extension.details.encode_prefixed(writer)
84 }
85 }
86 }
87}
88
89#[derive(Clone, PartialEq, Debug)]
97pub struct AddIdentityConstrained {
98 pub identity: AddIdentity,
100
101 pub constraints: Vec<KeyConstraint>,
103}
104
105impl Decode for AddIdentityConstrained {
106 type Error = Error;
107
108 fn decode(reader: &mut impl Reader) -> Result<Self> {
109 let identity = AddIdentity::decode(reader)?;
110 let mut constraints = vec![];
111
112 while !reader.is_finished() {
113 constraints.push(KeyConstraint::decode(reader)?);
114 }
115
116 Ok(Self {
117 identity,
118 constraints,
119 })
120 }
121}
122
123impl Encode for AddIdentityConstrained {
124 fn encoded_len(&self) -> ssh_encoding::Result<usize> {
125 self.constraints
126 .iter()
127 .try_fold(self.identity.encoded_len()?, |acc, e| {
128 let constraint_len = e.encoded_len()?;
129 usize::checked_add(acc, constraint_len).ok_or(ssh_encoding::Error::Length)
130 })
131 }
132
133 fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
134 self.identity.encode(writer)?;
135 for constraint in &self.constraints {
136 constraint.encode(writer)?;
137 }
138 Ok(())
139 }
140}
141
142#[derive(Clone, PartialEq, Debug)]
150pub struct AddSmartcardKeyConstrained {
151 pub key: SmartcardKey,
153
154 pub constraints: Vec<KeyConstraint>,
156}
157
158impl Decode for AddSmartcardKeyConstrained {
159 type Error = Error;
160
161 fn decode(reader: &mut impl Reader) -> Result<Self> {
162 let key = SmartcardKey::decode(reader)?;
163 let mut constraints = vec![];
164
165 while !reader.is_finished() {
166 constraints.push(KeyConstraint::decode(reader)?);
167 }
168 Ok(Self { key, constraints })
169 }
170}
171
172impl Encode for AddSmartcardKeyConstrained {
173 fn encoded_len(&self) -> ssh_encoding::Result<usize> {
174 self.constraints
175 .iter()
176 .try_fold(self.key.encoded_len()?, |acc, e| {
177 let constraint_len = e.encoded_len()?;
178 usize::checked_add(acc, constraint_len).ok_or(ssh_encoding::Error::Length)
179 })
180 }
181
182 fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
183 self.key.encode(writer)?;
184 for constraint in &self.constraints {
185 constraint.encode(writer)?;
186 }
187 Ok(())
188 }
189}