blob: 398a1e759c8a4f7a7a96a5764600cdff80d4bd80 [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"
11
12namespace command
13{
14
Tom Josephef02fb32017-01-19 12:55:11 +053015void applyIntegrityAlgo(const uint32_t bmcSessionID)
16{
17 auto session = (std::get<session::Manager&>(singletonPool).getSession(
18 bmcSessionID)).lock();
19
20 auto authAlgo = session->getAuthAlgo();
21
22 switch (authAlgo->intAlgo)
23 {
24 case cipher::integrity::Algorithms::HMAC_SHA1_96:
25 {
26 session->setIntegrityAlgo(
27 std::make_unique<cipher::integrity::AlgoSHA1>(
28 authAlgo->sessionIntegrityKey));
29 break;
30 }
31 default:
32 break;
33 }
34}
35
Tom Joseph50fb50a2016-12-06 17:51:06 +053036std::vector<uint8_t> RAKP34(std::vector<uint8_t>& inPayload,
37 const message::Handler& handler)
38{
39 std::cout << ">> RAKP34\n";
40
41 std::vector<uint8_t> outPayload(sizeof(RAKP4response));
42 auto request = reinterpret_cast<RAKP3request*>(inPayload.data());
43 auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
44
45 // Check if the RAKP3 Payload Length is as expected
46 if(inPayload.size() != sizeof(RAKP3request))
47 {
48 std::cerr << "RAKP34: Invalid RAKP3 request\n";
49 response->rmcpStatusCode =
50 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
51 return outPayload;
52 }
53
54 // Session ID zero is reserved for Session Setup
55 if(endian::from_ipmi(request->managedSystemSessionID) ==
56 session::SESSION_ZERO)
57 {
58 std::cerr << "RAKP34: BMC invalid Session ID\n";
59 response->rmcpStatusCode =
60 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
61 return outPayload;
62 }
63
64 std::shared_ptr<session::Session> session;
65 try
66 {
67 session = (std::get<session::Manager&>(singletonPool).getSession(
68 endian::from_ipmi(request->managedSystemSessionID))).lock();
69 }
70 catch (std::exception& e)
71 {
72 std::cerr << e.what() << "\n";
73 response->rmcpStatusCode =
74 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
75 return outPayload;
76 }
77
78 session->updateLastTransactionTime();
79
80 auto authAlgo = session->getAuthAlgo();
81 /*
82 * Key Authentication Code - RAKP 3
83 *
84 * 1) Managed System Random Number - 16 bytes
85 * 2) Remote Console Session ID - 4 bytes
86 * 3) Session Privilege Level - 1 byte
87 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
88 * 5) User Name - variable (absent for 'null' username)
89 */
90
91 // Remote Console Session ID
92 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
93
94 // Session Privilege Level
95 auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
96
97 // User Name Length Byte
98 uint8_t userLength = 0;
99
100 std::vector<uint8_t> input;
101 input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
102 sizeof(rcSessionID) + sizeof(sessPrivLevel) +
103 sizeof(userLength));
104
105 auto iter = input.begin();
106
107 // Managed System Random Number
108 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
109 iter);
110 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
111
112 // Remote Console Session ID
113 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
114 iter);
115 std::advance(iter, sizeof(rcSessionID));
116
117 // Session Privilege Level
118 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
119 sizeof(sessPrivLevel), iter);
120 std::advance(iter, sizeof(sessPrivLevel));
121
122 // User Name Length Byte
123 std::copy_n(&userLength, sizeof(userLength), iter);
124
125 // Generate Key Exchange Authentication Code - RAKP2
126 auto output = authAlgo->generateHMAC(input);
127
128 if (std::memcmp(output.data(), request->keyExchangeAuthCode,
129 output.size()))
130 {
131 std::cerr << "Mismatch in HMAC sent by remote console\n";
132
133 response->messageTag = request->messageTag;
134 response->rmcpStatusCode = static_cast<uint8_t>
135 (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
136 response->reserved = 0;
137 response->remoteConsoleSessionID = rcSessionID;
138
139 //close the session
140 std::get<session::Manager&>(singletonPool).stopSession(
141 session->getBMCSessionID());
142
143 return outPayload;
144 }
145
146 /*
147 * Session Integrity Key
148 *
149 * 1) Remote Console Random Number - 16 bytes
150 * 2) Managed System Random Number - 16 bytes
151 * 3) Session Privilege Level - 1 byte
152 * 4) User Name Length Byte - 1 byte (0 for 'null' username)
153 * 5) User Name - variable (absent for 'null' username)
154 */
155
156 input.clear();
157
158 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
159 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
160 sizeof(sessPrivLevel) + sizeof(userLength));
161 iter = input.begin();
162
163 // Remote Console Random Number
164 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
165 iter);
166 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
167
168 // Managed Console Random Number
169 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
170 iter);
171 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
172
173 // Session Privilege Level
174 std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
175 sizeof(sessPrivLevel), iter);
176 std::advance(iter, sizeof(sessPrivLevel));
177
178 // User Name Length Byte
179 std::copy_n(&userLength, sizeof(userLength), iter);
180
181 // Generate Session Integrity Key
182 auto sikOutput = authAlgo->generateHMAC(input);
183
184 // Update the SIK in the Authentication Algo Interface
185 authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
186 sikOutput.begin(), sikOutput.end());
187
188 /*
189 * Integrity Check Value
190 *
191 * 1) Remote Console Random Number - 16 bytes
192 * 2) Managed System Session ID - 4 bytes
193 * 3) Managed System GUID - 16 bytes
194 */
195
196 // Get Managed System Session ID
197 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
198
199 input.clear();
200
201 input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
202 sizeof(bmcSessionID) + BMC_GUID_LEN);
203 iter = input.begin();
204
205 // Remote Console Random Number
206 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
207 iter);
208 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
209
210 // Managed System Session ID
211 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
212 iter);
213 std::advance(iter, sizeof(bmcSessionID));
214
215 // Managed System GUID
216 auto guid = getSystemGUID();
217 std::copy_n(guid.data(), guid.size(), iter);
218
219 // Integrity Check Value
220 auto icv = authAlgo->generateICV(input);
221
222 outPayload.resize(sizeof(RAKP4response));
223
224 response->messageTag = request->messageTag;
225 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
226 response->reserved = 0;
227 response->remoteConsoleSessionID = rcSessionID;
228
229 // Insert the HMAC output into the payload
230 outPayload.insert(outPayload.end(), icv.begin(), icv.end());
231
Tom Josephef02fb32017-01-19 12:55:11 +0530232 // Set the Integrity Algorithm
233 applyIntegrityAlgo(session->getBMCSessionID());
Tom Joseph818d0702017-01-10 16:39:38 +0530234
Tom Joseph50fb50a2016-12-06 17:51:06 +0530235 session->state = session::State::ACTIVE;
236
237 std::cout << "<< RAKP34\n";
238 return outPayload;
239}
240
241} // namespace command