1 #include "rakp12.hpp"
2 
3 #include <openssl/rand.h>
4 
5 #include <algorithm>
6 #include <cstring>
7 #include <iomanip>
8 #include <iostream>
9 
10 #include "comm_module.hpp"
11 #include "endian.hpp"
12 #include "guid.hpp"
13 #include "main.hpp"
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).getSession(
39             endian::from_ipmi(request->managedSystemSessionID))).lock();
40     }
41     catch (std::exception& e)
42     {
43         std::cerr << e.what() << "\n";
44         response->rmcpStatusCode =
45             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
46         return outPayload;
47     }
48 
49     auto rakp1Size = sizeof(RAKP1request) -
50             (userNameMaxLen - request->user_name_len);
51 
52     // Validate user name length in the message
53     if (request->user_name_len > userNameMaxLen ||
54         inPayload.size() !=  rakp1Size)
55     {
56         response->rmcpStatusCode =
57             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_NAME_LENGTH);
58         return outPayload;
59     }
60 
61     session->userName.assign(request->user_name, request->user_name_len);
62 
63     // Validate the user name if the username is provided
64     if (request->user_name_len &&
65         (session->userName != cipher::rakp_auth::userName))
66     {
67         response->rmcpStatusCode =
68             static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
69         return outPayload;
70     }
71 
72     // Update transaction time
73     session->updateLastTransactionTime();
74 
75     auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
76     auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
77     auto authAlgo = session->getAuthAlgo();
78 
79     /*
80      * Generate Key Authentication Code - RAKP 2
81      *
82      * 1) Remote Console Session ID - 4 bytes
83      * 2) Managed System Session ID - 4 bytes
84      * 3) Remote Console Random Number - 16 bytes
85      * 4) Managed System Random Number - 16 bytes
86      * 5) Managed System GUID - 16 bytes
87      * 6) Requested Privilege Level - 1 byte
88      * 7) User Name Length Byte - 1 byte (0 for 'null' username)
89      * 8) User Name - variable (absent for 'null' username)
90      */
91 
92     std::vector<uint8_t> input;
93     input.resize(sizeof(rcSessionID) + sizeof(bmcSessionID) +
94                  cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
95                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
96                  BMC_GUID_LEN + sizeof(request->req_max_privilege_level) +
97                  sizeof(request->user_name_len) +
98                  session->userName.size());
99 
100     auto iter = input.begin();
101 
102     // Remote Console Session ID
103     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID),
104                 sizeof(rcSessionID), iter);
105     std::advance(iter, sizeof(rcSessionID));
106 
107     // Managed System Session ID
108     std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
109                 iter);
110     std::advance(iter, sizeof(bmcSessionID));
111 
112     // Copy the Remote Console Random Number from the RAKP1 request to the
113     // Authentication Algorithm
114     std::copy_n(reinterpret_cast<const uint8_t*>
115                 (request->remote_console_random_number),
116                 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
117                 authAlgo->rcRandomNum.begin());
118 
119     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
120               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 = static_cast<session::Privilege>
144                             (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(),
173                 cache::guid.size(),
174                 response->managed_system_guid);
175 
176     // Insert the HMAC output into the payload
177     outPayload.insert(outPayload.end(), output.begin(), output.end());
178     return outPayload;
179 }
180 
181 } // namespace command
182