blob: b0aad8782c3e033142e6cc120f97669353730770 [file] [log] [blame]
Tom Joseph8bb10b72016-12-06 17:47:56 +05301#include "rakp12.hpp"
2
Vernon Mauery9e801a22018-10-12 13:20:49 -07003#include "comm_module.hpp"
4#include "endian.hpp"
5#include "guid.hpp"
6#include "main.hpp"
7
Tom Joseph8bb10b72016-12-06 17:47:56 +05308#include <openssl/rand.h>
9
10#include <algorithm>
Tom Joseph56527b92018-03-21 19:31:58 +053011#include <cstring>
Tom Joseph8bb10b72016-12-06 17:47:56 +053012#include <iomanip>
13#include <iostream>
14
Tom Joseph8bb10b72016-12-06 17:47:56 +053015namespace command
16{
17
Tom Joseph18a45e92017-04-11 11:30:44 +053018std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload,
Tom Joseph8bb10b72016-12-06 17:47:56 +053019 const message::Handler& handler)
20{
Tom Joseph8bb10b72016-12-06 17:47:56 +053021 std::vector<uint8_t> outPayload(sizeof(RAKP2response));
Tom Joseph18a45e92017-04-11 11:30:44 +053022 auto request = reinterpret_cast<const RAKP1request*>(inPayload.data());
Tom Joseph8bb10b72016-12-06 17:47:56 +053023 auto response = reinterpret_cast<RAKP2response*>(outPayload.data());
24
25 // Session ID zero is reserved for Session Setup
Vernon Mauery9e801a22018-10-12 13:20:49 -070026 if (endian::from_ipmi(request->managedSystemSessionID) ==
27 session::SESSION_ZERO)
Tom Joseph8bb10b72016-12-06 17:47:56 +053028 {
29 std::cerr << "RAKP12: BMC invalid Session ID\n";
30 response->rmcpStatusCode =
31 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
32 return outPayload;
33 }
34
35 std::shared_ptr<session::Session> session;
36 try
37 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070038 session = (std::get<session::Manager&>(singletonPool)
39 .getSession(
40 endian::from_ipmi(request->managedSystemSessionID)))
41 .lock();
Tom Joseph8bb10b72016-12-06 17:47:56 +053042 }
43 catch (std::exception& e)
44 {
45 std::cerr << e.what() << "\n";
46 response->rmcpStatusCode =
47 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
48 return outPayload;
49 }
50
Vernon Mauery9e801a22018-10-12 13:20:49 -070051 auto rakp1Size =
52 sizeof(RAKP1request) - (userNameMaxLen - request->user_name_len);
Tom Joseph56527b92018-03-21 19:31:58 +053053
54 // Validate user name length in the message
55 if (request->user_name_len > userNameMaxLen ||
Vernon Mauery9e801a22018-10-12 13:20:49 -070056 inPayload.size() != rakp1Size)
Tom Joseph56527b92018-03-21 19:31:58 +053057 {
58 response->rmcpStatusCode =
59 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_NAME_LENGTH);
60 return outPayload;
61 }
62
63 session->userName.assign(request->user_name, request->user_name_len);
64
65 // Validate the user name if the username is provided
66 if (request->user_name_len &&
67 (session->userName != cipher::rakp_auth::userName))
68 {
69 response->rmcpStatusCode =
70 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
71 return outPayload;
72 }
73
Tom Joseph8bb10b72016-12-06 17:47:56 +053074 // Update transaction time
75 session->updateLastTransactionTime();
76
77 auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
78 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
79 auto authAlgo = session->getAuthAlgo();
80
81 /*
82 * Generate Key Authentication Code - RAKP 2
83 *
84 * 1) Remote Console Session ID - 4 bytes
85 * 2) Managed System Session ID - 4 bytes
86 * 3) Remote Console Random Number - 16 bytes
87 * 4) Managed System Random Number - 16 bytes
88 * 5) Managed System GUID - 16 bytes
89 * 6) Requested Privilege Level - 1 byte
90 * 7) User Name Length Byte - 1 byte (0 for 'null' username)
91 * 8) User Name - variable (absent for 'null' username)
92 */
93
94 std::vector<uint8_t> input;
95 input.resize(sizeof(rcSessionID) + sizeof(bmcSessionID) +
96 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
Vernon Mauery9e801a22018-10-12 13:20:49 -070097 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + BMC_GUID_LEN +
98 sizeof(request->req_max_privilege_level) +
99 sizeof(request->user_name_len) + session->userName.size());
Tom Joseph8bb10b72016-12-06 17:47:56 +0530100
101 auto iter = input.begin();
102
103 // Remote Console Session ID
Vernon Mauery9e801a22018-10-12 13:20:49 -0700104 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
105 iter);
Tom Joseph8bb10b72016-12-06 17:47:56 +0530106 std::advance(iter, sizeof(rcSessionID));
107
108 // Managed System Session ID
109 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
110 iter);
111 std::advance(iter, sizeof(bmcSessionID));
112
113 // Copy the Remote Console Random Number from the RAKP1 request to the
114 // Authentication Algorithm
Vernon Mauery9e801a22018-10-12 13:20:49 -0700115 std::copy_n(
116 reinterpret_cast<const uint8_t*>(request->remote_console_random_number),
117 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
118 authAlgo->rcRandomNum.begin());
Tom Joseph8bb10b72016-12-06 17:47:56 +0530119
Vernon Mauery9e801a22018-10-12 13:20:49 -0700120 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
Tom Joseph8bb10b72016-12-06 17:47:56 +0530121 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
122
123 // Generate the Managed System Random Number
124 if (!RAND_bytes(input.data() + sizeof(rcSessionID) + sizeof(bmcSessionID) +
Vernon Mauery9e801a22018-10-12 13:20:49 -0700125 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
Tom Joseph8bb10b72016-12-06 17:47:56 +0530126 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN))
127 {
128 response->rmcpStatusCode =
129 static_cast<uint8_t>(RAKP_ReturnCode::INSUFFICIENT_RESOURCE);
130 return outPayload;
131 }
132
133 // Copy the Managed System Random Number to the Authentication Algorithm
134 std::copy_n(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN,
135 authAlgo->bmcRandomNum.begin());
136 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
137
138 // Managed System GUID
Tom Joseph83029cb2017-09-01 16:37:31 +0530139 std::copy_n(cache::guid.data(), cache::guid.size(), iter);
Tom Joseph8bb10b72016-12-06 17:47:56 +0530140 std::advance(iter, BMC_GUID_LEN);
141
142 // Requested Privilege Level
Vernon Mauery9e801a22018-10-12 13:20:49 -0700143 session->curPrivLevel =
144 static_cast<session::Privilege>(request->req_max_privilege_level);
Tom Joseph8bb10b72016-12-06 17:47:56 +0530145 std::copy_n(&(request->req_max_privilege_level),
146 sizeof(request->req_max_privilege_level), iter);
147 std::advance(iter, sizeof(request->req_max_privilege_level));
148
149 // Set Max Privilege to ADMIN
150 session->maxPrivLevel = session::Privilege::ADMIN;
151
152 // User Name Length Byte
153 std::copy_n(&(request->user_name_len), sizeof(request->user_name_len),
154 iter);
Tom Joseph56527b92018-03-21 19:31:58 +0530155 std::advance(iter, sizeof(request->user_name_len));
156
157 std::copy_n(session->userName.data(), session->userName.size(), iter);
Tom Joseph8bb10b72016-12-06 17:47:56 +0530158
159 // Generate Key Exchange Authentication Code - RAKP2
160 auto output = authAlgo->generateHMAC(input);
161
162 response->messageTag = request->messageTag;
163 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
164 response->reserved = 0;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700165 response->remoteConsoleSessionID = rcSessionID;
Tom Joseph8bb10b72016-12-06 17:47:56 +0530166
167 // Copy Managed System Random Number to the Response
168 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
169 response->managed_system_random_number);
170
171 // Copy System GUID to the Response
Vernon Mauery9e801a22018-10-12 13:20:49 -0700172 std::copy_n(cache::guid.data(), cache::guid.size(),
Tom Joseph83029cb2017-09-01 16:37:31 +0530173 response->managed_system_guid);
Tom Joseph8bb10b72016-12-06 17:47:56 +0530174
175 // Insert the HMAC output into the payload
176 outPayload.insert(outPayload.end(), output.begin(), output.end());
Tom Joseph8bb10b72016-12-06 17:47:56 +0530177 return outPayload;
178}
179
180} // namespace command