blob: f14430e6cc285930131fd36bc9d408363b125152 [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"
Vernon Mauery9b307be2017-11-22 09:28:16 -08006#include "rmcp.hpp"
Vernon Mauery2085ae02021-06-10 11:51:00 -07007#include "sessions_manager.hpp"
Tom Joseph50fb50a2016-12-06 17:51:06 +05308
George Liu7b7f25f2022-07-04 17:07:32 +08009#include <phosphor-logging/lg2.hpp>
George Liubc8958f2022-07-04 09:29:49 +080010
Vernon Mauery9e801a22018-10-12 13:20:49 -070011#include <algorithm>
12#include <cstring>
Vernon Maueryfc37e592018-12-19 14:55:15 -080013
Tom Joseph50fb50a2016-12-06 17:51:06 +053014namespace command
15{
16
Tom Josephef02fb32017-01-19 12:55:11 +053017void applyIntegrityAlgo(const uint32_t bmcSessionID)
18{
Vernon Mauery2085ae02021-06-10 11:51:00 -070019 auto session = session::Manager::get().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 Mauery2085ae02021-06-10 11:51:00 -070046 auto session = session::Manager::get().getSession(bmcSessionID);
Tom Joseph4c766eb2017-01-24 18:24:57 +053047
48 auto authAlgo = session->getAuthAlgo();
49
50 switch (authAlgo->cryptAlgo)
51 {
52 case cipher::crypt::Algorithms::AES_CBC_128:
53 {
Vernon Mauery9b307be2017-11-22 09:28:16 -080054 auto intAlgo = session->getIntegrityAlgo();
Vernon Mauery9e801a22018-10-12 13:20:49 -070055 auto k2 = intAlgo->generateKn(authAlgo->sessionIntegrityKey,
56 rmcp::const_2);
Vernon Mauery9b307be2017-11-22 09:28:16 -080057 session->setCryptAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070058 std::make_unique<cipher::crypt::AlgoAES128>(k2));
Tom Joseph4c766eb2017-01-24 18:24:57 +053059 break;
60 }
61 default:
62 break;
63 }
64}
65
Tom Joseph18a45e92017-04-11 11:30:44 +053066std::vector<uint8_t> RAKP34(const std::vector<uint8_t>& inPayload,
George Liube1470c2022-07-04 14:33:24 +080067 std::shared_ptr<message::Handler>& /* handler */)
Tom Joseph50fb50a2016-12-06 17:51:06 +053068{
Tom Joseph50fb50a2016-12-06 17:51:06 +053069 std::vector<uint8_t> outPayload(sizeof(RAKP4response));
Tom Joseph18a45e92017-04-11 11:30:44 +053070 auto request = reinterpret_cast<const RAKP3request*>(inPayload.data());
Tom Joseph50fb50a2016-12-06 17:51:06 +053071 auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
72
73 // Check if the RAKP3 Payload Length is as expected
Vernon Mauery9b307be2017-11-22 09:28:16 -080074 if (inPayload.size() < sizeof(RAKP3request))
Tom Joseph50fb50a2016-12-06 17:51:06 +053075 {
George Liu7b7f25f2022-07-04 17:07:32 +080076 lg2::info("RAKP34: Invalid RAKP3 request");
Tom Joseph50fb50a2016-12-06 17:51:06 +053077 response->rmcpStatusCode =
78 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
79 return outPayload;
80 }
81
82 // Session ID zero is reserved for Session Setup
Vernon Mauery9e801a22018-10-12 13:20:49 -070083 if (endian::from_ipmi(request->managedSystemSessionID) ==
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053084 session::sessionZero)
Tom Joseph50fb50a2016-12-06 17:51:06 +053085 {
George Liu7b7f25f2022-07-04 17:07:32 +080086 lg2::info("RAKP34: BMC invalid Session ID");
Tom Joseph50fb50a2016-12-06 17:51:06 +053087 response->rmcpStatusCode =
88 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
89 return outPayload;
90 }
91
92 std::shared_ptr<session::Session> session;
93 try
94 {
Vernon Maueryae1fda42018-10-15 12:55:34 -070095 session =
Vernon Mauery2085ae02021-06-10 11:51:00 -070096 session::Manager::get().getSession(request->managedSystemSessionID);
Tom Joseph50fb50a2016-12-06 17:51:06 +053097 }
Patrick Williams12d199b2021-10-06 12:36:48 -050098 catch (const std::exception& e)
Tom Joseph50fb50a2016-12-06 17:51:06 +053099 {
George Liu7b7f25f2022-07-04 17:07:32 +0800100 lg2::error("RAKP12 : session not found: {ERROR}", "ERROR", e);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530101 response->rmcpStatusCode =
102 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
103 return outPayload;
104 }
105
106 session->updateLastTransactionTime();
107
108 auto authAlgo = session->getAuthAlgo();
109 /*
110 * Key Authentication Code - RAKP 3
111 *
112 * 1) Managed System Random Number - 16 bytes
113 * 2) Remote Console Session ID - 4 bytes
114 * 3) Session Privilege Level - 1 byte
115 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
116 * 5) User Name - variable (absent for 'null' username)
117 */
118
119 // Remote Console Session ID
120 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
121
122 // Session Privilege Level
Tom Joseph4021b1f2019-02-12 10:10:12 +0530123 auto sessPrivLevel = static_cast<uint8_t>(session->reqMaxPrivLevel);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530124
125 // User Name Length Byte
Tom Joseph56527b92018-03-21 19:31:58 +0530126 auto userLength = static_cast<uint8_t>(session->userName.size());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530127
128 std::vector<uint8_t> input;
129 input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
130 sizeof(rcSessionID) + sizeof(sessPrivLevel) +
Tom Joseph56527b92018-03-21 19:31:58 +0530131 sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530132
133 auto iter = input.begin();
134
135 // Managed System Random Number
136 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
137 iter);
138 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
139
140 // Remote Console Session ID
141 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
142 iter);
143 std::advance(iter, sizeof(rcSessionID));
144
145 // Session Privilege Level
146 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
147 sizeof(sessPrivLevel), iter);
148 std::advance(iter, sizeof(sessPrivLevel));
149
150 // User Name Length Byte
151 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530152 std::advance(iter, sizeof(userLength));
153
154 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530155
156 // Generate Key Exchange Authentication Code - RAKP2
157 auto output = authAlgo->generateHMAC(input);
158
Vernon Mauery9b307be2017-11-22 09:28:16 -0800159 if (inPayload.size() != (sizeof(RAKP3request) + output.size()) ||
Vernon Mauery9e801a22018-10-12 13:20:49 -0700160 std::memcmp(output.data(), request + 1, output.size()))
Tom Joseph50fb50a2016-12-06 17:51:06 +0530161 {
George Liu7b7f25f2022-07-04 17:07:32 +0800162 lg2::info("Mismatch in HMAC sent by remote console");
Tom Joseph50fb50a2016-12-06 17:51:06 +0530163
164 response->messageTag = request->messageTag;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700165 response->rmcpStatusCode =
166 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530167 response->reserved = 0;
168 response->remoteConsoleSessionID = rcSessionID;
169
Vernon Mauery9e801a22018-10-12 13:20:49 -0700170 // close the session
Vernon Mauery2085ae02021-06-10 11:51:00 -0700171 session::Manager::get().stopSession(session->getBMCSessionID());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530172
173 return outPayload;
174 }
175
176 /*
177 * Session Integrity Key
178 *
179 * 1) Remote Console Random Number - 16 bytes
180 * 2) Managed System Random Number - 16 bytes
181 * 3) Session Privilege Level - 1 byte
182 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
183 * 5) User Name - variable (absent for 'null' username)
184 */
185
186 input.clear();
187
188 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
189 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
Tom Joseph56527b92018-03-21 19:31:58 +0530190 sizeof(sessPrivLevel) + sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530191 iter = input.begin();
192
193 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700194 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530195 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
196
197 // Managed Console Random Number
198 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
199 iter);
200 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
201
202 // Session Privilege Level
203 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
204 sizeof(sessPrivLevel), iter);
205 std::advance(iter, sizeof(sessPrivLevel));
206
207 // User Name Length Byte
208 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530209 std::advance(iter, sizeof(userLength));
210
211 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530212
213 // Generate Session Integrity Key
214 auto sikOutput = authAlgo->generateHMAC(input);
215
216 // Update the SIK in the Authentication Algo Interface
217 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
218 sikOutput.begin(), sikOutput.end());
219
220 /*
221 * Integrity Check Value
222 *
223 * 1) Remote Console Random Number - 16 bytes
224 * 2) Managed System Session ID - 4 bytes
225 * 3) Managed System GUID - 16 bytes
226 */
227
228 // Get Managed System Session ID
229 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
230
231 input.clear();
232
233 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
234 sizeof(bmcSessionID) + BMC_GUID_LEN);
235 iter = input.begin();
236
237 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700238 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530239 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
240
241 // Managed System Session ID
242 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
243 iter);
244 std::advance(iter, sizeof(bmcSessionID));
245
246 // Managed System GUID
Tom Joseph83029cb2017-09-01 16:37:31 +0530247 std::copy_n(cache::guid.data(), cache::guid.size(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530248
249 // Integrity Check Value
250 auto icv = authAlgo->generateICV(input);
251
252 outPayload.resize(sizeof(RAKP4response));
253
254 response->messageTag = request->messageTag;
255 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
256 response->reserved = 0;
257 response->remoteConsoleSessionID = rcSessionID;
258
259 // Insert the HMAC output into the payload
260 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
261
Tom Josephef02fb32017-01-19 12:55:11 +0530262 // Set the Integrity Algorithm
263 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530264
Tom Joseph4c766eb2017-01-24 18:24:57 +0530265 // Set the Confidentiality Algorithm
266 applyCryptAlgo(session->getBMCSessionID());
267
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530268 session->state(static_cast<uint8_t>(session::State::active));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530269 return outPayload;
270}
271
272} // namespace command