xref: /openbmc/phosphor-net-ipmid/session.hpp (revision 895df94e3951666f30aea665d9f74f22fb43c5a7)
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