xref: /openbmc/phosphor-net-ipmid/session.hpp (revision bac2f1a31eb5d2613ae11b220b28764484d7c06c)
1f0ca513aSTom Joseph #pragma once
2f0ca513aSTom Joseph 
39e801a2bSVernon Mauery #include "auth_algo.hpp"
49e801a2bSVernon Mauery #include "crypt_algo.hpp"
59e801a2bSVernon Mauery #include "endian.hpp"
69e801a2bSVernon Mauery #include "integrity_algo.hpp"
78977d12aSVernon Mauery #include "prng.hpp"
89e801a2bSVernon Mauery #include "socket_channel.hpp"
99e801a2bSVernon Mauery 
10f8a34fc4SSuryakanth Sekar #include <ipmid/api.hpp>
11f8a34fc4SSuryakanth Sekar #include <ipmid/sessiondef.hpp>
12f8a34fc4SSuryakanth Sekar #include <sdbusplus/bus.hpp>
13f8a34fc4SSuryakanth Sekar #include <sdbusplus/server/object.hpp>
14992e53c7SRichard Marian Thomaiyar #include <user_channel/channel_layer.hpp>
15992e53c7SRichard Marian Thomaiyar #include <user_channel/user_layer.hpp>
16f8a34fc4SSuryakanth Sekar #include <xyz/openbmc_project/Ipmi/SessionInfo/server.hpp>
17f0ca513aSTom Joseph 
18bc8958feSGeorge Liu #include <chrono>
19bc8958feSGeorge Liu #include <exception>
20bc8958feSGeorge Liu #include <list>
21bc8958feSGeorge Liu #include <memory>
22bc8958feSGeorge Liu #include <string>
23bc8958feSGeorge Liu #include <unordered_map>
24bc8958feSGeorge Liu #include <vector>
25bc8958feSGeorge Liu 
26f0ca513aSTom Joseph namespace session
27f0ca513aSTom Joseph {
28f0ca513aSTom Joseph 
29f0ca513aSTom Joseph using namespace std::chrono_literals;
30f0ca513aSTom Joseph using SessionID = uint32_t;
31f0ca513aSTom Joseph 
32f0ca513aSTom Joseph enum class Privilege : uint8_t
33f0ca513aSTom Joseph {
34f0ca513aSTom Joseph     HIGHEST_MATCHING,
35f0ca513aSTom Joseph     CALLBACK,
36f0ca513aSTom Joseph     USER,
37f0ca513aSTom Joseph     OPERATOR,
38f0ca513aSTom Joseph     ADMIN,
39f0ca513aSTom Joseph     OEM,
40f0ca513aSTom Joseph };
41f0ca513aSTom Joseph 
42127748a8SRichard Marian Thomaiyar // Mask to get only the privilege from requested maximum privlege (RAKP message
43127748a8SRichard Marian Thomaiyar // 1)
44127748a8SRichard Marian Thomaiyar constexpr uint8_t reqMaxPrivMask = 0xF;
45127748a8SRichard Marian Thomaiyar 
463563f8feSTom Joseph /**
47f0ca513aSTom Joseph  * @struct SequenceNumbers Session Sequence Numbers
48f0ca513aSTom Joseph  *
49f0ca513aSTom Joseph  * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that
50f0ca513aSTom Joseph  * may have been duplicated by the network or intentionally replayed. There are
51f0ca513aSTom Joseph  * two sets of Session SequenceNumbers for a given session.One set of inbound
52f0ca513aSTom Joseph  * and outbound sequence numbers is used for authenticated (signed) packets,
53f0ca513aSTom Joseph  * and the other set is used for unauthenticated packets.
54f0ca513aSTom Joseph  *
55f0ca513aSTom Joseph  * The individual Session Sequence Numbers is are initialized to zero whenever
56f0ca513aSTom Joseph  * a session is created and incremented by one at the start of outbound
57f0ca513aSTom Joseph  * processing for a given packet (i.e. the first transmitted packet has a ‘1’
58f0ca513aSTom Joseph  * as the sequence number, not 0). Session Sequence numbers are incremented for
59f0ca513aSTom Joseph  * every packet that is transmitted by a given sender, regardless of whether
60f0ca513aSTom Joseph  * the payload for the packet is a ‘retry’ or not.
61f0ca513aSTom Joseph  */
62f0ca513aSTom Joseph struct SequenceNumbers
63f0ca513aSTom Joseph {
getsession::SequenceNumbers64f0ca513aSTom Joseph     auto get(bool inbound = true) const
65f0ca513aSTom Joseph     {
66f0ca513aSTom Joseph         return inbound ? in : out;
67f0ca513aSTom Joseph     }
68f0ca513aSTom Joseph 
setsession::SequenceNumbers69f0ca513aSTom Joseph     void set(uint32_t seqNumber, bool inbound = true)
70f0ca513aSTom Joseph     {
71f0ca513aSTom Joseph         inbound ? (in = seqNumber) : (out = seqNumber);
72f0ca513aSTom Joseph     }
73f0ca513aSTom Joseph 
incrementsession::SequenceNumbers74f0ca513aSTom Joseph     auto increment()
75f0ca513aSTom Joseph     {
76f0ca513aSTom Joseph         return ++out;
77f0ca513aSTom Joseph     }
78f0ca513aSTom Joseph 
79f0ca513aSTom Joseph   private:
8032db22e9STom Joseph     uint32_t in = 0;
8132db22e9STom Joseph     uint32_t out = 0;
82f0ca513aSTom Joseph };
833563f8feSTom Joseph /**
84f0ca513aSTom Joseph  * @class Session
85f0ca513aSTom Joseph  *
86f0ca513aSTom Joseph  * Encapsulates the data related to an IPMI Session
87f0ca513aSTom Joseph  *
88f0ca513aSTom Joseph  * Authenticated IPMI communication to the BMC is accomplished by establishing
89f0ca513aSTom Joseph  * a session. Once established, a session is identified by a Session ID. The
90f0ca513aSTom Joseph  * Session ID may be thought of as a handle that identifies a connection between
91f0ca513aSTom Joseph  * a given remote user and the BMC. The specification supports having multiple
92f0ca513aSTom Joseph  * active sessions established with the BMC. It is recommended that a BMC
93f0ca513aSTom Joseph  * implementation support at least four simultaneous sessions
94f0ca513aSTom Joseph  */
95f8a34fc4SSuryakanth Sekar 
960a59062cSPatrick Williams using SessionIface = sdbusplus::server::object_t<
97f8a34fc4SSuryakanth Sekar     sdbusplus::xyz::openbmc_project::Ipmi::server::SessionInfo>;
98f8a34fc4SSuryakanth Sekar 
99f8a34fc4SSuryakanth Sekar class Session : public SessionIface
100f0ca513aSTom Joseph {
101f0ca513aSTom Joseph   public:
102*bac2f1a3SLei YU     Session() = delete;
103f0ca513aSTom Joseph     ~Session() = default;
104f0ca513aSTom Joseph     Session(const Session&) = delete;
105f0ca513aSTom Joseph     Session& operator=(const Session&) = delete;
106*bac2f1a3SLei YU     Session(Session&&) = delete;
107*bac2f1a3SLei YU     Session& operator=(Session&&) = delete;
108f0ca513aSTom Joseph 
1093563f8feSTom Joseph     /**
110f0ca513aSTom Joseph      * @brief Session Constructor
111f0ca513aSTom Joseph      *
112f0ca513aSTom Joseph      * This is issued by the Session Manager when a session is started for
113f0ca513aSTom Joseph      * the Open SessionRequest command
114f0ca513aSTom Joseph      *
115f0ca513aSTom Joseph      * @param[in] inRemoteConsoleSessID - Remote Console Session ID
116f0ca513aSTom Joseph      * @param[in] priv - Privilege Level requested in the Command
117f0ca513aSTom Joseph      */
Session(sdbusplus::bus_t & bus,const char * path,SessionID inRemoteConsoleSessID,SessionID BMCSessionID,char priv)1180a59062cSPatrick Williams     Session(sdbusplus::bus_t& bus, const char* path,
119f8a34fc4SSuryakanth Sekar             SessionID inRemoteConsoleSessID, SessionID BMCSessionID,
1208425624aSPatrick Williams             char priv) : SessionIface(bus, path)
1219e801a2bSVernon Mauery     {
122f8a34fc4SSuryakanth Sekar         reqMaxPrivLevel = static_cast<session::Privilege>(priv);
123f8a34fc4SSuryakanth Sekar         bmcSessionID = BMCSessionID;
124f8a34fc4SSuryakanth Sekar         remoteConsoleSessionID = inRemoteConsoleSessID;
1259e801a2bSVernon Mauery     }
126f0ca513aSTom Joseph 
getBMCSessionID() const127f0ca513aSTom Joseph     auto getBMCSessionID() const
128f0ca513aSTom Joseph     {
129f0ca513aSTom Joseph         return bmcSessionID;
130f0ca513aSTom Joseph     }
131f0ca513aSTom Joseph 
getRCSessionID() const132f0ca513aSTom Joseph     auto getRCSessionID() const
133f0ca513aSTom Joseph     {
134f0ca513aSTom Joseph         return remoteConsoleSessionID;
135f0ca513aSTom Joseph     }
136f0ca513aSTom Joseph 
getAuthAlgo() const137f0ca513aSTom Joseph     auto getAuthAlgo() const
138f0ca513aSTom Joseph     {
139f0ca513aSTom Joseph         if (authAlgoInterface)
140f0ca513aSTom Joseph         {
141f0ca513aSTom Joseph             return authAlgoInterface.get();
142f0ca513aSTom Joseph         }
143f0ca513aSTom Joseph         else
144f0ca513aSTom Joseph         {
145f0ca513aSTom Joseph             throw std::runtime_error("Authentication Algorithm Empty");
146f0ca513aSTom Joseph         }
147f0ca513aSTom Joseph     }
148f0ca513aSTom Joseph 
setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface> && inAuthAlgo)1499e801a2bSVernon Mauery     void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& inAuthAlgo)
150f0ca513aSTom Joseph     {
151f0ca513aSTom Joseph         authAlgoInterface = std::move(inAuthAlgo);
152f0ca513aSTom Joseph     }
153f0ca513aSTom Joseph 
1543563f8feSTom Joseph     /**
155638d0666STom Joseph      * @brief Get Session's Integrity Algorithm
156638d0666STom Joseph      *
157638d0666STom Joseph      * @return pointer to the integrity algorithm
158638d0666STom Joseph      */
getIntegrityAlgo() const159638d0666STom Joseph     auto getIntegrityAlgo() const
160638d0666STom Joseph     {
161638d0666STom Joseph         if (integrityAlgoInterface)
162638d0666STom Joseph         {
163638d0666STom Joseph             return integrityAlgoInterface.get();
164638d0666STom Joseph         }
165638d0666STom Joseph         else
166638d0666STom Joseph         {
167638d0666STom Joseph             throw std::runtime_error("Integrity Algorithm Empty");
168638d0666STom Joseph         }
169638d0666STom Joseph     }
170638d0666STom Joseph 
1713563f8feSTom Joseph     /**
172638d0666STom Joseph      * @brief Set Session's Integrity Algorithm
173638d0666STom Joseph      *
174638d0666STom Joseph      * @param[in] integrityAlgo - unique pointer to integrity algorithm
175638d0666STom Joseph      *                              instance
176638d0666STom Joseph      */
setIntegrityAlgo(std::unique_ptr<cipher::integrity::Interface> && integrityAlgo)177638d0666STom Joseph     void setIntegrityAlgo(
178638d0666STom Joseph         std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo)
179638d0666STom Joseph     {
180638d0666STom Joseph         integrityAlgoInterface = std::move(integrityAlgo);
181638d0666STom Joseph     }
182638d0666STom Joseph 
183d8c7861dSTom Joseph     /** @brief Check if integrity algorithm is enabled for this session.
184d8c7861dSTom Joseph      *
185d8c7861dSTom Joseph      *  @return true if integrity algorithm is enabled else false.
186d8c7861dSTom Joseph      */
isIntegrityAlgoEnabled()187d8c7861dSTom Joseph     auto isIntegrityAlgoEnabled()
188d8c7861dSTom Joseph     {
189d8c7861dSTom Joseph         return integrityAlgoInterface ? true : false;
190d8c7861dSTom Joseph     }
191d8c7861dSTom Joseph 
1923563f8feSTom Joseph     /**
193491dbd01STom Joseph      * @brief Get Session's Confidentiality Algorithm
194491dbd01STom Joseph      *
195491dbd01STom Joseph      * @return pointer to the confidentiality algorithm
196491dbd01STom Joseph      */
getCryptAlgo() const197491dbd01STom Joseph     auto getCryptAlgo() const
198491dbd01STom Joseph     {
199491dbd01STom Joseph         if (cryptAlgoInterface)
200491dbd01STom Joseph         {
201491dbd01STom Joseph             return cryptAlgoInterface.get();
202491dbd01STom Joseph         }
203491dbd01STom Joseph         else
204491dbd01STom Joseph         {
205491dbd01STom Joseph             throw std::runtime_error("Confidentiality Algorithm Empty");
206491dbd01STom Joseph         }
207491dbd01STom Joseph     }
208491dbd01STom Joseph 
2093563f8feSTom Joseph     /**
210491dbd01STom Joseph      * @brief Set Session's Confidentiality Algorithm
211491dbd01STom Joseph      *
212491dbd01STom Joseph      * @param[in] confAlgo - unique pointer to confidentiality algorithm
213491dbd01STom Joseph      *                       instance
214491dbd01STom Joseph      */
setCryptAlgo(std::unique_ptr<cipher::crypt::Interface> && cryptAlgo)2159e801a2bSVernon Mauery     void setCryptAlgo(std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo)
216491dbd01STom Joseph     {
217491dbd01STom Joseph         cryptAlgoInterface = std::move(cryptAlgo);
218491dbd01STom Joseph     }
219491dbd01STom Joseph 
220895df94eSTom Joseph     /** @brief Check if confidentiality algorithm is enabled for this
221895df94eSTom Joseph      *         session.
222895df94eSTom Joseph      *
223895df94eSTom Joseph      *  @return true if confidentiality algorithm is enabled else false.
224895df94eSTom Joseph      */
isCryptAlgoEnabled()225895df94eSTom Joseph     auto isCryptAlgoEnabled()
226895df94eSTom Joseph     {
227895df94eSTom Joseph         return cryptAlgoInterface ? true : false;
228895df94eSTom Joseph     }
229895df94eSTom Joseph 
updateLastTransactionTime()230f0ca513aSTom Joseph     void updateLastTransactionTime()
231f0ca513aSTom Joseph     {
232f0ca513aSTom Joseph         lastTime = std::chrono::steady_clock::now();
233f0ca513aSTom Joseph     }
234f0ca513aSTom Joseph 
2353563f8feSTom Joseph     /**
236f0ca513aSTom Joseph      * @brief Session Active Status
237f0ca513aSTom Joseph      *
238f0ca513aSTom Joseph      * Session Active status is decided upon the Session State and the last
239f0ca513aSTom Joseph      * transaction time is compared against the session inactivity timeout.
240f0ca513aSTom Joseph      *
241ecc8efadSVernon Mauery      * @param[in] activeGrace - microseconds of idle time for active sessions
242ecc8efadSVernon Mauery      * @param[in] setupGrace - microseconds of idle time for sessions in setup
243ecc8efadSVernon Mauery      *
244f0ca513aSTom Joseph      */
isSessionActive(const std::chrono::microseconds & activeGrace,const std::chrono::microseconds & setupGrace)245ecc8efadSVernon Mauery     bool isSessionActive(const std::chrono::microseconds& activeGrace,
246ecc8efadSVernon Mauery                          const std::chrono::microseconds& setupGrace)
24707e5b28cSVernon Mauery     {
24807e5b28cSVernon Mauery         auto currentTime = std::chrono::steady_clock::now();
249ecc8efadSVernon Mauery         auto elapsedMicros =
2508425624aSPatrick Williams             std::chrono::duration_cast<std::chrono::microseconds>(
2518425624aSPatrick Williams                 currentTime - lastTime);
25207e5b28cSVernon Mauery 
253ecc8efadSVernon Mauery         State state = static_cast<session::State>(this->state());
254f8a34fc4SSuryakanth Sekar 
25507e5b28cSVernon Mauery         switch (state)
25607e5b28cSVernon Mauery         {
257ecc8efadSVernon Mauery             case State::active:
258ecc8efadSVernon Mauery                 if (elapsedMicros < activeGrace)
25907e5b28cSVernon Mauery                 {
26007e5b28cSVernon Mauery                     return true;
26107e5b28cSVernon Mauery                 }
26207e5b28cSVernon Mauery                 break;
263ecc8efadSVernon Mauery             case State::setupInProgress:
264ecc8efadSVernon Mauery                 if (elapsedMicros < setupGrace)
26507e5b28cSVernon Mauery                 {
26607e5b28cSVernon Mauery                     return true;
26707e5b28cSVernon Mauery                 }
26807e5b28cSVernon Mauery                 break;
269ecc8efadSVernon Mauery             case State::tearDownInProgress:
270ecc8efadSVernon Mauery                 break;
27107e5b28cSVernon Mauery             default:
272ecc8efadSVernon Mauery                 break;
27307e5b28cSVernon Mauery         }
27407e5b28cSVernon Mauery         return false;
27507e5b28cSVernon Mauery     }
276f0ca513aSTom Joseph 
2773563f8feSTom Joseph     /**
278127748a8SRichard Marian Thomaiyar      * @brief Session's Requested Maximum Privilege Level
279f0ca513aSTom Joseph      */
2804021b1f7STom Joseph     Privilege reqMaxPrivLevel;
281f0ca513aSTom Joseph 
282992e53c7SRichard Marian Thomaiyar     /**
283992e53c7SRichard Marian Thomaiyar      * @brief session's user & channel access details
284992e53c7SRichard Marian Thomaiyar      */
285992e53c7SRichard Marian Thomaiyar     ipmi::PrivAccess sessionUserPrivAccess{};
286992e53c7SRichard Marian Thomaiyar     ipmi::ChannelAccess sessionChannelAccess{};
287992e53c7SRichard Marian Thomaiyar 
288f0ca513aSTom Joseph     SequenceNumbers sequenceNums; // Session Sequence Numbers
28956527b93STom Joseph     std::string userName{};       // User Name
290f0ca513aSTom Joseph 
291cc27e12cSTom Joseph     /** @brief Socket channel for communicating with the remote client.*/
292cc27e12cSTom Joseph     std::shared_ptr<udpsocket::Channel> channelPtr;
293cc27e12cSTom Joseph 
294f0ca513aSTom Joseph   private:
295f0ca513aSTom Joseph     SessionID bmcSessionID = 0;           // BMC Session ID
296f0ca513aSTom Joseph     SessionID remoteConsoleSessionID = 0; // Remote Console Session ID
297f0ca513aSTom Joseph 
298f0ca513aSTom Joseph     // Authentication Algorithm Interface for the Session
299f0ca513aSTom Joseph     std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
300f0ca513aSTom Joseph 
301638d0666STom Joseph     // Integrity Algorithm Interface for the Session
302638d0666STom Joseph     std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
303638d0666STom Joseph         nullptr;
304638d0666STom Joseph 
305491dbd01STom Joseph     // Confidentiality Algorithm Interface for the Session
3069e801a2bSVernon Mauery     std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = nullptr;
307491dbd01STom Joseph 
308f0ca513aSTom Joseph     // Last Transaction Time
309f0ca513aSTom Joseph     decltype(std::chrono::steady_clock::now()) lastTime;
310f0ca513aSTom Joseph };
311f0ca513aSTom Joseph 
312f0ca513aSTom Joseph } // namespace session
313