blob: a89e75010b1b6c7b130d9e178c149a10ae732835 [file] [log] [blame]
Tom Joseph50fb50a2016-12-06 17:51:06 +05301#include "rakp34.hpp"
2
Tom Joseph50fb50a2016-12-06 17:51:06 +05303#include "comm_module.hpp"
4#include "endian.hpp"
5#include "guid.hpp"
6#include "main.hpp"
Vernon Mauery9b307be2017-11-22 09:28:16 -08007#include "rmcp.hpp"
Tom Joseph50fb50a2016-12-06 17:51:06 +05308
Vernon Mauery9e801a22018-10-12 13:20:49 -07009#include <algorithm>
10#include <cstring>
11#include <iostream>
12
Tom Joseph50fb50a2016-12-06 17:51:06 +053013namespace command
14{
15
Tom Josephef02fb32017-01-19 12:55:11 +053016void applyIntegrityAlgo(const uint32_t bmcSessionID)
17{
Vernon Mauery9e801a22018-10-12 13:20:49 -070018 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -070019 std::get<session::Manager&>(singletonPool).getSession(bmcSessionID);
Tom Josephef02fb32017-01-19 12:55:11 +053020
21 auto authAlgo = session->getAuthAlgo();
22
23 switch (authAlgo->intAlgo)
24 {
25 case cipher::integrity::Algorithms::HMAC_SHA1_96:
26 {
27 session->setIntegrityAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070028 std::make_unique<cipher::integrity::AlgoSHA1>(
29 authAlgo->sessionIntegrityKey));
Tom Josephef02fb32017-01-19 12:55:11 +053030 break;
31 }
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080032 case cipher::integrity::Algorithms::HMAC_SHA256_128:
33 {
34 session->setIntegrityAlgo(
35 std::make_unique<cipher::integrity::AlgoSHA256>(
Vernon Mauery9e801a22018-10-12 13:20:49 -070036 authAlgo->sessionIntegrityKey));
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080037 break;
38 }
Tom Josephef02fb32017-01-19 12:55:11 +053039 default:
40 break;
41 }
42}
43
Tom Joseph4c766eb2017-01-24 18:24:57 +053044void applyCryptAlgo(const uint32_t bmcSessionID)
45{
Vernon Mauery9e801a22018-10-12 13:20:49 -070046 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -070047 std::get<session::Manager&>(singletonPool).getSession(bmcSessionID);
Tom Joseph4c766eb2017-01-24 18:24:57 +053048
49 auto authAlgo = session->getAuthAlgo();
50
51 switch (authAlgo->cryptAlgo)
52 {
53 case cipher::crypt::Algorithms::AES_CBC_128:
54 {
Vernon Mauery9b307be2017-11-22 09:28:16 -080055 auto intAlgo = session->getIntegrityAlgo();
Vernon Mauery9e801a22018-10-12 13:20:49 -070056 auto k2 = intAlgo->generateKn(authAlgo->sessionIntegrityKey,
57 rmcp::const_2);
Vernon Mauery9b307be2017-11-22 09:28:16 -080058 session->setCryptAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070059 std::make_unique<cipher::crypt::AlgoAES128>(k2));
Tom Joseph4c766eb2017-01-24 18:24:57 +053060 break;
61 }
62 default:
63 break;
64 }
65}
66
Tom Joseph18a45e92017-04-11 11:30:44 +053067std::vector<uint8_t> RAKP34(const std::vector<uint8_t>& inPayload,
Tom Joseph50fb50a2016-12-06 17:51:06 +053068 const message::Handler& handler)
69{
Tom Joseph50fb50a2016-12-06 17:51:06 +053070
71 std::vector<uint8_t> outPayload(sizeof(RAKP4response));
Tom Joseph18a45e92017-04-11 11:30:44 +053072 auto request = reinterpret_cast<const RAKP3request*>(inPayload.data());
Tom Joseph50fb50a2016-12-06 17:51:06 +053073 auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
74
75 // Check if the RAKP3 Payload Length is as expected
Vernon Mauery9b307be2017-11-22 09:28:16 -080076 if (inPayload.size() < sizeof(RAKP3request))
Tom Joseph50fb50a2016-12-06 17:51:06 +053077 {
78 std::cerr << "RAKP34: Invalid RAKP3 request\n";
79 response->rmcpStatusCode =
80 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
81 return outPayload;
82 }
83
84 // Session ID zero is reserved for Session Setup
Vernon Mauery9e801a22018-10-12 13:20:49 -070085 if (endian::from_ipmi(request->managedSystemSessionID) ==
86 session::SESSION_ZERO)
Tom Joseph50fb50a2016-12-06 17:51:06 +053087 {
88 std::cerr << "RAKP34: BMC invalid Session ID\n";
89 response->rmcpStatusCode =
90 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
91 return outPayload;
92 }
93
94 std::shared_ptr<session::Session> session;
95 try
96 {
Vernon Maueryae1fda42018-10-15 12:55:34 -070097 session =
98 std::get<session::Manager&>(singletonPool)
99 .getSession(endian::from_ipmi(request->managedSystemSessionID));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530100 }
101 catch (std::exception& e)
102 {
103 std::cerr << e.what() << "\n";
104 response->rmcpStatusCode =
105 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
106 return outPayload;
107 }
108
109 session->updateLastTransactionTime();
110
111 auto authAlgo = session->getAuthAlgo();
112 /*
113 * Key Authentication Code - RAKP 3
114 *
115 * 1) Managed System Random Number - 16 bytes
116 * 2) Remote Console Session ID - 4 bytes
117 * 3) Session Privilege Level - 1 byte
118 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
119 * 5) User Name - variable (absent for 'null' username)
120 */
121
122 // Remote Console Session ID
123 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
124
125 // Session Privilege Level
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +0530126 auto sessPrivLevel = session->reqMaxPrivLevel;
Tom Joseph50fb50a2016-12-06 17:51:06 +0530127
128 // User Name Length Byte
Tom Joseph56527b92018-03-21 19:31:58 +0530129 auto userLength = static_cast<uint8_t>(session->userName.size());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530130
131 std::vector<uint8_t> input;
132 input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
133 sizeof(rcSessionID) + sizeof(sessPrivLevel) +
Tom Joseph56527b92018-03-21 19:31:58 +0530134 sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530135
136 auto iter = input.begin();
137
138 // Managed System Random Number
139 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
140 iter);
141 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
142
143 // Remote Console Session ID
144 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
145 iter);
146 std::advance(iter, sizeof(rcSessionID));
147
148 // Session Privilege Level
149 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
150 sizeof(sessPrivLevel), iter);
151 std::advance(iter, sizeof(sessPrivLevel));
152
153 // User Name Length Byte
154 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530155 std::advance(iter, sizeof(userLength));
156
157 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530158
159 // Generate Key Exchange Authentication Code - RAKP2
160 auto output = authAlgo->generateHMAC(input);
161
Vernon Mauery9b307be2017-11-22 09:28:16 -0800162 if (inPayload.size() != (sizeof(RAKP3request) + output.size()) ||
Vernon Mauery9e801a22018-10-12 13:20:49 -0700163 std::memcmp(output.data(), request + 1, output.size()))
Tom Joseph50fb50a2016-12-06 17:51:06 +0530164 {
165 std::cerr << "Mismatch in HMAC sent by remote console\n";
166
167 response->messageTag = request->messageTag;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700168 response->rmcpStatusCode =
169 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530170 response->reserved = 0;
171 response->remoteConsoleSessionID = rcSessionID;
172
Vernon Mauery9e801a22018-10-12 13:20:49 -0700173 // close the session
174 std::get<session::Manager&>(singletonPool)
175 .stopSession(session->getBMCSessionID());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530176
177 return outPayload;
178 }
179
180 /*
181 * Session Integrity Key
182 *
183 * 1) Remote Console Random Number - 16 bytes
184 * 2) Managed System Random Number - 16 bytes
185 * 3) Session Privilege Level - 1 byte
186 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
187 * 5) User Name - variable (absent for 'null' username)
188 */
189
190 input.clear();
191
192 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
193 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
Tom Joseph56527b92018-03-21 19:31:58 +0530194 sizeof(sessPrivLevel) + sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530195 iter = input.begin();
196
197 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700198 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530199 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
200
201 // Managed Console Random Number
202 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
203 iter);
204 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
205
206 // Session Privilege Level
207 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
208 sizeof(sessPrivLevel), iter);
209 std::advance(iter, sizeof(sessPrivLevel));
210
211 // User Name Length Byte
212 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530213 std::advance(iter, sizeof(userLength));
214
215 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530216
217 // Generate Session Integrity Key
218 auto sikOutput = authAlgo->generateHMAC(input);
219
220 // Update the SIK in the Authentication Algo Interface
221 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
222 sikOutput.begin(), sikOutput.end());
223
224 /*
225 * Integrity Check Value
226 *
227 * 1) Remote Console Random Number - 16 bytes
228 * 2) Managed System Session ID - 4 bytes
229 * 3) Managed System GUID - 16 bytes
230 */
231
232 // Get Managed System Session ID
233 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
234
235 input.clear();
236
237 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
238 sizeof(bmcSessionID) + BMC_GUID_LEN);
239 iter = input.begin();
240
241 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700242 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530243 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
244
245 // Managed System Session ID
246 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
247 iter);
248 std::advance(iter, sizeof(bmcSessionID));
249
250 // Managed System GUID
Tom Joseph83029cb2017-09-01 16:37:31 +0530251 std::copy_n(cache::guid.data(), cache::guid.size(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530252
253 // Integrity Check Value
254 auto icv = authAlgo->generateICV(input);
255
256 outPayload.resize(sizeof(RAKP4response));
257
258 response->messageTag = request->messageTag;
259 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
260 response->reserved = 0;
261 response->remoteConsoleSessionID = rcSessionID;
262
263 // Insert the HMAC output into the payload
264 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
265
Tom Josephef02fb32017-01-19 12:55:11 +0530266 // Set the Integrity Algorithm
267 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530268
Tom Joseph4c766eb2017-01-24 18:24:57 +0530269 // Set the Confidentiality Algorithm
270 applyCryptAlgo(session->getBMCSessionID());
271
Tom Joseph50fb50a2016-12-06 17:51:06 +0530272 session->state = session::State::ACTIVE;
Tom Joseph50fb50a2016-12-06 17:51:06 +0530273 return outPayload;
274}
275
276} // namespace command