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