1 #include "rakp12.hpp"
2 
3 #include <openssl/rand.h>
4 
5 #include <algorithm>
6 #include <iomanip>
7 #include <iostream>
8 
9 #include "comm_module.hpp"
10 #include "endian.hpp"
11 #include "guid.hpp"
12 #include "main.hpp"
13 
14 namespace command
15 {
16 
17 std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload,
18                             const message::Handler& handler)
19 {
20     std::cout << ">> RAKP12\n";
21 
22     std::vector<uint8_t> outPayload(sizeof(RAKP2response));
23     auto request = reinterpret_cast<const RAKP1request*>(inPayload.data());
24     auto response = reinterpret_cast<RAKP2response*>(outPayload.data());
25 
26     // Session ID zero is reserved for Session Setup
27     if(endian::from_ipmi(request->managedSystemSessionID) ==
28                          session::SESSION_ZERO)
29     {
30         std::cerr << "RAKP12: BMC invalid Session ID\n";
31         response->rmcpStatusCode =
32             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
33         return outPayload;
34     }
35 
36     std::shared_ptr<session::Session> session;
37     try
38     {
39         session = (std::get<session::Manager&>(singletonPool).getSession(
40             endian::from_ipmi(request->managedSystemSessionID))).lock();
41     }
42     catch (std::exception& e)
43     {
44         std::cerr << e.what() << "\n";
45         response->rmcpStatusCode =
46             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
47         return outPayload;
48     }
49 
50     // Update transaction time
51     session->updateLastTransactionTime();
52 
53     auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
54     auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
55     auto authAlgo = session->getAuthAlgo();
56 
57     /*
58      * Generate Key Authentication Code - RAKP 2
59      *
60      * 1) Remote Console Session ID - 4 bytes
61      * 2) Managed System Session ID - 4 bytes
62      * 3) Remote Console Random Number - 16 bytes
63      * 4) Managed System Random Number - 16 bytes
64      * 5) Managed System GUID - 16 bytes
65      * 6) Requested Privilege Level - 1 byte
66      * 7) User Name Length Byte - 1 byte (0 for 'null' username)
67      * 8) User Name - variable (absent for 'null' username)
68      */
69 
70     std::vector<uint8_t> input;
71     input.resize(sizeof(rcSessionID) + sizeof(bmcSessionID) +
72                  cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
73                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
74                  BMC_GUID_LEN + sizeof(request->req_max_privilege_level) +
75                  sizeof(request->user_name_len));
76 
77     auto iter = input.begin();
78 
79     // Remote Console Session ID
80     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID),
81                 sizeof(rcSessionID), iter);
82     std::advance(iter, sizeof(rcSessionID));
83 
84     // Managed System Session ID
85     std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
86                 iter);
87     std::advance(iter, sizeof(bmcSessionID));
88 
89     // Copy the Remote Console Random Number from the RAKP1 request to the
90     // Authentication Algorithm
91     std::copy_n(reinterpret_cast<const uint8_t*>
92                 (request->remote_console_random_number),
93                 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
94                 authAlgo->rcRandomNum.begin());
95 
96     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
97               iter);
98     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
99 
100     // Generate the Managed System Random Number
101     if (!RAND_bytes(input.data() + sizeof(rcSessionID) + sizeof(bmcSessionID) +
102                     cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
103                     cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN))
104     {
105         response->rmcpStatusCode =
106             static_cast<uint8_t>(RAKP_ReturnCode::INSUFFICIENT_RESOURCE);
107         return outPayload;
108     }
109 
110     // Copy the Managed System Random Number to the Authentication Algorithm
111     std::copy_n(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN,
112                 authAlgo->bmcRandomNum.begin());
113     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
114 
115     // Managed System GUID
116     std::copy_n(cache::guid.data(), cache::guid.size(), iter);
117     std::advance(iter, BMC_GUID_LEN);
118 
119     // Requested Privilege Level
120     session->curPrivLevel = static_cast<session::Privilege>
121                             (request->req_max_privilege_level);
122     std::copy_n(&(request->req_max_privilege_level),
123                 sizeof(request->req_max_privilege_level), iter);
124     std::advance(iter, sizeof(request->req_max_privilege_level));
125 
126     // Set Max Privilege to ADMIN
127     session->maxPrivLevel = session::Privilege::ADMIN;
128 
129     // User Name Length Byte
130     std::copy_n(&(request->user_name_len), sizeof(request->user_name_len),
131                 iter);
132 
133     // Generate Key Exchange Authentication Code - RAKP2
134     auto output = authAlgo->generateHMAC(input);
135 
136     response->messageTag = request->messageTag;
137     response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
138     response->reserved = 0;
139     response->remoteConsoleSessionID = rcSessionID ;
140 
141     // Copy Managed System Random Number to the Response
142     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
143               response->managed_system_random_number);
144 
145     // Copy System GUID to the Response
146     std::copy_n(cache::guid.data(),
147                 cache::guid.size(),
148                 response->managed_system_guid);
149 
150     // Insert the HMAC output into the payload
151     outPayload.insert(outPayload.end(), output.begin(), output.end());
152 
153     std::cout << "<< RAKP12\n";
154     return outPayload;
155 }
156 
157 } // namespace command
158