blob: f3dc2ae88cd4783dea8e2c551fb841ad377b2ff9 [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
Tom Joseph3563f8f2017-05-08 15:42:54 +053046/**
Tom Josephf0ca5132016-08-09 08:16:12 -050047 * @struct SequenceNumbers Session Sequence Numbers
48 *
49 * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that
50 * may have been duplicated by the network or intentionally replayed. There are
51 * two sets of Session SequenceNumbers for a given session.One set of inbound
52 * and outbound sequence numbers is used for authenticated (signed) packets,
53 * and the other set is used for unauthenticated packets.
54 *
55 * The individual Session Sequence Numbers is are initialized to zero whenever
56 * a session is created and incremented by one at the start of outbound
57 * processing for a given packet (i.e. the first transmitted packet has a ‘1’
58 * as the sequence number, not 0). Session Sequence numbers are incremented for
59 * every packet that is transmitted by a given sender, regardless of whether
60 * the payload for the packet is a ‘retry’ or not.
61 */
62struct SequenceNumbers
63{
Vernon Mauery9e801a22018-10-12 13:20:49 -070064 auto get(bool inbound = true) const
65 {
66 return inbound ? in : out;
67 }
Tom Josephf0ca5132016-08-09 08:16:12 -050068
Vernon Mauery9e801a22018-10-12 13:20:49 -070069 void set(uint32_t seqNumber, bool inbound = true)
70 {
71 inbound ? (in = seqNumber) : (out = seqNumber);
72 }
Tom Josephf0ca5132016-08-09 08:16:12 -050073
Vernon Mauery9e801a22018-10-12 13:20:49 -070074 auto increment()
75 {
76 return ++out;
77 }
Tom Josephf0ca5132016-08-09 08:16:12 -050078
Vernon Mauery9e801a22018-10-12 13:20:49 -070079 private:
80 uint32_t in = 0;
81 uint32_t out = 0;
Tom Josephf0ca5132016-08-09 08:16:12 -050082};
Tom Joseph3563f8f2017-05-08 15:42:54 +053083/**
Tom Josephf0ca5132016-08-09 08:16:12 -050084 * @class Session
85 *
86 * Encapsulates the data related to an IPMI Session
87 *
88 * Authenticated IPMI communication to the BMC is accomplished by establishing
89 * a session. Once established, a session is identified by a Session ID. The
90 * Session ID may be thought of as a handle that identifies a connection between
91 * a given remote user and the BMC. The specification supports having multiple
92 * active sessions established with the BMC. It is recommended that a BMC
93 * implementation support at least four simultaneous sessions
94 */
95class Session
96{
Vernon Mauery9e801a22018-10-12 13:20:49 -070097 public:
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;
Tom Josephf0ca5132016-08-09 08:16:12 -0500104
Vernon Mauery9e801a22018-10-12 13:20:49 -0700105 /**
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) :
Vernon Mauery8977d122018-10-24 14:02:16 -0700115 curPrivLevel(priv), bmcSessionID(crypto::prng::rand()),
Vernon Mauery9e801a22018-10-12 13:20:49 -0700116 remoteConsoleSessionID(inRemoteConsoleSessID)
117 {
118 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500119
Vernon Mauery9e801a22018-10-12 13:20:49 -0700120 auto getBMCSessionID() const
121 {
122 return bmcSessionID;
123 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500124
Vernon Mauery9e801a22018-10-12 13:20:49 -0700125 auto getRCSessionID() const
126 {
127 return remoteConsoleSessionID;
128 }
129
130 auto getAuthAlgo() const
131 {
132 if (authAlgoInterface)
Tom Josephf0ca5132016-08-09 08:16:12 -0500133 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700134 return authAlgoInterface.get();
Tom Josephf0ca5132016-08-09 08:16:12 -0500135 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700136 else
Tom Josephf0ca5132016-08-09 08:16:12 -0500137 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700138 throw std::runtime_error("Authentication Algorithm Empty");
Tom Josephf0ca5132016-08-09 08:16:12 -0500139 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700140 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500141
Vernon Mauery9e801a22018-10-12 13:20:49 -0700142 void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& 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)
Tom Josephf0ca5132016-08-09 08:16:12 -0500155 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700156 return integrityAlgoInterface.get();
Tom Josephf0ca5132016-08-09 08:16:12 -0500157 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700158 else
Tom Josephf0ca5132016-08-09 08:16:12 -0500159 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700160 throw std::runtime_error("Integrity Algorithm Empty");
Tom Josephf0ca5132016-08-09 08:16:12 -0500161 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700162 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500163
Vernon Mauery9e801a22018-10-12 13:20:49 -0700164 /**
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)
Tom Joseph638d0662017-01-10 16:02:07 +0530193 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700194 return cryptAlgoInterface.get();
Tom Joseph638d0662017-01-10 16:02:07 +0530195 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700196 else
Tom Joseph638d0662017-01-10 16:02:07 +0530197 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700198 throw std::runtime_error("Confidentiality Algorithm Empty");
Tom Joseph638d0662017-01-10 16:02:07 +0530199 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700200 }
Tom Joseph638d0662017-01-10 16:02:07 +0530201
Vernon Mauery9e801a22018-10-12 13:20:49 -0700202 /**
203 * @brief Set Session's Confidentiality Algorithm
204 *
205 * @param[in] confAlgo - unique pointer to confidentiality algorithm
206 * instance
207 */
208 void setCryptAlgo(std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo)
209 {
210 cryptAlgoInterface = std::move(cryptAlgo);
211 }
Tom Josephd8c78612017-03-31 10:17:30 +0530212
Vernon Mauery9e801a22018-10-12 13:20:49 -0700213 /** @brief Check if confidentiality algorithm is enabled for this
214 * session.
215 *
216 * @return true if confidentiality algorithm is enabled else false.
217 */
218 auto isCryptAlgoEnabled()
219 {
220 return cryptAlgoInterface ? true : false;
221 }
Tom Joseph491dbd02017-01-24 18:20:41 +0530222
Vernon Mauery9e801a22018-10-12 13:20:49 -0700223 void updateLastTransactionTime()
224 {
225 lastTime = std::chrono::steady_clock::now();
226 }
Tom Joseph491dbd02017-01-24 18:20:41 +0530227
Vernon Mauery9e801a22018-10-12 13:20:49 -0700228 /**
229 * @brief Session Active Status
230 *
231 * Session Active status is decided upon the Session State and the last
232 * transaction time is compared against the session inactivity timeout.
233 *
234 */
Vernon Mauery07e5b282018-10-24 13:11:23 -0700235 bool isSessionActive()
236 {
237 auto currentTime = std::chrono::steady_clock::now();
238 auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(
239 currentTime - lastTime);
240
241 switch (state)
242 {
243 case State::SETUP_IN_PROGRESS:
244 if (elapsedSeconds < SESSION_SETUP_TIMEOUT)
245 {
246 return true;
247 }
248 break;
249 case State::ACTIVE:
250 if (elapsedSeconds < SESSION_INACTIVITY_TIMEOUT)
251 {
252 return true;
253 }
254 break;
255 default:
256 return false;
257 }
258 return false;
259 }
Tom Joseph895df942017-03-31 10:19:40 +0530260
Vernon Mauery9e801a22018-10-12 13:20:49 -0700261 /**
262 * @brief Session's Current Privilege Level
263 */
264 Privilege curPrivLevel;
Tom Josephf0ca5132016-08-09 08:16:12 -0500265
Vernon Mauery9e801a22018-10-12 13:20:49 -0700266 /**
267 * @brief Session's Maximum Privilege Level
268 */
269 Privilege maxPrivLevel = Privilege::CALLBACK;
Tom Josephf0ca5132016-08-09 08:16:12 -0500270
Vernon Mauery9e801a22018-10-12 13:20:49 -0700271 SequenceNumbers sequenceNums; // Session Sequence Numbers
272 State state = State::INACTIVE; // Session State
273 std::string userName{}; // User Name
Tom Josephf0ca5132016-08-09 08:16:12 -0500274
Vernon Mauery9e801a22018-10-12 13:20:49 -0700275 /** @brief Socket channel for communicating with the remote client.*/
276 std::shared_ptr<udpsocket::Channel> channelPtr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500277
Vernon Mauery9e801a22018-10-12 13:20:49 -0700278 private:
279 SessionID bmcSessionID = 0; // BMC Session ID
280 SessionID remoteConsoleSessionID = 0; // Remote Console Session ID
Tom Josephf0ca5132016-08-09 08:16:12 -0500281
Vernon Mauery9e801a22018-10-12 13:20:49 -0700282 // Authentication Algorithm Interface for the Session
283 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
Tom Josephcc27e122017-03-31 10:21:04 +0530284
Vernon Mauery9e801a22018-10-12 13:20:49 -0700285 // Integrity Algorithm Interface for the Session
286 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
287 nullptr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500288
Vernon Mauery9e801a22018-10-12 13:20:49 -0700289 // Confidentiality Algorithm Interface for the Session
290 std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = nullptr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500291
Vernon Mauery9e801a22018-10-12 13:20:49 -0700292 // Last Transaction Time
293 decltype(std::chrono::steady_clock::now()) lastTime;
Tom Josephf0ca5132016-08-09 08:16:12 -0500294};
295
296} // namespace session