1 #include "rakp12.hpp"
2 
3 #include "comm_module.hpp"
4 #include "endian.hpp"
5 #include "guid.hpp"
6 #include "main.hpp"
7 
8 #include <openssl/rand.h>
9 
10 #include <algorithm>
11 #include <cstring>
12 #include <iomanip>
13 #include <phosphor-logging/log.hpp>
14 
15 using namespace phosphor::logging;
16 
17 namespace command
18 {
19 
20 std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload,
21                             const message::Handler& handler)
22 {
23     std::vector<uint8_t> outPayload(sizeof(RAKP2response));
24     auto request = reinterpret_cast<const RAKP1request*>(inPayload.data());
25     auto response = reinterpret_cast<RAKP2response*>(outPayload.data());
26 
27     // Session ID zero is reserved for Session Setup
28     if (endian::from_ipmi(request->managedSystemSessionID) ==
29         session::sessionZero)
30     {
31         log<level::INFO>("RAKP12: BMC invalid Session ID");
32         response->rmcpStatusCode =
33             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
34         return outPayload;
35     }
36 
37     std::shared_ptr<session::Session> session;
38     try
39     {
40         session =
41             std::get<session::Manager&>(singletonPool)
42                 .getSession(endian::from_ipmi(request->managedSystemSessionID));
43     }
44     catch (std::exception& e)
45     {
46         log<level::ERR>("RAKP12 : session not found",
47                         entry("EXCEPTION=%s", e.what()));
48         response->rmcpStatusCode =
49             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
50         return outPayload;
51     }
52 
53     auto rakp1Size =
54         sizeof(RAKP1request) - (userNameMaxLen - request->user_name_len);
55 
56     // Validate user name length in the message
57     if (request->user_name_len > userNameMaxLen ||
58         inPayload.size() != rakp1Size)
59     {
60         response->rmcpStatusCode =
61             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_NAME_LENGTH);
62         return outPayload;
63     }
64 
65     session->userName.assign(request->user_name, request->user_name_len);
66 
67     // Update transaction time
68     session->updateLastTransactionTime();
69 
70     auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
71     auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
72     auto authAlgo = session->getAuthAlgo();
73 
74     /*
75      * Generate Key Authentication Code - RAKP 2
76      *
77      * 1) Remote Console Session ID - 4 bytes
78      * 2) Managed System Session ID - 4 bytes
79      * 3) Remote Console Random Number - 16 bytes
80      * 4) Managed System Random Number - 16 bytes
81      * 5) Managed System GUID - 16 bytes
82      * 6) Requested Privilege Level - 1 byte
83      * 7) User Name Length Byte - 1 byte (0 for 'null' username)
84      * 8) User Name - variable (absent for 'null' username)
85      */
86 
87     std::vector<uint8_t> input;
88     input.resize(sizeof(rcSessionID) + sizeof(bmcSessionID) +
89                  cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
90                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + BMC_GUID_LEN +
91                  sizeof(request->req_max_privilege_level) +
92                  sizeof(request->user_name_len) + session->userName.size());
93 
94     auto iter = input.begin();
95 
96     // Remote Console Session ID
97     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
98                 iter);
99     std::advance(iter, sizeof(rcSessionID));
100 
101     // Managed System Session ID
102     std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
103                 iter);
104     std::advance(iter, sizeof(bmcSessionID));
105 
106     // Copy the Remote Console Random Number from the RAKP1 request to the
107     // Authentication Algorithm
108     std::copy_n(
109         reinterpret_cast<const uint8_t*>(request->remote_console_random_number),
110         cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
111         authAlgo->rcRandomNum.begin());
112 
113     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
114     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
115 
116     // Generate the Managed System Random Number
117     if (!RAND_bytes(input.data() + sizeof(rcSessionID) + sizeof(bmcSessionID) +
118                         cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
119                     cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN))
120     {
121         response->rmcpStatusCode =
122             static_cast<uint8_t>(RAKP_ReturnCode::INSUFFICIENT_RESOURCE);
123         return outPayload;
124     }
125     // As stated in Set Session Privilege Level command in IPMI Spec, when
126     // creating a session through Activate command / RAKP 1 message, it must
127     // be established with USER privilege as well as all other sessions are
128     // initially set to USER privilege, regardless of the requested maximum
129     // privilege.
130     if (!(static_cast<session::Privilege>(request->req_max_privilege_level &
131                                           session::reqMaxPrivMask) >
132           session::Privilege::CALLBACK))
133     {
134         response->rmcpStatusCode =
135             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_ROLE_PRIV);
136         return outPayload;
137     }
138     session->currentPrivilege(static_cast<uint8_t>(session::Privilege::USER));
139 
140     session->reqMaxPrivLevel =
141         static_cast<session::Privilege>(request->req_max_privilege_level);
142     if (request->user_name_len == 0)
143     {
144         // Bail out, if user name is not specified.
145         // Yes, NULL user name is not supported for security reasons.
146         response->rmcpStatusCode =
147             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
148         return outPayload;
149     }
150 
151     // Perform user name based lookup
152     std::string userName(request->user_name, request->user_name_len);
153     std::string passwd;
154     uint8_t userId = ipmi::ipmiUserGetUserId(userName);
155     if (userId == ipmi::invalidUserId)
156     {
157         response->rmcpStatusCode =
158             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
159         return outPayload;
160     }
161     // check user is enabled before proceeding.
162     bool userEnabled = false;
163     ipmi::ipmiUserCheckEnabled(userId, userEnabled);
164     if (!userEnabled)
165     {
166         response->rmcpStatusCode =
167             static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE);
168         return outPayload;
169     }
170     // Get the user password for RAKP message authenticate
171     passwd = ipmi::ipmiUserGetPassword(userName);
172     if (passwd.empty())
173     {
174         response->rmcpStatusCode =
175             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
176         return outPayload;
177     }
178     // Check whether user is already locked for failed attempts
179     if (!ipmi::ipmiUserPamAuthenticate(userName, passwd))
180     {
181         log<level::ERR>("Authentication failed - user already locked out",
182                         entry("USER-ID=%d", static_cast<uint8_t>(userId)));
183 
184         response->rmcpStatusCode =
185             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
186         return outPayload;
187     }
188 
189     uint8_t chNum = static_cast<uint8_t>(getInterfaceIndex());
190     // Get channel based access information
191     if ((ipmi::ipmiUserGetPrivilegeAccess(
192              userId, chNum, session->sessionUserPrivAccess) != IPMI_CC_OK) ||
193         (ipmi::getChannelAccessData(chNum, session->sessionChannelAccess) !=
194          IPMI_CC_OK))
195     {
196         response->rmcpStatusCode =
197             static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE);
198         return outPayload;
199     }
200     if (session->sessionUserPrivAccess.privilege >
201         static_cast<uint8_t>(session::Privilege::OEM))
202     {
203         response->rmcpStatusCode =
204             static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE);
205         return outPayload;
206     }
207     session->channelNum(chNum);
208     session->userID(userId);
209     // minimum privilege of Channel / User / session::privilege::USER
210     // has to be used as session current privilege level
211     uint8_t minPriv = 0;
212     if (session->sessionChannelAccess.privLimit <
213         session->sessionUserPrivAccess.privilege)
214     {
215         minPriv = session->sessionChannelAccess.privLimit;
216     }
217     else
218     {
219         minPriv = session->sessionUserPrivAccess.privilege;
220     }
221     if (session->currentPrivilege() > minPriv)
222     {
223         session->currentPrivilege(static_cast<uint8_t>(minPriv));
224     }
225     // For username / privilege lookup, fail with UNAUTH_NAME, if requested
226     // max privilege does not match user privilege
227     if (((request->req_max_privilege_level & userNameOnlyLookupMask) ==
228          userNamePrivLookup) &&
229         ((request->req_max_privilege_level & session::reqMaxPrivMask) !=
230          session->sessionUserPrivAccess.privilege))
231     {
232         log<level::INFO>(
233             "Username/Privilege lookup failed for requested privilege");
234         response->rmcpStatusCode =
235             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
236         return outPayload;
237     }
238 
239     std::fill(authAlgo->userKey.data(),
240               authAlgo->userKey.data() + authAlgo->userKey.size(), 0);
241     std::copy_n(passwd.c_str(), passwd.size(), authAlgo->userKey.data());
242 
243     // Copy the Managed System Random Number to the Authentication Algorithm
244     std::copy_n(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN,
245                 authAlgo->bmcRandomNum.begin());
246     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
247 
248     // Managed System GUID
249     std::copy_n(cache::guid.data(), cache::guid.size(), iter);
250     std::advance(iter, BMC_GUID_LEN);
251 
252     // Requested Privilege Level
253     std::copy_n(&(request->req_max_privilege_level),
254                 sizeof(request->req_max_privilege_level), iter);
255     std::advance(iter, sizeof(request->req_max_privilege_level));
256 
257     // User Name Length Byte
258     std::copy_n(&(request->user_name_len), sizeof(request->user_name_len),
259                 iter);
260     std::advance(iter, sizeof(request->user_name_len));
261 
262     std::copy_n(session->userName.data(), session->userName.size(), iter);
263 
264     // Generate Key Exchange Authentication Code - RAKP2
265     auto output = authAlgo->generateHMAC(input);
266 
267     response->messageTag = request->messageTag;
268     response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
269     response->reserved = 0;
270     response->remoteConsoleSessionID = rcSessionID;
271 
272     // Copy Managed System Random Number to the Response
273     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
274               response->managed_system_random_number);
275 
276     // Copy System GUID to the Response
277     std::copy_n(cache::guid.data(), cache::guid.size(),
278                 response->managed_system_guid);
279 
280     // Insert the HMAC output into the payload
281     outPayload.insert(outPayload.end(), output.begin(), output.end());
282     return outPayload;
283 }
284 
285 } // namespace command
286