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