blob: cdeb617f9714a327951610e9256812792b79627e [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)
51 {
52 }
Tom Joseph77531db2017-01-10 15:44:44 +053053
Vernon Mauery9e801a22018-10-12 13:20:49 -070054 Interface() = delete;
55 virtual ~Interface() = default;
56 Interface(const Interface&) = default;
57 Interface& operator=(const Interface&) = default;
58 Interface(Interface&&) = default;
59 Interface& operator=(Interface&&) = default;
Tom Joseph77531db2017-01-10 15:44:44 +053060
Vernon Mauery9e801a22018-10-12 13:20:49 -070061 /**
62 * @brief Verify the integrity data of the packet
63 *
64 * @param[in] packet - Incoming IPMI packet
65 * @param[in] packetLen - Packet length excluding authCode
66 * @param[in] integrityData - Iterator to the authCode in the packet
67 *
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,
73 std::vector<uint8_t>::const_iterator integrityData) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053074
Vernon Mauery9e801a22018-10-12 13:20:49 -070075 /**
76 * @brief Generate integrity data for the outgoing IPMI packet
77 *
78 * @param[in] input - Outgoing IPMI packet
79 *
80 * @return authcode for the outgoing IPMI packet
81 *
82 */
83 std::vector<uint8_t> virtual generateIntegrityData(
84 const std::vector<uint8_t>& input) const = 0;
Tom Joseph77531db2017-01-10 15:44:44 +053085
Vernon Mauery9e801a22018-10-12 13:20:49 -070086 /**
87 * @brief Check if the Integrity algorithm is supported
88 *
89 * @param[in] algo - integrity algorithm
90 *
91 * @return true if algorithm is supported else false
92 *
93 */
94 static bool isAlgorithmSupported(Algorithms algo)
95 {
Suryakanth Sekar4c494392020-03-31 13:22:43 +053096 if (algo == Algorithms::HMAC_SHA256_128)
Tom Joseph1e7aa192017-02-24 17:16:49 +053097 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070098 return true;
Tom Joseph1e7aa192017-02-24 17:16:49 +053099 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700100 else
101 {
102 return false;
103 }
104 }
Tom Joseph1e7aa192017-02-24 17:16:49 +0530105
Vernon Mauery9e801a22018-10-12 13:20:49 -0700106 /**
107 * @brief Generate additional keying material based on SIK
108 *
109 * @note
110 * The IPMI 2.0 spec only states that the additional keying material is
111 * generated by running HMAC(constN) using SIK as the key. It does not
112 * state whether this is the integrity algorithm or the authentication
113 * algorithm. Other implementations of the RMCP+ algorithm (ipmitool
114 * and ipmiutil) are not consistent on this matter. But it does not
115 * really matter because based on any of the defined cipher suites, the
116 * integrity and authentication algorithms are both based on the same
117 * digest method (integrity::Algorithms::HMAC_SHA1_96 uses SHA1 and
118 * rakp_auth::Algorithms::RAKP_HMAC_SHA1 uses SHA1). None of the
119 * defined cipher suites mix and match digests for integrity and
120 * authentication. Generating Kn belongs in either the integrity or
121 * authentication classes, so in this implementation, integrity has
122 * been chosen.
123 *
124 * @param[in] sik - session integrity key
125 * @param[in] data - 20-byte Const_n
126 *
127 * @return on success returns the Kn based on this integrity class
128 *
129 */
130 std::vector<uint8_t> virtual generateKn(
131 const std::vector<uint8_t>& sik, const rmcp::Const_n& data) const = 0;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800132
Vernon Mauery9e801a22018-10-12 13:20:49 -0700133 /** @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.
138 */
139 size_t authCodeLength;
Tom Joseph77531db2017-01-10 15:44:44 +0530140
Vernon Mauery9e801a22018-10-12 13:20:49 -0700141 protected:
142 /** @brief K1 key used to generated the integrity data. */
143 std::vector<uint8_t> k1;
Tom Joseph77531db2017-01-10 15:44:44 +0530144};
145
Tom Joseph3563f8f2017-05-08 15:42:54 +0530146/**
Tom Josephd212a6d2017-01-10 15:48:40 +0530147 * @class AlgoSHA1
148 *
149 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
150 *
151 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
152 * then used as the key for use in HMAC to produce the AuthCode field.
153 * For “one-key” logins, the user’s key (password) is used in the creation of
154 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
155 * the resulting AuthCode field is 12 bytes (96 bits).
156 */
157class AlgoSHA1 final : public Interface
158{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700159 public:
160 static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
Tom Josephd212a6d2017-01-10 15:48:40 +0530161
Vernon Mauery9e801a22018-10-12 13:20:49 -0700162 /**
163 * @brief Constructor for AlgoSHA1
164 *
165 * @param[in] - Session Integrity Key
166 */
167 explicit AlgoSHA1(const std::vector<uint8_t>& sik);
Tom Josephd212a6d2017-01-10 15:48:40 +0530168
Vernon Mauery9e801a22018-10-12 13:20:49 -0700169 AlgoSHA1() = delete;
170 ~AlgoSHA1() = default;
171 AlgoSHA1(const AlgoSHA1&) = default;
172 AlgoSHA1& operator=(const AlgoSHA1&) = default;
173 AlgoSHA1(AlgoSHA1&&) = default;
174 AlgoSHA1& operator=(AlgoSHA1&&) = default;
Tom Josephd212a6d2017-01-10 15:48:40 +0530175
Vernon Mauery9e801a22018-10-12 13:20:49 -0700176 /**
177 * @brief Verify the integrity data of the packet
178 *
179 * @param[in] packet - Incoming IPMI packet
180 * @param[in] length - Length of the data in the packet to calculate
181 * the integrity data
182 * @param[in] integrityData - Iterator to the authCode in the packet
183 *
184 * @return true if authcode in the packet is equal to one generated
185 * using integrity algorithm on the packet data, false otherwise
186 */
187 bool verifyIntegrityData(
188 const std::vector<uint8_t>& packet, const size_t length,
189 std::vector<uint8_t>::const_iterator integrityData) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530190
Vernon Mauery9e801a22018-10-12 13:20:49 -0700191 /**
192 * @brief Generate integrity data for the outgoing IPMI packet
193 *
194 * @param[in] input - Outgoing IPMI packet
195 *
196 * @return on success return the integrity data for the outgoing IPMI
197 * packet
198 */
199 std::vector<uint8_t> generateIntegrityData(
200 const std::vector<uint8_t>& packet) const override;
Tom Josephd212a6d2017-01-10 15:48:40 +0530201
Vernon Mauery9e801a22018-10-12 13:20:49 -0700202 /**
203 * @brief Generate additional keying material based on SIK
204 *
205 * @param[in] sik - session integrity key
206 * @param[in] data - 20-byte Const_n
207 *
208 * @return on success returns the Kn based on HMAC-SHA1
209 *
210 */
211 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
212 const rmcp::Const_n& const_n) const;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800213
Vernon Mauery9e801a22018-10-12 13:20:49 -0700214 private:
215 /**
216 * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
217 *
218 * @param[in] input - pointer to the message
219 * @param[in] length - length of the message
220 *
221 * @return on success returns the message authentication code
222 *
223 */
224 std::vector<uint8_t> generateHMAC(const uint8_t* input,
225 const size_t len) const;
Tom Josephd212a6d2017-01-10 15:48:40 +0530226};
227
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800228/**
229 * @class AlgoSHA256
230 *
231 * @brief Implementation of the HMAC-SHA256-128 Integrity algorithm
232 *
233 * HMAC-SHA256-128 take the Session Integrity Key and use it to generate K1. K1
234 * is then used as the key for use in HMAC to produce the AuthCode field. For
235 * “one-key” logins, the user’s key (password) is used in the creation of the
236 * Session Integrity Key. When the HMAC-SHA256-128 Integrity Algorithm is used
237 * the resulting AuthCode field is 16 bytes (128 bits).
238 */
239class AlgoSHA256 final : public Interface
240{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700241 public:
242 static constexpr size_t SHA256_128_AUTHCODE_LENGTH = 16;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800243
Vernon Mauery9e801a22018-10-12 13:20:49 -0700244 /**
245 * @brief Constructor for AlgoSHA256
246 *
247 * @param[in] - Session Integrity Key
248 */
249 explicit AlgoSHA256(const std::vector<uint8_t>& sik);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800250
Vernon Mauery9e801a22018-10-12 13:20:49 -0700251 AlgoSHA256() = delete;
252 ~AlgoSHA256() = default;
253 AlgoSHA256(const AlgoSHA256&) = default;
254 AlgoSHA256& operator=(const AlgoSHA256&) = default;
255 AlgoSHA256(AlgoSHA256&&) = default;
256 AlgoSHA256& operator=(AlgoSHA256&&) = default;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800257
Vernon Mauery9e801a22018-10-12 13:20:49 -0700258 /**
259 * @brief Verify the integrity data of the packet
260 *
261 * @param[in] packet - Incoming IPMI packet
262 * @param[in] length - Length of the data in the packet to calculate
263 * the integrity data
264 * @param[in] integrityData - Iterator to the authCode in the packet
265 *
266 * @return true if authcode in the packet is equal to one generated
267 * using integrity algorithm on the packet data, false otherwise
268 */
269 bool verifyIntegrityData(
270 const std::vector<uint8_t>& packet, const size_t length,
271 std::vector<uint8_t>::const_iterator integrityData) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800272
Vernon Mauery9e801a22018-10-12 13:20:49 -0700273 /**
274 * @brief Generate integrity data for the outgoing IPMI packet
275 *
276 * @param[in] packet - Outgoing IPMI packet
277 *
278 * @return on success return the integrity data for the outgoing IPMI
279 * packet
280 */
281 std::vector<uint8_t> generateIntegrityData(
282 const std::vector<uint8_t>& packet) const override;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800283
Vernon Mauery9e801a22018-10-12 13:20:49 -0700284 /**
285 * @brief Generate additional keying material based on SIK
286 *
287 * @param[in] sik - session integrity key
288 * @param[in] data - 20-byte Const_n
289 *
290 * @return on success returns the Kn based on HMAC-SHA256
291 *
292 */
293 std::vector<uint8_t> generateKn(const std::vector<uint8_t>& sik,
294 const rmcp::Const_n& const_n) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800295
Vernon Mauery9e801a22018-10-12 13:20:49 -0700296 private:
297 /**
298 * @brief Generate HMAC based on HMAC-SHA256-128 algorithm
299 *
300 * @param[in] input - pointer to the message
301 * @param[in] len - length of the message
302 *
303 * @return on success returns the message authentication code
304 *
305 */
306 std::vector<uint8_t> generateHMAC(const uint8_t* input,
307 const size_t len) const;
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800308};
309
Vernon Mauery9e801a22018-10-12 13:20:49 -0700310} // namespace integrity
Tom Joseph77531db2017-01-10 15:44:44 +0530311
Vernon Mauery9e801a22018-10-12 13:20:49 -0700312} // namespace cipher