blob: eb7857815dd4cb7dd1a55eef2dcc847e21222137 [file] [log] [blame]
#pragma once
#include <openssl/sha.h>
#include <array>
#include <vector>
namespace cipher
{
namespace integrity
{
using Buffer = std::vector<uint8_t>;
using Key = std::array<uint8_t, SHA_DIGEST_LENGTH>;
/*
* 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;
}
}
/** @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. */
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