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