xref: /openbmc/phosphor-net-ipmid/session.hpp (revision 8425624a)
1 #pragma once
2 
3 #include "auth_algo.hpp"
4 #include "crypt_algo.hpp"
5 #include "endian.hpp"
6 #include "integrity_algo.hpp"
7 #include "prng.hpp"
8 #include "socket_channel.hpp"
9 
10 #include <ipmid/api.hpp>
11 #include <ipmid/sessiondef.hpp>
12 #include <sdbusplus/bus.hpp>
13 #include <sdbusplus/server/object.hpp>
14 #include <user_channel/channel_layer.hpp>
15 #include <user_channel/user_layer.hpp>
16 #include <xyz/openbmc_project/Ipmi/SessionInfo/server.hpp>
17 
18 #include <chrono>
19 #include <exception>
20 #include <list>
21 #include <memory>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25 
26 namespace session
27 {
28 
29 using namespace std::chrono_literals;
30 using SessionID = uint32_t;
31 
32 enum class Privilege : uint8_t
33 {
34     HIGHEST_MATCHING,
35     CALLBACK,
36     USER,
37     OPERATOR,
38     ADMIN,
39     OEM,
40 };
41 
42 // Mask to get only the privilege from requested maximum privlege (RAKP message
43 // 1)
44 constexpr uint8_t reqMaxPrivMask = 0xF;
45 
46 /**
47  * @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  */
62 struct SequenceNumbers
63 {
getsession::SequenceNumbers64     auto get(bool inbound = true) const
65     {
66         return inbound ? in : out;
67     }
68 
setsession::SequenceNumbers69     void set(uint32_t seqNumber, bool inbound = true)
70     {
71         inbound ? (in = seqNumber) : (out = seqNumber);
72     }
73 
incrementsession::SequenceNumbers74     auto increment()
75     {
76         return ++out;
77     }
78 
79   private:
80     uint32_t in = 0;
81     uint32_t out = 0;
82 };
83 /**
84  * @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  */
95 
96 using SessionIface = sdbusplus::server::object_t<
97     sdbusplus::xyz::openbmc_project::Ipmi::server::SessionInfo>;
98 
99 class Session : public SessionIface
100 {
101   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;
108 
109     /**
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      */
Session(sdbusplus::bus_t & bus,const char * path,SessionID inRemoteConsoleSessID,SessionID BMCSessionID,char priv)118     Session(sdbusplus::bus_t& bus, const char* path,
119             SessionID inRemoteConsoleSessID, SessionID BMCSessionID,
120             char priv) : SessionIface(bus, path)
121     {
122         reqMaxPrivLevel = static_cast<session::Privilege>(priv);
123         bmcSessionID = BMCSessionID;
124         remoteConsoleSessionID = inRemoteConsoleSessID;
125     }
126 
getBMCSessionID() const127     auto getBMCSessionID() const
128     {
129         return bmcSessionID;
130     }
131 
getRCSessionID() const132     auto getRCSessionID() const
133     {
134         return remoteConsoleSessionID;
135     }
136 
getAuthAlgo() const137     auto getAuthAlgo() const
138     {
139         if (authAlgoInterface)
140         {
141             return authAlgoInterface.get();
142         }
143         else
144         {
145             throw std::runtime_error("Authentication Algorithm Empty");
146         }
147     }
148 
setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface> && inAuthAlgo)149     void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& inAuthAlgo)
150     {
151         authAlgoInterface = std::move(inAuthAlgo);
152     }
153 
154     /**
155      * @brief Get Session's Integrity Algorithm
156      *
157      * @return pointer to the integrity algorithm
158      */
getIntegrityAlgo() const159     auto getIntegrityAlgo() const
160     {
161         if (integrityAlgoInterface)
162         {
163             return integrityAlgoInterface.get();
164         }
165         else
166         {
167             throw std::runtime_error("Integrity Algorithm Empty");
168         }
169     }
170 
171     /**
172      * @brief Set Session's Integrity Algorithm
173      *
174      * @param[in] integrityAlgo - unique pointer to integrity algorithm
175      *                              instance
176      */
setIntegrityAlgo(std::unique_ptr<cipher::integrity::Interface> && integrityAlgo)177     void setIntegrityAlgo(
178         std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo)
179     {
180         integrityAlgoInterface = std::move(integrityAlgo);
181     }
182 
183     /** @brief Check if integrity algorithm is enabled for this session.
184      *
185      *  @return true if integrity algorithm is enabled else false.
186      */
isIntegrityAlgoEnabled()187     auto isIntegrityAlgoEnabled()
188     {
189         return integrityAlgoInterface ? true : false;
190     }
191 
192     /**
193      * @brief Get Session's Confidentiality Algorithm
194      *
195      * @return pointer to the confidentiality algorithm
196      */
getCryptAlgo() const197     auto getCryptAlgo() const
198     {
199         if (cryptAlgoInterface)
200         {
201             return cryptAlgoInterface.get();
202         }
203         else
204         {
205             throw std::runtime_error("Confidentiality Algorithm Empty");
206         }
207     }
208 
209     /**
210      * @brief Set Session's Confidentiality Algorithm
211      *
212      * @param[in] confAlgo - unique pointer to confidentiality algorithm
213      *                       instance
214      */
setCryptAlgo(std::unique_ptr<cipher::crypt::Interface> && cryptAlgo)215     void setCryptAlgo(std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo)
216     {
217         cryptAlgoInterface = std::move(cryptAlgo);
218     }
219 
220     /** @brief Check if confidentiality algorithm is enabled for this
221      *         session.
222      *
223      *  @return true if confidentiality algorithm is enabled else false.
224      */
isCryptAlgoEnabled()225     auto isCryptAlgoEnabled()
226     {
227         return cryptAlgoInterface ? true : false;
228     }
229 
updateLastTransactionTime()230     void updateLastTransactionTime()
231     {
232         lastTime = std::chrono::steady_clock::now();
233     }
234 
235     /**
236      * @brief Session Active Status
237      *
238      * Session Active status is decided upon the Session State and the last
239      * transaction time is compared against the session inactivity timeout.
240      *
241      * @param[in] activeGrace - microseconds of idle time for active sessions
242      * @param[in] setupGrace - microseconds of idle time for sessions in setup
243      *
244      */
isSessionActive(const std::chrono::microseconds & activeGrace,const std::chrono::microseconds & setupGrace)245     bool isSessionActive(const std::chrono::microseconds& activeGrace,
246                          const std::chrono::microseconds& setupGrace)
247     {
248         auto currentTime = std::chrono::steady_clock::now();
249         auto elapsedMicros =
250             std::chrono::duration_cast<std::chrono::microseconds>(
251                 currentTime - lastTime);
252 
253         State state = static_cast<session::State>(this->state());
254 
255         switch (state)
256         {
257             case State::active:
258                 if (elapsedMicros < activeGrace)
259                 {
260                     return true;
261                 }
262                 break;
263             case State::setupInProgress:
264                 if (elapsedMicros < setupGrace)
265                 {
266                     return true;
267                 }
268                 break;
269             case State::tearDownInProgress:
270                 break;
271             default:
272                 break;
273         }
274         return false;
275     }
276 
277     /**
278      * @brief Session's Requested Maximum Privilege Level
279      */
280     Privilege reqMaxPrivLevel;
281 
282     /**
283      * @brief session's user & channel access details
284      */
285     ipmi::PrivAccess sessionUserPrivAccess{};
286     ipmi::ChannelAccess sessionChannelAccess{};
287 
288     SequenceNumbers sequenceNums; // Session Sequence Numbers
289     std::string userName{};       // User Name
290 
291     /** @brief Socket channel for communicating with the remote client.*/
292     std::shared_ptr<udpsocket::Channel> channelPtr;
293 
294   private:
295     SessionID bmcSessionID = 0;           // BMC Session ID
296     SessionID remoteConsoleSessionID = 0; // Remote Console Session ID
297 
298     // Authentication Algorithm Interface for the Session
299     std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
300 
301     // Integrity Algorithm Interface for the Session
302     std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
303         nullptr;
304 
305     // Confidentiality Algorithm Interface for the Session
306     std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = nullptr;
307 
308     // Last Transaction Time
309     decltype(std::chrono::steady_clock::now()) lastTime;
310 };
311 
312 } // namespace session
313