1 #pragma once 2 3 #include <chrono> 4 #include <exception> 5 #include <list> 6 #include <memory> 7 #include <string> 8 #include <vector> 9 10 #include "auth_algo.hpp" 11 #include "crypt_algo.hpp" 12 #include "integrity_algo.hpp" 13 #include "endian.hpp" 14 #include "socket_channel.hpp" 15 16 namespace session 17 { 18 19 using namespace std::chrono_literals; 20 using SessionID = uint32_t; 21 22 enum class Privilege : uint8_t 23 { 24 HIGHEST_MATCHING, 25 CALLBACK, 26 USER, 27 OPERATOR, 28 ADMIN, 29 OEM, 30 }; 31 32 enum class State 33 { 34 INACTIVE, // Session is not in use 35 SETUP_IN_PROGRESS, // Session Setup Sequence is progressing 36 ACTIVE, // Session is active 37 TEAR_DOWN_IN_PROGRESS,// When Closing Session 38 }; 39 40 // Seconds of inactivity allowed during session setup stage 41 constexpr auto SESSION_SETUP_TIMEOUT = 5s; 42 // Seconds of inactivity allowed when session is active 43 constexpr auto SESSION_INACTIVITY_TIMEOUT = 60s; 44 45 /* 46 * @struct SequenceNumbers Session Sequence Numbers 47 * 48 * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that 49 * may have been duplicated by the network or intentionally replayed. There are 50 * two sets of Session SequenceNumbers for a given session.One set of inbound 51 * and outbound sequence numbers is used for authenticated (signed) packets, 52 * and the other set is used for unauthenticated packets. 53 * 54 * The individual Session Sequence Numbers is are initialized to zero whenever 55 * a session is created and incremented by one at the start of outbound 56 * processing for a given packet (i.e. the first transmitted packet has a ‘1’ 57 * as the sequence number, not 0). Session Sequence numbers are incremented for 58 * every packet that is transmitted by a given sender, regardless of whether 59 * the payload for the packet is a ‘retry’ or not. 60 */ 61 struct SequenceNumbers 62 { 63 auto get(bool inbound = true) const 64 { 65 return inbound ? in : out; 66 } 67 68 void set(uint32_t seqNumber, bool inbound = true) 69 { 70 inbound ? (in = seqNumber) : (out = seqNumber); 71 } 72 73 auto increment() 74 { 75 return ++out; 76 } 77 78 private: 79 uint32_t in = 0; 80 uint32_t out = 0; 81 }; 82 /* 83 * @class Session 84 * 85 * Encapsulates the data related to an IPMI Session 86 * 87 * Authenticated IPMI communication to the BMC is accomplished by establishing 88 * a session. Once established, a session is identified by a Session ID. The 89 * Session ID may be thought of as a handle that identifies a connection between 90 * a given remote user and the BMC. The specification supports having multiple 91 * active sessions established with the BMC. It is recommended that a BMC 92 * implementation support at least four simultaneous sessions 93 */ 94 class Session 95 { 96 public: 97 98 Session() = default; 99 ~Session() = default; 100 Session(const Session&) = delete; 101 Session& operator=(const Session&) = delete; 102 Session(Session&&) = default; 103 Session& operator=(Session&&) = default; 104 105 /* 106 * @brief Session Constructor 107 * 108 * This is issued by the Session Manager when a session is started for 109 * the Open SessionRequest command 110 * 111 * @param[in] inRemoteConsoleSessID - Remote Console Session ID 112 * @param[in] priv - Privilege Level requested in the Command 113 */ 114 Session(SessionID inRemoteConsoleSessID, Privilege priv): 115 curPrivLevel(priv), 116 bmcSessionID(std::rand()), 117 remoteConsoleSessionID(inRemoteConsoleSessID) {} 118 119 auto getBMCSessionID() const 120 { 121 return bmcSessionID; 122 } 123 124 auto getRCSessionID() const 125 { 126 return remoteConsoleSessionID; 127 } 128 129 auto getAuthAlgo() const 130 { 131 if(authAlgoInterface) 132 { 133 return authAlgoInterface.get(); 134 } 135 else 136 { 137 throw std::runtime_error("Authentication Algorithm Empty"); 138 } 139 } 140 141 void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& 142 inAuthAlgo) 143 { 144 authAlgoInterface = std::move(inAuthAlgo); 145 } 146 147 /* 148 * @brief Get Session's Integrity Algorithm 149 * 150 * @return pointer to the integrity algorithm 151 */ 152 auto getIntegrityAlgo() const 153 { 154 if(integrityAlgoInterface) 155 { 156 return integrityAlgoInterface.get(); 157 } 158 else 159 { 160 throw std::runtime_error("Integrity Algorithm Empty"); 161 } 162 } 163 164 /* 165 * @brief Set Session's Integrity Algorithm 166 * 167 * @param[in] integrityAlgo - unique pointer to integrity algorithm 168 * instance 169 */ 170 void setIntegrityAlgo( 171 std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo) 172 { 173 integrityAlgoInterface = std::move(integrityAlgo); 174 } 175 176 /** @brief Check if integrity algorithm is enabled for this session. 177 * 178 * @return true if integrity algorithm is enabled else false. 179 */ 180 auto isIntegrityAlgoEnabled() 181 { 182 return integrityAlgoInterface ? true : false; 183 } 184 185 /* 186 * @brief Get Session's Confidentiality Algorithm 187 * 188 * @return pointer to the confidentiality algorithm 189 */ 190 auto getCryptAlgo() const 191 { 192 if(cryptAlgoInterface) 193 { 194 return cryptAlgoInterface.get(); 195 } 196 else 197 { 198 throw std::runtime_error("Confidentiality Algorithm Empty"); 199 } 200 } 201 202 /* 203 * @brief Set Session's Confidentiality Algorithm 204 * 205 * @param[in] confAlgo - unique pointer to confidentiality algorithm 206 * instance 207 */ 208 void setCryptAlgo( 209 std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo) 210 { 211 cryptAlgoInterface = std::move(cryptAlgo); 212 } 213 214 /** @brief Check if confidentiality algorithm is enabled for this 215 * session. 216 * 217 * @return true if confidentiality algorithm is enabled else false. 218 */ 219 auto isCryptAlgoEnabled() 220 { 221 return cryptAlgoInterface ? true : false; 222 } 223 224 void updateLastTransactionTime() 225 { 226 lastTime = std::chrono::steady_clock::now(); 227 } 228 229 /* 230 * @brief Session Active Status 231 * 232 * Session Active status is decided upon the Session State and the last 233 * transaction time is compared against the session inactivity timeout. 234 * 235 */ 236 bool isSessionActive(); 237 238 /* 239 * @brief Session's Current Privilege Level 240 */ 241 Privilege curPrivLevel; 242 243 /* 244 * @brief Session's Maximum Privilege Level 245 */ 246 Privilege maxPrivLevel = Privilege::CALLBACK; 247 248 SequenceNumbers sequenceNums; // Session Sequence Numbers 249 State state = State::INACTIVE; // Session State 250 std::vector<char> userName; // User Name 251 252 private: 253 254 SessionID bmcSessionID = 0; //BMC Session ID 255 SessionID remoteConsoleSessionID = 0; //Remote Console Session ID 256 257 // Authentication Algorithm Interface for the Session 258 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface; 259 260 // Integrity Algorithm Interface for the Session 261 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface = 262 nullptr; 263 264 // Confidentiality Algorithm Interface for the Session 265 std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = 266 nullptr; 267 268 // Last Transaction Time 269 decltype(std::chrono::steady_clock::now()) lastTime; 270 }; 271 272 } // namespace session 273