ipmi_rs/connection/impls/rmcp/v2_0/messages/
open_session.rs1use std::num::NonZeroU32;
2
3use crate::app::auth::PrivilegeLevel;
4
5use super::RakpErrorStatusCode;
6
7use crate::connection::rmcp::v2_0::crypto::{
8 AuthenticationAlgorithm, ConfidentialityAlgorithm, IntegrityAlgorithm,
9};
10
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum AlgorithmPayloadError {
13 IncorrectDataLen,
14 IncorrectPayloadLenValue,
15 UnknownAuthAlgorithm(u8),
16 UnknownIntegrityAlgorithm(u8),
17 UnknownConfidentialityAlgorithm(u8),
18 UnknownPayloadType(u8),
19}
20
21#[derive(Debug, Clone, Copy)]
22pub enum AlgorithmPayload {
23 Authentication(AuthenticationAlgorithm),
24 Integrity(IntegrityAlgorithm),
25 Confidentiality(ConfidentialityAlgorithm),
26}
27
28impl AlgorithmPayload {
29 pub fn write(&self, null_byte: bool, buffer: &mut Vec<u8>) {
30 let (ty, value) = match *self {
31 Self::Authentication(a) => (0x00, u8::from(a)),
32 Self::Integrity(i) => (0x01, u8::from(i)),
33 Self::Confidentiality(c) => (0x02, u8::from(c)),
34 };
35
36 assert!((value & 0xC0) == 0);
38
39 buffer.push(ty);
41
42 buffer.extend_from_slice(&[0x00, 0x00]);
44
45 if null_byte {
47 buffer.push(0x00)
48 } else {
49 buffer.push(0x08);
50 }
51
52 buffer.push(value);
54
55 buffer.extend_from_slice(&[0x00, 0x00, 0x00]);
57 }
58
59 pub fn from_data(data: &[u8]) -> Result<Self, AlgorithmPayloadError> {
60 use AlgorithmPayloadError::*;
61
62 if data.len() != 8 {
63 return Err(IncorrectDataLen);
64 }
65
66 let ty = data[0];
67 let payload_len = data[3];
68
69 if payload_len != 8 {
70 return Err(IncorrectPayloadLenValue);
71 }
72
73 let algo = data[4];
74
75 match ty {
76 0x00 => {
77 let algo = AuthenticationAlgorithm::try_from(algo)
78 .map_err(|_| UnknownAuthAlgorithm(algo))?;
79 Ok(Self::Authentication(algo))
80 }
81 0x01 => {
82 let algo = IntegrityAlgorithm::try_from(algo)
83 .map_err(|_| UnknownIntegrityAlgorithm(algo))?;
84 Ok(Self::Integrity(algo))
85 }
86 0x02 => {
87 let algo = ConfidentialityAlgorithm::try_from(algo)
88 .map_err(|_| UnknownConfidentialityAlgorithm(algo))?;
89 Ok(Self::Confidentiality(algo))
90 }
91 _ => Err(UnknownPayloadType(ty)),
92 }
93 }
94}
95
96#[derive(Debug, Clone)]
97pub struct OpenSessionRequest {
98 pub message_tag: u8,
99 pub requested_max_privilege: Option<PrivilegeLevel>,
100 pub remote_console_session_id: NonZeroU32,
101 pub authentication_algorithms: AuthenticationAlgorithm,
105 pub integrity_algorithms: IntegrityAlgorithm,
106 pub confidentiality_algorithms: ConfidentialityAlgorithm,
107}
108
109impl OpenSessionRequest {
110 pub fn write_data(&self, buffer: &mut Vec<u8>) {
111 buffer.push(self.message_tag);
112 buffer.push(self.requested_max_privilege.map(Into::into).unwrap_or(0));
113
114 buffer.push(0);
116 buffer.push(0);
117
118 buffer.extend_from_slice(&self.remote_console_session_id.get().to_le_bytes());
119
120 AlgorithmPayload::Authentication(self.authentication_algorithms).write(false, buffer);
121 AlgorithmPayload::Integrity(self.integrity_algorithms).write(false, buffer);
122 AlgorithmPayload::Confidentiality(self.confidentiality_algorithms).write(false, buffer);
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq)]
127pub enum ParseSessionResponseError {
128 NotEnoughData,
129 HaveErrorCode(Result<OpenSessionResponseErrorStatusCode, u8>),
130 ZeroRemoteConsoleSessionId,
131 ZeroManagedSystemSessionId,
132 InvalidPrivilegeLevel(u8),
133 InvalidAlgorithmPayload,
134 AuthPayloadWasNonAuthAlgorithm,
135 IntegrityPayloadWasNonIntegrityAlgorithm,
136 ConfidentialityPayloadWasNonConfidentialityAlgorithm,
137 AlgorithmPayloadError(AlgorithmPayloadError),
138}
139
140#[derive(Debug, Clone, PartialEq)]
141pub struct OpenSessionResponse {
142 pub message_tag: u8,
143 pub maximum_privilege_level: PrivilegeLevel,
144 pub remote_console_session_id: NonZeroU32,
145 pub managed_system_session_id: NonZeroU32,
146 pub authentication_payload: AuthenticationAlgorithm,
147 pub integrity_payload: IntegrityAlgorithm,
148 pub confidentiality_payload: ConfidentialityAlgorithm,
149}
150
151impl OpenSessionResponse {
152 pub fn from_data(data: &[u8]) -> Result<Self, ParseSessionResponseError> {
153 use ParseSessionResponseError::*;
154
155 if data.len() < 2 {
156 return Err(NotEnoughData);
157 }
158
159 let message_tag = data[0];
160 let status_code = data[1];
161
162 if status_code != 00 {
163 return Err(HaveErrorCode(
164 OpenSessionResponseErrorStatusCode::try_from(status_code).map_err(|_| status_code),
165 ));
166 }
167
168 if data.len() != 36 {
169 return Err(NotEnoughData);
170 }
171
172 let max_privilege_level =
173 PrivilegeLevel::try_from(data[2]).map_err(|_| InvalidPrivilegeLevel(data[2]))?;
174
175 let remote_console_session_id = u32::from_le_bytes(data[4..8].try_into().unwrap());
176 let remote_console_session_id =
177 NonZeroU32::new(remote_console_session_id).ok_or(ZeroRemoteConsoleSessionId)?;
178 let managed_system_session_id = u32::from_le_bytes(data[8..12].try_into().unwrap());
179 let managed_system_session_id =
180 NonZeroU32::new(managed_system_session_id).ok_or(ZeroManagedSystemSessionId)?;
181
182 let authentication_payload =
183 match AlgorithmPayload::from_data(&data[12..20]).map_err(AlgorithmPayloadError)? {
184 AlgorithmPayload::Authentication(a) => a,
185 _ => return Err(AuthPayloadWasNonAuthAlgorithm),
186 };
187
188 let integrity_payload =
189 match AlgorithmPayload::from_data(&data[20..28]).map_err(AlgorithmPayloadError)? {
190 AlgorithmPayload::Integrity(i) => i,
191 _ => return Err(IntegrityPayloadWasNonIntegrityAlgorithm),
192 };
193
194 let confidentiality_payload =
195 match AlgorithmPayload::from_data(&data[28..36]).map_err(AlgorithmPayloadError)? {
196 AlgorithmPayload::Confidentiality(c) => c,
197 _ => return Err(ConfidentialityPayloadWasNonConfidentialityAlgorithm),
198 };
199
200 Ok(Self {
201 message_tag,
202 maximum_privilege_level: max_privilege_level,
203 remote_console_session_id,
204 managed_system_session_id,
205 authentication_payload,
206 integrity_payload,
207 confidentiality_payload,
208 })
209 }
210}
211
212#[derive(Debug, Clone, Copy, PartialEq)]
213#[repr(u8)]
214pub enum OpenSessionResponseErrorStatusCode {
215 CommonRakp(RakpErrorStatusCode),
216 InvalidPayloadType = 0x03,
217 InvalidAuthenticationAlgorithm = 0x04,
218 InvalidIntegrityAlgorithm = 0x05,
219 InvalidConfidentialityAlgorithm = 0x10,
220 NoMatchingAuthenticationPayload = 0x06,
221 NoMatchingIntegrityPayload = 0x07,
222 NoMatchingCipherSuite = 0x011,
223 InvalidRole = 0x09,
224}
225
226impl TryFrom<u8> for OpenSessionResponseErrorStatusCode {
227 type Error = ();
228
229 fn try_from(value: u8) -> Result<Self, Self::Error> {
230 use OpenSessionResponseErrorStatusCode::*;
231
232 if let Ok(common) = TryFrom::try_from(value) {
233 return Ok(CommonRakp(common));
234 }
235
236 let value = match value {
237 0x03 => InvalidPayloadType,
238 0x04 => InvalidAuthenticationAlgorithm,
239 0x05 => InvalidIntegrityAlgorithm,
240 0x10 => InvalidConfidentialityAlgorithm,
241 0x06 => NoMatchingAuthenticationPayload,
242 0x07 => NoMatchingIntegrityPayload,
243 0x11 => NoMatchingCipherSuite,
244 0x09 => InvalidRole,
245 _ => return Err(()),
246 };
247
248 Ok(value)
249 }
250}
251
252#[test]
253pub fn from_data() {
254 let data = [
255 0x00, 0x00, 0x04, 0x00, 0xa4, 0xa3, 0xa2, 0x0a, 0xe0, 0x34, 0x71, 0x4a, 0x00, 0x00, 0x00,
256 0x08, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
257 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
258 ];
259
260 let message = OpenSessionResponse::from_data(&data).unwrap();
261
262 let expected = OpenSessionResponse {
263 message_tag: 0x00,
264 maximum_privilege_level: PrivilegeLevel::Administrator,
265 remote_console_session_id: NonZeroU32::new(0x0aa2a3a4).unwrap(),
266 managed_system_session_id: NonZeroU32::new(0x4a7134e0).unwrap(),
267 authentication_payload: AuthenticationAlgorithm::RakpHmacSha1,
268 integrity_payload: IntegrityAlgorithm::HmacSha1_96,
269 confidentiality_payload: ConfidentialityAlgorithm::None,
270 };
271
272 assert_eq!(message, expected);
273}