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