blob: eb7857815dd4cb7dd1a55eef2dcc847e21222137 [file] [log] [blame]
Tom Joseph77531db2017-01-10 15:44:44 +05301#pragma once
2
3#include <openssl/sha.h>
4#include <array>
5#include <vector>
6
7namespace cipher
8{
9
10namespace integrity
11{
12
13using Buffer = std::vector<uint8_t>;
14using 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 */
27constexpr 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
Tom Joseph3563f8f2017-05-08 15:42:54 +053033/**
Tom Joseph77531db2017-01-10 15:44:44 +053034 * @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 */
42enum 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
Tom Joseph3563f8f2017-05-08 15:42:54 +053051/**
Tom Joseph77531db2017-01-10 15:44:44 +053052 * @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 */
59class Interface
60{
61 public:
Tom Joseph3563f8f2017-05-08 15:42:54 +053062 /**
Tom Joseph77531db2017-01-10 15:44:44 +053063 * @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
Tom Joseph3563f8f2017-05-08 15:42:54 +053080 /**
Tom Joseph77531db2017-01-10 15:44:44 +053081 * @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
Tom Joseph3563f8f2017-05-08 15:42:54 +053095 /**
Tom Joseph77531db2017-01-10 15:44:44 +053096 * @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
Tom Joseph1e7aa192017-02-24 17:16:49 +0530105 /**
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
Tom Joseph3563f8f2017-05-08 15:42:54 +0530125 /** @brief Authcode field
126 *
127 * AuthCode field length varies based on the integrity algorithm, for
128 * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and
129 * HMAC-MD5-128 the authcode field is 16 bytes.
Tom Joseph77531db2017-01-10 15:44:44 +0530130 */
131 size_t authCodeLength;
132
133 protected:
134
Tom Joseph3563f8f2017-05-08 15:42:54 +0530135 /** @brief K1 key used to generated the integrity data. */
Tom Joseph77531db2017-01-10 15:44:44 +0530136 Key K1;
137};
138
Tom Joseph3563f8f2017-05-08 15:42:54 +0530139/**
Tom Josephd212a6d2017-01-10 15:48:40 +0530140 * @class AlgoSHA1
141 *
142 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
143 *
144 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
145 * then used as the key for use in HMAC to produce the AuthCode field.
146 * For “one-key” logins, the user’s key (password) is used in the creation of
147 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
148 * the resulting AuthCode field is 12 bytes (96 bits).
149 */
150class AlgoSHA1 final : public Interface
151{
152 public:
153 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
154
Tom Joseph3563f8f2017-05-08 15:42:54 +0530155 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530156 * @brief Constructor for AlgoSHA1
157 *
158 * @param[in] - Session Integrity Key
159 */
160 explicit AlgoSHA1(const Buffer& sik) :
161 Interface(sik, const1, SHA1_96_AUTHCODE_LENGTH) {}
162
163 AlgoSHA1() = delete;
164 ~AlgoSHA1() = default;
165 AlgoSHA1(const AlgoSHA1&) = default;
166 AlgoSHA1& operator=(const AlgoSHA1&) = default;
167 AlgoSHA1(AlgoSHA1&&) = default;
168 AlgoSHA1& operator=(AlgoSHA1&&) = default;
169
Tom Joseph3563f8f2017-05-08 15:42:54 +0530170 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530171 * @brief Verify the integrity data of the packet
172 *
173 * @param[in] packet - Incoming IPMI packet
174 * @param[in] length - Length of the data in the packet to calculate
175 * the integrity data
176 * @param[in] integrityData - Iterator to the authCode in the packet
177 *
178 * @return true if authcode in the packet is equal to one generated
179 * using integrity algorithm on the packet data, false otherwise
180 */
181 bool verifyIntegrityData(
182 const Buffer& packet,
183 const size_t length,
184 Buffer::const_iterator integrityData) const override;
185
Tom Joseph3563f8f2017-05-08 15:42:54 +0530186 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530187 * @brief Generate integrity data for the outgoing IPMI packet
188 *
189 * @param[in] input - Outgoing IPMI packet
190 *
191 * @return on success return the integrity data for the outgoing IPMI
192 * packet
193 */
194 Buffer generateIntegrityData(const Buffer& packet) const override;
195
196 private:
Tom Joseph3563f8f2017-05-08 15:42:54 +0530197 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530198 * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
199 *
200 * @param[in] input - pointer to the message
201 * @param[in] length - length of the message
202 *
203 * @return on success returns the message authentication code
204 *
205 */
206 Buffer generateHMAC(const uint8_t* input, const size_t len) const;
207};
208
Tom Joseph77531db2017-01-10 15:44:44 +0530209}// namespace integrity
210
211}// namespace cipher
212