1 #pragma once 2 3 #include <array> 4 #include <vector> 5 #include "crypt_algo.hpp" 6 #include "integrity_algo.hpp" 7 8 namespace cipher 9 { 10 namespace rakp_auth 11 { 12 constexpr size_t USER_KEY_MAX_LENGTH = 20; 13 constexpr size_t BMC_RANDOM_NUMBER_LEN = 16; 14 constexpr size_t REMOTE_CONSOLE_RANDOM_NUMBER_LEN = 16; 15 extern const std::string userName; 16 17 /** 18 * @enum RAKP Authentication Algorithms 19 * 20 * RMCP+ Authenticated Key-Exchange Protocol (RAKP) 21 * 22 * RAKP-None is not supported as per the following recommendation 23 * (https://www.us-cert.gov/ncas/alerts/TA13-207A) 24 * ("cipher 0" is an option enabled by default on many IPMI enabled devices that 25 * allows authentication to be bypassed. Disable "cipher 0" to prevent 26 * attackers from bypassing authentication and sending arbitrary IPMI commands.) 27 */ 28 enum class Algorithms : uint8_t 29 { 30 RAKP_NONE = 0, // Mandatory (implemented, not supported) 31 RAKP_HMAC_SHA1, // Mandatory (implemented, default choice in ipmitool) 32 RAKP_HMAC_MD5, // Optional (not implemented) 33 RAKP_HMAC_SHA256, // Optional (implemented, best available) 34 // Reserved used to indicate an invalid authentication algorithm 35 RAKP_HMAC_INVALID = 0xB0 36 }; 37 38 /** 39 * @class Interface 40 * 41 * Interface is the base class for the Authentication Algorithms. 42 * The Authentication Algorithm specifies the type of authentication “handshake” 43 * process that is used and identifies any particular variations of hashing or 44 * signature algorithm that is used as part of the process. 45 * 46 */ 47 class Interface 48 { 49 public: 50 explicit Interface(integrity::Algorithms intAlgo, 51 crypt::Algorithms cryptAlgo) : 52 intAlgo(intAlgo), 53 cryptAlgo(cryptAlgo) {} 54 55 Interface() = delete; 56 virtual ~Interface() = default; 57 Interface(const Interface&) = default; 58 Interface& operator=(const Interface&) = default; 59 Interface(Interface&&) = default; 60 Interface& operator=(Interface&&) = default; 61 62 /** 63 * @brief Generate the Hash Message Authentication Code 64 * 65 * This API is invoked to generate the Key Exchange Authentication Code 66 * in the RAKP2 and RAKP4 sequence and for generating the Session 67 * Integrity Key. 68 * 69 * @param input message 70 * 71 * @return hash output 72 * 73 * @note The user key which is the secret key for the hash operation 74 * needs to be set before this operation. 75 */ 76 std::vector<uint8_t> virtual generateHMAC( 77 const std::vector<uint8_t>& input) const = 0; 78 79 /** 80 * @brief Generate the Integrity Check Value 81 * 82 * This API is invoked in the RAKP4 sequence for generating the 83 * Integrity Check Value. 84 * 85 * @param input message 86 * 87 * @return hash output 88 * 89 * @note The session integrity key which is the secret key for the 90 * hash operation needs to be set before this operation. 91 */ 92 std::vector<uint8_t> virtual generateICV( 93 const std::vector<uint8_t>& input) const = 0; 94 95 /** 96 * @brief Check if the Authentication algorithm is supported 97 * 98 * @param[in] algo - authentication algorithm 99 * 100 * @return true if algorithm is supported else false 101 * 102 */ 103 static bool isAlgorithmSupported(Algorithms algo) 104 { 105 if (algo == Algorithms::RAKP_HMAC_SHA1 || 106 algo == Algorithms::RAKP_HMAC_SHA256) 107 { 108 return true; 109 } 110 else 111 { 112 return false; 113 } 114 } 115 116 // User Key is hardcoded to PASSW0RD till the IPMI User account 117 // management is in place. 118 std::array<uint8_t, USER_KEY_MAX_LENGTH> userKey = {"0penBmc"}; 119 120 // Managed System Random Number 121 std::array<uint8_t, BMC_RANDOM_NUMBER_LEN> bmcRandomNum; 122 123 // Remote Console Random Number 124 std::array<uint8_t, REMOTE_CONSOLE_RANDOM_NUMBER_LEN> rcRandomNum; 125 126 // Session Integrity Key 127 std::vector<uint8_t> sessionIntegrityKey; 128 129 /** 130 * Integrity Algorithm is activated and set in the session data only 131 * once the session setup is succeeded in the RAKP34 command. But the 132 * integrity algorithm is negotiated in the Open Session Request command 133 * . So the integrity algorithm successfully negotiated is stored 134 * in the authentication algorithm's instance. 135 */ 136 integrity::Algorithms intAlgo; 137 138 /** 139 * Confidentiality Algorithm is activated and set in the session data 140 * only once the session setup is succeeded in the RAKP34 command. But 141 * the confidentiality algorithm is negotiated in the Open Session 142 * Request command. So the confidentiality algorithm successfully 143 * negotiated is stored in the authentication algorithm's instance. 144 */ 145 crypt::Algorithms cryptAlgo; 146 }; 147 148 /** 149 * @class AlgoSHA1 150 * 151 * RAKP-HMAC-SHA1 specifies the use of RAKP messages for the key exchange 152 * portion of establishing the session, and that HMAC-SHA1 (per [RFC2104]) is 153 * used to create 20-byte Key Exchange Authentication Code fields in RAKP 154 * Message 2 and RAKP Message 3. HMAC-SHA1-96(per [RFC2404]) is used for 155 * generating a 12-byte Integrity Check Value field for RAKP Message 4. 156 */ 157 158 class AlgoSHA1 : public Interface 159 { 160 public: 161 static constexpr size_t integrityCheckValueLength = 12; 162 163 explicit AlgoSHA1(integrity::Algorithms intAlgo, 164 crypt::Algorithms cryptAlgo) : 165 Interface(intAlgo, cryptAlgo) {} 166 167 AlgoSHA1() = delete; 168 ~AlgoSHA1() = default; 169 AlgoSHA1(const AlgoSHA1&) = default; 170 AlgoSHA1& operator=(const AlgoSHA1&) = default; 171 AlgoSHA1(AlgoSHA1&&) = default; 172 AlgoSHA1& operator=(AlgoSHA1&&) = default; 173 174 std::vector<uint8_t> generateHMAC( 175 const std::vector<uint8_t>& input) const override; 176 177 std::vector<uint8_t> generateICV( 178 const std::vector<uint8_t>& input) const override; 179 }; 180 181 /** 182 * @class AlgoSHA256 183 * 184 * RAKP-HMAC-SHA256 specifies the use of RAKP messages for the key exchange 185 * portion of establishing the session, and that HMAC-SHA256 (per [FIPS 180-2] 186 * and [RFC4634] and is used to create a 32-byte Key Exchange Authentication 187 * Code fields in RAKP Message 2 and RAKP Message 3. HMAC-SHA256-128 (per 188 * [RFC4868]) is used for generating a 16-byte Integrity Check Value field for 189 * RAKP Message 4. 190 */ 191 192 class AlgoSHA256 : public Interface 193 { 194 public: 195 static constexpr size_t integrityCheckValueLength = 16; 196 197 explicit AlgoSHA256(integrity::Algorithms intAlgo, 198 crypt::Algorithms cryptAlgo) : 199 Interface(intAlgo, cryptAlgo) {} 200 201 ~AlgoSHA256() = default; 202 AlgoSHA256(const AlgoSHA256&) = default; 203 AlgoSHA256& operator=(const AlgoSHA256&) = default; 204 AlgoSHA256(AlgoSHA256&&) = default; 205 AlgoSHA256& operator=(AlgoSHA256&&) = default; 206 207 std::vector<uint8_t> generateHMAC( 208 const std::vector<uint8_t>& input) const override; 209 210 std::vector<uint8_t> generateICV( 211 const std::vector<uint8_t>& input) const override; 212 }; 213 214 }// namespace auth 215 216 }// namespace cipher 217 218