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