|  | #pragma once | 
|  |  | 
|  | #include <array> | 
|  | #include <vector> | 
|  | #include "rmcp.hpp" | 
|  |  | 
|  | namespace cipher | 
|  | { | 
|  |  | 
|  | namespace integrity | 
|  | { | 
|  |  | 
|  | /** | 
|  | * @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] - AuthCode length | 
|  | */ | 
|  | explicit Interface(size_t authLength) | 
|  | : authCodeLength(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 std::vector<uint8_t>& packet, | 
|  | const size_t packetLen, | 
|  | std::vector<uint8_t>::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 | 
|  | * | 
|  | */ | 
|  | std::vector<uint8_t> virtual generateIntegrityData( | 
|  | const std::vector<uint8_t>& 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Generate additional keying material based on SIK | 
|  | * | 
|  | * @note | 
|  | * The IPMI 2.0 spec only states that the additional keying material is | 
|  | * generated by running HMAC(constN) using SIK as the key. It does not | 
|  | * state whether this is the integrity algorithm or the authentication | 
|  | * algorithm. Other implementations of the RMCP+ algorithm (ipmitool | 
|  | * and ipmiutil) are not consistent on this matter. But it does not | 
|  | * really matter because based on any of the defined cipher suites, the | 
|  | * integrity and authentication algorithms are both based on the same | 
|  | * digest method (integrity::Algorithms::HMAC_SHA1_96 uses SHA1 and | 
|  | * rakp_auth::Algorithms::RAKP_HMAC_SHA1 uses SHA1). None of the | 
|  | * defined cipher suites mix and match digests for integrity and | 
|  | * authentication. Generating Kn belongs in either the integrity or | 
|  | * authentication classes, so in this implementation, integrity has | 
|  | * been chosen. | 
|  | * | 
|  | * @param[in] sik - session integrity key | 
|  | * @param[in] data - 20-byte Const_n | 
|  | * | 
|  | * @return on success returns the Kn based on this integrity class | 
|  | * | 
|  | */ | 
|  | std::vector<uint8_t> virtual generateKn( | 
|  | const std::vector<uint8_t>& sik, | 
|  | const rmcp::Const_n& data) const = 0; | 
|  |  | 
|  | /** @brief Authcode field | 
|  | * | 
|  | *  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: | 
|  |  | 
|  | /** @brief K1 key used to generated the integrity data. */ | 
|  | std::vector<uint8_t> 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 std::vector<uint8_t>& sik); | 
|  |  | 
|  | 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 std::vector<uint8_t>& packet, | 
|  | const size_t length, | 
|  | std::vector<uint8_t>::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 | 
|  | */ | 
|  | std::vector<uint8_t> generateIntegrityData( | 
|  | const std::vector<uint8_t>& packet) const override; | 
|  |  | 
|  | /** | 
|  | * @brief Generate additional keying material based on SIK | 
|  | * | 
|  | * @param[in] sik - session integrity key | 
|  | * @param[in] data - 20-byte Const_n | 
|  | * | 
|  | * @return on success returns the Kn based on HMAC-SHA1 | 
|  | * | 
|  | */ | 
|  | std::vector<uint8_t> generateKn( | 
|  | const std::vector<uint8_t>& sik, | 
|  | const rmcp::Const_n& const_n) const; | 
|  |  | 
|  | 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 | 
|  | * | 
|  | */ | 
|  | std::vector<uint8_t> generateHMAC(const uint8_t* input, | 
|  | const size_t len) const; | 
|  | }; | 
|  |  | 
|  | }// namespace integrity | 
|  |  | 
|  | }// namespace cipher | 
|  |  |