150fb50a9STom Joseph #include "rakp34.hpp" 250fb50a9STom Joseph 350fb50a9STom Joseph #include <algorithm> 450fb50a9STom Joseph #include <cstring> 550fb50a9STom Joseph #include <iostream> 650fb50a9STom Joseph 750fb50a9STom Joseph #include "comm_module.hpp" 850fb50a9STom Joseph #include "endian.hpp" 950fb50a9STom Joseph #include "guid.hpp" 1050fb50a9STom Joseph #include "main.hpp" 11*9b307be6SVernon Mauery #include "rmcp.hpp" 1250fb50a9STom Joseph 1350fb50a9STom Joseph namespace command 1450fb50a9STom Joseph { 1550fb50a9STom Joseph 16ef02fb3dSTom Joseph void applyIntegrityAlgo(const uint32_t bmcSessionID) 17ef02fb3dSTom Joseph { 18ef02fb3dSTom Joseph auto session = (std::get<session::Manager&>(singletonPool).getSession( 19ef02fb3dSTom Joseph bmcSessionID)).lock(); 20ef02fb3dSTom Joseph 21ef02fb3dSTom Joseph auto authAlgo = session->getAuthAlgo(); 22ef02fb3dSTom Joseph 23ef02fb3dSTom Joseph switch (authAlgo->intAlgo) 24ef02fb3dSTom Joseph { 25ef02fb3dSTom Joseph case cipher::integrity::Algorithms::HMAC_SHA1_96: 26ef02fb3dSTom Joseph { 27ef02fb3dSTom Joseph session->setIntegrityAlgo( 28ef02fb3dSTom Joseph std::make_unique<cipher::integrity::AlgoSHA1>( 29ef02fb3dSTom Joseph authAlgo->sessionIntegrityKey)); 30ef02fb3dSTom Joseph break; 31ef02fb3dSTom Joseph } 32ef02fb3dSTom Joseph default: 33ef02fb3dSTom Joseph break; 34ef02fb3dSTom Joseph } 35ef02fb3dSTom Joseph } 36ef02fb3dSTom Joseph 374c766eb1STom Joseph void applyCryptAlgo(const uint32_t bmcSessionID) 384c766eb1STom Joseph { 394c766eb1STom Joseph auto session = (std::get<session::Manager&>(singletonPool).getSession( 404c766eb1STom Joseph bmcSessionID)).lock(); 414c766eb1STom Joseph 424c766eb1STom Joseph auto authAlgo = session->getAuthAlgo(); 434c766eb1STom Joseph 444c766eb1STom Joseph switch (authAlgo->cryptAlgo) 454c766eb1STom Joseph { 464c766eb1STom Joseph case cipher::crypt::Algorithms::AES_CBC_128: 474c766eb1STom Joseph { 48*9b307be6SVernon Mauery auto intAlgo = session->getIntegrityAlgo(); 49*9b307be6SVernon Mauery auto k2 = intAlgo->generateKn( 50*9b307be6SVernon Mauery authAlgo->sessionIntegrityKey, rmcp::const_2); 51*9b307be6SVernon Mauery session->setCryptAlgo( 52*9b307be6SVernon Mauery std::make_unique<cipher::crypt::AlgoAES128>(k2)); 534c766eb1STom Joseph break; 544c766eb1STom Joseph } 554c766eb1STom Joseph default: 564c766eb1STom Joseph break; 574c766eb1STom Joseph } 584c766eb1STom Joseph } 594c766eb1STom Joseph 6018a45e9dSTom Joseph std::vector<uint8_t> RAKP34(const std::vector<uint8_t>& inPayload, 6150fb50a9STom Joseph const message::Handler& handler) 6250fb50a9STom Joseph { 6350fb50a9STom Joseph std::cout << ">> RAKP34\n"; 6450fb50a9STom Joseph 6550fb50a9STom Joseph std::vector<uint8_t> outPayload(sizeof(RAKP4response)); 6618a45e9dSTom Joseph auto request = reinterpret_cast<const RAKP3request*>(inPayload.data()); 6750fb50a9STom Joseph auto response = reinterpret_cast<RAKP4response*>(outPayload.data()); 6850fb50a9STom Joseph 6950fb50a9STom Joseph // Check if the RAKP3 Payload Length is as expected 70*9b307be6SVernon Mauery if (inPayload.size() < sizeof(RAKP3request)) 7150fb50a9STom Joseph { 7250fb50a9STom Joseph std::cerr << "RAKP34: Invalid RAKP3 request\n"; 7350fb50a9STom Joseph response->rmcpStatusCode = 7450fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE); 7550fb50a9STom Joseph return outPayload; 7650fb50a9STom Joseph } 7750fb50a9STom Joseph 7850fb50a9STom Joseph // Session ID zero is reserved for Session Setup 7950fb50a9STom Joseph if(endian::from_ipmi(request->managedSystemSessionID) == 8050fb50a9STom Joseph session::SESSION_ZERO) 8150fb50a9STom Joseph { 8250fb50a9STom Joseph std::cerr << "RAKP34: BMC invalid Session ID\n"; 8350fb50a9STom Joseph response->rmcpStatusCode = 8450fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID); 8550fb50a9STom Joseph return outPayload; 8650fb50a9STom Joseph } 8750fb50a9STom Joseph 8850fb50a9STom Joseph std::shared_ptr<session::Session> session; 8950fb50a9STom Joseph try 9050fb50a9STom Joseph { 9150fb50a9STom Joseph session = (std::get<session::Manager&>(singletonPool).getSession( 9250fb50a9STom Joseph endian::from_ipmi(request->managedSystemSessionID))).lock(); 9350fb50a9STom Joseph } 9450fb50a9STom Joseph catch (std::exception& e) 9550fb50a9STom Joseph { 9650fb50a9STom Joseph std::cerr << e.what() << "\n"; 9750fb50a9STom Joseph response->rmcpStatusCode = 9850fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID); 9950fb50a9STom Joseph return outPayload; 10050fb50a9STom Joseph } 10150fb50a9STom Joseph 10250fb50a9STom Joseph session->updateLastTransactionTime(); 10350fb50a9STom Joseph 10450fb50a9STom Joseph auto authAlgo = session->getAuthAlgo(); 10550fb50a9STom Joseph /* 10650fb50a9STom Joseph * Key Authentication Code - RAKP 3 10750fb50a9STom Joseph * 10850fb50a9STom Joseph * 1) Managed System Random Number - 16 bytes 10950fb50a9STom Joseph * 2) Remote Console Session ID - 4 bytes 11050fb50a9STom Joseph * 3) Session Privilege Level - 1 byte 11150fb50a9STom Joseph * 4) User Name Length Byte - 1 byte (0 for 'null' username) 11250fb50a9STom Joseph * 5) User Name - variable (absent for 'null' username) 11350fb50a9STom Joseph */ 11450fb50a9STom Joseph 11550fb50a9STom Joseph // Remote Console Session ID 11650fb50a9STom Joseph auto rcSessionID = endian::to_ipmi(session->getRCSessionID()); 11750fb50a9STom Joseph 11850fb50a9STom Joseph // Session Privilege Level 11950fb50a9STom Joseph auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel); 12050fb50a9STom Joseph 12150fb50a9STom Joseph // User Name Length Byte 12250fb50a9STom Joseph uint8_t userLength = 0; 12350fb50a9STom Joseph 12450fb50a9STom Joseph std::vector<uint8_t> input; 12550fb50a9STom Joseph input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + 12650fb50a9STom Joseph sizeof(rcSessionID) + sizeof(sessPrivLevel) + 12750fb50a9STom Joseph sizeof(userLength)); 12850fb50a9STom Joseph 12950fb50a9STom Joseph auto iter = input.begin(); 13050fb50a9STom Joseph 13150fb50a9STom Joseph // Managed System Random Number 13250fb50a9STom Joseph std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(), 13350fb50a9STom Joseph iter); 13450fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN); 13550fb50a9STom Joseph 13650fb50a9STom Joseph // Remote Console Session ID 13750fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID), 13850fb50a9STom Joseph iter); 13950fb50a9STom Joseph std::advance(iter, sizeof(rcSessionID)); 14050fb50a9STom Joseph 14150fb50a9STom Joseph // Session Privilege Level 14250fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel), 14350fb50a9STom Joseph sizeof(sessPrivLevel), iter); 14450fb50a9STom Joseph std::advance(iter, sizeof(sessPrivLevel)); 14550fb50a9STom Joseph 14650fb50a9STom Joseph // User Name Length Byte 14750fb50a9STom Joseph std::copy_n(&userLength, sizeof(userLength), iter); 14850fb50a9STom Joseph 14950fb50a9STom Joseph // Generate Key Exchange Authentication Code - RAKP2 15050fb50a9STom Joseph auto output = authAlgo->generateHMAC(input); 15150fb50a9STom Joseph 152*9b307be6SVernon Mauery if (inPayload.size() != (sizeof(RAKP3request) + output.size()) || 153*9b307be6SVernon Mauery std::memcmp(output.data(), request+1, output.size())) 15450fb50a9STom Joseph { 15550fb50a9STom Joseph std::cerr << "Mismatch in HMAC sent by remote console\n"; 15650fb50a9STom Joseph 15750fb50a9STom Joseph response->messageTag = request->messageTag; 15850fb50a9STom Joseph response->rmcpStatusCode = static_cast<uint8_t> 15950fb50a9STom Joseph (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE); 16050fb50a9STom Joseph response->reserved = 0; 16150fb50a9STom Joseph response->remoteConsoleSessionID = rcSessionID; 16250fb50a9STom Joseph 16350fb50a9STom Joseph //close the session 16450fb50a9STom Joseph std::get<session::Manager&>(singletonPool).stopSession( 16550fb50a9STom Joseph session->getBMCSessionID()); 16650fb50a9STom Joseph 16750fb50a9STom Joseph return outPayload; 16850fb50a9STom Joseph } 16950fb50a9STom Joseph 17050fb50a9STom Joseph /* 17150fb50a9STom Joseph * Session Integrity Key 17250fb50a9STom Joseph * 17350fb50a9STom Joseph * 1) Remote Console Random Number - 16 bytes 17450fb50a9STom Joseph * 2) Managed System Random Number - 16 bytes 17550fb50a9STom Joseph * 3) Session Privilege Level - 1 byte 17650fb50a9STom Joseph * 4) User Name Length Byte - 1 byte (0 for 'null' username) 17750fb50a9STom Joseph * 5) User Name - variable (absent for 'null' username) 17850fb50a9STom Joseph */ 17950fb50a9STom Joseph 18050fb50a9STom Joseph input.clear(); 18150fb50a9STom Joseph 18250fb50a9STom Joseph input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN + 18350fb50a9STom Joseph cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + 18450fb50a9STom Joseph sizeof(sessPrivLevel) + sizeof(userLength)); 18550fb50a9STom Joseph iter = input.begin(); 18650fb50a9STom Joseph 18750fb50a9STom Joseph // Remote Console Random Number 18850fb50a9STom Joseph std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), 18950fb50a9STom Joseph iter); 19050fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN); 19150fb50a9STom Joseph 19250fb50a9STom Joseph // Managed Console Random Number 19350fb50a9STom Joseph std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(), 19450fb50a9STom Joseph iter); 19550fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN); 19650fb50a9STom Joseph 19750fb50a9STom Joseph // Session Privilege Level 19850fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel), 19950fb50a9STom Joseph sizeof(sessPrivLevel), iter); 20050fb50a9STom Joseph std::advance(iter, sizeof(sessPrivLevel)); 20150fb50a9STom Joseph 20250fb50a9STom Joseph // User Name Length Byte 20350fb50a9STom Joseph std::copy_n(&userLength, sizeof(userLength), iter); 20450fb50a9STom Joseph 20550fb50a9STom Joseph // Generate Session Integrity Key 20650fb50a9STom Joseph auto sikOutput = authAlgo->generateHMAC(input); 20750fb50a9STom Joseph 20850fb50a9STom Joseph // Update the SIK in the Authentication Algo Interface 20950fb50a9STom Joseph authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(), 21050fb50a9STom Joseph sikOutput.begin(), sikOutput.end()); 21150fb50a9STom Joseph 21250fb50a9STom Joseph /* 21350fb50a9STom Joseph * Integrity Check Value 21450fb50a9STom Joseph * 21550fb50a9STom Joseph * 1) Remote Console Random Number - 16 bytes 21650fb50a9STom Joseph * 2) Managed System Session ID - 4 bytes 21750fb50a9STom Joseph * 3) Managed System GUID - 16 bytes 21850fb50a9STom Joseph */ 21950fb50a9STom Joseph 22050fb50a9STom Joseph // Get Managed System Session ID 22150fb50a9STom Joseph auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID()); 22250fb50a9STom Joseph 22350fb50a9STom Joseph input.clear(); 22450fb50a9STom Joseph 22550fb50a9STom Joseph input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN + 22650fb50a9STom Joseph sizeof(bmcSessionID) + BMC_GUID_LEN); 22750fb50a9STom Joseph iter = input.begin(); 22850fb50a9STom Joseph 22950fb50a9STom Joseph // Remote Console Random Number 23050fb50a9STom Joseph std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), 23150fb50a9STom Joseph iter); 23250fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN); 23350fb50a9STom Joseph 23450fb50a9STom Joseph // Managed System Session ID 23550fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID), 23650fb50a9STom Joseph iter); 23750fb50a9STom Joseph std::advance(iter, sizeof(bmcSessionID)); 23850fb50a9STom Joseph 23950fb50a9STom Joseph // Managed System GUID 24083029cb8STom Joseph std::copy_n(cache::guid.data(), cache::guid.size(), iter); 24150fb50a9STom Joseph 24250fb50a9STom Joseph // Integrity Check Value 24350fb50a9STom Joseph auto icv = authAlgo->generateICV(input); 24450fb50a9STom Joseph 24550fb50a9STom Joseph outPayload.resize(sizeof(RAKP4response)); 24650fb50a9STom Joseph 24750fb50a9STom Joseph response->messageTag = request->messageTag; 24850fb50a9STom Joseph response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR); 24950fb50a9STom Joseph response->reserved = 0; 25050fb50a9STom Joseph response->remoteConsoleSessionID = rcSessionID; 25150fb50a9STom Joseph 25250fb50a9STom Joseph // Insert the HMAC output into the payload 25350fb50a9STom Joseph outPayload.insert(outPayload.end(), icv.begin(), icv.end()); 25450fb50a9STom Joseph 255ef02fb3dSTom Joseph // Set the Integrity Algorithm 256ef02fb3dSTom Joseph applyIntegrityAlgo(session->getBMCSessionID()); 257818d0701STom Joseph 2584c766eb1STom Joseph // Set the Confidentiality Algorithm 2594c766eb1STom Joseph applyCryptAlgo(session->getBMCSessionID()); 2604c766eb1STom Joseph 26150fb50a9STom Joseph session->state = session::State::ACTIVE; 26250fb50a9STom Joseph 26350fb50a9STom Joseph std::cout << "<< RAKP34\n"; 26450fb50a9STom Joseph return outPayload; 26550fb50a9STom Joseph } 26650fb50a9STom Joseph 26750fb50a9STom Joseph } // namespace command 268