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