blob: bf136e308c23116769af8330db0167ad5b80ed3e [file] [log] [blame]
Tom Josephf0ca5132016-08-09 08:16:12 -05001#pragma once
2
Vernon Mauery9e801a22018-10-12 13:20:49 -07003#include "auth_algo.hpp"
4#include "crypt_algo.hpp"
5#include "endian.hpp"
6#include "integrity_algo.hpp"
Vernon Mauery8977d122018-10-24 14:02:16 -07007#include "prng.hpp"
Vernon Mauery9e801a22018-10-12 13:20:49 -07008#include "socket_channel.hpp"
9
Tom Josephf0ca5132016-08-09 08:16:12 -050010#include <chrono>
11#include <exception>
12#include <list>
13#include <memory>
14#include <string>
15#include <vector>
16
Tom Josephf0ca5132016-08-09 08:16:12 -050017namespace session
18{
19
20using namespace std::chrono_literals;
21using SessionID = uint32_t;
22
23enum class Privilege : uint8_t
24{
25 HIGHEST_MATCHING,
26 CALLBACK,
27 USER,
28 OPERATOR,
29 ADMIN,
30 OEM,
31};
32
33enum class State
34{
Vernon Mauery9e801a22018-10-12 13:20:49 -070035 INACTIVE, // Session is not in use
36 SETUP_IN_PROGRESS, // Session Setup Sequence is progressing
37 ACTIVE, // Session is active
38 TEAR_DOWN_IN_PROGRESS, // When Closing Session
Tom Josephf0ca5132016-08-09 08:16:12 -050039};
40
41// Seconds of inactivity allowed during session setup stage
42constexpr auto SESSION_SETUP_TIMEOUT = 5s;
43// Seconds of inactivity allowed when session is active
44constexpr auto SESSION_INACTIVITY_TIMEOUT = 60s;
45
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053046// Mask to get only the privilege from requested maximum privlege (RAKP message
47// 1)
48constexpr uint8_t reqMaxPrivMask = 0xF;
49
Tom Joseph3563f8f2017-05-08 15:42:54 +053050/**
Tom Josephf0ca5132016-08-09 08:16:12 -050051 * @struct SequenceNumbers Session Sequence Numbers
52 *
53 * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that
54 * may have been duplicated by the network or intentionally replayed. There are
55 * two sets of Session SequenceNumbers for a given session.One set of inbound
56 * and outbound sequence numbers is used for authenticated (signed) packets,
57 * and the other set is used for unauthenticated packets.
58 *
59 * The individual Session Sequence Numbers is are initialized to zero whenever
60 * a session is created and incremented by one at the start of outbound
61 * processing for a given packet (i.e. the first transmitted packet has a ‘1’
62 * as the sequence number, not 0). Session Sequence numbers are incremented for
63 * every packet that is transmitted by a given sender, regardless of whether
64 * the payload for the packet is a ‘retry’ or not.
65 */
66struct SequenceNumbers
67{
Vernon Mauery9e801a22018-10-12 13:20:49 -070068 auto get(bool inbound = true) const
69 {
70 return inbound ? in : out;
71 }
Tom Josephf0ca5132016-08-09 08:16:12 -050072
Vernon Mauery9e801a22018-10-12 13:20:49 -070073 void set(uint32_t seqNumber, bool inbound = true)
74 {
75 inbound ? (in = seqNumber) : (out = seqNumber);
76 }
Tom Josephf0ca5132016-08-09 08:16:12 -050077
Vernon Mauery9e801a22018-10-12 13:20:49 -070078 auto increment()
79 {
80 return ++out;
81 }
Tom Josephf0ca5132016-08-09 08:16:12 -050082
Vernon Mauery9e801a22018-10-12 13:20:49 -070083 private:
84 uint32_t in = 0;
85 uint32_t out = 0;
Tom Josephf0ca5132016-08-09 08:16:12 -050086};
Tom Joseph3563f8f2017-05-08 15:42:54 +053087/**
Tom Josephf0ca5132016-08-09 08:16:12 -050088 * @class Session
89 *
90 * Encapsulates the data related to an IPMI Session
91 *
92 * Authenticated IPMI communication to the BMC is accomplished by establishing
93 * a session. Once established, a session is identified by a Session ID. The
94 * Session ID may be thought of as a handle that identifies a connection between
95 * a given remote user and the BMC. The specification supports having multiple
96 * active sessions established with the BMC. It is recommended that a BMC
97 * implementation support at least four simultaneous sessions
98 */
99class Session
100{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700101 public:
102 Session() = default;
103 ~Session() = default;
104 Session(const Session&) = delete;
105 Session& operator=(const Session&) = delete;
106 Session(Session&&) = default;
107 Session& operator=(Session&&) = default;
Tom Josephf0ca5132016-08-09 08:16:12 -0500108
Vernon Mauery9e801a22018-10-12 13:20:49 -0700109 /**
110 * @brief Session Constructor
111 *
112 * This is issued by the Session Manager when a session is started for
113 * the Open SessionRequest command
114 *
115 * @param[in] inRemoteConsoleSessID - Remote Console Session ID
116 * @param[in] priv - Privilege Level requested in the Command
117 */
118 Session(SessionID inRemoteConsoleSessID, Privilege priv) :
Vernon Mauery8977d122018-10-24 14:02:16 -0700119 curPrivLevel(priv), bmcSessionID(crypto::prng::rand()),
Vernon Mauery9e801a22018-10-12 13:20:49 -0700120 remoteConsoleSessionID(inRemoteConsoleSessID)
121 {
122 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500123
Vernon Mauery9e801a22018-10-12 13:20:49 -0700124 auto getBMCSessionID() const
125 {
126 return bmcSessionID;
127 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500128
Vernon Mauery9e801a22018-10-12 13:20:49 -0700129 auto getRCSessionID() const
130 {
131 return remoteConsoleSessionID;
132 }
133
134 auto getAuthAlgo() const
135 {
136 if (authAlgoInterface)
Tom Josephf0ca5132016-08-09 08:16:12 -0500137 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700138 return authAlgoInterface.get();
Tom Josephf0ca5132016-08-09 08:16:12 -0500139 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700140 else
Tom Josephf0ca5132016-08-09 08:16:12 -0500141 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700142 throw std::runtime_error("Authentication Algorithm Empty");
Tom Josephf0ca5132016-08-09 08:16:12 -0500143 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700144 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500145
Vernon Mauery9e801a22018-10-12 13:20:49 -0700146 void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& inAuthAlgo)
147 {
148 authAlgoInterface = std::move(inAuthAlgo);
149 }
150
151 /**
152 * @brief Get Session's Integrity Algorithm
153 *
154 * @return pointer to the integrity algorithm
155 */
156 auto getIntegrityAlgo() const
157 {
158 if (integrityAlgoInterface)
Tom Josephf0ca5132016-08-09 08:16:12 -0500159 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700160 return integrityAlgoInterface.get();
Tom Josephf0ca5132016-08-09 08:16:12 -0500161 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700162 else
Tom Josephf0ca5132016-08-09 08:16:12 -0500163 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700164 throw std::runtime_error("Integrity Algorithm Empty");
Tom Josephf0ca5132016-08-09 08:16:12 -0500165 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700166 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500167
Vernon Mauery9e801a22018-10-12 13:20:49 -0700168 /**
169 * @brief Set Session's Integrity Algorithm
170 *
171 * @param[in] integrityAlgo - unique pointer to integrity algorithm
172 * instance
173 */
174 void setIntegrityAlgo(
175 std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo)
176 {
177 integrityAlgoInterface = std::move(integrityAlgo);
178 }
179
180 /** @brief Check if integrity algorithm is enabled for this session.
181 *
182 * @return true if integrity algorithm is enabled else false.
183 */
184 auto isIntegrityAlgoEnabled()
185 {
186 return integrityAlgoInterface ? true : false;
187 }
188
189 /**
190 * @brief Get Session's Confidentiality Algorithm
191 *
192 * @return pointer to the confidentiality algorithm
193 */
194 auto getCryptAlgo() const
195 {
196 if (cryptAlgoInterface)
Tom Joseph638d0662017-01-10 16:02:07 +0530197 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700198 return cryptAlgoInterface.get();
Tom Joseph638d0662017-01-10 16:02:07 +0530199 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700200 else
Tom Joseph638d0662017-01-10 16:02:07 +0530201 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700202 throw std::runtime_error("Confidentiality Algorithm Empty");
Tom Joseph638d0662017-01-10 16:02:07 +0530203 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700204 }
Tom Joseph638d0662017-01-10 16:02:07 +0530205
Vernon Mauery9e801a22018-10-12 13:20:49 -0700206 /**
207 * @brief Set Session's Confidentiality Algorithm
208 *
209 * @param[in] confAlgo - unique pointer to confidentiality algorithm
210 * instance
211 */
212 void setCryptAlgo(std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo)
213 {
214 cryptAlgoInterface = std::move(cryptAlgo);
215 }
Tom Josephd8c78612017-03-31 10:17:30 +0530216
Vernon Mauery9e801a22018-10-12 13:20:49 -0700217 /** @brief Check if confidentiality algorithm is enabled for this
218 * session.
219 *
220 * @return true if confidentiality algorithm is enabled else false.
221 */
222 auto isCryptAlgoEnabled()
223 {
224 return cryptAlgoInterface ? true : false;
225 }
Tom Joseph491dbd02017-01-24 18:20:41 +0530226
Vernon Mauery9e801a22018-10-12 13:20:49 -0700227 void updateLastTransactionTime()
228 {
229 lastTime = std::chrono::steady_clock::now();
230 }
Tom Joseph491dbd02017-01-24 18:20:41 +0530231
Vernon Mauery9e801a22018-10-12 13:20:49 -0700232 /**
233 * @brief Session Active Status
234 *
235 * Session Active status is decided upon the Session State and the last
236 * transaction time is compared against the session inactivity timeout.
237 *
238 */
Vernon Mauery07e5b282018-10-24 13:11:23 -0700239 bool isSessionActive()
240 {
241 auto currentTime = std::chrono::steady_clock::now();
242 auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(
243 currentTime - lastTime);
244
245 switch (state)
246 {
247 case State::SETUP_IN_PROGRESS:
248 if (elapsedSeconds < SESSION_SETUP_TIMEOUT)
249 {
250 return true;
251 }
252 break;
253 case State::ACTIVE:
254 if (elapsedSeconds < SESSION_INACTIVITY_TIMEOUT)
255 {
256 return true;
257 }
258 break;
259 default:
260 return false;
261 }
262 return false;
263 }
Tom Joseph895df942017-03-31 10:19:40 +0530264
Vernon Mauery9e801a22018-10-12 13:20:49 -0700265 /**
266 * @brief Session's Current Privilege Level
267 */
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +0530268 Privilege curPrivLevel = Privilege::CALLBACK;
Tom Josephf0ca5132016-08-09 08:16:12 -0500269
Vernon Mauery9e801a22018-10-12 13:20:49 -0700270 /**
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +0530271 * @brief Session's Requested Maximum Privilege Level
Vernon Mauery9e801a22018-10-12 13:20:49 -0700272 */
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +0530273 uint8_t reqMaxPrivLevel;
Tom Josephf0ca5132016-08-09 08:16:12 -0500274
Vernon Mauery9e801a22018-10-12 13:20:49 -0700275 SequenceNumbers sequenceNums; // Session Sequence Numbers
276 State state = State::INACTIVE; // Session State
277 std::string userName{}; // User Name
Tom Josephf0ca5132016-08-09 08:16:12 -0500278
Vernon Mauery9e801a22018-10-12 13:20:49 -0700279 /** @brief Socket channel for communicating with the remote client.*/
280 std::shared_ptr<udpsocket::Channel> channelPtr;
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +0530281 uint8_t chNum;
Tom Josephf0ca5132016-08-09 08:16:12 -0500282
Vernon Mauery9e801a22018-10-12 13:20:49 -0700283 private:
284 SessionID bmcSessionID = 0; // BMC Session ID
285 SessionID remoteConsoleSessionID = 0; // Remote Console Session ID
Tom Josephf0ca5132016-08-09 08:16:12 -0500286
Vernon Mauery9e801a22018-10-12 13:20:49 -0700287 // Authentication Algorithm Interface for the Session
288 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
Tom Josephcc27e122017-03-31 10:21:04 +0530289
Vernon Mauery9e801a22018-10-12 13:20:49 -0700290 // Integrity Algorithm Interface for the Session
291 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
292 nullptr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500293
Vernon Mauery9e801a22018-10-12 13:20:49 -0700294 // Confidentiality Algorithm Interface for the Session
295 std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = nullptr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500296
Vernon Mauery9e801a22018-10-12 13:20:49 -0700297 // Last Transaction Time
298 decltype(std::chrono::steady_clock::now()) lastTime;
Tom Josephf0ca5132016-08-09 08:16:12 -0500299};
300
301} // namespace session