blob: b106b6f97a0995b449677f40d00145cf6ff1b07b [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>
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 Mauery9e801a22018-10-12 13:20:49 -070020 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -070021 std::get<session::Manager&>(singletonPool).getSession(bmcSessionID);
Tom Josephef02fb32017-01-19 12:55:11 +053022
23 auto authAlgo = session->getAuthAlgo();
24
25 switch (authAlgo->intAlgo)
26 {
27 case cipher::integrity::Algorithms::HMAC_SHA1_96:
28 {
29 session->setIntegrityAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070030 std::make_unique<cipher::integrity::AlgoSHA1>(
31 authAlgo->sessionIntegrityKey));
Tom Josephef02fb32017-01-19 12:55:11 +053032 break;
33 }
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080034 case cipher::integrity::Algorithms::HMAC_SHA256_128:
35 {
36 session->setIntegrityAlgo(
37 std::make_unique<cipher::integrity::AlgoSHA256>(
Vernon Mauery9e801a22018-10-12 13:20:49 -070038 authAlgo->sessionIntegrityKey));
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080039 break;
40 }
Tom Josephef02fb32017-01-19 12:55:11 +053041 default:
42 break;
43 }
44}
45
Tom Joseph4c766eb2017-01-24 18:24:57 +053046void applyCryptAlgo(const uint32_t bmcSessionID)
47{
Vernon Mauery9e801a22018-10-12 13:20:49 -070048 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -070049 std::get<session::Manager&>(singletonPool).getSession(bmcSessionID);
Tom Joseph4c766eb2017-01-24 18:24:57 +053050
51 auto authAlgo = session->getAuthAlgo();
52
53 switch (authAlgo->cryptAlgo)
54 {
55 case cipher::crypt::Algorithms::AES_CBC_128:
56 {
Vernon Mauery9b307be2017-11-22 09:28:16 -080057 auto intAlgo = session->getIntegrityAlgo();
Vernon Mauery9e801a22018-10-12 13:20:49 -070058 auto k2 = intAlgo->generateKn(authAlgo->sessionIntegrityKey,
59 rmcp::const_2);
Vernon Mauery9b307be2017-11-22 09:28:16 -080060 session->setCryptAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070061 std::make_unique<cipher::crypt::AlgoAES128>(k2));
Tom Joseph4c766eb2017-01-24 18:24:57 +053062 break;
63 }
64 default:
65 break;
66 }
67}
68
Tom Joseph18a45e92017-04-11 11:30:44 +053069std::vector<uint8_t> RAKP34(const std::vector<uint8_t>& inPayload,
Tom Joseph50fb50a2016-12-06 17:51:06 +053070 const message::Handler& handler)
71{
Tom Joseph50fb50a2016-12-06 17:51:06 +053072
73 std::vector<uint8_t> outPayload(sizeof(RAKP4response));
Tom Joseph18a45e92017-04-11 11:30:44 +053074 auto request = reinterpret_cast<const RAKP3request*>(inPayload.data());
Tom Joseph50fb50a2016-12-06 17:51:06 +053075 auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
76
77 // Check if the RAKP3 Payload Length is as expected
Vernon Mauery9b307be2017-11-22 09:28:16 -080078 if (inPayload.size() < sizeof(RAKP3request))
Tom Joseph50fb50a2016-12-06 17:51:06 +053079 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080080 log<level::INFO>("RAKP34: Invalid RAKP3 request");
Tom Joseph50fb50a2016-12-06 17:51:06 +053081 response->rmcpStatusCode =
82 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
83 return outPayload;
84 }
85
86 // Session ID zero is reserved for Session Setup
Vernon Mauery9e801a22018-10-12 13:20:49 -070087 if (endian::from_ipmi(request->managedSystemSessionID) ==
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053088 session::sessionZero)
Tom Joseph50fb50a2016-12-06 17:51:06 +053089 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080090 log<level::INFO>("RAKP34: BMC invalid Session ID");
Tom Joseph50fb50a2016-12-06 17:51:06 +053091 response->rmcpStatusCode =
92 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
93 return outPayload;
94 }
95
96 std::shared_ptr<session::Session> session;
97 try
98 {
Vernon Maueryae1fda42018-10-15 12:55:34 -070099 session =
100 std::get<session::Manager&>(singletonPool)
101 .getSession(endian::from_ipmi(request->managedSystemSessionID));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530102 }
103 catch (std::exception& e)
104 {
Vernon Maueryfc37e592018-12-19 14:55:15 -0800105 log<level::ERR>("RAKP12 : session not found",
106 entry("EXCEPTION=%s", e.what()));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530107 response->rmcpStatusCode =
108 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
109 return outPayload;
110 }
111
112 session->updateLastTransactionTime();
113
114 auto authAlgo = session->getAuthAlgo();
115 /*
116 * Key Authentication Code - RAKP 3
117 *
118 * 1) Managed System Random Number - 16 bytes
119 * 2) Remote Console Session ID - 4 bytes
120 * 3) Session Privilege Level - 1 byte
121 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
122 * 5) User Name - variable (absent for 'null' username)
123 */
124
125 // Remote Console Session ID
126 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
127
128 // Session Privilege Level
Tom Joseph4021b1f2019-02-12 10:10:12 +0530129 auto sessPrivLevel = static_cast<uint8_t>(session->reqMaxPrivLevel);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530130
131 // User Name Length Byte
Tom Joseph56527b92018-03-21 19:31:58 +0530132 auto userLength = static_cast<uint8_t>(session->userName.size());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530133
134 std::vector<uint8_t> input;
135 input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
136 sizeof(rcSessionID) + sizeof(sessPrivLevel) +
Tom Joseph56527b92018-03-21 19:31:58 +0530137 sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530138
139 auto iter = input.begin();
140
141 // Managed System Random Number
142 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
143 iter);
144 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
145
146 // Remote Console Session ID
147 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
148 iter);
149 std::advance(iter, sizeof(rcSessionID));
150
151 // Session Privilege Level
152 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
153 sizeof(sessPrivLevel), iter);
154 std::advance(iter, sizeof(sessPrivLevel));
155
156 // User Name Length Byte
157 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530158 std::advance(iter, sizeof(userLength));
159
160 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530161
162 // Generate Key Exchange Authentication Code - RAKP2
163 auto output = authAlgo->generateHMAC(input);
164
Vernon Mauery9b307be2017-11-22 09:28:16 -0800165 if (inPayload.size() != (sizeof(RAKP3request) + output.size()) ||
Vernon Mauery9e801a22018-10-12 13:20:49 -0700166 std::memcmp(output.data(), request + 1, output.size()))
Tom Joseph50fb50a2016-12-06 17:51:06 +0530167 {
Vernon Maueryfc37e592018-12-19 14:55:15 -0800168 log<level::INFO>("Mismatch in HMAC sent by remote console");
Tom Joseph50fb50a2016-12-06 17:51:06 +0530169
170 response->messageTag = request->messageTag;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700171 response->rmcpStatusCode =
172 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530173 response->reserved = 0;
174 response->remoteConsoleSessionID = rcSessionID;
175
Vernon Mauery9e801a22018-10-12 13:20:49 -0700176 // close the session
177 std::get<session::Manager&>(singletonPool)
178 .stopSession(session->getBMCSessionID());
Tom Joseph50fb50a2016-12-06 17:51:06 +0530179
180 return outPayload;
181 }
182
183 /*
184 * Session Integrity Key
185 *
186 * 1) Remote Console Random Number - 16 bytes
187 * 2) Managed System Random Number - 16 bytes
188 * 3) Session Privilege Level - 1 byte
189 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
190 * 5) User Name - variable (absent for 'null' username)
191 */
192
193 input.clear();
194
195 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
196 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
Tom Joseph56527b92018-03-21 19:31:58 +0530197 sizeof(sessPrivLevel) + sizeof(userLength) + userLength);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530198 iter = input.begin();
199
200 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700201 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530202 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
203
204 // Managed Console Random Number
205 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
206 iter);
207 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
208
209 // Session Privilege Level
210 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
211 sizeof(sessPrivLevel), iter);
212 std::advance(iter, sizeof(sessPrivLevel));
213
214 // User Name Length Byte
215 std::copy_n(&userLength, sizeof(userLength), iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530216 std::advance(iter, sizeof(userLength));
217
218 std::copy_n(session->userName.data(), userLength, iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530219
220 // Generate Session Integrity Key
221 auto sikOutput = authAlgo->generateHMAC(input);
222
223 // Update the SIK in the Authentication Algo Interface
224 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
225 sikOutput.begin(), sikOutput.end());
226
227 /*
228 * Integrity Check Value
229 *
230 * 1) Remote Console Random Number - 16 bytes
231 * 2) Managed System Session ID - 4 bytes
232 * 3) Managed System GUID - 16 bytes
233 */
234
235 // Get Managed System Session ID
236 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
237
238 input.clear();
239
240 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
241 sizeof(bmcSessionID) + BMC_GUID_LEN);
242 iter = input.begin();
243
244 // Remote Console Random Number
Vernon Mauery9e801a22018-10-12 13:20:49 -0700245 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530246 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
247
248 // Managed System Session ID
249 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
250 iter);
251 std::advance(iter, sizeof(bmcSessionID));
252
253 // Managed System GUID
Tom Joseph83029cb2017-09-01 16:37:31 +0530254 std::copy_n(cache::guid.data(), cache::guid.size(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530255
256 // Integrity Check Value
257 auto icv = authAlgo->generateICV(input);
258
259 outPayload.resize(sizeof(RAKP4response));
260
261 response->messageTag = request->messageTag;
262 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
263 response->reserved = 0;
264 response->remoteConsoleSessionID = rcSessionID;
265
266 // Insert the HMAC output into the payload
267 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
268
Tom Josephef02fb32017-01-19 12:55:11 +0530269 // Set the Integrity Algorithm
270 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530271
Tom Joseph4c766eb2017-01-24 18:24:57 +0530272 // Set the Confidentiality Algorithm
273 applyCryptAlgo(session->getBMCSessionID());
274
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530275 session->state(static_cast<uint8_t>(session::State::active));
Tom Joseph50fb50a2016-12-06 17:51:06 +0530276 return outPayload;
277}
278
279} // namespace command