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" 1150fb50a9STom Joseph 1250fb50a9STom Joseph namespace command 1350fb50a9STom Joseph { 1450fb50a9STom Joseph 1550fb50a9STom Joseph std::vector<uint8_t> RAKP34(std::vector<uint8_t>& inPayload, 1650fb50a9STom Joseph const message::Handler& handler) 1750fb50a9STom Joseph { 1850fb50a9STom Joseph std::cout << ">> RAKP34\n"; 1950fb50a9STom Joseph 2050fb50a9STom Joseph std::vector<uint8_t> outPayload(sizeof(RAKP4response)); 2150fb50a9STom Joseph auto request = reinterpret_cast<RAKP3request*>(inPayload.data()); 2250fb50a9STom Joseph auto response = reinterpret_cast<RAKP4response*>(outPayload.data()); 2350fb50a9STom Joseph 2450fb50a9STom Joseph // Check if the RAKP3 Payload Length is as expected 2550fb50a9STom Joseph if(inPayload.size() != sizeof(RAKP3request)) 2650fb50a9STom Joseph { 2750fb50a9STom Joseph std::cerr << "RAKP34: Invalid RAKP3 request\n"; 2850fb50a9STom Joseph response->rmcpStatusCode = 2950fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE); 3050fb50a9STom Joseph return outPayload; 3150fb50a9STom Joseph } 3250fb50a9STom Joseph 3350fb50a9STom Joseph // Session ID zero is reserved for Session Setup 3450fb50a9STom Joseph if(endian::from_ipmi(request->managedSystemSessionID) == 3550fb50a9STom Joseph session::SESSION_ZERO) 3650fb50a9STom Joseph { 3750fb50a9STom Joseph std::cerr << "RAKP34: BMC invalid Session ID\n"; 3850fb50a9STom Joseph response->rmcpStatusCode = 3950fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID); 4050fb50a9STom Joseph return outPayload; 4150fb50a9STom Joseph } 4250fb50a9STom Joseph 4350fb50a9STom Joseph std::shared_ptr<session::Session> session; 4450fb50a9STom Joseph try 4550fb50a9STom Joseph { 4650fb50a9STom Joseph session = (std::get<session::Manager&>(singletonPool).getSession( 4750fb50a9STom Joseph endian::from_ipmi(request->managedSystemSessionID))).lock(); 4850fb50a9STom Joseph } 4950fb50a9STom Joseph catch (std::exception& e) 5050fb50a9STom Joseph { 5150fb50a9STom Joseph std::cerr << e.what() << "\n"; 5250fb50a9STom Joseph response->rmcpStatusCode = 5350fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID); 5450fb50a9STom Joseph return outPayload; 5550fb50a9STom Joseph } 5650fb50a9STom Joseph 5750fb50a9STom Joseph session->updateLastTransactionTime(); 5850fb50a9STom Joseph 5950fb50a9STom Joseph auto authAlgo = session->getAuthAlgo(); 6050fb50a9STom Joseph /* 6150fb50a9STom Joseph * Key Authentication Code - RAKP 3 6250fb50a9STom Joseph * 6350fb50a9STom Joseph * 1) Managed System Random Number - 16 bytes 6450fb50a9STom Joseph * 2) Remote Console Session ID - 4 bytes 6550fb50a9STom Joseph * 3) Session Privilege Level - 1 byte 6650fb50a9STom Joseph * 4) User Name Length Byte - 1 byte (0 for 'null' username) 6750fb50a9STom Joseph * 5) User Name - variable (absent for 'null' username) 6850fb50a9STom Joseph */ 6950fb50a9STom Joseph 7050fb50a9STom Joseph // Remote Console Session ID 7150fb50a9STom Joseph auto rcSessionID = endian::to_ipmi(session->getRCSessionID()); 7250fb50a9STom Joseph 7350fb50a9STom Joseph // Session Privilege Level 7450fb50a9STom Joseph auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel); 7550fb50a9STom Joseph 7650fb50a9STom Joseph // User Name Length Byte 7750fb50a9STom Joseph uint8_t userLength = 0; 7850fb50a9STom Joseph 7950fb50a9STom Joseph std::vector<uint8_t> input; 8050fb50a9STom Joseph input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + 8150fb50a9STom Joseph sizeof(rcSessionID) + sizeof(sessPrivLevel) + 8250fb50a9STom Joseph sizeof(userLength)); 8350fb50a9STom Joseph 8450fb50a9STom Joseph auto iter = input.begin(); 8550fb50a9STom Joseph 8650fb50a9STom Joseph // Managed System Random Number 8750fb50a9STom Joseph std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(), 8850fb50a9STom Joseph iter); 8950fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN); 9050fb50a9STom Joseph 9150fb50a9STom Joseph // Remote Console Session ID 9250fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID), 9350fb50a9STom Joseph iter); 9450fb50a9STom Joseph std::advance(iter, sizeof(rcSessionID)); 9550fb50a9STom Joseph 9650fb50a9STom Joseph // Session Privilege Level 9750fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel), 9850fb50a9STom Joseph sizeof(sessPrivLevel), iter); 9950fb50a9STom Joseph std::advance(iter, sizeof(sessPrivLevel)); 10050fb50a9STom Joseph 10150fb50a9STom Joseph // User Name Length Byte 10250fb50a9STom Joseph std::copy_n(&userLength, sizeof(userLength), iter); 10350fb50a9STom Joseph 10450fb50a9STom Joseph // Generate Key Exchange Authentication Code - RAKP2 10550fb50a9STom Joseph auto output = authAlgo->generateHMAC(input); 10650fb50a9STom Joseph 10750fb50a9STom Joseph if (std::memcmp(output.data(), request->keyExchangeAuthCode, 10850fb50a9STom Joseph output.size())) 10950fb50a9STom Joseph { 11050fb50a9STom Joseph std::cerr << "Mismatch in HMAC sent by remote console\n"; 11150fb50a9STom Joseph 11250fb50a9STom Joseph response->messageTag = request->messageTag; 11350fb50a9STom Joseph response->rmcpStatusCode = static_cast<uint8_t> 11450fb50a9STom Joseph (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE); 11550fb50a9STom Joseph response->reserved = 0; 11650fb50a9STom Joseph response->remoteConsoleSessionID = rcSessionID; 11750fb50a9STom Joseph 11850fb50a9STom Joseph //close the session 11950fb50a9STom Joseph std::get<session::Manager&>(singletonPool).stopSession( 12050fb50a9STom Joseph session->getBMCSessionID()); 12150fb50a9STom Joseph 12250fb50a9STom Joseph return outPayload; 12350fb50a9STom Joseph } 12450fb50a9STom Joseph 12550fb50a9STom Joseph /* 12650fb50a9STom Joseph * Session Integrity Key 12750fb50a9STom Joseph * 12850fb50a9STom Joseph * 1) Remote Console Random Number - 16 bytes 12950fb50a9STom Joseph * 2) Managed System Random Number - 16 bytes 13050fb50a9STom Joseph * 3) Session Privilege Level - 1 byte 13150fb50a9STom Joseph * 4) User Name Length Byte - 1 byte (0 for 'null' username) 13250fb50a9STom Joseph * 5) User Name - variable (absent for 'null' username) 13350fb50a9STom Joseph */ 13450fb50a9STom Joseph 13550fb50a9STom Joseph input.clear(); 13650fb50a9STom Joseph 13750fb50a9STom Joseph input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN + 13850fb50a9STom Joseph cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + 13950fb50a9STom Joseph sizeof(sessPrivLevel) + sizeof(userLength)); 14050fb50a9STom Joseph iter = input.begin(); 14150fb50a9STom Joseph 14250fb50a9STom Joseph // Remote Console Random Number 14350fb50a9STom Joseph std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), 14450fb50a9STom Joseph iter); 14550fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN); 14650fb50a9STom Joseph 14750fb50a9STom Joseph // Managed Console Random Number 14850fb50a9STom Joseph std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(), 14950fb50a9STom Joseph iter); 15050fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN); 15150fb50a9STom Joseph 15250fb50a9STom Joseph // Session Privilege Level 15350fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel), 15450fb50a9STom Joseph sizeof(sessPrivLevel), iter); 15550fb50a9STom Joseph std::advance(iter, sizeof(sessPrivLevel)); 15650fb50a9STom Joseph 15750fb50a9STom Joseph // User Name Length Byte 15850fb50a9STom Joseph std::copy_n(&userLength, sizeof(userLength), iter); 15950fb50a9STom Joseph 16050fb50a9STom Joseph // Generate Session Integrity Key 16150fb50a9STom Joseph auto sikOutput = authAlgo->generateHMAC(input); 16250fb50a9STom Joseph 16350fb50a9STom Joseph // Update the SIK in the Authentication Algo Interface 16450fb50a9STom Joseph authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(), 16550fb50a9STom Joseph sikOutput.begin(), sikOutput.end()); 16650fb50a9STom Joseph 16750fb50a9STom Joseph /* 16850fb50a9STom Joseph * Integrity Check Value 16950fb50a9STom Joseph * 17050fb50a9STom Joseph * 1) Remote Console Random Number - 16 bytes 17150fb50a9STom Joseph * 2) Managed System Session ID - 4 bytes 17250fb50a9STom Joseph * 3) Managed System GUID - 16 bytes 17350fb50a9STom Joseph */ 17450fb50a9STom Joseph 17550fb50a9STom Joseph // Get Managed System Session ID 17650fb50a9STom Joseph auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID()); 17750fb50a9STom Joseph 17850fb50a9STom Joseph input.clear(); 17950fb50a9STom Joseph 18050fb50a9STom Joseph input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN + 18150fb50a9STom Joseph sizeof(bmcSessionID) + BMC_GUID_LEN); 18250fb50a9STom Joseph iter = input.begin(); 18350fb50a9STom Joseph 18450fb50a9STom Joseph // Remote Console Random Number 18550fb50a9STom Joseph std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), 18650fb50a9STom Joseph iter); 18750fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN); 18850fb50a9STom Joseph 18950fb50a9STom Joseph // Managed System Session ID 19050fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID), 19150fb50a9STom Joseph iter); 19250fb50a9STom Joseph std::advance(iter, sizeof(bmcSessionID)); 19350fb50a9STom Joseph 19450fb50a9STom Joseph // Managed System GUID 19550fb50a9STom Joseph auto guid = getSystemGUID(); 19650fb50a9STom Joseph std::copy_n(guid.data(), guid.size(), iter); 19750fb50a9STom Joseph 19850fb50a9STom Joseph // Integrity Check Value 19950fb50a9STom Joseph auto icv = authAlgo->generateICV(input); 20050fb50a9STom Joseph 20150fb50a9STom Joseph outPayload.resize(sizeof(RAKP4response)); 20250fb50a9STom Joseph 20350fb50a9STom Joseph response->messageTag = request->messageTag; 20450fb50a9STom Joseph response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR); 20550fb50a9STom Joseph response->reserved = 0; 20650fb50a9STom Joseph response->remoteConsoleSessionID = rcSessionID; 20750fb50a9STom Joseph 20850fb50a9STom Joseph // Insert the HMAC output into the payload 20950fb50a9STom Joseph outPayload.insert(outPayload.end(), icv.begin(), icv.end()); 21050fb50a9STom Joseph 211*818d0701STom Joseph // Set the Authentication Algorithm to RAKP_HMAC_SHA1 212*818d0701STom Joseph switch (authAlgo->intAlgo) 213*818d0701STom Joseph { 214*818d0701STom Joseph case cipher::integrity::Algorithms::HMAC_SHA1_96: 215*818d0701STom Joseph { 216*818d0701STom Joseph session->setIntegrityAlgo( 217*818d0701STom Joseph std::make_unique<cipher::integrity::AlgoSHA1>(sikOutput)); 218*818d0701STom Joseph break; 219*818d0701STom Joseph } 220*818d0701STom Joseph default: 221*818d0701STom Joseph break; 222*818d0701STom Joseph } 223*818d0701STom Joseph 22450fb50a9STom Joseph session->state = session::State::ACTIVE; 22550fb50a9STom Joseph 22650fb50a9STom Joseph std::cout << "<< RAKP34\n"; 22750fb50a9STom Joseph return outPayload; 22850fb50a9STom Joseph } 22950fb50a9STom Joseph 23050fb50a9STom Joseph } // namespace command 231