blob: 637438a1b4929ce2add8da6c832075e8427cb2ec [file] [log] [blame]
Tom Josephf0ca5132016-08-09 08:16:12 -05001#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"
Tom Joseph491dbd02017-01-24 18:20:41 +053011#include "crypt_algo.hpp"
Tom Joseph638d0662017-01-10 16:02:07 +053012#include "integrity_algo.hpp"
Tom Josephf0ca5132016-08-09 08:16:12 -050013#include "endian.hpp"
14#include "socket_channel.hpp"
15
16namespace session
17{
18
19using namespace std::chrono_literals;
20using SessionID = uint32_t;
21
22enum class Privilege : uint8_t
23{
24 HIGHEST_MATCHING,
25 CALLBACK,
26 USER,
27 OPERATOR,
28 ADMIN,
29 OEM,
30};
31
32enum 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
41constexpr auto SESSION_SETUP_TIMEOUT = 5s;
42// Seconds of inactivity allowed when session is active
43constexpr 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 */
61struct 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:
Tom Joseph32db22e2017-01-26 15:17:30 +053079 uint32_t in = 0;
80 uint32_t out = 0;
Tom Josephf0ca5132016-08-09 08:16:12 -050081};
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 */
94class 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
Tom Joseph638d0662017-01-10 16:02:07 +0530147 /*
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
Tom Josephd8c78612017-03-31 10:17:30 +0530176 /** @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
Tom Joseph491dbd02017-01-24 18:20:41 +0530185 /*
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
Tom Joseph895df942017-03-31 10:19:40 +0530214 /** @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
Tom Josephf0ca5132016-08-09 08:16:12 -0500224 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
Tom Josephcc27e122017-03-31 10:21:04 +0530252 /** @brief Socket channel for communicating with the remote client.*/
253 std::shared_ptr<udpsocket::Channel> channelPtr;
254
Tom Josephf0ca5132016-08-09 08:16:12 -0500255 private:
256
257 SessionID bmcSessionID = 0; //BMC Session ID
258 SessionID remoteConsoleSessionID = 0; //Remote Console Session ID
259
260 // Authentication Algorithm Interface for the Session
261 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
262
Tom Joseph638d0662017-01-10 16:02:07 +0530263 // Integrity Algorithm Interface for the Session
264 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
Tom Josephbeca5ac2017-01-19 12:29:45 +0530265 nullptr;
Tom Joseph638d0662017-01-10 16:02:07 +0530266
Tom Joseph491dbd02017-01-24 18:20:41 +0530267 // Confidentiality Algorithm Interface for the Session
268 std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface =
269 nullptr;
270
Tom Josephf0ca5132016-08-09 08:16:12 -0500271 // Last Transaction Time
272 decltype(std::chrono::steady_clock::now()) lastTime;
273};
274
275} // namespace session