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