blob: 6ba6340d2da0136bc747f7ad3c8569ad321a6d0f [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 */
Patrick Williams099fb092023-05-10 07:50:31 -050050 explicit Interface(size_t authLength) : authCodeLength(authLength) {}
Tom Joseph77531db2017-01-10 15:44:44 +053051
Vernon Mauery9e801a22018-10-12 13:20:49 -070052 Interface() = delete;
53 virtual ~Interface() = default;
54 Interface(const Interface&) = default;
55 Interface& operator=(const Interface&) = default;
56 Interface(Interface&&) = default;
57 Interface& operator=(Interface&&) = default;
Tom Joseph77531db2017-01-10 15:44:44 +053058
Vernon Mauery9e801a22018-10-12 13:20:49 -070059 /**
60 * @brief Verify the integrity data of the packet
61 *
62 * @param[in] packet - Incoming IPMI packet
63 * @param[in] packetLen - Packet length excluding authCode
George Liu198b0f82022-08-04 20:22:48 +080064 * @param[in] integrityDataBegin - Begin iterator to the authCode in the
65 * packet
66 * @param[in] integrityDataEnd - End to the authCode in the packet
Vernon Mauery9e801a22018-10-12 13:20:49 -070067 *
68 * @return true if authcode in the packet is equal to one generated
69 * using integrity algorithm on the packet data, false otherwise
70 */
71 bool virtual verifyIntegrityData(
72 const std::vector<uint8_t>& packet, const size_t packetLen,
George Liu198b0f82022-08-04 20:22:48 +080073 std::vector<uint8_t>::const_iterator integrityDataBegin,
74 std::vector<uint8_t>::const_iterator integrityDataEnd) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053075
Vernon Mauery9e801a22018-10-12 13:20:49 -070076 /**
77 * @brief Generate integrity data for the outgoing IPMI packet
78 *
79 * @param[in] input - Outgoing IPMI packet
80 *
81 * @return authcode for the outgoing IPMI packet
82 *
83 */
84 std::vector<uint8_t> virtual generateIntegrityData(
85 const std::vector<uint8_t>& input) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053086
Vernon Mauery9e801a22018-10-12 13:20:49 -070087 /**
88 * @brief Check if the Integrity algorithm is supported
89 *
90 * @param[in] algo - integrity algorithm
91 *
92 * @return true if algorithm is supported else false
93 *
94 */
95 static bool isAlgorithmSupported(Algorithms algo)
96 {
Suryakanth Sekar4c494392020-03-31 13:22:43 +053097 if (algo == Algorithms::HMAC_SHA256_128)
Tom Joseph1e7aa192017-02-24 17:16:49 +053098 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070099 return true;
Tom Joseph1e7aa192017-02-24 17:16:49 +0530100 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700101 else
102 {
103 return false;
104 }
105 }
Tom Joseph1e7aa192017-02-24 17:16:49 +0530106
Vernon Mauery9e801a22018-10-12 13:20:49 -0700107 /**
108 * @brief Generate additional keying material based on SIK
109 *
110 * @note
111 * The IPMI 2.0 spec only states that the additional keying material is
112 * generated by running HMAC(constN) using SIK as the key. It does not
113 * state whether this is the integrity algorithm or the authentication
114 * algorithm. Other implementations of the RMCP+ algorithm (ipmitool
115 * and ipmiutil) are not consistent on this matter. But it does not
116 * really matter because based on any of the defined cipher suites, the
117 * integrity and authentication algorithms are both based on the same
118 * digest method (integrity::Algorithms::HMAC_SHA1_96 uses SHA1 and
119 * rakp_auth::Algorithms::RAKP_HMAC_SHA1 uses SHA1). None of the
120 * defined cipher suites mix and match digests for integrity and
121 * authentication. Generating Kn belongs in either the integrity or
122 * authentication classes, so in this implementation, integrity has
123 * been chosen.
124 *
125 * @param[in] sik - session integrity key
126 * @param[in] data - 20-byte Const_n
127 *
128 * @return on success returns the Kn based on this integrity class
129 *
130 */
131 std::vector<uint8_t> virtual generateKn(
132 const std::vector<uint8_t>& sik, const rmcp::Const_n& data) const = 0;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800133
Vernon Mauery9e801a22018-10-12 13:20:49 -0700134 /** @brief Authcode field
135 *
136 * AuthCode field length varies based on the integrity algorithm, for
137 * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and
138 * HMAC-MD5-128 the authcode field is 16 bytes.
139 */
140 size_t authCodeLength;
Tom Joseph77531db2017-01-10 15:44:44 +0530141
Vernon Mauery9e801a22018-10-12 13:20:49 -0700142 protected:
143 /** @brief K1 key used to generated the integrity data. */
144 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{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700160 public:
161 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
Tom Josephd212a6d2017-01-10 15:48:40 +0530162
Vernon Mauery9e801a22018-10-12 13:20:49 -0700163 /**
164 * @brief Constructor for AlgoSHA1
165 *
166 * @param[in] - Session Integrity Key
167 */
168 explicit AlgoSHA1(const std::vector<uint8_t>& sik);
Tom Josephd212a6d2017-01-10 15:48:40 +0530169
Vernon Mauery9e801a22018-10-12 13:20:49 -0700170 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;
Tom Josephd212a6d2017-01-10 15:48:40 +0530176
Vernon Mauery9e801a22018-10-12 13:20:49 -0700177 /**
178 * @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
George Liu198b0f82022-08-04 20:22:48 +0800183 * @param[in] integrityDataBegin - Begin iterator to the authCode in the
184 * packet
185 * @param[in] integrityDataEnd - End to the authCode in the packet
Vernon Mauery9e801a22018-10-12 13:20:49 -0700186 *
187 * @return true if authcode in the packet is equal to one generated
188 * using integrity algorithm on the packet data, false otherwise
189 */
190 bool verifyIntegrityData(
191 const std::vector<uint8_t>& packet, const size_t length,
George Liu198b0f82022-08-04 20:22:48 +0800192 std::vector<uint8_t>::const_iterator integrityDataBegin,
193 std::vector<uint8_t>::const_iterator integrityDataEnd) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530194
Vernon Mauery9e801a22018-10-12 13:20:49 -0700195 /**
196 * @brief Generate integrity data for the outgoing IPMI packet
197 *
198 * @param[in] input - Outgoing IPMI packet
199 *
200 * @return on success return the integrity data for the outgoing IPMI
201 * packet
202 */
203 std::vector<uint8_t> generateIntegrityData(
204 const std::vector<uint8_t>& packet) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530205
Vernon Mauery9e801a22018-10-12 13:20:49 -0700206 /**
207 * @brief Generate additional keying material based on SIK
208 *
209 * @param[in] sik - session integrity key
210 * @param[in] data - 20-byte Const_n
211 *
212 * @return on success returns the Kn based on HMAC-SHA1
213 *
214 */
215 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
216 const rmcp::Const_n& const_n) const;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800217
Vernon Mauery9e801a22018-10-12 13:20:49 -0700218 private:
219 /**
220 * @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 */
228 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{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700245 public:
246 static constexpr size_t SHA256_128_AUTHCODE_LENGTH = 16;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800247
Vernon Mauery9e801a22018-10-12 13:20:49 -0700248 /**
249 * @brief Constructor for AlgoSHA256
250 *
251 * @param[in] - Session Integrity Key
252 */
253 explicit AlgoSHA256(const std::vector<uint8_t>& sik);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800254
Vernon Mauery9e801a22018-10-12 13:20:49 -0700255 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;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800261
Vernon Mauery9e801a22018-10-12 13:20:49 -0700262 /**
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
George Liu198b0f82022-08-04 20:22:48 +0800268 * @param[in] integrityDataBegin - Begin iterator to the authCode in the
269 * packet
270 * @param[in] integrityDataEnd - End to the authCode in the packet
Vernon Mauery9e801a22018-10-12 13:20:49 -0700271 *
272 * @return true if authcode in the packet is equal to one generated
273 * using integrity algorithm on the packet data, false otherwise
274 */
275 bool verifyIntegrityData(
276 const std::vector<uint8_t>& packet, const size_t length,
George Liu198b0f82022-08-04 20:22:48 +0800277 std::vector<uint8_t>::const_iterator integrityDataBegin,
278 std::vector<uint8_t>::const_iterator integrityDataEnd) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800279
Vernon Mauery9e801a22018-10-12 13:20:49 -0700280 /**
281 * @brief Generate integrity data for the outgoing IPMI packet
282 *
283 * @param[in] packet - Outgoing IPMI packet
284 *
285 * @return on success return the integrity data for the outgoing IPMI
286 * packet
287 */
288 std::vector<uint8_t> generateIntegrityData(
289 const std::vector<uint8_t>& packet) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800290
Vernon Mauery9e801a22018-10-12 13:20:49 -0700291 /**
292 * @brief Generate additional keying material based on SIK
293 *
294 * @param[in] sik - session integrity key
295 * @param[in] data - 20-byte Const_n
296 *
297 * @return on success returns the Kn based on HMAC-SHA256
298 *
299 */
300 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
301 const rmcp::Const_n& const_n) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800302
Vernon Mauery9e801a22018-10-12 13:20:49 -0700303 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;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800315};
316
Vernon Mauery9e801a22018-10-12 13:20:49 -0700317} // namespace integrity
Tom Joseph77531db2017-01-10 15:44:44 +0530318
Vernon Mauery9e801a22018-10-12 13:20:49 -0700319} // namespace cipher