#pragma once #include #include #include namespace cipher { namespace integrity { using Buffer = std::vector; using Key = std::array; /* * RSP needs more keying material than can be provided by session integrity key * alone. As a result all keying material for the RSP integrity algorithms * will be generated by processing a pre-defined set of constants using HMAC per * [RFC2104], keyed by SIK. These constants are constructed using a hexadecimal * octet value repeated up to the HMAC block size in length starting with the * constant 01h. This mechanism can be used to derive up to 255 * HMAC-block-length pieces of keying material from a single SIK. For the * mandatory integrity algorithm HMAC-SHA1-96, processing the following * constant will generate the required amount of keying material. */ constexpr Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; /* * @enum Integrity Algorithms * * The Integrity Algorithm Number specifies the algorithm used to generate the * contents for the AuthCode “signature” field that accompanies authenticated * IPMI v2.0/RMCP+ messages once the session has been established. If the * Integrity Algorithm is none the AuthCode value is not calculated and the * AuthCode field in the message is not present. */ enum class Algorithms : uint8_t { NONE, // Mandatory HMAC_SHA1_96, // Mandatory HMAC_MD5_128, // Optional MD5_128, // Optional HMAC_SHA256_128, // Optional }; /* * @class Interface * * Interface is the base class for the Integrity Algorithms. * Unless otherwise specified, the integrity algorithm is applied to the packet * data starting with the AuthType/Format field up to and including the field * that immediately precedes the AuthCode field itself. */ class Interface { public: /* * @brief Constructor for Interface * * @param[in] - Session Integrity Key to generate K1 * @param[in] - Additional keying material to generate K1 * @param[in] - AuthCode length */ explicit Interface(const Buffer& sik, const Key& addKey, size_t authLength); Interface() = delete; virtual ~Interface() = default; Interface(const Interface&) = default; Interface& operator=(const Interface&) = default; Interface(Interface&&) = default; Interface& operator=(Interface&&) = default; /* * @brief Verify the integrity data of the packet * * @param[in] packet - Incoming IPMI packet * @param[in] packetLen - Packet length excluding authCode * @param[in] integrityData - Iterator to the authCode in the packet * * @return true if authcode in the packet is equal to one generated * using integrity algorithm on the packet data, false otherwise */ bool virtual verifyIntegrityData( const Buffer& packet, const size_t packetLen, Buffer::const_iterator integrityData) const = 0; /* * @brief Generate integrity data for the outgoing IPMI packet * * @param[in] input - Outgoing IPMI packet * * @return authcode for the outgoing IPMI packet * */ Buffer virtual generateIntegrityData(const Buffer& input) const = 0; /** * @brief Check if the Integrity algorithm is supported * * @param[in] algo - integrity algorithm * * @return true if algorithm is supported else false * */ static bool isAlgorithmSupported(Algorithms algo) { if (algo == Algorithms::NONE || algo == Algorithms::HMAC_SHA1_96) { return true; } else { return false; } } /* * AuthCode field length varies based on the integrity algorithm, for * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and * HMAC-MD5-128 the authcode field is 16 bytes. */ size_t authCodeLength; protected: // K1 key used to generated the integrity data Key K1; }; /* * @class AlgoSHA1 * * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm * * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is * then used as the key for use in HMAC to produce the AuthCode field. * For “one-key” logins, the user’s key (password) is used in the creation of * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used * the resulting AuthCode field is 12 bytes (96 bits). */ class AlgoSHA1 final : public Interface { public: static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12; /* * @brief Constructor for AlgoSHA1 * * @param[in] - Session Integrity Key */ explicit AlgoSHA1(const Buffer& sik) : Interface(sik, const1, SHA1_96_AUTHCODE_LENGTH) {} AlgoSHA1() = delete; ~AlgoSHA1() = default; AlgoSHA1(const AlgoSHA1&) = default; AlgoSHA1& operator=(const AlgoSHA1&) = default; AlgoSHA1(AlgoSHA1&&) = default; AlgoSHA1& operator=(AlgoSHA1&&) = default; /* * @brief Verify the integrity data of the packet * * @param[in] packet - Incoming IPMI packet * @param[in] length - Length of the data in the packet to calculate * the integrity data * @param[in] integrityData - Iterator to the authCode in the packet * * @return true if authcode in the packet is equal to one generated * using integrity algorithm on the packet data, false otherwise */ bool verifyIntegrityData( const Buffer& packet, const size_t length, Buffer::const_iterator integrityData) const override; /* * @brief Generate integrity data for the outgoing IPMI packet * * @param[in] input - Outgoing IPMI packet * * @return on success return the integrity data for the outgoing IPMI * packet */ Buffer generateIntegrityData(const Buffer& packet) const override; private: /* * @brief Generate HMAC based on HMAC-SHA1-96 algorithm * * @param[in] input - pointer to the message * @param[in] length - length of the message * * @return on success returns the message authentication code * */ Buffer generateHMAC(const uint8_t* input, const size_t len) const; }; }// namespace integrity }// namespace cipher