1 #pragma once 2 3 #include <openssl/sha.h> 4 #include <array> 5 #include <vector> 6 7 namespace cipher 8 { 9 10 namespace integrity 11 { 12 13 using Buffer = std::vector<uint8_t>; 14 using Key = std::array<uint8_t, SHA_DIGEST_LENGTH>; 15 16 /* 17 * RSP needs more keying material than can be provided by session integrity key 18 * alone. As a result all keying material for the RSP integrity algorithms 19 * will be generated by processing a pre-defined set of constants using HMAC per 20 * [RFC2104], keyed by SIK. These constants are constructed using a hexadecimal 21 * octet value repeated up to the HMAC block size in length starting with the 22 * constant 01h. This mechanism can be used to derive up to 255 23 * HMAC-block-length pieces of keying material from a single SIK. For the 24 * mandatory integrity algorithm HMAC-SHA1-96, processing the following 25 * constant will generate the required amount of keying material. 26 */ 27 constexpr Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01, 28 0x01, 0x01, 0x01, 0x01, 0x01, 29 0x01, 0x01, 0x01, 0x01, 0x01, 30 0x01, 0x01, 0x01, 0x01, 0x01 31 }; 32 33 /* 34 * @enum Integrity Algorithms 35 * 36 * The Integrity Algorithm Number specifies the algorithm used to generate the 37 * contents for the AuthCode “signature” field that accompanies authenticated 38 * IPMI v2.0/RMCP+ messages once the session has been established. If the 39 * Integrity Algorithm is none the AuthCode value is not calculated and the 40 * AuthCode field in the message is not present. 41 */ 42 enum class Algorithms : uint8_t 43 { 44 NONE, // Mandatory 45 HMAC_SHA1_96, // Mandatory 46 HMAC_MD5_128, // Optional 47 MD5_128, // Optional 48 HMAC_SHA256_128, // Optional 49 }; 50 51 /* 52 * @class Interface 53 * 54 * Interface is the base class for the Integrity Algorithms. 55 * Unless otherwise specified, the integrity algorithm is applied to the packet 56 * data starting with the AuthType/Format field up to and including the field 57 * that immediately precedes the AuthCode field itself. 58 */ 59 class Interface 60 { 61 public: 62 /* 63 * @brief Constructor for Interface 64 * 65 * @param[in] - Session Integrity Key to generate K1 66 * @param[in] - Additional keying material to generate K1 67 * @param[in] - AuthCode length 68 */ 69 explicit Interface(const Buffer& sik, 70 const Key& addKey, 71 size_t authLength); 72 73 Interface() = delete; 74 virtual ~Interface() = default; 75 Interface(const Interface&) = default; 76 Interface& operator=(const Interface&) = default; 77 Interface(Interface&&) = default; 78 Interface& operator=(Interface&&) = default; 79 80 /* 81 * @brief Verify the integrity data of the packet 82 * 83 * @param[in] packet - Incoming IPMI packet 84 * @param[in] packetLen - Packet length excluding authCode 85 * @param[in] integrityData - Iterator to the authCode in the packet 86 * 87 * @return true if authcode in the packet is equal to one generated 88 * using integrity algorithm on the packet data, false otherwise 89 */ 90 bool virtual verifyIntegrityData( 91 const Buffer& packet, 92 const size_t packetLen, 93 Buffer::const_iterator integrityData) const = 0; 94 95 /* 96 * @brief Generate integrity data for the outgoing IPMI packet 97 * 98 * @param[in] input - Outgoing IPMI packet 99 * 100 * @return authcode for the outgoing IPMI packet 101 * 102 */ 103 Buffer virtual generateIntegrityData(const Buffer& input) const = 0; 104 105 /** 106 * @brief Check if the Integrity algorithm is supported 107 * 108 * @param[in] algo - integrity algorithm 109 * 110 * @return true if algorithm is supported else false 111 * 112 */ 113 static bool isAlgorithmSupported(Algorithms algo) 114 { 115 if (algo == Algorithms::NONE || algo == Algorithms::HMAC_SHA1_96) 116 { 117 return true; 118 } 119 else 120 { 121 return false; 122 } 123 } 124 125 /* 126 * AuthCode field length varies based on the integrity algorithm, for 127 * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and 128 * HMAC-MD5-128 the authcode field is 16 bytes. 129 */ 130 size_t authCodeLength; 131 132 protected: 133 134 // K1 key used to generated the integrity data 135 Key K1; 136 }; 137 138 /* 139 * @class AlgoSHA1 140 * 141 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm 142 * 143 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is 144 * then used as the key for use in HMAC to produce the AuthCode field. 145 * For “one-key” logins, the user’s key (password) is used in the creation of 146 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used 147 * the resulting AuthCode field is 12 bytes (96 bits). 148 */ 149 class AlgoSHA1 final : public Interface 150 { 151 public: 152 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12; 153 154 /* 155 * @brief Constructor for AlgoSHA1 156 * 157 * @param[in] - Session Integrity Key 158 */ 159 explicit AlgoSHA1(const Buffer& sik) : 160 Interface(sik, const1, SHA1_96_AUTHCODE_LENGTH) {} 161 162 AlgoSHA1() = delete; 163 ~AlgoSHA1() = default; 164 AlgoSHA1(const AlgoSHA1&) = default; 165 AlgoSHA1& operator=(const AlgoSHA1&) = default; 166 AlgoSHA1(AlgoSHA1&&) = default; 167 AlgoSHA1& operator=(AlgoSHA1&&) = default; 168 169 /* 170 * @brief Verify the integrity data of the packet 171 * 172 * @param[in] packet - Incoming IPMI packet 173 * @param[in] length - Length of the data in the packet to calculate 174 * the integrity data 175 * @param[in] integrityData - Iterator to the authCode in the packet 176 * 177 * @return true if authcode in the packet is equal to one generated 178 * using integrity algorithm on the packet data, false otherwise 179 */ 180 bool verifyIntegrityData( 181 const Buffer& packet, 182 const size_t length, 183 Buffer::const_iterator integrityData) const override; 184 185 /* 186 * @brief Generate integrity data for the outgoing IPMI packet 187 * 188 * @param[in] input - Outgoing IPMI packet 189 * 190 * @return on success return the integrity data for the outgoing IPMI 191 * packet 192 */ 193 Buffer generateIntegrityData(const Buffer& packet) const override; 194 195 private: 196 /* 197 * @brief Generate HMAC based on HMAC-SHA1-96 algorithm 198 * 199 * @param[in] input - pointer to the message 200 * @param[in] length - length of the message 201 * 202 * @return on success returns the message authentication code 203 * 204 */ 205 Buffer generateHMAC(const uint8_t* input, const size_t len) const; 206 }; 207 208 }// namespace integrity 209 210 }// namespace cipher 211 212