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