18bb10b79STom Joseph #include "rakp12.hpp"
28bb10b79STom Joseph 
38bb10b79STom Joseph #include <openssl/rand.h>
48bb10b79STom Joseph 
58bb10b79STom Joseph #include <algorithm>
68bb10b79STom Joseph #include <iomanip>
78bb10b79STom Joseph #include <iostream>
88bb10b79STom Joseph 
98bb10b79STom Joseph #include "comm_module.hpp"
108bb10b79STom Joseph #include "endian.hpp"
118bb10b79STom Joseph #include "guid.hpp"
128bb10b79STom Joseph #include "main.hpp"
138bb10b79STom Joseph 
148bb10b79STom Joseph namespace command
158bb10b79STom Joseph {
168bb10b79STom Joseph 
17*18a45e9dSTom Joseph std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload,
188bb10b79STom Joseph                             const message::Handler& handler)
198bb10b79STom Joseph {
208bb10b79STom Joseph     std::cout << ">> RAKP12\n";
218bb10b79STom Joseph 
228bb10b79STom Joseph     std::vector<uint8_t> outPayload(sizeof(RAKP2response));
23*18a45e9dSTom Joseph     auto request = reinterpret_cast<const RAKP1request*>(inPayload.data());
248bb10b79STom Joseph     auto response = reinterpret_cast<RAKP2response*>(outPayload.data());
258bb10b79STom Joseph 
268bb10b79STom Joseph     // Session ID zero is reserved for Session Setup
278bb10b79STom Joseph     if(endian::from_ipmi(request->managedSystemSessionID) ==
288bb10b79STom Joseph                          session::SESSION_ZERO)
298bb10b79STom Joseph     {
308bb10b79STom Joseph         std::cerr << "RAKP12: BMC invalid Session ID\n";
318bb10b79STom Joseph         response->rmcpStatusCode =
328bb10b79STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
338bb10b79STom Joseph         return outPayload;
348bb10b79STom Joseph     }
358bb10b79STom Joseph 
368bb10b79STom Joseph     std::shared_ptr<session::Session> session;
378bb10b79STom Joseph     try
388bb10b79STom Joseph     {
398bb10b79STom Joseph         session = (std::get<session::Manager&>(singletonPool).getSession(
408bb10b79STom Joseph             endian::from_ipmi(request->managedSystemSessionID))).lock();
418bb10b79STom Joseph     }
428bb10b79STom Joseph     catch (std::exception& e)
438bb10b79STom Joseph     {
448bb10b79STom Joseph         std::cerr << e.what() << "\n";
458bb10b79STom Joseph         response->rmcpStatusCode =
468bb10b79STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
478bb10b79STom Joseph         return outPayload;
488bb10b79STom Joseph     }
498bb10b79STom Joseph 
508bb10b79STom Joseph     // Update transaction time
518bb10b79STom Joseph     session->updateLastTransactionTime();
528bb10b79STom Joseph 
538bb10b79STom Joseph     auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
548bb10b79STom Joseph     auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
558bb10b79STom Joseph     auto authAlgo = session->getAuthAlgo();
568bb10b79STom Joseph 
578bb10b79STom Joseph     /*
588bb10b79STom Joseph      * Generate Key Authentication Code - RAKP 2
598bb10b79STom Joseph      *
608bb10b79STom Joseph      * 1) Remote Console Session ID - 4 bytes
618bb10b79STom Joseph      * 2) Managed System Session ID - 4 bytes
628bb10b79STom Joseph      * 3) Remote Console Random Number - 16 bytes
638bb10b79STom Joseph      * 4) Managed System Random Number - 16 bytes
648bb10b79STom Joseph      * 5) Managed System GUID - 16 bytes
658bb10b79STom Joseph      * 6) Requested Privilege Level - 1 byte
668bb10b79STom Joseph      * 7) User Name Length Byte - 1 byte (0 for 'null' username)
678bb10b79STom Joseph      * 8) User Name - variable (absent for 'null' username)
688bb10b79STom Joseph      */
698bb10b79STom Joseph 
708bb10b79STom Joseph     std::vector<uint8_t> input;
718bb10b79STom Joseph     input.resize(sizeof(rcSessionID) + sizeof(bmcSessionID) +
728bb10b79STom Joseph                  cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
738bb10b79STom Joseph                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
748bb10b79STom Joseph                  BMC_GUID_LEN + sizeof(request->req_max_privilege_level) +
758bb10b79STom Joseph                  sizeof(request->user_name_len));
768bb10b79STom Joseph 
778bb10b79STom Joseph     auto iter = input.begin();
788bb10b79STom Joseph 
798bb10b79STom Joseph     // Remote Console Session ID
808bb10b79STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID),
818bb10b79STom Joseph                 sizeof(rcSessionID), iter);
828bb10b79STom Joseph     std::advance(iter, sizeof(rcSessionID));
838bb10b79STom Joseph 
848bb10b79STom Joseph     // Managed System Session ID
858bb10b79STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
868bb10b79STom Joseph                 iter);
878bb10b79STom Joseph     std::advance(iter, sizeof(bmcSessionID));
888bb10b79STom Joseph 
898bb10b79STom Joseph     // Copy the Remote Console Random Number from the RAKP1 request to the
908bb10b79STom Joseph     // Authentication Algorithm
91*18a45e9dSTom Joseph     std::copy_n(reinterpret_cast<const uint8_t*>
928bb10b79STom Joseph                 (request->remote_console_random_number),
938bb10b79STom Joseph                 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
948bb10b79STom Joseph                 authAlgo->rcRandomNum.begin());
958bb10b79STom Joseph 
968bb10b79STom Joseph     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
978bb10b79STom Joseph               iter);
988bb10b79STom Joseph     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
998bb10b79STom Joseph 
1008bb10b79STom Joseph     // Generate the Managed System Random Number
1018bb10b79STom Joseph     if (!RAND_bytes(input.data() + sizeof(rcSessionID) + sizeof(bmcSessionID) +
1028bb10b79STom Joseph                     cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN,
1038bb10b79STom Joseph                     cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN))
1048bb10b79STom Joseph     {
1058bb10b79STom Joseph         response->rmcpStatusCode =
1068bb10b79STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INSUFFICIENT_RESOURCE);
1078bb10b79STom Joseph         return outPayload;
1088bb10b79STom Joseph     }
1098bb10b79STom Joseph 
1108bb10b79STom Joseph     // Copy the Managed System Random Number to the Authentication Algorithm
1118bb10b79STom Joseph     std::copy_n(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN,
1128bb10b79STom Joseph                 authAlgo->bmcRandomNum.begin());
1138bb10b79STom Joseph     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
1148bb10b79STom Joseph 
1158bb10b79STom Joseph     // Managed System GUID
1168bb10b79STom Joseph     auto guid = getSystemGUID();
1178bb10b79STom Joseph     std::copy_n(guid.data(), guid.size(), iter);
1188bb10b79STom Joseph     std::advance(iter, BMC_GUID_LEN);
1198bb10b79STom Joseph 
1208bb10b79STom Joseph     // Requested Privilege Level
1218bb10b79STom Joseph     session->curPrivLevel = static_cast<session::Privilege>
1228bb10b79STom Joseph                             (request->req_max_privilege_level);
1238bb10b79STom Joseph     std::copy_n(&(request->req_max_privilege_level),
1248bb10b79STom Joseph                 sizeof(request->req_max_privilege_level), iter);
1258bb10b79STom Joseph     std::advance(iter, sizeof(request->req_max_privilege_level));
1268bb10b79STom Joseph 
1278bb10b79STom Joseph     // Set Max Privilege to ADMIN
1288bb10b79STom Joseph     session->maxPrivLevel = session::Privilege::ADMIN;
1298bb10b79STom Joseph 
1308bb10b79STom Joseph     // User Name Length Byte
1318bb10b79STom Joseph     std::copy_n(&(request->user_name_len), sizeof(request->user_name_len),
1328bb10b79STom Joseph                 iter);
1338bb10b79STom Joseph 
1348bb10b79STom Joseph     // Generate Key Exchange Authentication Code - RAKP2
1358bb10b79STom Joseph     auto output = authAlgo->generateHMAC(input);
1368bb10b79STom Joseph 
1378bb10b79STom Joseph     response->messageTag = request->messageTag;
1388bb10b79STom Joseph     response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
1398bb10b79STom Joseph     response->reserved = 0;
1408bb10b79STom Joseph     response->remoteConsoleSessionID = rcSessionID ;
1418bb10b79STom Joseph 
1428bb10b79STom Joseph     // Copy Managed System Random Number to the Response
1438bb10b79STom Joseph     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
1448bb10b79STom Joseph               response->managed_system_random_number);
1458bb10b79STom Joseph 
1468bb10b79STom Joseph     // Copy System GUID to the Response
1478bb10b79STom Joseph     std::copy_n(guid.data(), guid.size(), response->managed_system_guid);
1488bb10b79STom Joseph 
1498bb10b79STom Joseph     // Insert the HMAC output into the payload
1508bb10b79STom Joseph     outPayload.insert(outPayload.end(), output.begin(), output.end());
1518bb10b79STom Joseph 
1528bb10b79STom Joseph     std::cout << "<< RAKP12\n";
1538bb10b79STom Joseph     return outPayload;
1548bb10b79STom Joseph }
1558bb10b79STom Joseph 
1568bb10b79STom Joseph } // namespace command
157