blob: 59707d0da069612a11c82439be9820d61441408a [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
Vernon Mauery9e801a22018-10-12 13:20:49 -07009#include <algorithm>
10#include <cstring>
Vernon Maueryfc37e592018-12-19 14:55:15 -080011#include <phosphor-logging/log.hpp>
12
13using namespace phosphor::logging;
Vernon Mauery9e801a22018-10-12 13:20:49 -070014
Tom Joseph50fb50a2016-12-06 17:51:06 +053015namespace command
16{
17
Tom Josephef02fb32017-01-19 12:55:11 +053018void applyIntegrityAlgo(const uint32_t bmcSessionID)
19{
Vernon Mauery2085ae02021-06-10 11:51:00 -070020 auto session = session::Manager::get().getSession(bmcSessionID);
Tom Josephef02fb32017-01-19 12:55:11 +053021
22 auto authAlgo = session->getAuthAlgo();
23
24 switch (authAlgo->intAlgo)
25 {
26 case cipher::integrity::Algorithms::HMAC_SHA1_96:
27 {
28 session->setIntegrityAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070029 std::make_unique<cipher::integrity::AlgoSHA1>(
30 authAlgo->sessionIntegrityKey));
Tom Josephef02fb32017-01-19 12:55:11 +053031 break;
32 }
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080033 case cipher::integrity::Algorithms::HMAC_SHA256_128:
34 {
35 session->setIntegrityAlgo(
36 std::make_unique<cipher::integrity::AlgoSHA256>(
Vernon Mauery9e801a22018-10-12 13:20:49 -070037 authAlgo->sessionIntegrityKey));
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080038 break;
39 }
Tom Josephef02fb32017-01-19 12:55:11 +053040 default:
41 break;
42 }
43}
44
Tom Joseph4c766eb2017-01-24 18:24:57 +053045void applyCryptAlgo(const uint32_t bmcSessionID)
46{
Vernon Mauery2085ae02021-06-10 11:51:00 -070047 auto session = session::Manager::get().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,
Vernon Mauery41ff9b52021-06-11 11:37:40 -070068 std::shared_ptr<message::Handler>& handler)
Tom Joseph50fb50a2016-12-06 17:51:06 +053069{
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 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080078 log<level::INFO>("RAKP34: Invalid RAKP3 request");
Tom Joseph50fb50a2016-12-06 17:51:06 +053079 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) ==
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053086 session::sessionZero)
Tom Joseph50fb50a2016-12-06 17:51:06 +053087 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080088 log<level::INFO>("RAKP34: BMC invalid Session ID");
Tom Joseph50fb50a2016-12-06 17:51:06 +053089 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 =
Vernon Mauery2085ae02021-06-10 11:51:00 -070098 session::Manager::get().getSession(request->managedSystemSessionID);
Tom Joseph50fb50a2016-12-06 17:51:06 +053099 }
100 catch (std::exception& e)
101 {
Vernon Maueryfc37e592018-12-19 14:55:15 -0800102 log<level::ERR>("RAKP12 : session not found",
103 entry("EXCEPTION=%s", e.what()));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530104 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
Tom Joseph4021b1f2019-02-12 10:10:12 +0530126 auto sessPrivLevel = static_cast<uint8_t>(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 {
Vernon Maueryfc37e592018-12-19 14:55:15 -0800165 log<level::INFO>("Mismatch in HMAC sent by remote console");
Tom Joseph50fb50a2016-12-06 17:51:06 +0530166
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
Vernon Mauery2085ae02021-06-10 11:51:00 -0700174 session::Manager::get().stopSession(session->getBMCSessionID());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530175
176 return outPayload;
177 }
178
179 /*
180 * Session Integrity Key
181 *
182 * 1) Remote Console Random Number - 16 bytes
183 * 2) Managed System Random Number - 16 bytes
184 * 3) Session Privilege Level - 1 byte
185 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
186 * 5) User Name - variable (absent for 'null' username)
187 */
188
189 input.clear();
190
191 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
192 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
Tom Joseph56527b92018-03-21 19:31:58 +0530193 sizeof(sessPrivLevel) + sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530194 iter = input.begin();
195
196 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700197 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530198 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
199
200 // Managed Console Random Number
201 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
202 iter);
203 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
204
205 // Session Privilege Level
206 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
207 sizeof(sessPrivLevel), iter);
208 std::advance(iter, sizeof(sessPrivLevel));
209
210 // User Name Length Byte
211 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530212 std::advance(iter, sizeof(userLength));
213
214 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530215
216 // Generate Session Integrity Key
217 auto sikOutput = authAlgo->generateHMAC(input);
218
219 // Update the SIK in the Authentication Algo Interface
220 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
221 sikOutput.begin(), sikOutput.end());
222
223 /*
224 * Integrity Check Value
225 *
226 * 1) Remote Console Random Number - 16 bytes
227 * 2) Managed System Session ID - 4 bytes
228 * 3) Managed System GUID - 16 bytes
229 */
230
231 // Get Managed System Session ID
232 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
233
234 input.clear();
235
236 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
237 sizeof(bmcSessionID) + BMC_GUID_LEN);
238 iter = input.begin();
239
240 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700241 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530242 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
243
244 // Managed System Session ID
245 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
246 iter);
247 std::advance(iter, sizeof(bmcSessionID));
248
249 // Managed System GUID
Tom Joseph83029cb2017-09-01 16:37:31 +0530250 std::copy_n(cache::guid.data(), cache::guid.size(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530251
252 // Integrity Check Value
253 auto icv = authAlgo->generateICV(input);
254
255 outPayload.resize(sizeof(RAKP4response));
256
257 response->messageTag = request->messageTag;
258 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
259 response->reserved = 0;
260 response->remoteConsoleSessionID = rcSessionID;
261
262 // Insert the HMAC output into the payload
263 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
264
Tom Josephef02fb32017-01-19 12:55:11 +0530265 // Set the Integrity Algorithm
266 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530267
Tom Joseph4c766eb2017-01-24 18:24:57 +0530268 // Set the Confidentiality Algorithm
269 applyCryptAlgo(session->getBMCSessionID());
270
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530271 session->state(static_cast<uint8_t>(session::State::active));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530272 return outPayload;
273}
274
275} // namespace command