blob: 3640ce26a7a8e49d2dd3cb743b578acd3d439ed5 [file] [log] [blame]
Tom Joseph77531db2017-01-10 15:44:44 +05301#pragma once
2
Vernon Mauery9e801a22018-10-12 13:20:49 -07003#include "rmcp.hpp"
4
Tom Joseph77531db2017-01-10 15:44:44 +05305#include <array>
Andrew Geissler9d9b7632020-05-17 09:18:05 -05006#include <cstddef>
Tom Joseph77531db2017-01-10 15:44:44 +05307#include <vector>
8
9namespace cipher
10{
11
12namespace integrity
13{
14
Tom Joseph3563f8f2017-05-08 15:42:54 +053015/**
Tom Joseph77531db2017-01-10 15:44:44 +053016 * @enum Integrity Algorithms
17 *
18 * The Integrity Algorithm Number specifies the algorithm used to generate the
19 * contents for the AuthCode “signature” field that accompanies authenticated
20 * IPMI v2.0/RMCP+ messages once the session has been established. If the
21 * Integrity Algorithm is none the AuthCode value is not calculated and the
Tom Josephfe5a6452018-07-30 18:15:12 +053022 * AuthCode field in the message is not present. Based on security
23 * recommendations NONE will not be supported.
Tom Joseph77531db2017-01-10 15:44:44 +053024 */
25enum class Algorithms : uint8_t
26{
Tom Josephfe5a6452018-07-30 18:15:12 +053027 NONE, // Mandatory (implemented, not supported)
28 HMAC_SHA1_96, // Mandatory (implemented, default choice in ipmitool)
29 HMAC_MD5_128, // Optional (not implemented)
30 MD5_128, // Optional (not implemented)
31 HMAC_SHA256_128, // Optional (implemented, best available)
Tom Joseph77531db2017-01-10 15:44:44 +053032};
33
Tom Joseph3563f8f2017-05-08 15:42:54 +053034/**
Tom Joseph77531db2017-01-10 15:44:44 +053035 * @class Interface
36 *
37 * Interface is the base class for the Integrity Algorithms.
38 * Unless otherwise specified, the integrity algorithm is applied to the packet
39 * data starting with the AuthType/Format field up to and including the field
40 * that immediately precedes the AuthCode field itself.
41 */
42class Interface
43{
Vernon Mauery9e801a22018-10-12 13:20:49 -070044 public:
45 /**
46 * @brief Constructor for Interface
47 *
48 * @param[in] - AuthCode length
49 */
50 explicit Interface(size_t authLength) : authCodeLength(authLength)
George Liubc8958f2022-07-04 09:29:49 +080051 {}
Tom Joseph77531db2017-01-10 15:44:44 +053052
Vernon Mauery9e801a22018-10-12 13:20:49 -070053 Interface() = delete;
54 virtual ~Interface() = default;
55 Interface(const Interface&) = default;
56 Interface& operator=(const Interface&) = default;
57 Interface(Interface&&) = default;
58 Interface& operator=(Interface&&) = default;
Tom Joseph77531db2017-01-10 15:44:44 +053059
Vernon Mauery9e801a22018-10-12 13:20:49 -070060 /**
61 * @brief Verify the integrity data of the packet
62 *
63 * @param[in] packet - Incoming IPMI packet
64 * @param[in] packetLen - Packet length excluding authCode
65 * @param[in] integrityData - Iterator to the authCode in the packet
66 *
67 * @return true if authcode in the packet is equal to one generated
68 * using integrity algorithm on the packet data, false otherwise
69 */
70 bool virtual verifyIntegrityData(
71 const std::vector<uint8_t>& packet, const size_t packetLen,
72 std::vector<uint8_t>::const_iterator integrityData) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053073
Vernon Mauery9e801a22018-10-12 13:20:49 -070074 /**
75 * @brief Generate integrity data for the outgoing IPMI packet
76 *
77 * @param[in] input - Outgoing IPMI packet
78 *
79 * @return authcode for the outgoing IPMI packet
80 *
81 */
82 std::vector<uint8_t> virtual generateIntegrityData(
83 const std::vector<uint8_t>& input) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053084
Vernon Mauery9e801a22018-10-12 13:20:49 -070085 /**
86 * @brief Check if the Integrity algorithm is supported
87 *
88 * @param[in] algo - integrity algorithm
89 *
90 * @return true if algorithm is supported else false
91 *
92 */
93 static bool isAlgorithmSupported(Algorithms algo)
94 {
Suryakanth Sekar4c494392020-03-31 13:22:43 +053095 if (algo == Algorithms::HMAC_SHA256_128)
Tom Joseph1e7aa192017-02-24 17:16:49 +053096 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070097 return true;
Tom Joseph1e7aa192017-02-24 17:16:49 +053098 }
Vernon Mauery9e801a22018-10-12 13:20:49 -070099 else
100 {
101 return false;
102 }
103 }
Tom Joseph1e7aa192017-02-24 17:16:49 +0530104
Vernon Mauery9e801a22018-10-12 13:20:49 -0700105 /**
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, const rmcp::Const_n& data) const = 0;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800131
Vernon Mauery9e801a22018-10-12 13:20:49 -0700132 /** @brief Authcode field
133 *
134 * AuthCode field length varies based on the integrity algorithm, for
135 * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and
136 * HMAC-MD5-128 the authcode field is 16 bytes.
137 */
138 size_t authCodeLength;
Tom Joseph77531db2017-01-10 15:44:44 +0530139
Vernon Mauery9e801a22018-10-12 13:20:49 -0700140 protected:
141 /** @brief K1 key used to generated the integrity data. */
142 std::vector<uint8_t> k1;
Tom Joseph77531db2017-01-10 15:44:44 +0530143};
144
Tom Joseph3563f8f2017-05-08 15:42:54 +0530145/**
Tom Josephd212a6d2017-01-10 15:48:40 +0530146 * @class AlgoSHA1
147 *
148 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
149 *
150 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
151 * then used as the key for use in HMAC to produce the AuthCode field.
152 * For “one-key” logins, the user’s key (password) is used in the creation of
153 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
154 * the resulting AuthCode field is 12 bytes (96 bits).
155 */
156class AlgoSHA1 final : public Interface
157{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700158 public:
159 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
Tom Josephd212a6d2017-01-10 15:48:40 +0530160
Vernon Mauery9e801a22018-10-12 13:20:49 -0700161 /**
162 * @brief Constructor for AlgoSHA1
163 *
164 * @param[in] - Session Integrity Key
165 */
166 explicit AlgoSHA1(const std::vector<uint8_t>& sik);
Tom Josephd212a6d2017-01-10 15:48:40 +0530167
Vernon Mauery9e801a22018-10-12 13:20:49 -0700168 AlgoSHA1() = delete;
169 ~AlgoSHA1() = default;
170 AlgoSHA1(const AlgoSHA1&) = default;
171 AlgoSHA1& operator=(const AlgoSHA1&) = default;
172 AlgoSHA1(AlgoSHA1&&) = default;
173 AlgoSHA1& operator=(AlgoSHA1&&) = default;
Tom Josephd212a6d2017-01-10 15:48:40 +0530174
Vernon Mauery9e801a22018-10-12 13:20:49 -0700175 /**
176 * @brief Verify the integrity data of the packet
177 *
178 * @param[in] packet - Incoming IPMI packet
179 * @param[in] length - Length of the data in the packet to calculate
180 * the integrity data
181 * @param[in] integrityData - Iterator to the authCode in the packet
182 *
183 * @return true if authcode in the packet is equal to one generated
184 * using integrity algorithm on the packet data, false otherwise
185 */
186 bool verifyIntegrityData(
187 const std::vector<uint8_t>& packet, const size_t length,
188 std::vector<uint8_t>::const_iterator integrityData) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530189
Vernon Mauery9e801a22018-10-12 13:20:49 -0700190 /**
191 * @brief Generate integrity data for the outgoing IPMI packet
192 *
193 * @param[in] input - Outgoing IPMI packet
194 *
195 * @return on success return the integrity data for the outgoing IPMI
196 * packet
197 */
198 std::vector<uint8_t> generateIntegrityData(
199 const std::vector<uint8_t>& packet) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530200
Vernon Mauery9e801a22018-10-12 13:20:49 -0700201 /**
202 * @brief Generate additional keying material based on SIK
203 *
204 * @param[in] sik - session integrity key
205 * @param[in] data - 20-byte Const_n
206 *
207 * @return on success returns the Kn based on HMAC-SHA1
208 *
209 */
210 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
211 const rmcp::Const_n& const_n) const;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800212
Vernon Mauery9e801a22018-10-12 13:20:49 -0700213 private:
214 /**
215 * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
216 *
217 * @param[in] input - pointer to the message
218 * @param[in] length - length of the message
219 *
220 * @return on success returns the message authentication code
221 *
222 */
223 std::vector<uint8_t> generateHMAC(const uint8_t* input,
224 const size_t len) const;
Tom Josephd212a6d2017-01-10 15:48:40 +0530225};
226
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800227/**
228 * @class AlgoSHA256
229 *
230 * @brief Implementation of the HMAC-SHA256-128 Integrity algorithm
231 *
232 * HMAC-SHA256-128 take the Session Integrity Key and use it to generate K1. K1
233 * is then used as the key for use in HMAC to produce the AuthCode field. For
234 * “one-key” logins, the user’s key (password) is used in the creation of the
235 * Session Integrity Key. When the HMAC-SHA256-128 Integrity Algorithm is used
236 * the resulting AuthCode field is 16 bytes (128 bits).
237 */
238class AlgoSHA256 final : public Interface
239{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700240 public:
241 static constexpr size_t SHA256_128_AUTHCODE_LENGTH = 16;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800242
Vernon Mauery9e801a22018-10-12 13:20:49 -0700243 /**
244 * @brief Constructor for AlgoSHA256
245 *
246 * @param[in] - Session Integrity Key
247 */
248 explicit AlgoSHA256(const std::vector<uint8_t>& sik);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800249
Vernon Mauery9e801a22018-10-12 13:20:49 -0700250 AlgoSHA256() = delete;
251 ~AlgoSHA256() = default;
252 AlgoSHA256(const AlgoSHA256&) = default;
253 AlgoSHA256& operator=(const AlgoSHA256&) = default;
254 AlgoSHA256(AlgoSHA256&&) = default;
255 AlgoSHA256& operator=(AlgoSHA256&&) = default;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800256
Vernon Mauery9e801a22018-10-12 13:20:49 -0700257 /**
258 * @brief Verify the integrity data of the packet
259 *
260 * @param[in] packet - Incoming IPMI packet
261 * @param[in] length - Length of the data in the packet to calculate
262 * the integrity data
263 * @param[in] integrityData - Iterator to the authCode in the packet
264 *
265 * @return true if authcode in the packet is equal to one generated
266 * using integrity algorithm on the packet data, false otherwise
267 */
268 bool verifyIntegrityData(
269 const std::vector<uint8_t>& packet, const size_t length,
270 std::vector<uint8_t>::const_iterator integrityData) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800271
Vernon Mauery9e801a22018-10-12 13:20:49 -0700272 /**
273 * @brief Generate integrity data for the outgoing IPMI packet
274 *
275 * @param[in] packet - Outgoing IPMI packet
276 *
277 * @return on success return the integrity data for the outgoing IPMI
278 * packet
279 */
280 std::vector<uint8_t> generateIntegrityData(
281 const std::vector<uint8_t>& packet) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800282
Vernon Mauery9e801a22018-10-12 13:20:49 -0700283 /**
284 * @brief Generate additional keying material based on SIK
285 *
286 * @param[in] sik - session integrity key
287 * @param[in] data - 20-byte Const_n
288 *
289 * @return on success returns the Kn based on HMAC-SHA256
290 *
291 */
292 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
293 const rmcp::Const_n& const_n) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800294
Vernon Mauery9e801a22018-10-12 13:20:49 -0700295 private:
296 /**
297 * @brief Generate HMAC based on HMAC-SHA256-128 algorithm
298 *
299 * @param[in] input - pointer to the message
300 * @param[in] len - length of the message
301 *
302 * @return on success returns the message authentication code
303 *
304 */
305 std::vector<uint8_t> generateHMAC(const uint8_t* input,
306 const size_t len) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800307};
308
Vernon Mauery9e801a22018-10-12 13:20:49 -0700309} // namespace integrity
Tom Joseph77531db2017-01-10 15:44:44 +0530310
Vernon Mauery9e801a22018-10-12 13:20:49 -0700311} // namespace cipher