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