1 #pragma once
2 
3 #include <array>
4 #include <vector>
5 #include "crypt_algo.hpp"
6 #include "integrity_algo.hpp"
7 
8 namespace cipher
9 {
10 namespace rakp_auth
11 {
12 constexpr size_t USER_KEY_MAX_LENGTH = 20;
13 constexpr size_t BMC_RANDOM_NUMBER_LEN = 16;
14 constexpr size_t REMOTE_CONSOLE_RANDOM_NUMBER_LEN = 16;
15 extern const std::string userName;
16 
17 /**
18  * @enum RAKP Authentication Algorithms
19  *
20  * RMCP+ Authenticated Key-Exchange Protocol (RAKP)
21  *
22  * RAKP-None is not supported as per the following recommendation
23  * (https://www.us-cert.gov/ncas/alerts/TA13-207A)
24  * ("cipher 0" is an option enabled by default on many IPMI enabled devices that
25  * allows authentication to be bypassed.  Disable "cipher 0" to prevent
26  * attackers from bypassing authentication and sending arbitrary IPMI commands.)
27  */
28 enum class Algorithms : uint8_t
29 {
30     RAKP_NONE = 0,    // Mandatory (implemented, not supported)
31     RAKP_HMAC_SHA1,   // Mandatory (implemented, default choice in ipmitool)
32     RAKP_HMAC_MD5,    // Optional (not implemented)
33     RAKP_HMAC_SHA256, // Optional (implemented, best available)
34     // Reserved used to indicate an invalid authentication algorithm
35     RAKP_HMAC_INVALID = 0xB0
36 };
37 
38 /**
39  * @class Interface
40  *
41  * Interface is the base class for the Authentication Algorithms.
42  * The Authentication Algorithm specifies the type of authentication “handshake”
43  * process that is used and identifies any particular variations of hashing or
44  * signature algorithm that is used as part of the process.
45  *
46  */
47 class Interface
48 {
49     public:
50         explicit Interface(integrity::Algorithms intAlgo,
51                            crypt::Algorithms cryptAlgo) :
52                 intAlgo(intAlgo),
53                 cryptAlgo(cryptAlgo) {}
54 
55         Interface() = delete;
56         virtual ~Interface() = default;
57         Interface(const Interface&) = default;
58         Interface& operator=(const Interface&) = default;
59         Interface(Interface&&) = default;
60         Interface& operator=(Interface&&) = default;
61 
62         /**
63          * @brief Generate the Hash Message Authentication Code
64          *
65          * This API is invoked to generate the Key Exchange Authentication Code
66          * in the RAKP2 and RAKP4 sequence and for generating the Session
67          * Integrity Key.
68          *
69          * @param input message
70          *
71          * @return hash output
72          *
73          * @note The user key which is the secret key for the hash operation
74          *        needs to be set before this operation.
75          */
76         std::vector<uint8_t> virtual generateHMAC(
77             const std::vector<uint8_t>& input) const = 0;
78 
79         /**
80          * @brief Generate the Integrity Check Value
81          *
82          * This API is invoked in the RAKP4 sequence for generating the
83          * Integrity Check Value.
84          *
85          * @param input message
86          *
87          * @return hash output
88          *
89          * @note The session integrity key which is the secret key for the
90          *        hash operation needs to be set before this operation.
91          */
92         std::vector<uint8_t> virtual generateICV(
93             const std::vector<uint8_t>& input) const = 0;
94 
95         /**
96          * @brief Check if the Authentication algorithm is supported
97          *
98          * @param[in] algo - authentication algorithm
99          *
100          * @return true if algorithm is supported else false
101          *
102          */
103         static bool isAlgorithmSupported(Algorithms algo)
104         {
105             if (algo == Algorithms::RAKP_HMAC_SHA1 ||
106                 algo == Algorithms::RAKP_HMAC_SHA256)
107             {
108                return true;
109             }
110             else
111             {
112                 return false;
113             }
114         }
115 
116         // User Key is hardcoded to PASSW0RD till the IPMI User account
117         // management is in place.
118         std::array<uint8_t, USER_KEY_MAX_LENGTH> userKey = {"0penBmc"};
119 
120         // Managed System Random Number
121         std::array<uint8_t, BMC_RANDOM_NUMBER_LEN> bmcRandomNum;
122 
123         // Remote Console Random Number
124         std::array<uint8_t, REMOTE_CONSOLE_RANDOM_NUMBER_LEN> rcRandomNum;
125 
126         // Session Integrity Key
127         std::vector<uint8_t> sessionIntegrityKey;
128 
129         /**
130          * Integrity Algorithm is activated and set in the session data only
131          * once the session setup is succeeded in the RAKP34 command. But the
132          * integrity algorithm is negotiated in the Open Session Request command
133          * . So the integrity algorithm successfully negotiated is stored
134          * in the authentication algorithm's instance.
135          */
136         integrity::Algorithms intAlgo;
137 
138         /**
139          * Confidentiality Algorithm is activated and set in the session data
140          * only once the session setup is succeeded in the RAKP34 command. But
141          * the confidentiality algorithm is negotiated in the Open Session
142          * Request command. So the confidentiality algorithm successfully
143          * negotiated is stored in the authentication algorithm's instance.
144          */
145         crypt::Algorithms cryptAlgo;
146 };
147 
148 /**
149  * @class AlgoSHA1
150  *
151  * RAKP-HMAC-SHA1 specifies the use of RAKP messages for the key exchange
152  * portion of establishing the session, and that HMAC-SHA1 (per [RFC2104]) is
153  * used to create 20-byte Key Exchange Authentication Code fields in RAKP
154  * Message 2 and RAKP Message 3. HMAC-SHA1-96(per [RFC2404]) is used for
155  * generating a 12-byte Integrity Check Value field for RAKP Message 4.
156  */
157 
158 class AlgoSHA1 : public Interface
159 {
160     public:
161         static constexpr size_t integrityCheckValueLength = 12;
162 
163         explicit AlgoSHA1(integrity::Algorithms intAlgo,
164                           crypt::Algorithms cryptAlgo) :
165                 Interface(intAlgo, cryptAlgo) {}
166 
167         AlgoSHA1() = delete;
168         ~AlgoSHA1() = default;
169         AlgoSHA1(const AlgoSHA1&) = default;
170         AlgoSHA1& operator=(const AlgoSHA1&) = default;
171         AlgoSHA1(AlgoSHA1&&) = default;
172         AlgoSHA1& operator=(AlgoSHA1&&) = default;
173 
174         std::vector<uint8_t> generateHMAC(
175                 const std::vector<uint8_t>& input) const override;
176 
177         std::vector<uint8_t> generateICV(
178                 const std::vector<uint8_t>& input) const override;
179 };
180 
181 /**
182  * @class AlgoSHA256
183  *
184  * RAKP-HMAC-SHA256 specifies the use of RAKP messages for the key exchange
185  * portion of establishing the session, and that HMAC-SHA256 (per [FIPS 180-2]
186  * and [RFC4634] and is used to create a 32-byte Key Exchange Authentication
187  * Code fields in RAKP Message 2 and RAKP Message 3. HMAC-SHA256-128 (per
188  * [RFC4868]) is used for generating a 16-byte Integrity Check Value field for
189  * RAKP Message 4.
190  */
191 
192 class AlgoSHA256 : public Interface
193 {
194     public:
195         static constexpr size_t integrityCheckValueLength = 16;
196 
197         explicit AlgoSHA256(integrity::Algorithms intAlgo,
198                           crypt::Algorithms cryptAlgo) :
199                 Interface(intAlgo, cryptAlgo) {}
200 
201         ~AlgoSHA256() = default;
202         AlgoSHA256(const AlgoSHA256&) = default;
203         AlgoSHA256& operator=(const AlgoSHA256&) = default;
204         AlgoSHA256(AlgoSHA256&&) = default;
205         AlgoSHA256& operator=(AlgoSHA256&&) = default;
206 
207         std::vector<uint8_t> generateHMAC(
208                 const std::vector<uint8_t>& input) const override;
209 
210         std::vector<uint8_t> generateICV(
211                 const std::vector<uint8_t>& input) const override;
212 };
213 
214 }// namespace auth
215 
216 }// namespace cipher
217 
218