blob: 95b8af7b3d7969eba0252d231d78ada45ed15527 [file] [log] [blame]
Tom Joseph50fb50a2016-12-06 17:51:06 +05301#include "rakp34.hpp"
2
3#include <algorithm>
4#include <cstring>
5#include <iostream>
6
7#include "comm_module.hpp"
8#include "endian.hpp"
9#include "guid.hpp"
10#include "main.hpp"
11
12namespace command
13{
14
Tom Josephef02fb32017-01-19 12:55:11 +053015void applyIntegrityAlgo(const uint32_t bmcSessionID)
16{
17 auto session = (std::get<session::Manager&>(singletonPool).getSession(
18 bmcSessionID)).lock();
19
20 auto authAlgo = session->getAuthAlgo();
21
22 switch (authAlgo->intAlgo)
23 {
24 case cipher::integrity::Algorithms::HMAC_SHA1_96:
25 {
26 session->setIntegrityAlgo(
27 std::make_unique<cipher::integrity::AlgoSHA1>(
28 authAlgo->sessionIntegrityKey));
29 break;
30 }
31 default:
32 break;
33 }
34}
35
Tom Joseph4c766eb2017-01-24 18:24:57 +053036void applyCryptAlgo(const uint32_t bmcSessionID)
37{
38 auto session = (std::get<session::Manager&>(singletonPool).getSession(
39 bmcSessionID)).lock();
40
41 auto authAlgo = session->getAuthAlgo();
42
43 switch (authAlgo->cryptAlgo)
44 {
45 case cipher::crypt::Algorithms::AES_CBC_128:
46 {
47 session->setCryptAlgo(std::make_unique<cipher::crypt::AlgoAES128>(
48 authAlgo->sessionIntegrityKey));
49 break;
50 }
51 default:
52 break;
53 }
54}
55
Tom Joseph18a45e92017-04-11 11:30:44 +053056std::vector<uint8_t> RAKP34(const std::vector<uint8_t>& inPayload,
Tom Joseph50fb50a2016-12-06 17:51:06 +053057 const message::Handler& handler)
58{
59 std::cout << ">> RAKP34\n";
60
61 std::vector<uint8_t> outPayload(sizeof(RAKP4response));
Tom Joseph18a45e92017-04-11 11:30:44 +053062 auto request = reinterpret_cast<const RAKP3request*>(inPayload.data());
Tom Joseph50fb50a2016-12-06 17:51:06 +053063 auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
64
65 // Check if the RAKP3 Payload Length is as expected
66 if(inPayload.size() != sizeof(RAKP3request))
67 {
68 std::cerr << "RAKP34: Invalid RAKP3 request\n";
69 response->rmcpStatusCode =
70 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
71 return outPayload;
72 }
73
74 // Session ID zero is reserved for Session Setup
75 if(endian::from_ipmi(request->managedSystemSessionID) ==
76 session::SESSION_ZERO)
77 {
78 std::cerr << "RAKP34: BMC invalid Session ID\n";
79 response->rmcpStatusCode =
80 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
81 return outPayload;
82 }
83
84 std::shared_ptr<session::Session> session;
85 try
86 {
87 session = (std::get<session::Manager&>(singletonPool).getSession(
88 endian::from_ipmi(request->managedSystemSessionID))).lock();
89 }
90 catch (std::exception& e)
91 {
92 std::cerr << e.what() << "\n";
93 response->rmcpStatusCode =
94 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
95 return outPayload;
96 }
97
98 session->updateLastTransactionTime();
99
100 auto authAlgo = session->getAuthAlgo();
101 /*
102 * Key Authentication Code - RAKP 3
103 *
104 * 1) Managed System Random Number - 16 bytes
105 * 2) Remote Console Session ID - 4 bytes
106 * 3) Session Privilege Level - 1 byte
107 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
108 * 5) User Name - variable (absent for 'null' username)
109 */
110
111 // Remote Console Session ID
112 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
113
114 // Session Privilege Level
115 auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
116
117 // User Name Length Byte
118 uint8_t userLength = 0;
119
120 std::vector<uint8_t> input;
121 input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
122 sizeof(rcSessionID) + sizeof(sessPrivLevel) +
123 sizeof(userLength));
124
125 auto iter = input.begin();
126
127 // Managed System Random Number
128 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
129 iter);
130 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
131
132 // Remote Console Session ID
133 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
134 iter);
135 std::advance(iter, sizeof(rcSessionID));
136
137 // Session Privilege Level
138 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
139 sizeof(sessPrivLevel), iter);
140 std::advance(iter, sizeof(sessPrivLevel));
141
142 // User Name Length Byte
143 std::copy_n(&userLength, sizeof(userLength), iter);
144
145 // Generate Key Exchange Authentication Code - RAKP2
146 auto output = authAlgo->generateHMAC(input);
147
148 if (std::memcmp(output.data(), request->keyExchangeAuthCode,
149 output.size()))
150 {
151 std::cerr << "Mismatch in HMAC sent by remote console\n";
152
153 response->messageTag = request->messageTag;
154 response->rmcpStatusCode = static_cast<uint8_t>
155 (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
156 response->reserved = 0;
157 response->remoteConsoleSessionID = rcSessionID;
158
159 //close the session
160 std::get<session::Manager&>(singletonPool).stopSession(
161 session->getBMCSessionID());
162
163 return outPayload;
164 }
165
166 /*
167 * Session Integrity Key
168 *
169 * 1) Remote Console Random Number - 16 bytes
170 * 2) Managed System Random Number - 16 bytes
171 * 3) Session Privilege Level - 1 byte
172 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
173 * 5) User Name - variable (absent for 'null' username)
174 */
175
176 input.clear();
177
178 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
179 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
180 sizeof(sessPrivLevel) + sizeof(userLength));
181 iter = input.begin();
182
183 // Remote Console Random Number
184 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
185 iter);
186 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
187
188 // Managed Console Random Number
189 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
190 iter);
191 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
192
193 // Session Privilege Level
194 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
195 sizeof(sessPrivLevel), iter);
196 std::advance(iter, sizeof(sessPrivLevel));
197
198 // User Name Length Byte
199 std::copy_n(&userLength, sizeof(userLength), iter);
200
201 // Generate Session Integrity Key
202 auto sikOutput = authAlgo->generateHMAC(input);
203
204 // Update the SIK in the Authentication Algo Interface
205 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
206 sikOutput.begin(), sikOutput.end());
207
208 /*
209 * Integrity Check Value
210 *
211 * 1) Remote Console Random Number - 16 bytes
212 * 2) Managed System Session ID - 4 bytes
213 * 3) Managed System GUID - 16 bytes
214 */
215
216 // Get Managed System Session ID
217 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
218
219 input.clear();
220
221 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
222 sizeof(bmcSessionID) + BMC_GUID_LEN);
223 iter = input.begin();
224
225 // Remote Console Random Number
226 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
227 iter);
228 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
229
230 // Managed System Session ID
231 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
232 iter);
233 std::advance(iter, sizeof(bmcSessionID));
234
235 // Managed System GUID
236 auto guid = getSystemGUID();
237 std::copy_n(guid.data(), guid.size(), iter);
238
239 // Integrity Check Value
240 auto icv = authAlgo->generateICV(input);
241
242 outPayload.resize(sizeof(RAKP4response));
243
244 response->messageTag = request->messageTag;
245 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
246 response->reserved = 0;
247 response->remoteConsoleSessionID = rcSessionID;
248
249 // Insert the HMAC output into the payload
250 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
251
Tom Josephef02fb32017-01-19 12:55:11 +0530252 // Set the Integrity Algorithm
253 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530254
Tom Joseph4c766eb2017-01-24 18:24:57 +0530255 // Set the Confidentiality Algorithm
256 applyCryptAlgo(session->getBMCSessionID());
257
Tom Joseph50fb50a2016-12-06 17:51:06 +0530258 session->state = session::State::ACTIVE;
259
260 std::cout << "<< RAKP34\n";
261 return outPayload;
262}
263
264} // namespace command