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 <iostream>
14 
15 namespace command
16 {
17 
18 std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload,
19                             const message::Handler& handler)
20 {
21     std::vector<uint8_t> outPayload(sizeof(RAKP2response));
22     auto request = reinterpret_cast<const RAKP1request*>(inPayload.data());
23     auto response = reinterpret_cast<RAKP2response*>(outPayload.data());
24 
25     // Session ID zero is reserved for Session Setup
26     if (endian::from_ipmi(request->managedSystemSessionID) ==
27         session::SESSION_ZERO)
28     {
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     {
38         session = (std::get<session::Manager&>(singletonPool)
39                        .getSession(
40                            endian::from_ipmi(request->managedSystemSessionID)))
41                       .lock();
42     }
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 
51     auto rakp1Size =
52         sizeof(RAKP1request) - (userNameMaxLen - request->user_name_len);
53 
54     // Validate user name length in the message
55     if (request->user_name_len > userNameMaxLen ||
56         inPayload.size() != rakp1Size)
57     {
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 
74     // 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 +
97                  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());
100 
101     auto iter = input.begin();
102 
103     // Remote Console Session ID
104     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
105                 iter);
106     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
115     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());
119 
120     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
121     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) +
125                         cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
126                     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
139     std::copy_n(cache::guid.data(), cache::guid.size(), iter);
140     std::advance(iter, BMC_GUID_LEN);
141 
142     // Requested Privilege Level
143     session->curPrivLevel =
144         static_cast<session::Privilege>(request->req_max_privilege_level);
145     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);
155     std::advance(iter, sizeof(request->user_name_len));
156 
157     std::copy_n(session->userName.data(), session->userName.size(), iter);
158 
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;
165     response->remoteConsoleSessionID = rcSessionID;
166 
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
172     std::copy_n(cache::guid.data(), cache::guid.size(),
173                 response->managed_system_guid);
174 
175     // Insert the HMAC output into the payload
176     outPayload.insert(outPayload.end(), output.begin(), output.end());
177     return outPayload;
178 }
179 
180 } // namespace command
181