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