177531db5STom Joseph #pragma once 277531db5STom Joseph 39e801a2bSVernon Mauery #include "rmcp.hpp" 49e801a2bSVernon Mauery 577531db5STom Joseph #include <array> 69d9b7638SAndrew Geissler #include <cstddef> 777531db5STom Joseph #include <vector> 877531db5STom Joseph 977531db5STom Joseph namespace cipher 1077531db5STom Joseph { 1177531db5STom Joseph 1277531db5STom Joseph namespace integrity 1377531db5STom Joseph { 1477531db5STom Joseph 153563f8feSTom Joseph /** 1677531db5STom Joseph * @enum Integrity Algorithms 1777531db5STom Joseph * 1877531db5STom Joseph * The Integrity Algorithm Number specifies the algorithm used to generate the 1977531db5STom Joseph * contents for the AuthCode “signature” field that accompanies authenticated 2077531db5STom Joseph * IPMI v2.0/RMCP+ messages once the session has been established. If the 2177531db5STom Joseph * Integrity Algorithm is none the AuthCode value is not calculated and the 22fe5a6458STom Joseph * AuthCode field in the message is not present. Based on security 23fe5a6458STom Joseph * recommendations NONE will not be supported. 2477531db5STom Joseph */ 2577531db5STom Joseph enum class Algorithms : uint8_t 2677531db5STom Joseph { 27fe5a6458STom Joseph NONE, // Mandatory (implemented, not supported) 28fe5a6458STom Joseph HMAC_SHA1_96, // Mandatory (implemented, default choice in ipmitool) 29fe5a6458STom Joseph HMAC_MD5_128, // Optional (not implemented) 30fe5a6458STom Joseph MD5_128, // Optional (not implemented) 31fe5a6458STom Joseph HMAC_SHA256_128, // Optional (implemented, best available) 3277531db5STom Joseph }; 3377531db5STom Joseph 343563f8feSTom Joseph /** 3577531db5STom Joseph * @class Interface 3677531db5STom Joseph * 3777531db5STom Joseph * Interface is the base class for the Integrity Algorithms. 3877531db5STom Joseph * Unless otherwise specified, the integrity algorithm is applied to the packet 3977531db5STom Joseph * data starting with the AuthType/Format field up to and including the field 4077531db5STom Joseph * that immediately precedes the AuthCode field itself. 4177531db5STom Joseph */ 4277531db5STom Joseph class Interface 4377531db5STom Joseph { 4477531db5STom Joseph public: 453563f8feSTom Joseph /** 4677531db5STom Joseph * @brief Constructor for Interface 4777531db5STom Joseph * 4877531db5STom Joseph * @param[in] - AuthCode length 4977531db5STom Joseph */ Interface(size_t authLength)50099fb097SPatrick Williams explicit Interface(size_t authLength) : authCodeLength(authLength) {} 5177531db5STom Joseph 5277531db5STom Joseph Interface() = delete; 5377531db5STom Joseph virtual ~Interface() = default; 5477531db5STom Joseph Interface(const Interface&) = default; 5577531db5STom Joseph Interface& operator=(const Interface&) = default; 5677531db5STom Joseph Interface(Interface&&) = default; 5777531db5STom Joseph Interface& operator=(Interface&&) = default; 5877531db5STom Joseph 593563f8feSTom Joseph /** 6077531db5STom Joseph * @brief Verify the integrity data of the packet 6177531db5STom Joseph * 6277531db5STom Joseph * @param[in] packet - Incoming IPMI packet 6377531db5STom Joseph * @param[in] packetLen - Packet length excluding authCode 64198b0f81SGeorge Liu * @param[in] integrityDataBegin - Begin iterator to the authCode in the 65198b0f81SGeorge Liu * packet 66198b0f81SGeorge Liu * @param[in] integrityDataEnd - End to the authCode in the packet 6777531db5STom Joseph * 6877531db5STom Joseph * @return true if authcode in the packet is equal to one generated 6977531db5STom Joseph * using integrity algorithm on the packet data, false otherwise 7077531db5STom Joseph */ 7177531db5STom Joseph bool virtual verifyIntegrityData( 729e801a2bSVernon Mauery const std::vector<uint8_t>& packet, const size_t packetLen, 73198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataBegin, 74198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataEnd) const = 0; 7577531db5STom Joseph 763563f8feSTom Joseph /** 7777531db5STom Joseph * @brief Generate integrity data for the outgoing IPMI packet 7877531db5STom Joseph * 7977531db5STom Joseph * @param[in] input - Outgoing IPMI packet 8077531db5STom Joseph * 8177531db5STom Joseph * @return authcode for the outgoing IPMI packet 8277531db5STom Joseph * 8377531db5STom Joseph */ 8470fd29cfSVernon Mauery std::vector<uint8_t> virtual generateIntegrityData( 8570fd29cfSVernon Mauery const std::vector<uint8_t>& input) const = 0; 8677531db5STom Joseph 871e7aa196STom Joseph /** 881e7aa196STom Joseph * @brief Check if the Integrity algorithm is supported 891e7aa196STom Joseph * 901e7aa196STom Joseph * @param[in] algo - integrity algorithm 911e7aa196STom Joseph * 921e7aa196STom Joseph * @return true if algorithm is supported else false 931e7aa196STom Joseph * 941e7aa196STom Joseph */ isAlgorithmSupported(Algorithms algo)951e7aa196STom Joseph static bool isAlgorithmSupported(Algorithms algo) 961e7aa196STom Joseph { 974c494398SSuryakanth Sekar if (algo == Algorithms::HMAC_SHA256_128) 981e7aa196STom Joseph { 991e7aa196STom Joseph return true; 1001e7aa196STom Joseph } 1011e7aa196STom Joseph else 1021e7aa196STom Joseph { 1031e7aa196STom Joseph return false; 1041e7aa196STom Joseph } 1051e7aa196STom Joseph } 1061e7aa196STom Joseph 1079b307be6SVernon Mauery /** 1089b307be6SVernon Mauery * @brief Generate additional keying material based on SIK 1099b307be6SVernon Mauery * 1109b307be6SVernon Mauery * @note 1119b307be6SVernon Mauery * The IPMI 2.0 spec only states that the additional keying material is 1129b307be6SVernon Mauery * generated by running HMAC(constN) using SIK as the key. It does not 1139b307be6SVernon Mauery * state whether this is the integrity algorithm or the authentication 1149b307be6SVernon Mauery * algorithm. Other implementations of the RMCP+ algorithm (ipmitool 1159b307be6SVernon Mauery * and ipmiutil) are not consistent on this matter. But it does not 1169b307be6SVernon Mauery * really matter because based on any of the defined cipher suites, the 1179b307be6SVernon Mauery * integrity and authentication algorithms are both based on the same 1189b307be6SVernon Mauery * digest method (integrity::Algorithms::HMAC_SHA1_96 uses SHA1 and 1199b307be6SVernon Mauery * rakp_auth::Algorithms::RAKP_HMAC_SHA1 uses SHA1). None of the 1209b307be6SVernon Mauery * defined cipher suites mix and match digests for integrity and 1219b307be6SVernon Mauery * authentication. Generating Kn belongs in either the integrity or 1229b307be6SVernon Mauery * authentication classes, so in this implementation, integrity has 1239b307be6SVernon Mauery * been chosen. 1249b307be6SVernon Mauery * 1259b307be6SVernon Mauery * @param[in] sik - session integrity key 1269b307be6SVernon Mauery * @param[in] data - 20-byte Const_n 1279b307be6SVernon Mauery * 1289b307be6SVernon Mauery * @return on success returns the Kn based on this integrity class 1299b307be6SVernon Mauery * 1309b307be6SVernon Mauery */ 1319b307be6SVernon Mauery std::vector<uint8_t> virtual generateKn( 1329e801a2bSVernon Mauery const std::vector<uint8_t>& sik, const rmcp::Const_n& data) const = 0; 1339b307be6SVernon Mauery 1343563f8feSTom Joseph /** @brief Authcode field 1353563f8feSTom Joseph * 13677531db5STom Joseph * AuthCode field length varies based on the integrity algorithm, for 13777531db5STom Joseph * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and 13877531db5STom Joseph * HMAC-MD5-128 the authcode field is 16 bytes. 13977531db5STom Joseph */ 14077531db5STom Joseph size_t authCodeLength; 14177531db5STom Joseph 14277531db5STom Joseph protected: 1433563f8feSTom Joseph /** @brief K1 key used to generated the integrity data. */ 1449b307be6SVernon Mauery std::vector<uint8_t> k1; 14577531db5STom Joseph }; 14677531db5STom Joseph 1473563f8feSTom Joseph /** 148d212a6dcSTom Joseph * @class AlgoSHA1 149d212a6dcSTom Joseph * 150d212a6dcSTom Joseph * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm 151d212a6dcSTom Joseph * 152d212a6dcSTom Joseph * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is 153d212a6dcSTom Joseph * then used as the key for use in HMAC to produce the AuthCode field. 154d212a6dcSTom Joseph * For “one-key” logins, the user’s key (password) is used in the creation of 155d212a6dcSTom Joseph * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used 156d212a6dcSTom Joseph * the resulting AuthCode field is 12 bytes (96 bits). 157d212a6dcSTom Joseph */ 158d212a6dcSTom Joseph class AlgoSHA1 final : public Interface 159d212a6dcSTom Joseph { 160d212a6dcSTom Joseph public: 161d212a6dcSTom Joseph static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12; 162d212a6dcSTom Joseph 1633563f8feSTom Joseph /** 164d212a6dcSTom Joseph * @brief Constructor for AlgoSHA1 165d212a6dcSTom Joseph * 166d212a6dcSTom Joseph * @param[in] - Session Integrity Key 167d212a6dcSTom Joseph */ 1689b307be6SVernon Mauery explicit AlgoSHA1(const std::vector<uint8_t>& sik); 169d212a6dcSTom Joseph 170d212a6dcSTom Joseph AlgoSHA1() = delete; 171d212a6dcSTom Joseph ~AlgoSHA1() = default; 172d212a6dcSTom Joseph AlgoSHA1(const AlgoSHA1&) = default; 173d212a6dcSTom Joseph AlgoSHA1& operator=(const AlgoSHA1&) = default; 174d212a6dcSTom Joseph AlgoSHA1(AlgoSHA1&&) = default; 175d212a6dcSTom Joseph AlgoSHA1& operator=(AlgoSHA1&&) = default; 176d212a6dcSTom Joseph 1773563f8feSTom Joseph /** 178d212a6dcSTom Joseph * @brief Verify the integrity data of the packet 179d212a6dcSTom Joseph * 180d212a6dcSTom Joseph * @param[in] packet - Incoming IPMI packet 181d212a6dcSTom Joseph * @param[in] length - Length of the data in the packet to calculate 182d212a6dcSTom Joseph * the integrity data 183198b0f81SGeorge Liu * @param[in] integrityDataBegin - Begin iterator to the authCode in the 184198b0f81SGeorge Liu * packet 185198b0f81SGeorge Liu * @param[in] integrityDataEnd - End to the authCode in the packet 186d212a6dcSTom Joseph * 187d212a6dcSTom Joseph * @return true if authcode in the packet is equal to one generated 188d212a6dcSTom Joseph * using integrity algorithm on the packet data, false otherwise 189d212a6dcSTom Joseph */ 190d212a6dcSTom Joseph bool verifyIntegrityData( 1919e801a2bSVernon Mauery const std::vector<uint8_t>& packet, const size_t length, 192198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataBegin, 193198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataEnd) const override; 194d212a6dcSTom Joseph 1953563f8feSTom Joseph /** 196d212a6dcSTom Joseph * @brief Generate integrity data for the outgoing IPMI packet 197d212a6dcSTom Joseph * 198d212a6dcSTom Joseph * @param[in] input - Outgoing IPMI packet 199d212a6dcSTom Joseph * 200d212a6dcSTom Joseph * @return on success return the integrity data for the outgoing IPMI 201d212a6dcSTom Joseph * packet 202d212a6dcSTom Joseph */ 20370fd29cfSVernon Mauery std::vector<uint8_t> generateIntegrityData( 20470fd29cfSVernon Mauery const std::vector<uint8_t>& packet) const override; 205d212a6dcSTom Joseph 2069b307be6SVernon Mauery /** 2079b307be6SVernon Mauery * @brief Generate additional keying material based on SIK 2089b307be6SVernon Mauery * 2099b307be6SVernon Mauery * @param[in] sik - session integrity key 2109b307be6SVernon Mauery * @param[in] data - 20-byte Const_n 2119b307be6SVernon Mauery * 2129b307be6SVernon Mauery * @return on success returns the Kn based on HMAC-SHA1 2139b307be6SVernon Mauery * 2149b307be6SVernon Mauery */ 215*bac2f1a3SLei YU std::vector<uint8_t> generateKn( 216*bac2f1a3SLei YU const std::vector<uint8_t>& sik, 217*bac2f1a3SLei YU const rmcp::Const_n& const_n) const override; 2189b307be6SVernon Mauery 219d212a6dcSTom Joseph private: 2203563f8feSTom Joseph /** 221d212a6dcSTom Joseph * @brief Generate HMAC based on HMAC-SHA1-96 algorithm 222d212a6dcSTom Joseph * 223d212a6dcSTom Joseph * @param[in] input - pointer to the message 224d212a6dcSTom Joseph * @param[in] length - length of the message 225d212a6dcSTom Joseph * 226d212a6dcSTom Joseph * @return on success returns the message authentication code 227d212a6dcSTom Joseph * 228d212a6dcSTom Joseph */ 22970fd29cfSVernon Mauery std::vector<uint8_t> generateHMAC(const uint8_t* input, 23070fd29cfSVernon Mauery const size_t len) const; 231d212a6dcSTom Joseph }; 232d212a6dcSTom Joseph 2337e9e2ef6SVernon Mauery /** 2347e9e2ef6SVernon Mauery * @class AlgoSHA256 2357e9e2ef6SVernon Mauery * 2367e9e2ef6SVernon Mauery * @brief Implementation of the HMAC-SHA256-128 Integrity algorithm 2377e9e2ef6SVernon Mauery * 2387e9e2ef6SVernon Mauery * HMAC-SHA256-128 take the Session Integrity Key and use it to generate K1. K1 2397e9e2ef6SVernon Mauery * is then used as the key for use in HMAC to produce the AuthCode field. For 2407e9e2ef6SVernon Mauery * “one-key” logins, the user’s key (password) is used in the creation of the 2417e9e2ef6SVernon Mauery * Session Integrity Key. When the HMAC-SHA256-128 Integrity Algorithm is used 2427e9e2ef6SVernon Mauery * the resulting AuthCode field is 16 bytes (128 bits). 2437e9e2ef6SVernon Mauery */ 2447e9e2ef6SVernon Mauery class AlgoSHA256 final : public Interface 2457e9e2ef6SVernon Mauery { 2467e9e2ef6SVernon Mauery public: 2477e9e2ef6SVernon Mauery static constexpr size_t SHA256_128_AUTHCODE_LENGTH = 16; 2487e9e2ef6SVernon Mauery 2497e9e2ef6SVernon Mauery /** 2507e9e2ef6SVernon Mauery * @brief Constructor for AlgoSHA256 2517e9e2ef6SVernon Mauery * 2527e9e2ef6SVernon Mauery * @param[in] - Session Integrity Key 2537e9e2ef6SVernon Mauery */ 2547e9e2ef6SVernon Mauery explicit AlgoSHA256(const std::vector<uint8_t>& sik); 2557e9e2ef6SVernon Mauery 2567e9e2ef6SVernon Mauery AlgoSHA256() = delete; 2577e9e2ef6SVernon Mauery ~AlgoSHA256() = default; 2587e9e2ef6SVernon Mauery AlgoSHA256(const AlgoSHA256&) = default; 2597e9e2ef6SVernon Mauery AlgoSHA256& operator=(const AlgoSHA256&) = default; 2607e9e2ef6SVernon Mauery AlgoSHA256(AlgoSHA256&&) = default; 2617e9e2ef6SVernon Mauery AlgoSHA256& operator=(AlgoSHA256&&) = default; 2627e9e2ef6SVernon Mauery 2637e9e2ef6SVernon Mauery /** 2647e9e2ef6SVernon Mauery * @brief Verify the integrity data of the packet 2657e9e2ef6SVernon Mauery * 2667e9e2ef6SVernon Mauery * @param[in] packet - Incoming IPMI packet 2677e9e2ef6SVernon Mauery * @param[in] length - Length of the data in the packet to calculate 2687e9e2ef6SVernon Mauery * the integrity data 269198b0f81SGeorge Liu * @param[in] integrityDataBegin - Begin iterator to the authCode in the 270198b0f81SGeorge Liu * packet 271198b0f81SGeorge Liu * @param[in] integrityDataEnd - End to the authCode in the packet 2727e9e2ef6SVernon Mauery * 2737e9e2ef6SVernon Mauery * @return true if authcode in the packet is equal to one generated 2747e9e2ef6SVernon Mauery * using integrity algorithm on the packet data, false otherwise 2757e9e2ef6SVernon Mauery */ 2767e9e2ef6SVernon Mauery bool verifyIntegrityData( 2779e801a2bSVernon Mauery const std::vector<uint8_t>& packet, const size_t length, 278198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataBegin, 279198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataEnd) const override; 2807e9e2ef6SVernon Mauery 2817e9e2ef6SVernon Mauery /** 2827e9e2ef6SVernon Mauery * @brief Generate integrity data for the outgoing IPMI packet 2837e9e2ef6SVernon Mauery * 2847e9e2ef6SVernon Mauery * @param[in] packet - Outgoing IPMI packet 2857e9e2ef6SVernon Mauery * 2867e9e2ef6SVernon Mauery * @return on success return the integrity data for the outgoing IPMI 2877e9e2ef6SVernon Mauery * packet 2887e9e2ef6SVernon Mauery */ 2897e9e2ef6SVernon Mauery std::vector<uint8_t> generateIntegrityData( 2907e9e2ef6SVernon Mauery const std::vector<uint8_t>& packet) const override; 2917e9e2ef6SVernon Mauery 2927e9e2ef6SVernon Mauery /** 2937e9e2ef6SVernon Mauery * @brief Generate additional keying material based on SIK 2947e9e2ef6SVernon Mauery * 2957e9e2ef6SVernon Mauery * @param[in] sik - session integrity key 2967e9e2ef6SVernon Mauery * @param[in] data - 20-byte Const_n 2977e9e2ef6SVernon Mauery * 2987e9e2ef6SVernon Mauery * @return on success returns the Kn based on HMAC-SHA256 2997e9e2ef6SVernon Mauery * 3007e9e2ef6SVernon Mauery */ 301*bac2f1a3SLei YU std::vector<uint8_t> generateKn( 302*bac2f1a3SLei YU const std::vector<uint8_t>& sik, 303*bac2f1a3SLei YU const rmcp::Const_n& const_n) const override; 3047e9e2ef6SVernon Mauery 3057e9e2ef6SVernon Mauery private: 3067e9e2ef6SVernon Mauery /** 3077e9e2ef6SVernon Mauery * @brief Generate HMAC based on HMAC-SHA256-128 algorithm 3087e9e2ef6SVernon Mauery * 3097e9e2ef6SVernon Mauery * @param[in] input - pointer to the message 3107e9e2ef6SVernon Mauery * @param[in] len - length of the message 3117e9e2ef6SVernon Mauery * 3127e9e2ef6SVernon Mauery * @return on success returns the message authentication code 3137e9e2ef6SVernon Mauery * 3147e9e2ef6SVernon Mauery */ 3157e9e2ef6SVernon Mauery std::vector<uint8_t> generateHMAC(const uint8_t* input, 3167e9e2ef6SVernon Mauery const size_t len) const; 3177e9e2ef6SVernon Mauery }; 3187e9e2ef6SVernon Mauery 31977531db5STom Joseph } // namespace integrity 32077531db5STom Joseph 32177531db5STom Joseph } // namespace cipher 322