blob: d451d0ec5f25c95115831d27012e2dd02c4604b6 [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
George Liu198b0f82022-08-04 20:22:48 +080065 * @param[in] integrityDataBegin - Begin iterator to the authCode in the
66 * packet
67 * @param[in] integrityDataEnd - End to the authCode in the packet
Vernon Mauery9e801a22018-10-12 13:20:49 -070068 *
69 * @return true if authcode in the packet is equal to one generated
70 * using integrity algorithm on the packet data, false otherwise
71 */
72 bool virtual verifyIntegrityData(
73 const std::vector<uint8_t>& packet, const size_t packetLen,
George Liu198b0f82022-08-04 20:22:48 +080074 std::vector<uint8_t>::const_iterator integrityDataBegin,
75 std::vector<uint8_t>::const_iterator integrityDataEnd) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053076
Vernon Mauery9e801a22018-10-12 13:20:49 -070077 /**
78 * @brief Generate integrity data for the outgoing IPMI packet
79 *
80 * @param[in] input - Outgoing IPMI packet
81 *
82 * @return authcode for the outgoing IPMI packet
83 *
84 */
85 std::vector<uint8_t> virtual generateIntegrityData(
86 const std::vector<uint8_t>& input) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053087
Vernon Mauery9e801a22018-10-12 13:20:49 -070088 /**
89 * @brief Check if the Integrity algorithm is supported
90 *
91 * @param[in] algo - integrity algorithm
92 *
93 * @return true if algorithm is supported else false
94 *
95 */
96 static bool isAlgorithmSupported(Algorithms algo)
97 {
Suryakanth Sekar4c494392020-03-31 13:22:43 +053098 if (algo == Algorithms::HMAC_SHA256_128)
Tom Joseph1e7aa192017-02-24 17:16:49 +053099 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700100 return true;
Tom Joseph1e7aa192017-02-24 17:16:49 +0530101 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700102 else
103 {
104 return false;
105 }
106 }
Tom Joseph1e7aa192017-02-24 17:16:49 +0530107
Vernon Mauery9e801a22018-10-12 13:20:49 -0700108 /**
109 * @brief Generate additional keying material based on SIK
110 *
111 * @note
112 * The IPMI 2.0 spec only states that the additional keying material is
113 * generated by running HMAC(constN) using SIK as the key. It does not
114 * state whether this is the integrity algorithm or the authentication
115 * algorithm. Other implementations of the RMCP+ algorithm (ipmitool
116 * and ipmiutil) are not consistent on this matter. But it does not
117 * really matter because based on any of the defined cipher suites, the
118 * integrity and authentication algorithms are both based on the same
119 * digest method (integrity::Algorithms::HMAC_SHA1_96 uses SHA1 and
120 * rakp_auth::Algorithms::RAKP_HMAC_SHA1 uses SHA1). None of the
121 * defined cipher suites mix and match digests for integrity and
122 * authentication. Generating Kn belongs in either the integrity or
123 * authentication classes, so in this implementation, integrity has
124 * been chosen.
125 *
126 * @param[in] sik - session integrity key
127 * @param[in] data - 20-byte Const_n
128 *
129 * @return on success returns the Kn based on this integrity class
130 *
131 */
132 std::vector<uint8_t> virtual generateKn(
133 const std::vector<uint8_t>& sik, const rmcp::Const_n& data) const = 0;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800134
Vernon Mauery9e801a22018-10-12 13:20:49 -0700135 /** @brief Authcode field
136 *
137 * AuthCode field length varies based on the integrity algorithm, for
138 * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and
139 * HMAC-MD5-128 the authcode field is 16 bytes.
140 */
141 size_t authCodeLength;
Tom Joseph77531db2017-01-10 15:44:44 +0530142
Vernon Mauery9e801a22018-10-12 13:20:49 -0700143 protected:
144 /** @brief K1 key used to generated the integrity data. */
145 std::vector<uint8_t> k1;
Tom Joseph77531db2017-01-10 15:44:44 +0530146};
147
Tom Joseph3563f8f2017-05-08 15:42:54 +0530148/**
Tom Josephd212a6d2017-01-10 15:48:40 +0530149 * @class AlgoSHA1
150 *
151 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
152 *
153 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
154 * then used as the key for use in HMAC to produce the AuthCode field.
155 * For “one-key” logins, the user’s key (password) is used in the creation of
156 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
157 * the resulting AuthCode field is 12 bytes (96 bits).
158 */
159class AlgoSHA1 final : public Interface
160{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700161 public:
162 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
Tom Josephd212a6d2017-01-10 15:48:40 +0530163
Vernon Mauery9e801a22018-10-12 13:20:49 -0700164 /**
165 * @brief Constructor for AlgoSHA1
166 *
167 * @param[in] - Session Integrity Key
168 */
169 explicit AlgoSHA1(const std::vector<uint8_t>& sik);
Tom Josephd212a6d2017-01-10 15:48:40 +0530170
Vernon Mauery9e801a22018-10-12 13:20:49 -0700171 AlgoSHA1() = delete;
172 ~AlgoSHA1() = default;
173 AlgoSHA1(const AlgoSHA1&) = default;
174 AlgoSHA1& operator=(const AlgoSHA1&) = default;
175 AlgoSHA1(AlgoSHA1&&) = default;
176 AlgoSHA1& operator=(AlgoSHA1&&) = default;
Tom Josephd212a6d2017-01-10 15:48:40 +0530177
Vernon Mauery9e801a22018-10-12 13:20:49 -0700178 /**
179 * @brief Verify the integrity data of the packet
180 *
181 * @param[in] packet - Incoming IPMI packet
182 * @param[in] length - Length of the data in the packet to calculate
183 * the integrity data
George Liu198b0f82022-08-04 20:22:48 +0800184 * @param[in] integrityDataBegin - Begin iterator to the authCode in the
185 * packet
186 * @param[in] integrityDataEnd - End to the authCode in the packet
Vernon Mauery9e801a22018-10-12 13:20:49 -0700187 *
188 * @return true if authcode in the packet is equal to one generated
189 * using integrity algorithm on the packet data, false otherwise
190 */
191 bool verifyIntegrityData(
192 const std::vector<uint8_t>& packet, const size_t length,
George Liu198b0f82022-08-04 20:22:48 +0800193 std::vector<uint8_t>::const_iterator integrityDataBegin,
194 std::vector<uint8_t>::const_iterator integrityDataEnd) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530195
Vernon Mauery9e801a22018-10-12 13:20:49 -0700196 /**
197 * @brief Generate integrity data for the outgoing IPMI packet
198 *
199 * @param[in] input - Outgoing IPMI packet
200 *
201 * @return on success return the integrity data for the outgoing IPMI
202 * packet
203 */
204 std::vector<uint8_t> generateIntegrityData(
205 const std::vector<uint8_t>& packet) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530206
Vernon Mauery9e801a22018-10-12 13:20:49 -0700207 /**
208 * @brief Generate additional keying material based on SIK
209 *
210 * @param[in] sik - session integrity key
211 * @param[in] data - 20-byte Const_n
212 *
213 * @return on success returns the Kn based on HMAC-SHA1
214 *
215 */
216 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
217 const rmcp::Const_n& const_n) const;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800218
Vernon Mauery9e801a22018-10-12 13:20:49 -0700219 private:
220 /**
221 * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
222 *
223 * @param[in] input - pointer to the message
224 * @param[in] length - length of the message
225 *
226 * @return on success returns the message authentication code
227 *
228 */
229 std::vector<uint8_t> generateHMAC(const uint8_t* input,
230 const size_t len) const;
Tom Josephd212a6d2017-01-10 15:48:40 +0530231};
232
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800233/**
234 * @class AlgoSHA256
235 *
236 * @brief Implementation of the HMAC-SHA256-128 Integrity algorithm
237 *
238 * HMAC-SHA256-128 take the Session Integrity Key and use it to generate K1. K1
239 * is then used as the key for use in HMAC to produce the AuthCode field. For
240 * “one-key” logins, the user’s key (password) is used in the creation of the
241 * Session Integrity Key. When the HMAC-SHA256-128 Integrity Algorithm is used
242 * the resulting AuthCode field is 16 bytes (128 bits).
243 */
244class AlgoSHA256 final : public Interface
245{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700246 public:
247 static constexpr size_t SHA256_128_AUTHCODE_LENGTH = 16;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800248
Vernon Mauery9e801a22018-10-12 13:20:49 -0700249 /**
250 * @brief Constructor for AlgoSHA256
251 *
252 * @param[in] - Session Integrity Key
253 */
254 explicit AlgoSHA256(const std::vector<uint8_t>& sik);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800255
Vernon Mauery9e801a22018-10-12 13:20:49 -0700256 AlgoSHA256() = delete;
257 ~AlgoSHA256() = default;
258 AlgoSHA256(const AlgoSHA256&) = default;
259 AlgoSHA256& operator=(const AlgoSHA256&) = default;
260 AlgoSHA256(AlgoSHA256&&) = default;
261 AlgoSHA256& operator=(AlgoSHA256&&) = default;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800262
Vernon Mauery9e801a22018-10-12 13:20:49 -0700263 /**
264 * @brief Verify the integrity data of the packet
265 *
266 * @param[in] packet - Incoming IPMI packet
267 * @param[in] length - Length of the data in the packet to calculate
268 * the integrity data
George Liu198b0f82022-08-04 20:22:48 +0800269 * @param[in] integrityDataBegin - Begin iterator to the authCode in the
270 * packet
271 * @param[in] integrityDataEnd - End to the authCode in the packet
Vernon Mauery9e801a22018-10-12 13:20:49 -0700272 *
273 * @return true if authcode in the packet is equal to one generated
274 * using integrity algorithm on the packet data, false otherwise
275 */
276 bool verifyIntegrityData(
277 const std::vector<uint8_t>& packet, const size_t length,
George Liu198b0f82022-08-04 20:22:48 +0800278 std::vector<uint8_t>::const_iterator integrityDataBegin,
279 std::vector<uint8_t>::const_iterator integrityDataEnd) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800280
Vernon Mauery9e801a22018-10-12 13:20:49 -0700281 /**
282 * @brief Generate integrity data for the outgoing IPMI packet
283 *
284 * @param[in] packet - Outgoing IPMI packet
285 *
286 * @return on success return the integrity data for the outgoing IPMI
287 * packet
288 */
289 std::vector<uint8_t> generateIntegrityData(
290 const std::vector<uint8_t>& packet) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800291
Vernon Mauery9e801a22018-10-12 13:20:49 -0700292 /**
293 * @brief Generate additional keying material based on SIK
294 *
295 * @param[in] sik - session integrity key
296 * @param[in] data - 20-byte Const_n
297 *
298 * @return on success returns the Kn based on HMAC-SHA256
299 *
300 */
301 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
302 const rmcp::Const_n& const_n) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800303
Vernon Mauery9e801a22018-10-12 13:20:49 -0700304 private:
305 /**
306 * @brief Generate HMAC based on HMAC-SHA256-128 algorithm
307 *
308 * @param[in] input - pointer to the message
309 * @param[in] len - length of the message
310 *
311 * @return on success returns the message authentication code
312 *
313 */
314 std::vector<uint8_t> generateHMAC(const uint8_t* input,
315 const size_t len) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800316};
317
Vernon Mauery9e801a22018-10-12 13:20:49 -0700318} // namespace integrity
Tom Joseph77531db2017-01-10 15:44:44 +0530319
Vernon Mauery9e801a22018-10-12 13:20:49 -0700320} // namespace cipher