xref: /openbmc/phosphor-net-ipmid/command/rakp34.cpp (revision 50fb50a97a93c0192e5b481297e1ecd6b47ea18a)
1*50fb50a9STom Joseph #include "rakp34.hpp"
2*50fb50a9STom Joseph 
3*50fb50a9STom Joseph #include <algorithm>
4*50fb50a9STom Joseph #include <cstring>
5*50fb50a9STom Joseph #include <iostream>
6*50fb50a9STom Joseph 
7*50fb50a9STom Joseph #include "comm_module.hpp"
8*50fb50a9STom Joseph #include "endian.hpp"
9*50fb50a9STom Joseph #include "guid.hpp"
10*50fb50a9STom Joseph #include "main.hpp"
11*50fb50a9STom Joseph 
12*50fb50a9STom Joseph namespace command
13*50fb50a9STom Joseph {
14*50fb50a9STom Joseph 
15*50fb50a9STom Joseph std::vector<uint8_t> RAKP34(std::vector<uint8_t>& inPayload,
16*50fb50a9STom Joseph                             const message::Handler& handler)
17*50fb50a9STom Joseph {
18*50fb50a9STom Joseph     std::cout << ">> RAKP34\n";
19*50fb50a9STom Joseph 
20*50fb50a9STom Joseph     std::vector<uint8_t> outPayload(sizeof(RAKP4response));
21*50fb50a9STom Joseph     auto request = reinterpret_cast<RAKP3request*>(inPayload.data());
22*50fb50a9STom Joseph     auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
23*50fb50a9STom Joseph 
24*50fb50a9STom Joseph     // Check if the RAKP3 Payload Length is as expected
25*50fb50a9STom Joseph     if(inPayload.size() != sizeof(RAKP3request))
26*50fb50a9STom Joseph     {
27*50fb50a9STom Joseph         std::cerr << "RAKP34: Invalid RAKP3 request\n";
28*50fb50a9STom Joseph         response->rmcpStatusCode =
29*50fb50a9STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
30*50fb50a9STom Joseph         return outPayload;
31*50fb50a9STom Joseph     }
32*50fb50a9STom Joseph 
33*50fb50a9STom Joseph     // Session ID zero is reserved for Session Setup
34*50fb50a9STom Joseph     if(endian::from_ipmi(request->managedSystemSessionID) ==
35*50fb50a9STom Joseph                          session::SESSION_ZERO)
36*50fb50a9STom Joseph     {
37*50fb50a9STom Joseph         std::cerr << "RAKP34: BMC invalid Session ID\n";
38*50fb50a9STom Joseph         response->rmcpStatusCode =
39*50fb50a9STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
40*50fb50a9STom Joseph         return outPayload;
41*50fb50a9STom Joseph     }
42*50fb50a9STom Joseph 
43*50fb50a9STom Joseph     std::shared_ptr<session::Session> session;
44*50fb50a9STom Joseph     try
45*50fb50a9STom Joseph     {
46*50fb50a9STom Joseph         session = (std::get<session::Manager&>(singletonPool).getSession(
47*50fb50a9STom Joseph             endian::from_ipmi(request->managedSystemSessionID))).lock();
48*50fb50a9STom Joseph     }
49*50fb50a9STom Joseph     catch (std::exception& e)
50*50fb50a9STom Joseph     {
51*50fb50a9STom Joseph         std::cerr << e.what() << "\n";
52*50fb50a9STom Joseph         response->rmcpStatusCode =
53*50fb50a9STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
54*50fb50a9STom Joseph         return outPayload;
55*50fb50a9STom Joseph     }
56*50fb50a9STom Joseph 
57*50fb50a9STom Joseph     session->updateLastTransactionTime();
58*50fb50a9STom Joseph 
59*50fb50a9STom Joseph     auto authAlgo = session->getAuthAlgo();
60*50fb50a9STom Joseph     /*
61*50fb50a9STom Joseph      * Key Authentication Code - RAKP 3
62*50fb50a9STom Joseph      *
63*50fb50a9STom Joseph      * 1) Managed System Random Number - 16 bytes
64*50fb50a9STom Joseph      * 2) Remote Console Session ID - 4 bytes
65*50fb50a9STom Joseph      * 3) Session Privilege Level - 1 byte
66*50fb50a9STom Joseph      * 4) User Name Length Byte - 1 byte (0 for 'null' username)
67*50fb50a9STom Joseph      * 5) User Name - variable (absent for 'null' username)
68*50fb50a9STom Joseph      */
69*50fb50a9STom Joseph 
70*50fb50a9STom Joseph     // Remote Console Session ID
71*50fb50a9STom Joseph     auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
72*50fb50a9STom Joseph 
73*50fb50a9STom Joseph     // Session Privilege Level
74*50fb50a9STom Joseph     auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
75*50fb50a9STom Joseph 
76*50fb50a9STom Joseph     // User Name Length Byte
77*50fb50a9STom Joseph     uint8_t userLength = 0;
78*50fb50a9STom Joseph 
79*50fb50a9STom Joseph     std::vector<uint8_t> input;
80*50fb50a9STom Joseph     input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
81*50fb50a9STom Joseph                  sizeof(rcSessionID) + sizeof(sessPrivLevel) +
82*50fb50a9STom Joseph                  sizeof(userLength));
83*50fb50a9STom Joseph 
84*50fb50a9STom Joseph     auto iter = input.begin();
85*50fb50a9STom Joseph 
86*50fb50a9STom Joseph     // Managed System Random Number
87*50fb50a9STom Joseph     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
88*50fb50a9STom Joseph               iter);
89*50fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
90*50fb50a9STom Joseph 
91*50fb50a9STom Joseph     // Remote Console Session ID
92*50fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
93*50fb50a9STom Joseph                 iter);
94*50fb50a9STom Joseph     std::advance(iter, sizeof(rcSessionID));
95*50fb50a9STom Joseph 
96*50fb50a9STom Joseph     // Session Privilege Level
97*50fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
98*50fb50a9STom Joseph                 sizeof(sessPrivLevel), iter);
99*50fb50a9STom Joseph     std::advance(iter, sizeof(sessPrivLevel));
100*50fb50a9STom Joseph 
101*50fb50a9STom Joseph     // User Name Length Byte
102*50fb50a9STom Joseph     std::copy_n(&userLength, sizeof(userLength), iter);
103*50fb50a9STom Joseph 
104*50fb50a9STom Joseph     // Generate Key Exchange Authentication Code - RAKP2
105*50fb50a9STom Joseph     auto output = authAlgo->generateHMAC(input);
106*50fb50a9STom Joseph 
107*50fb50a9STom Joseph     if (std::memcmp(output.data(), request->keyExchangeAuthCode,
108*50fb50a9STom Joseph                     output.size()))
109*50fb50a9STom Joseph     {
110*50fb50a9STom Joseph         std::cerr << "Mismatch in HMAC sent by remote console\n";
111*50fb50a9STom Joseph 
112*50fb50a9STom Joseph         response->messageTag = request->messageTag;
113*50fb50a9STom Joseph         response->rmcpStatusCode = static_cast<uint8_t>
114*50fb50a9STom Joseph                                    (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
115*50fb50a9STom Joseph         response->reserved = 0;
116*50fb50a9STom Joseph         response->remoteConsoleSessionID = rcSessionID;
117*50fb50a9STom Joseph 
118*50fb50a9STom Joseph         //close the session
119*50fb50a9STom Joseph         std::get<session::Manager&>(singletonPool).stopSession(
120*50fb50a9STom Joseph             session->getBMCSessionID());
121*50fb50a9STom Joseph 
122*50fb50a9STom Joseph         return outPayload;
123*50fb50a9STom Joseph     }
124*50fb50a9STom Joseph 
125*50fb50a9STom Joseph     /*
126*50fb50a9STom Joseph      * Session Integrity Key
127*50fb50a9STom Joseph      *
128*50fb50a9STom Joseph      * 1) Remote Console Random Number - 16 bytes
129*50fb50a9STom Joseph      * 2) Managed System Random Number - 16 bytes
130*50fb50a9STom Joseph      * 3) Session Privilege Level - 1 byte
131*50fb50a9STom Joseph      * 4) User Name Length Byte - 1 byte (0 for 'null' username)
132*50fb50a9STom Joseph      * 5) User Name - variable (absent for 'null' username)
133*50fb50a9STom Joseph      */
134*50fb50a9STom Joseph 
135*50fb50a9STom Joseph     input.clear();
136*50fb50a9STom Joseph 
137*50fb50a9STom Joseph     input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
138*50fb50a9STom Joseph                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
139*50fb50a9STom Joseph                  sizeof(sessPrivLevel) + sizeof(userLength));
140*50fb50a9STom Joseph     iter = input.begin();
141*50fb50a9STom Joseph 
142*50fb50a9STom Joseph     // Remote Console Random Number
143*50fb50a9STom Joseph     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
144*50fb50a9STom Joseph               iter);
145*50fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
146*50fb50a9STom Joseph 
147*50fb50a9STom Joseph     // Managed Console Random Number
148*50fb50a9STom Joseph     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
149*50fb50a9STom Joseph               iter);
150*50fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
151*50fb50a9STom Joseph 
152*50fb50a9STom Joseph     // Session Privilege Level
153*50fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
154*50fb50a9STom Joseph                 sizeof(sessPrivLevel), iter);
155*50fb50a9STom Joseph     std::advance(iter, sizeof(sessPrivLevel));
156*50fb50a9STom Joseph 
157*50fb50a9STom Joseph     // User Name Length Byte
158*50fb50a9STom Joseph     std::copy_n(&userLength, sizeof(userLength), iter);
159*50fb50a9STom Joseph 
160*50fb50a9STom Joseph     // Generate Session Integrity Key
161*50fb50a9STom Joseph     auto sikOutput = authAlgo->generateHMAC(input);
162*50fb50a9STom Joseph 
163*50fb50a9STom Joseph     // Update the SIK in the Authentication Algo Interface
164*50fb50a9STom Joseph     authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
165*50fb50a9STom Joseph                                          sikOutput.begin(), sikOutput.end());
166*50fb50a9STom Joseph 
167*50fb50a9STom Joseph     /*
168*50fb50a9STom Joseph      * Integrity Check Value
169*50fb50a9STom Joseph      *
170*50fb50a9STom Joseph      * 1) Remote Console Random Number - 16 bytes
171*50fb50a9STom Joseph      * 2) Managed System Session ID - 4 bytes
172*50fb50a9STom Joseph      * 3) Managed System GUID - 16 bytes
173*50fb50a9STom Joseph      */
174*50fb50a9STom Joseph 
175*50fb50a9STom Joseph     // Get Managed System Session ID
176*50fb50a9STom Joseph     auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
177*50fb50a9STom Joseph 
178*50fb50a9STom Joseph     input.clear();
179*50fb50a9STom Joseph 
180*50fb50a9STom Joseph     input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
181*50fb50a9STom Joseph                  sizeof(bmcSessionID) + BMC_GUID_LEN);
182*50fb50a9STom Joseph     iter = input.begin();
183*50fb50a9STom Joseph 
184*50fb50a9STom Joseph     // Remote Console Random Number
185*50fb50a9STom Joseph     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
186*50fb50a9STom Joseph               iter);
187*50fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
188*50fb50a9STom Joseph 
189*50fb50a9STom Joseph     // Managed System Session ID
190*50fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
191*50fb50a9STom Joseph                 iter);
192*50fb50a9STom Joseph     std::advance(iter, sizeof(bmcSessionID));
193*50fb50a9STom Joseph 
194*50fb50a9STom Joseph     // Managed System GUID
195*50fb50a9STom Joseph     auto guid = getSystemGUID();
196*50fb50a9STom Joseph     std::copy_n(guid.data(), guid.size(), iter);
197*50fb50a9STom Joseph 
198*50fb50a9STom Joseph     // Integrity Check Value
199*50fb50a9STom Joseph     auto icv = authAlgo->generateICV(input);
200*50fb50a9STom Joseph 
201*50fb50a9STom Joseph     outPayload.resize(sizeof(RAKP4response));
202*50fb50a9STom Joseph 
203*50fb50a9STom Joseph     response->messageTag = request->messageTag;
204*50fb50a9STom Joseph     response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
205*50fb50a9STom Joseph     response->reserved = 0;
206*50fb50a9STom Joseph     response->remoteConsoleSessionID = rcSessionID;
207*50fb50a9STom Joseph 
208*50fb50a9STom Joseph     // Insert the HMAC output into the payload
209*50fb50a9STom Joseph     outPayload.insert(outPayload.end(), icv.begin(), icv.end());
210*50fb50a9STom Joseph 
211*50fb50a9STom Joseph     session->state = session::State::ACTIVE;
212*50fb50a9STom Joseph 
213*50fb50a9STom Joseph     std::cout << "<< RAKP34\n";
214*50fb50a9STom Joseph     return outPayload;
215*50fb50a9STom Joseph }
216*50fb50a9STom Joseph 
217*50fb50a9STom Joseph } // namespace command
218