18c0446c1STom Joseph #pragma once 28c0446c1STom Joseph 3ba11f792STom Joseph #include "crypt_algo.hpp" 4dd1be1a2STom Joseph #include "integrity_algo.hpp" 58c0446c1STom Joseph 69e801a2bSVernon Mauery #include <array> 79d9b7638SAndrew Geissler #include <cstddef> 87408e76aSAndrew Geissler #include <string> 99e801a2bSVernon Mauery #include <vector> 109e801a2bSVernon Mauery 118c0446c1STom Joseph namespace cipher 128c0446c1STom Joseph { 138c0446c1STom Joseph namespace rakp_auth 148c0446c1STom Joseph { 158c0446c1STom Joseph constexpr size_t USER_KEY_MAX_LENGTH = 20; 168c0446c1STom Joseph constexpr size_t BMC_RANDOM_NUMBER_LEN = 16; 178c0446c1STom Joseph constexpr size_t REMOTE_CONSOLE_RANDOM_NUMBER_LEN = 16; 1856527b93STom Joseph extern const std::string userName; 198c0446c1STom Joseph 203563f8feSTom Joseph /** 218c0446c1STom Joseph * @enum RAKP Authentication Algorithms 228c0446c1STom Joseph * 238c0446c1STom Joseph * RMCP+ Authenticated Key-Exchange Protocol (RAKP) 248c0446c1STom Joseph * 258c0446c1STom Joseph * RAKP-None is not supported as per the following recommendation 268c0446c1STom Joseph * (https://www.us-cert.gov/ncas/alerts/TA13-207A) 278c0446c1STom Joseph * ("cipher 0" is an option enabled by default on many IPMI enabled devices that 288c0446c1STom Joseph * allows authentication to be bypassed. Disable "cipher 0" to prevent 298c0446c1STom Joseph * attackers from bypassing authentication and sending arbitrary IPMI commands.) 308c0446c1STom Joseph */ 318c0446c1STom Joseph enum class Algorithms : uint8_t 328c0446c1STom Joseph { 33fe5a6458STom Joseph RAKP_NONE = 0, // Mandatory (implemented, not supported) 34fe5a6458STom Joseph RAKP_HMAC_SHA1, // Mandatory (implemented, default choice in ipmitool) 35fe5a6458STom Joseph RAKP_HMAC_MD5, // Optional (not implemented) 36fe5a6458STom Joseph RAKP_HMAC_SHA256, // Optional (implemented, best available) 378c0446c1STom Joseph // Reserved used to indicate an invalid authentication algorithm 388c0446c1STom Joseph RAKP_HMAC_INVALID = 0xB0 398c0446c1STom Joseph }; 408c0446c1STom Joseph 413563f8feSTom Joseph /** 428c0446c1STom Joseph * @class Interface 438c0446c1STom Joseph * 448c0446c1STom Joseph * Interface is the base class for the Authentication Algorithms. 458c0446c1STom Joseph * The Authentication Algorithm specifies the type of authentication “handshake” 468c0446c1STom Joseph * process that is used and identifies any particular variations of hashing or 478c0446c1STom Joseph * signature algorithm that is used as part of the process. 488c0446c1STom Joseph * 498c0446c1STom Joseph */ 508c0446c1STom Joseph class Interface 518c0446c1STom Joseph { 528c0446c1STom Joseph public: Interface(integrity::Algorithms intAlgo,crypt::Algorithms cryptAlgo)53ba11f792STom Joseph explicit Interface(integrity::Algorithms intAlgo, 54ba11f792STom Joseph crypt::Algorithms cryptAlgo) : 55ba11f792STom Joseph intAlgo(intAlgo), 569e801a2bSVernon Mauery cryptAlgo(cryptAlgo) 57*bc8958feSGeorge Liu {} 58ba11f792STom Joseph 59dd1be1a2STom Joseph Interface() = delete; 608c0446c1STom Joseph virtual ~Interface() = default; 618c0446c1STom Joseph Interface(const Interface&) = default; 628c0446c1STom Joseph Interface& operator=(const Interface&) = default; 638c0446c1STom Joseph Interface(Interface&&) = default; 648c0446c1STom Joseph Interface& operator=(Interface&&) = default; 658c0446c1STom Joseph 663563f8feSTom Joseph /** 678c0446c1STom Joseph * @brief Generate the Hash Message Authentication Code 688c0446c1STom Joseph * 698c0446c1STom Joseph * This API is invoked to generate the Key Exchange Authentication Code 708c0446c1STom Joseph * in the RAKP2 and RAKP4 sequence and for generating the Session 718c0446c1STom Joseph * Integrity Key. 728c0446c1STom Joseph * 738c0446c1STom Joseph * @param input message 748c0446c1STom Joseph * 758c0446c1STom Joseph * @return hash output 768c0446c1STom Joseph * 778c0446c1STom Joseph * @note The user key which is the secret key for the hash operation 788c0446c1STom Joseph * needs to be set before this operation. 798c0446c1STom Joseph */ 808c0446c1STom Joseph std::vector<uint8_t> virtual generateHMAC( 8170fd29cfSVernon Mauery const std::vector<uint8_t>& input) const = 0; 828c0446c1STom Joseph 833563f8feSTom Joseph /** 848c0446c1STom Joseph * @brief Generate the Integrity Check Value 858c0446c1STom Joseph * 868c0446c1STom Joseph * This API is invoked in the RAKP4 sequence for generating the 878c0446c1STom Joseph * Integrity Check Value. 888c0446c1STom Joseph * 898c0446c1STom Joseph * @param input message 908c0446c1STom Joseph * 918c0446c1STom Joseph * @return hash output 928c0446c1STom Joseph * 938c0446c1STom Joseph * @note The session integrity key which is the secret key for the 948c0446c1STom Joseph * hash operation needs to be set before this operation. 958c0446c1STom Joseph */ 968c0446c1STom Joseph std::vector<uint8_t> virtual generateICV( 9770fd29cfSVernon Mauery const std::vector<uint8_t>& input) const = 0; 988c0446c1STom Joseph 999b307be6SVernon Mauery /** 1009b307be6SVernon Mauery * @brief Check if the Authentication algorithm is supported 1019b307be6SVernon Mauery * 1029b307be6SVernon Mauery * @param[in] algo - authentication algorithm 1039b307be6SVernon Mauery * 1049b307be6SVernon Mauery * @return true if algorithm is supported else false 1059b307be6SVernon Mauery * 1069b307be6SVernon Mauery */ isAlgorithmSupported(Algorithms algo)1079b307be6SVernon Mauery static bool isAlgorithmSupported(Algorithms algo) 1089b307be6SVernon Mauery { 1094c494398SSuryakanth Sekar if (algo == Algorithms::RAKP_HMAC_SHA256) 1109b307be6SVernon Mauery { 1119b307be6SVernon Mauery return true; 1129b307be6SVernon Mauery } 1139b307be6SVernon Mauery else 1149b307be6SVernon Mauery { 1159b307be6SVernon Mauery return false; 1169b307be6SVernon Mauery } 1179b307be6SVernon Mauery } 1189b307be6SVernon Mauery 1198c0446c1STom Joseph // User Key is hardcoded to PASSW0RD till the IPMI User account 1208c0446c1STom Joseph // management is in place. 121e2e97660STom Joseph std::array<uint8_t, USER_KEY_MAX_LENGTH> userKey = {"0penBmc"}; 1228c0446c1STom Joseph 1238c0446c1STom Joseph // Managed System Random Number 1248c0446c1STom Joseph std::array<uint8_t, BMC_RANDOM_NUMBER_LEN> bmcRandomNum; 1258c0446c1STom Joseph 1268c0446c1STom Joseph // Remote Console Random Number 1278c0446c1STom Joseph std::array<uint8_t, REMOTE_CONSOLE_RANDOM_NUMBER_LEN> rcRandomNum; 1288c0446c1STom Joseph 1298c0446c1STom Joseph // Session Integrity Key 1308c0446c1STom Joseph std::vector<uint8_t> sessionIntegrityKey; 131dd1be1a2STom Joseph 1323563f8feSTom Joseph /** 133dd1be1a2STom Joseph * Integrity Algorithm is activated and set in the session data only 134dd1be1a2STom Joseph * once the session setup is succeeded in the RAKP34 command. But the 135dd1be1a2STom Joseph * integrity algorithm is negotiated in the Open Session Request command 136ba11f792STom Joseph * . So the integrity algorithm successfully negotiated is stored 137ba11f792STom Joseph * in the authentication algorithm's instance. 138dd1be1a2STom Joseph */ 139dd1be1a2STom Joseph integrity::Algorithms intAlgo; 140ba11f792STom Joseph 1413563f8feSTom Joseph /** 142ba11f792STom Joseph * Confidentiality Algorithm is activated and set in the session data 143ba11f792STom Joseph * only once the session setup is succeeded in the RAKP34 command. But 144ba11f792STom Joseph * the confidentiality algorithm is negotiated in the Open Session 145ba11f792STom Joseph * Request command. So the confidentiality algorithm successfully 146ba11f792STom Joseph * negotiated is stored in the authentication algorithm's instance. 147ba11f792STom Joseph */ 148ba11f792STom Joseph crypt::Algorithms cryptAlgo; 1498c0446c1STom Joseph }; 1508c0446c1STom Joseph 1513563f8feSTom Joseph /** 1528c0446c1STom Joseph * @class AlgoSHA1 1538c0446c1STom Joseph * 1548c0446c1STom Joseph * RAKP-HMAC-SHA1 specifies the use of RAKP messages for the key exchange 1558c0446c1STom Joseph * portion of establishing the session, and that HMAC-SHA1 (per [RFC2104]) is 1568c0446c1STom Joseph * used to create 20-byte Key Exchange Authentication Code fields in RAKP 1578c0446c1STom Joseph * Message 2 and RAKP Message 3. HMAC-SHA1-96(per [RFC2404]) is used for 1588c0446c1STom Joseph * generating a 12-byte Integrity Check Value field for RAKP Message 4. 1598c0446c1STom Joseph */ 1608c0446c1STom Joseph 1618c0446c1STom Joseph class AlgoSHA1 : public Interface 1628c0446c1STom Joseph { 1638c0446c1STom Joseph public: 1642207f51cSVernon Mauery static constexpr size_t integrityCheckValueLength = 12; 1652207f51cSVernon Mauery AlgoSHA1(integrity::Algorithms intAlgo,crypt::Algorithms cryptAlgo)166ba11f792STom Joseph explicit AlgoSHA1(integrity::Algorithms intAlgo, 167ba11f792STom Joseph crypt::Algorithms cryptAlgo) : 1689e801a2bSVernon Mauery Interface(intAlgo, cryptAlgo) 169*bc8958feSGeorge Liu {} 170ba11f792STom Joseph 171dd1be1a2STom Joseph AlgoSHA1() = delete; 1728c0446c1STom Joseph ~AlgoSHA1() = default; 1738c0446c1STom Joseph AlgoSHA1(const AlgoSHA1&) = default; 1748c0446c1STom Joseph AlgoSHA1& operator=(const AlgoSHA1&) = default; 1758c0446c1STom Joseph AlgoSHA1(AlgoSHA1&&) = default; 1768c0446c1STom Joseph AlgoSHA1& operator=(AlgoSHA1&&) = default; 1778c0446c1STom Joseph 1789e801a2bSVernon Mauery std::vector<uint8_t> 1799e801a2bSVernon Mauery generateHMAC(const std::vector<uint8_t>& input) const override; 1808c0446c1STom Joseph 1819e801a2bSVernon Mauery std::vector<uint8_t> 1829e801a2bSVernon Mauery generateICV(const std::vector<uint8_t>& input) const override; 1838c0446c1STom Joseph }; 1848c0446c1STom Joseph 1857e9e2ef6SVernon Mauery /** 1867e9e2ef6SVernon Mauery * @class AlgoSHA256 1877e9e2ef6SVernon Mauery * 1887e9e2ef6SVernon Mauery * RAKP-HMAC-SHA256 specifies the use of RAKP messages for the key exchange 1897e9e2ef6SVernon Mauery * portion of establishing the session, and that HMAC-SHA256 (per [FIPS 180-2] 1907e9e2ef6SVernon Mauery * and [RFC4634] and is used to create a 32-byte Key Exchange Authentication 1917e9e2ef6SVernon Mauery * Code fields in RAKP Message 2 and RAKP Message 3. HMAC-SHA256-128 (per 1927e9e2ef6SVernon Mauery * [RFC4868]) is used for generating a 16-byte Integrity Check Value field for 1937e9e2ef6SVernon Mauery * RAKP Message 4. 1947e9e2ef6SVernon Mauery */ 1957e9e2ef6SVernon Mauery 1967e9e2ef6SVernon Mauery class AlgoSHA256 : public Interface 1977e9e2ef6SVernon Mauery { 1987e9e2ef6SVernon Mauery public: 1997e9e2ef6SVernon Mauery static constexpr size_t integrityCheckValueLength = 16; 2007e9e2ef6SVernon Mauery AlgoSHA256(integrity::Algorithms intAlgo,crypt::Algorithms cryptAlgo)2017e9e2ef6SVernon Mauery explicit AlgoSHA256(integrity::Algorithms intAlgo, 2027e9e2ef6SVernon Mauery crypt::Algorithms cryptAlgo) : 2039e801a2bSVernon Mauery Interface(intAlgo, cryptAlgo) 204*bc8958feSGeorge Liu {} 2057e9e2ef6SVernon Mauery 2067e9e2ef6SVernon Mauery ~AlgoSHA256() = default; 2077e9e2ef6SVernon Mauery AlgoSHA256(const AlgoSHA256&) = default; 2087e9e2ef6SVernon Mauery AlgoSHA256& operator=(const AlgoSHA256&) = default; 2097e9e2ef6SVernon Mauery AlgoSHA256(AlgoSHA256&&) = default; 2107e9e2ef6SVernon Mauery AlgoSHA256& operator=(AlgoSHA256&&) = default; 2117e9e2ef6SVernon Mauery 2129e801a2bSVernon Mauery std::vector<uint8_t> 2139e801a2bSVernon Mauery generateHMAC(const std::vector<uint8_t>& input) const override; 2147e9e2ef6SVernon Mauery 2159e801a2bSVernon Mauery std::vector<uint8_t> 2169e801a2bSVernon Mauery generateICV(const std::vector<uint8_t>& input) const override; 2177e9e2ef6SVernon Mauery }; 2187e9e2ef6SVernon Mauery 2199e801a2bSVernon Mauery } // namespace rakp_auth 2208c0446c1STom Joseph 2218c0446c1STom Joseph } // namespace cipher 222