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