leodos_protocols/datalink/security/sdls/
sa_mgmt.rs1use super::Error;
10use super::SecurityAssociation;
11use super::ServiceType;
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq)]
15pub enum SaState {
16 Unkeyed,
18 Keyed,
20 Operational,
22}
23
24pub struct ManagedSa {
26 pub sa: SecurityAssociation,
28 pub state: SaState,
30 pub key_id: Option<u16>,
32}
33
34pub const MAX_SAS: usize = 64;
36
37impl ManagedSa {
38 pub fn new(spi: u16, service_type: ServiceType) -> Result<Self, Error> {
40 if spi == 0 || spi == 0xFFFF {
41 return Err(Error::ReservedSpi(spi));
42 }
43 Ok(Self {
44 sa: SecurityAssociation {
45 spi,
46 service_type,
47 iv_len: 0,
48 sn_len: 0,
49 pl_len: 0,
50 mac_len: 0,
51 sequence_number: 0,
52 sequence_window: 0,
53 auth_mask: heapless::Vec::new(),
54 },
55 state: SaState::Unkeyed,
56 key_id: None,
57 })
58 }
59
60 pub fn rekey(&mut self, key_id: u16) -> Result<(), Error> {
64 (self.state == SaState::Unkeyed)
65 .then(|| {
66 self.key_id = Some(key_id);
67 self.state = SaState::Keyed;
68 })
69 .ok_or(Error::InvalidSaState)
70 }
71
72 pub fn start(&mut self) -> Result<(), Error> {
74 (self.state == SaState::Keyed)
75 .then(|| self.state = SaState::Operational)
76 .ok_or(Error::InvalidSaState)
77 }
78
79 pub fn stop(&mut self) -> Result<(), Error> {
81 (self.state == SaState::Operational)
82 .then(|| self.state = SaState::Keyed)
83 .ok_or(Error::InvalidSaState)
84 }
85
86 pub fn expire(&mut self) -> Result<(), Error> {
90 (self.state == SaState::Keyed)
91 .then(|| {
92 self.key_id = None;
93 self.state = SaState::Unkeyed;
94 })
95 .ok_or(Error::InvalidSaState)
96 }
97
98 pub fn set_arsn(&mut self, arsn: u64) {
100 self.sa.sequence_number = arsn;
101 }
102
103 pub fn read_arsn(&self) -> u64 {
105 self.sa.sequence_number
106 }
107}
108
109pub struct SaTable {
111 entries: heapless::Vec<ManagedSa, MAX_SAS>,
112}
113
114impl SaTable {
115 pub fn new() -> Self {
117 Self {
118 entries: heapless::Vec::new(),
119 }
120 }
121
122 pub fn create(&mut self, spi: u16, service_type: ServiceType) -> Result<(), Error> {
124 if self.find(spi).is_some() {
125 return Err(Error::DuplicateSpi(spi));
126 }
127 let sa = ManagedSa::new(spi, service_type)?;
128 self.entries.push(sa).map_err(|_| Error::SaTableFull)
129 }
130
131 pub fn delete(&mut self, spi: u16) -> Result<(), Error> {
135 let pos = self
136 .entries
137 .iter()
138 .position(|e| e.sa.spi == spi)
139 .ok_or(Error::UnknownSpi(spi))?;
140 if self.entries[pos].state != SaState::Unkeyed {
141 return Err(Error::InvalidSaState);
142 }
143 self.entries.swap_remove(pos);
144 Ok(())
145 }
146
147 pub fn find(&self, spi: u16) -> Option<&ManagedSa> {
149 self.entries.iter().find(|e| e.sa.spi == spi)
150 }
151
152 pub fn find_mut(&mut self, spi: u16) -> Option<&mut ManagedSa> {
154 self.entries.iter_mut().find(|e| e.sa.spi == spi)
155 }
156
157 pub fn rekey(&mut self, spi: u16, key_id: u16) -> Result<(), Error> {
159 self.find_mut(spi)
160 .ok_or(Error::UnknownSpi(spi))?
161 .rekey(key_id)
162 }
163
164 pub fn start(&mut self, spi: u16) -> Result<(), Error> {
166 self.find_mut(spi)
167 .ok_or(Error::UnknownSpi(spi))?
168 .start()
169 }
170
171 pub fn stop(&mut self, spi: u16) -> Result<(), Error> {
173 self.find_mut(spi)
174 .ok_or(Error::UnknownSpi(spi))?
175 .stop()
176 }
177
178 pub fn expire(&mut self, spi: u16) -> Result<(), Error> {
180 self.find_mut(spi)
181 .ok_or(Error::UnknownSpi(spi))?
182 .expire()
183 }
184
185 pub fn set_arsn(&mut self, spi: u16, arsn: u64) -> Result<(), Error> {
187 self.find_mut(spi)
188 .ok_or(Error::UnknownSpi(spi))?
189 .set_arsn(arsn);
190 Ok(())
191 }
192
193 pub fn read_arsn(&self, spi: u16) -> Result<u64, Error> {
195 Ok(self.find(spi).ok_or(Error::UnknownSpi(spi))?.read_arsn())
196 }
197
198 pub fn iter(&self) -> impl Iterator<Item = &ManagedSa> {
200 self.entries.iter()
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn sa_lifecycle() {
210 let mut sa = ManagedSa::new(1, ServiceType::AuthenticatedEncryption).unwrap();
211 assert_eq!(sa.state, SaState::Unkeyed);
212
213 assert!(sa.start().is_err());
214 assert!(sa.stop().is_err());
215 assert!(sa.expire().is_err());
216
217 sa.rekey(10).unwrap();
218 assert_eq!(sa.state, SaState::Keyed);
219 assert_eq!(sa.key_id, Some(10));
220
221 assert!(sa.rekey(20).is_err());
223
224 sa.start().unwrap();
225 assert_eq!(sa.state, SaState::Operational);
226 assert!(sa.start().is_err());
227
228 assert!(sa.expire().is_err());
230
231 sa.stop().unwrap();
232 assert_eq!(sa.state, SaState::Keyed);
233
234 sa.expire().unwrap();
235 assert_eq!(sa.state, SaState::Unkeyed);
236 assert_eq!(sa.key_id, None);
237 }
238
239 #[test]
240 fn sa_table_crud() {
241 let mut table = SaTable::new();
242 table
243 .create(1, ServiceType::Authentication)
244 .unwrap();
245 table
246 .create(2, ServiceType::Encryption)
247 .unwrap();
248
249 assert!(table
250 .create(1, ServiceType::Authentication)
251 .is_err());
252
253 table.rekey(1, 100).unwrap();
254 table.start(1).unwrap();
255 assert_eq!(
256 table.find(1).unwrap().state,
257 SaState::Operational
258 );
259
260 assert!(table.delete(1).is_err());
262
263 table.stop(1).unwrap();
264 assert!(table.delete(1).is_err());
266
267 table.expire(1).unwrap();
268 table.delete(1).unwrap();
270 assert!(table.find(1).is_none());
271 }
272
273 #[test]
274 fn sa_table_arsn() {
275 let mut table = SaTable::new();
276 table
277 .create(5, ServiceType::AuthenticatedEncryption)
278 .unwrap();
279
280 table.set_arsn(5, 42).unwrap();
281 assert_eq!(table.read_arsn(5).unwrap(), 42);
282
283 assert!(table.set_arsn(99, 0).is_err());
284 }
285
286 #[test]
287 fn reserved_spi_rejected() {
288 assert!(ManagedSa::new(0, ServiceType::Authentication).is_err());
289 assert!(ManagedSa::new(0xFFFF, ServiceType::Authentication).is_err());
290 }
291}