blob: f4e3c4993484efd629446a1c0034faf656de88ab [file] [log] [blame]
#pragma once
#include "crypt_algo.hpp"
#include "integrity_algo.hpp"
#include <array>
#include <vector>
namespace cipher
{
namespace rakp_auth
{
constexpr size_t USER_KEY_MAX_LENGTH = 20;
constexpr size_t BMC_RANDOM_NUMBER_LEN = 16;
constexpr size_t REMOTE_CONSOLE_RANDOM_NUMBER_LEN = 16;
extern const std::string userName;
/**
* @enum RAKP Authentication Algorithms
*
* RMCP+ Authenticated Key-Exchange Protocol (RAKP)
*
* RAKP-None is not supported as per the following recommendation
* (https://www.us-cert.gov/ncas/alerts/TA13-207A)
* ("cipher 0" is an option enabled by default on many IPMI enabled devices that
* allows authentication to be bypassed. Disable "cipher 0" to prevent
* attackers from bypassing authentication and sending arbitrary IPMI commands.)
*/
enum class Algorithms : uint8_t
{
RAKP_NONE = 0, // Mandatory (implemented, not supported)
RAKP_HMAC_SHA1, // Mandatory (implemented, default choice in ipmitool)
RAKP_HMAC_MD5, // Optional (not implemented)
RAKP_HMAC_SHA256, // Optional (implemented, best available)
// Reserved used to indicate an invalid authentication algorithm
RAKP_HMAC_INVALID = 0xB0
};
/**
* @class Interface
*
* Interface is the base class for the Authentication Algorithms.
* The Authentication Algorithm specifies the type of authentication “handshake”
* process that is used and identifies any particular variations of hashing or
* signature algorithm that is used as part of the process.
*
*/
class Interface
{
public:
explicit Interface(integrity::Algorithms intAlgo,
crypt::Algorithms cryptAlgo) :
intAlgo(intAlgo),
cryptAlgo(cryptAlgo)
{
}
Interface() = delete;
virtual ~Interface() = default;
Interface(const Interface&) = default;
Interface& operator=(const Interface&) = default;
Interface(Interface&&) = default;
Interface& operator=(Interface&&) = default;
/**
* @brief Generate the Hash Message Authentication Code
*
* This API is invoked to generate the Key Exchange Authentication Code
* in the RAKP2 and RAKP4 sequence and for generating the Session
* Integrity Key.
*
* @param input message
*
* @return hash output
*
* @note The user key which is the secret key for the hash operation
* needs to be set before this operation.
*/
std::vector<uint8_t> virtual generateHMAC(
const std::vector<uint8_t>& input) const = 0;
/**
* @brief Generate the Integrity Check Value
*
* This API is invoked in the RAKP4 sequence for generating the
* Integrity Check Value.
*
* @param input message
*
* @return hash output
*
* @note The session integrity key which is the secret key for the
* hash operation needs to be set before this operation.
*/
std::vector<uint8_t> virtual generateICV(
const std::vector<uint8_t>& input) const = 0;
/**
* @brief Check if the Authentication algorithm is supported
*
* @param[in] algo - authentication algorithm
*
* @return true if algorithm is supported else false
*
*/
static bool isAlgorithmSupported(Algorithms algo)
{
if (algo == Algorithms::RAKP_HMAC_SHA1 ||
algo == Algorithms::RAKP_HMAC_SHA256)
{
return true;
}
else
{
return false;
}
}
// User Key is hardcoded to PASSW0RD till the IPMI User account
// management is in place.
std::array<uint8_t, USER_KEY_MAX_LENGTH> userKey = {"0penBmc"};
// Managed System Random Number
std::array<uint8_t, BMC_RANDOM_NUMBER_LEN> bmcRandomNum;
// Remote Console Random Number
std::array<uint8_t, REMOTE_CONSOLE_RANDOM_NUMBER_LEN> rcRandomNum;
// Session Integrity Key
std::vector<uint8_t> sessionIntegrityKey;
/**
* Integrity Algorithm is activated and set in the session data only
* once the session setup is succeeded in the RAKP34 command. But the
* integrity algorithm is negotiated in the Open Session Request command
* . So the integrity algorithm successfully negotiated is stored
* in the authentication algorithm's instance.
*/
integrity::Algorithms intAlgo;
/**
* Confidentiality Algorithm is activated and set in the session data
* only once the session setup is succeeded in the RAKP34 command. But
* the confidentiality algorithm is negotiated in the Open Session
* Request command. So the confidentiality algorithm successfully
* negotiated is stored in the authentication algorithm's instance.
*/
crypt::Algorithms cryptAlgo;
};
/**
* @class AlgoSHA1
*
* RAKP-HMAC-SHA1 specifies the use of RAKP messages for the key exchange
* portion of establishing the session, and that HMAC-SHA1 (per [RFC2104]) is
* used to create 20-byte Key Exchange Authentication Code fields in RAKP
* Message 2 and RAKP Message 3. HMAC-SHA1-96(per [RFC2404]) is used for
* generating a 12-byte Integrity Check Value field for RAKP Message 4.
*/
class AlgoSHA1 : public Interface
{
public:
static constexpr size_t integrityCheckValueLength = 12;
explicit AlgoSHA1(integrity::Algorithms intAlgo,
crypt::Algorithms cryptAlgo) :
Interface(intAlgo, cryptAlgo)
{
}
AlgoSHA1() = delete;
~AlgoSHA1() = default;
AlgoSHA1(const AlgoSHA1&) = default;
AlgoSHA1& operator=(const AlgoSHA1&) = default;
AlgoSHA1(AlgoSHA1&&) = default;
AlgoSHA1& operator=(AlgoSHA1&&) = default;
std::vector<uint8_t>
generateHMAC(const std::vector<uint8_t>& input) const override;
std::vector<uint8_t>
generateICV(const std::vector<uint8_t>& input) const override;
};
/**
* @class AlgoSHA256
*
* RAKP-HMAC-SHA256 specifies the use of RAKP messages for the key exchange
* portion of establishing the session, and that HMAC-SHA256 (per [FIPS 180-2]
* and [RFC4634] and is used to create a 32-byte Key Exchange Authentication
* Code fields in RAKP Message 2 and RAKP Message 3. HMAC-SHA256-128 (per
* [RFC4868]) is used for generating a 16-byte Integrity Check Value field for
* RAKP Message 4.
*/
class AlgoSHA256 : public Interface
{
public:
static constexpr size_t integrityCheckValueLength = 16;
explicit AlgoSHA256(integrity::Algorithms intAlgo,
crypt::Algorithms cryptAlgo) :
Interface(intAlgo, cryptAlgo)
{
}
~AlgoSHA256() = default;
AlgoSHA256(const AlgoSHA256&) = default;
AlgoSHA256& operator=(const AlgoSHA256&) = default;
AlgoSHA256(AlgoSHA256&&) = default;
AlgoSHA256& operator=(AlgoSHA256&&) = default;
std::vector<uint8_t>
generateHMAC(const std::vector<uint8_t>& input) const override;
std::vector<uint8_t>
generateICV(const std::vector<uint8_t>& input) const override;
};
} // namespace rakp_auth
} // namespace cipher