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