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