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