ipmi_rs_core/app/auth/
mod.rs

1//! IPMI authentication commands.
2
3mod get_channel_authentication_capabilities;
4use core::cmp::Ordering;
5
6pub use get_channel_authentication_capabilities::{
7    ChannelAuthenticationCapabilities, GetChannelAuthenticationCapabilities,
8};
9
10mod get_session_challenge;
11pub use get_session_challenge::{GetSessionChallenge, SessionChallenge};
12
13mod activate_session;
14pub use activate_session::{ActivateSession, BeginSessionInfo};
15
16mod get_channel_cipher_suites;
17pub use get_channel_cipher_suites::{ChannelCipherSuites, CipherSuite, GetChannelCipherSuites};
18
19mod algorithms;
20pub use algorithms::*;
21
22/// Errors that can occur during authentication.
23#[derive(Debug, Clone)]
24pub enum AuthError {
25    /// One of the exchanged authentication responses did not
26    /// contain enough data to parse the expected message.
27    NotEnoughData,
28    /// A non-zero session ID was received at a stage where
29    /// non-zero session numbers are not allowed.
30    InvalidZeroSession,
31    /// An invalid auth type was encountered.
32    InvalidAuthType(u8),
33    /// An unknown privilege level was encountered.
34    InvalidPrivilegeLevel(u8),
35}
36
37/// The authentication type that is used.
38#[allow(missing_docs)]
39#[derive(Debug, Clone, Copy, PartialEq)]
40pub enum AuthType {
41    None,
42    MD2,
43    MD5,
44    Key,
45}
46
47impl AuthType {
48    /// Compare the strength of an authentication type. [`Ordering::Greater`] means
49    /// that `self` is stronger than `other`.
50    pub fn compare_strength(&self, other: &Self) -> Ordering {
51        if self == other {
52            Ordering::Equal
53        } else if self == &AuthType::None {
54            Ordering::Less
55        } else if other == &AuthType::None {
56            Ordering::Greater
57        } else if self == &AuthType::Key {
58            Ordering::Less
59        } else if other == &AuthType::Key {
60            Ordering::Greater
61        } else if self == &AuthType::MD2 {
62            Ordering::Less
63        } else {
64            Ordering::Greater
65        }
66    }
67}
68
69#[test]
70fn strength_ordering_individual() {
71    let gt_pairs = [
72        (AuthType::Key, AuthType::None),
73        (AuthType::MD2, AuthType::None),
74        (AuthType::MD5, AuthType::None),
75        (AuthType::MD2, AuthType::Key),
76        (AuthType::MD5, AuthType::Key),
77        (AuthType::MD5, AuthType::MD2),
78    ];
79
80    for (greater, lesser) in gt_pairs {
81        assert_eq!(greater.compare_strength(&lesser), Ordering::Greater);
82        assert_eq!(lesser.compare_strength(&greater), Ordering::Less);
83    }
84}
85
86#[test]
87fn strength_ordering() {
88    let types = [AuthType::None, AuthType::MD2, AuthType::MD5, AuthType::Key];
89
90    let max = types.into_iter().max_by(AuthType::compare_strength);
91    let min = types.into_iter().min_by(AuthType::compare_strength);
92
93    assert_eq!(max, Some(AuthType::MD5));
94    assert_eq!(min, Some(AuthType::None));
95}
96
97impl TryFrom<u8> for AuthType {
98    type Error = ();
99
100    fn try_from(value: u8) -> Result<Self, Self::Error> {
101        let value = match value {
102            0 => Self::None,
103            0x01 => Self::MD2,
104            0x02 => Self::MD5,
105            0x04 => Self::Key,
106            _ => return Err(()),
107        };
108
109        Ok(value)
110    }
111}
112
113impl From<AuthType> for u8 {
114    fn from(value: AuthType) -> Self {
115        match value {
116            AuthType::None => 0x00,
117            AuthType::MD2 => 0x01,
118            AuthType::MD5 => 0x02,
119            AuthType::Key => 0x04,
120        }
121    }
122}
123
124/// The privilege level of a session.
125#[allow(missing_docs)]
126#[derive(Debug, Clone, Copy, PartialEq)]
127pub enum PrivilegeLevel {
128    Callback,
129    User,
130    Operator,
131    Administrator,
132    OemProperietary,
133}
134
135impl TryFrom<u8> for PrivilegeLevel {
136    type Error = ();
137
138    fn try_from(value: u8) -> Result<Self, Self::Error> {
139        let value = value & 0x0F;
140        let level = match value {
141            1 => Self::Callback,
142            2 => Self::User,
143            3 => Self::Operator,
144            4 => Self::Administrator,
145            5 => Self::OemProperietary,
146            _ => return Err(()),
147        };
148        Ok(level)
149    }
150}
151
152impl From<PrivilegeLevel> for u8 {
153    fn from(value: PrivilegeLevel) -> Self {
154        match value {
155            PrivilegeLevel::Callback => 1,
156            PrivilegeLevel::User => 2,
157            PrivilegeLevel::Operator => 3,
158            PrivilegeLevel::Administrator => 4,
159            PrivilegeLevel::OemProperietary => 5,
160        }
161    }
162}