blob: 71b1e524d63f219d6ca2ed21cbf734bab376f7aa [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 }
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>(
36 authAlgo->sessionIntegrityKey));
37 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{
46 auto session = (std::get<session::Manager&>(singletonPool).getSession(
47 bmcSessionID)).lock();
48
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();
56 auto k2 = intAlgo->generateKn(
57 authAlgo->sessionIntegrityKey, rmcp::const_2);
58 session->setCryptAlgo(
59 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
85 if(endian::from_ipmi(request->managedSystemSessionID) ==
86 session::SESSION_ZERO)
87 {
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 {
97 session = (std::get<session::Manager&>(singletonPool).getSession(
98 endian::from_ipmi(request->managedSystemSessionID))).lock();
99 }
100 catch (std::exception& e)
101 {
102 std::cerr << e.what() << "\n";
103 response->rmcpStatusCode =
104 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
105 return outPayload;
106 }
107
108 session->updateLastTransactionTime();
109
110 auto authAlgo = session->getAuthAlgo();
111 /*
112 * Key Authentication Code - RAKP 3
113 *
114 * 1) Managed System Random Number - 16 bytes
115 * 2) Remote Console Session ID - 4 bytes
116 * 3) Session Privilege Level - 1 byte
117 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
118 * 5) User Name - variable (absent for 'null' username)
119 */
120
121 // Remote Console Session ID
122 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
123
124 // Session Privilege Level
125 auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
126
127 // User Name Length Byte
128 uint8_t userLength = 0;
129
130 std::vector<uint8_t> input;
131 input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
132 sizeof(rcSessionID) + sizeof(sessPrivLevel) +
133 sizeof(userLength));
134
135 auto iter = input.begin();
136
137 // Managed System Random Number
138 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
139 iter);
140 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
141
142 // Remote Console Session ID
143 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
144 iter);
145 std::advance(iter, sizeof(rcSessionID));
146
147 // Session Privilege Level
148 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
149 sizeof(sessPrivLevel), iter);
150 std::advance(iter, sizeof(sessPrivLevel));
151
152 // User Name Length Byte
153 std::copy_n(&userLength, sizeof(userLength), iter);
154
155 // Generate Key Exchange Authentication Code - RAKP2
156 auto output = authAlgo->generateHMAC(input);
157
Vernon Mauery9b307be2017-11-22 09:28:16 -0800158 if (inPayload.size() != (sizeof(RAKP3request) + output.size()) ||
159 std::memcmp(output.data(), request+1, output.size()))
Tom Joseph50fb50a2016-12-06 17:51:06 +0530160 {
161 std::cerr << "Mismatch in HMAC sent by remote console\n";
162
163 response->messageTag = request->messageTag;
164 response->rmcpStatusCode = static_cast<uint8_t>
165 (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
166 response->reserved = 0;
167 response->remoteConsoleSessionID = rcSessionID;
168
169 //close the session
170 std::get<session::Manager&>(singletonPool).stopSession(
171 session->getBMCSessionID());
172
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 +
190 sizeof(sessPrivLevel) + sizeof(userLength));
191 iter = input.begin();
192
193 // Remote Console Random Number
194 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
195 iter);
196 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
197
198 // Managed Console Random Number
199 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
200 iter);
201 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
202
203 // Session Privilege Level
204 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
205 sizeof(sessPrivLevel), iter);
206 std::advance(iter, sizeof(sessPrivLevel));
207
208 // User Name Length Byte
209 std::copy_n(&userLength, sizeof(userLength), iter);
210
211 // Generate Session Integrity Key
212 auto sikOutput = authAlgo->generateHMAC(input);
213
214 // Update the SIK in the Authentication Algo Interface
215 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
216 sikOutput.begin(), sikOutput.end());
217
218 /*
219 * Integrity Check Value
220 *
221 * 1) Remote Console Random Number - 16 bytes
222 * 2) Managed System Session ID - 4 bytes
223 * 3) Managed System GUID - 16 bytes
224 */
225
226 // Get Managed System Session ID
227 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
228
229 input.clear();
230
231 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
232 sizeof(bmcSessionID) + BMC_GUID_LEN);
233 iter = input.begin();
234
235 // Remote Console Random Number
236 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
237 iter);
238 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
239
240 // Managed System Session ID
241 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
242 iter);
243 std::advance(iter, sizeof(bmcSessionID));
244
245 // Managed System GUID
Tom Joseph83029cb2017-09-01 16:37:31 +0530246 std::copy_n(cache::guid.data(), cache::guid.size(), iter);
Tom Joseph50fb50a2016-12-06 17:51:06 +0530247
248 // Integrity Check Value
249 auto icv = authAlgo->generateICV(input);
250
251 outPayload.resize(sizeof(RAKP4response));
252
253 response->messageTag = request->messageTag;
254 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
255 response->reserved = 0;
256 response->remoteConsoleSessionID = rcSessionID;
257
258 // Insert the HMAC output into the payload
259 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
260
Tom Josephef02fb32017-01-19 12:55:11 +0530261 // Set the Integrity Algorithm
262 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530263
Tom Joseph4c766eb2017-01-24 18:24:57 +0530264 // Set the Confidentiality Algorithm
265 applyCryptAlgo(session->getBMCSessionID());
266
Tom Joseph50fb50a2016-12-06 17:51:06 +0530267 session->state = session::State::ACTIVE;
Tom Joseph50fb50a2016-12-06 17:51:06 +0530268 return outPayload;
269}
270
271} // namespace command