blob: 3d56b8272119a1bb1d1366c4b1568b8780e81485 [file] [log] [blame]
Tom Joseph77531db2017-01-10 15:44:44 +05301#pragma once
2
Tom Joseph77531db2017-01-10 15:44:44 +05303#include <array>
4#include <vector>
Vernon Mauery9b307be2017-11-22 09:28:16 -08005#include "rmcp.hpp"
Tom Joseph77531db2017-01-10 15:44:44 +05306
7namespace cipher
8{
9
10namespace integrity
11{
12
Tom Joseph3563f8f2017-05-08 15:42:54 +053013/**
Tom Joseph77531db2017-01-10 15:44:44 +053014 * @enum Integrity Algorithms
15 *
16 * The Integrity Algorithm Number specifies the algorithm used to generate the
17 * contents for the AuthCode “signature” field that accompanies authenticated
18 * IPMI v2.0/RMCP+ messages once the session has been established. If the
19 * Integrity Algorithm is none the AuthCode value is not calculated and the
Tom Josephfe5a6452018-07-30 18:15:12 +053020 * AuthCode field in the message is not present. Based on security
21 * recommendations NONE will not be supported.
Tom Joseph77531db2017-01-10 15:44:44 +053022 */
23enum class Algorithms : uint8_t
24{
Tom Josephfe5a6452018-07-30 18:15:12 +053025 NONE, // Mandatory (implemented, not supported)
26 HMAC_SHA1_96, // Mandatory (implemented, default choice in ipmitool)
27 HMAC_MD5_128, // Optional (not implemented)
28 MD5_128, // Optional (not implemented)
29 HMAC_SHA256_128, // Optional (implemented, best available)
Tom Joseph77531db2017-01-10 15:44:44 +053030};
31
Tom Joseph3563f8f2017-05-08 15:42:54 +053032/**
Tom Joseph77531db2017-01-10 15:44:44 +053033 * @class Interface
34 *
35 * Interface is the base class for the Integrity Algorithms.
36 * Unless otherwise specified, the integrity algorithm is applied to the packet
37 * data starting with the AuthType/Format field up to and including the field
38 * that immediately precedes the AuthCode field itself.
39 */
40class Interface
41{
42 public:
Tom Joseph3563f8f2017-05-08 15:42:54 +053043 /**
Tom Joseph77531db2017-01-10 15:44:44 +053044 * @brief Constructor for Interface
45 *
Tom Joseph77531db2017-01-10 15:44:44 +053046 * @param[in] - AuthCode length
47 */
Vernon Mauery9b307be2017-11-22 09:28:16 -080048 explicit Interface(size_t authLength)
49 : authCodeLength(authLength) {}
Tom Joseph77531db2017-01-10 15:44:44 +053050
51 Interface() = delete;
52 virtual ~Interface() = default;
53 Interface(const Interface&) = default;
54 Interface& operator=(const Interface&) = default;
55 Interface(Interface&&) = default;
56 Interface& operator=(Interface&&) = default;
57
Tom Joseph3563f8f2017-05-08 15:42:54 +053058 /**
Tom Joseph77531db2017-01-10 15:44:44 +053059 * @brief Verify the integrity data of the packet
60 *
61 * @param[in] packet - Incoming IPMI packet
62 * @param[in] packetLen - Packet length excluding authCode
63 * @param[in] integrityData - Iterator to the authCode in the packet
64 *
65 * @return true if authcode in the packet is equal to one generated
66 * using integrity algorithm on the packet data, false otherwise
67 */
68 bool virtual verifyIntegrityData(
Vernon Mauery70fd29c2017-11-30 13:11:43 -080069 const std::vector<uint8_t>& packet,
Tom Joseph77531db2017-01-10 15:44:44 +053070 const size_t packetLen,
Vernon Mauery70fd29c2017-11-30 13:11:43 -080071 std::vector<uint8_t>::const_iterator integrityData) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053072
Tom Joseph3563f8f2017-05-08 15:42:54 +053073 /**
Tom Joseph77531db2017-01-10 15:44:44 +053074 * @brief Generate integrity data for the outgoing IPMI packet
75 *
76 * @param[in] input - Outgoing IPMI packet
77 *
78 * @return authcode for the outgoing IPMI packet
79 *
80 */
Vernon Mauery70fd29c2017-11-30 13:11:43 -080081 std::vector<uint8_t> virtual generateIntegrityData(
82 const std::vector<uint8_t>& input) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053083
Tom Joseph1e7aa192017-02-24 17:16:49 +053084 /**
85 * @brief Check if the Integrity algorithm is supported
86 *
87 * @param[in] algo - integrity algorithm
88 *
89 * @return true if algorithm is supported else false
90 *
91 */
92 static bool isAlgorithmSupported(Algorithms algo)
93 {
Tom Josephfe5a6452018-07-30 18:15:12 +053094 if (algo == Algorithms::HMAC_SHA1_96 ||
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080095 algo == Algorithms::HMAC_SHA256_128)
Tom Joseph1e7aa192017-02-24 17:16:49 +053096 {
97 return true;
98 }
99 else
100 {
101 return false;
102 }
103 }
104
Vernon Mauery9b307be2017-11-22 09:28:16 -0800105 /**
106 * @brief Generate additional keying material based on SIK
107 *
108 * @note
109 * The IPMI 2.0 spec only states that the additional keying material is
110 * generated by running HMAC(constN) using SIK as the key. It does not
111 * state whether this is the integrity algorithm or the authentication
112 * algorithm. Other implementations of the RMCP+ algorithm (ipmitool
113 * and ipmiutil) are not consistent on this matter. But it does not
114 * really matter because based on any of the defined cipher suites, the
115 * integrity and authentication algorithms are both based on the same
116 * digest method (integrity::Algorithms::HMAC_SHA1_96 uses SHA1 and
117 * rakp_auth::Algorithms::RAKP_HMAC_SHA1 uses SHA1). None of the
118 * defined cipher suites mix and match digests for integrity and
119 * authentication. Generating Kn belongs in either the integrity or
120 * authentication classes, so in this implementation, integrity has
121 * been chosen.
122 *
123 * @param[in] sik - session integrity key
124 * @param[in] data - 20-byte Const_n
125 *
126 * @return on success returns the Kn based on this integrity class
127 *
128 */
129 std::vector<uint8_t> virtual generateKn(
130 const std::vector<uint8_t>& sik,
131 const rmcp::Const_n& data) const = 0;
132
Tom Joseph3563f8f2017-05-08 15:42:54 +0530133 /** @brief Authcode field
134 *
135 * AuthCode field length varies based on the integrity algorithm, for
136 * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and
137 * HMAC-MD5-128 the authcode field is 16 bytes.
Tom Joseph77531db2017-01-10 15:44:44 +0530138 */
139 size_t authCodeLength;
140
141 protected:
142
Tom Joseph3563f8f2017-05-08 15:42:54 +0530143 /** @brief K1 key used to generated the integrity data. */
Vernon Mauery9b307be2017-11-22 09:28:16 -0800144 std::vector<uint8_t> k1;
Tom Joseph77531db2017-01-10 15:44:44 +0530145};
146
Tom Joseph3563f8f2017-05-08 15:42:54 +0530147/**
Tom Josephd212a6d2017-01-10 15:48:40 +0530148 * @class AlgoSHA1
149 *
150 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
151 *
152 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
153 * then used as the key for use in HMAC to produce the AuthCode field.
154 * For “one-key” logins, the user’s key (password) is used in the creation of
155 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
156 * the resulting AuthCode field is 12 bytes (96 bits).
157 */
158class AlgoSHA1 final : public Interface
159{
160 public:
161 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
162
Tom Joseph3563f8f2017-05-08 15:42:54 +0530163 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530164 * @brief Constructor for AlgoSHA1
165 *
166 * @param[in] - Session Integrity Key
167 */
Vernon Mauery9b307be2017-11-22 09:28:16 -0800168 explicit AlgoSHA1(const std::vector<uint8_t>& sik);
Tom Josephd212a6d2017-01-10 15:48:40 +0530169
170 AlgoSHA1() = delete;
171 ~AlgoSHA1() = default;
172 AlgoSHA1(const AlgoSHA1&) = default;
173 AlgoSHA1& operator=(const AlgoSHA1&) = default;
174 AlgoSHA1(AlgoSHA1&&) = default;
175 AlgoSHA1& operator=(AlgoSHA1&&) = default;
176
Tom Joseph3563f8f2017-05-08 15:42:54 +0530177 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530178 * @brief Verify the integrity data of the packet
179 *
180 * @param[in] packet - Incoming IPMI packet
181 * @param[in] length - Length of the data in the packet to calculate
182 * the integrity data
183 * @param[in] integrityData - Iterator to the authCode in the packet
184 *
185 * @return true if authcode in the packet is equal to one generated
186 * using integrity algorithm on the packet data, false otherwise
187 */
188 bool verifyIntegrityData(
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800189 const std::vector<uint8_t>& packet,
Tom Josephd212a6d2017-01-10 15:48:40 +0530190 const size_t length,
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800191 std::vector<uint8_t>::const_iterator integrityData)
192 const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530193
Tom Joseph3563f8f2017-05-08 15:42:54 +0530194 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530195 * @brief Generate integrity data for the outgoing IPMI packet
196 *
197 * @param[in] input - Outgoing IPMI packet
198 *
199 * @return on success return the integrity data for the outgoing IPMI
200 * packet
201 */
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800202 std::vector<uint8_t> generateIntegrityData(
203 const std::vector<uint8_t>& packet) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530204
Vernon Mauery9b307be2017-11-22 09:28:16 -0800205 /**
206 * @brief Generate additional keying material based on SIK
207 *
208 * @param[in] sik - session integrity key
209 * @param[in] data - 20-byte Const_n
210 *
211 * @return on success returns the Kn based on HMAC-SHA1
212 *
213 */
214 std::vector<uint8_t> generateKn(
215 const std::vector<uint8_t>& sik,
216 const rmcp::Const_n& const_n) const;
217
Tom Josephd212a6d2017-01-10 15:48:40 +0530218 private:
Tom Joseph3563f8f2017-05-08 15:42:54 +0530219 /**
Tom Josephd212a6d2017-01-10 15:48:40 +0530220 * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
221 *
222 * @param[in] input - pointer to the message
223 * @param[in] length - length of the message
224 *
225 * @return on success returns the message authentication code
226 *
227 */
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800228 std::vector<uint8_t> generateHMAC(const uint8_t* input,
229 const size_t len) const;
Tom Josephd212a6d2017-01-10 15:48:40 +0530230};
231
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800232/**
233 * @class AlgoSHA256
234 *
235 * @brief Implementation of the HMAC-SHA256-128 Integrity algorithm
236 *
237 * HMAC-SHA256-128 take the Session Integrity Key and use it to generate K1. K1
238 * is then used as the key for use in HMAC to produce the AuthCode field. For
239 * “one-key” logins, the user’s key (password) is used in the creation of the
240 * Session Integrity Key. When the HMAC-SHA256-128 Integrity Algorithm is used
241 * the resulting AuthCode field is 16 bytes (128 bits).
242 */
243class AlgoSHA256 final : public Interface
244{
245 public:
246 static constexpr size_t SHA256_128_AUTHCODE_LENGTH = 16;
247
248 /**
249 * @brief Constructor for AlgoSHA256
250 *
251 * @param[in] - Session Integrity Key
252 */
253 explicit AlgoSHA256(const std::vector<uint8_t>& sik);
254
255 AlgoSHA256() = delete;
256 ~AlgoSHA256() = default;
257 AlgoSHA256(const AlgoSHA256&) = default;
258 AlgoSHA256& operator=(const AlgoSHA256&) = default;
259 AlgoSHA256(AlgoSHA256&&) = default;
260 AlgoSHA256& operator=(AlgoSHA256&&) = default;
261
262 /**
263 * @brief Verify the integrity data of the packet
264 *
265 * @param[in] packet - Incoming IPMI packet
266 * @param[in] length - Length of the data in the packet to calculate
267 * the integrity data
268 * @param[in] integrityData - Iterator to the authCode in the packet
269 *
270 * @return true if authcode in the packet is equal to one generated
271 * using integrity algorithm on the packet data, false otherwise
272 */
273 bool verifyIntegrityData(
274 const std::vector<uint8_t>& packet,
275 const size_t length,
276 std::vector<uint8_t>::const_iterator integrityData)
277 const override;
278
279 /**
280 * @brief Generate integrity data for the outgoing IPMI packet
281 *
282 * @param[in] packet - Outgoing IPMI packet
283 *
284 * @return on success return the integrity data for the outgoing IPMI
285 * packet
286 */
287 std::vector<uint8_t> generateIntegrityData(
288 const std::vector<uint8_t>& packet) const override;
289
290 /**
291 * @brief Generate additional keying material based on SIK
292 *
293 * @param[in] sik - session integrity key
294 * @param[in] data - 20-byte Const_n
295 *
296 * @return on success returns the Kn based on HMAC-SHA256
297 *
298 */
299 std::vector<uint8_t> generateKn(
300 const std::vector<uint8_t>& sik,
301 const rmcp::Const_n& const_n) const;
302
303 private:
304 /**
305 * @brief Generate HMAC based on HMAC-SHA256-128 algorithm
306 *
307 * @param[in] input - pointer to the message
308 * @param[in] len - length of the message
309 *
310 * @return on success returns the message authentication code
311 *
312 */
313 std::vector<uint8_t> generateHMAC(const uint8_t* input,
314 const size_t len) const;
315};
316
Tom Joseph77531db2017-01-10 15:44:44 +0530317}// namespace integrity
318
319}// namespace cipher
320