1 #include "config.h" 2 3 #include "rakp12.hpp" 4 5 #include "comm_module.hpp" 6 #include "endian.hpp" 7 #include "guid.hpp" 8 #include "sessions_manager.hpp" 9 10 #include <openssl/rand.h> 11 12 #include <ipmid/types.hpp> 13 #include <phosphor-logging/lg2.hpp> 14 15 #include <algorithm> 16 #include <cstring> 17 #include <iomanip> 18 19 namespace command 20 { 21 22 bool isChannelAccessModeEnabled(const uint8_t accessMode) 23 { 24 return accessMode != 25 static_cast<uint8_t>(ipmi::EChannelAccessMode::disabled); 26 } 27 28 void logInvalidLoginRedfishEvent(const std::string& journalMsg, 29 const std::optional<std::string>& messageArgs) 30 { 31 static constexpr std::string_view openBMCMessageRegistryVersion = "0.1."; 32 std::string messageID = "OpenBMC." + 33 std::string(openBMCMessageRegistryVersion) + 34 "InvalidLoginAttempted"; 35 lg2::error( 36 "message: {MSG}, id: {REDFISH_MESSAGE_ID}, args: {REDFISH_MESSAGE_ARGS}", 37 "MSG", journalMsg, "REDFISH_MESSAGE_ID", messageID, 38 "REDFISH_MESSAGE_ARGS", messageArgs.value()); 39 } 40 std::vector<uint8_t> RAKP12(const std::vector<uint8_t>& inPayload, 41 std::shared_ptr<message::Handler>& /* handler */) 42 { 43 auto request = reinterpret_cast<const RAKP1request*>(inPayload.data()); 44 // verify inPayload minimum size 45 if (inPayload.size() < (sizeof(*request) - userNameMaxLen)) 46 { 47 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 48 return errorPayload; 49 } 50 51 std::vector<uint8_t> outPayload(sizeof(RAKP2response)); 52 auto response = reinterpret_cast<RAKP2response*>(outPayload.data()); 53 54 // Session ID zero is reserved for Session Setup 55 if (endian::from_ipmi(request->managedSystemSessionID) == 56 session::sessionZero) 57 { 58 lg2::info("RAKP12: BMC invalid Session ID"); 59 response->rmcpStatusCode = 60 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID); 61 return outPayload; 62 } 63 64 std::shared_ptr<session::Session> session; 65 try 66 { 67 session = session::Manager::get().getSession( 68 endian::from_ipmi(request->managedSystemSessionID)); 69 } 70 catch (const std::exception& e) 71 { 72 lg2::error("RAKP12 : session not found: {ERROR}", "ERROR", e); 73 response->rmcpStatusCode = 74 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID); 75 return outPayload; 76 } 77 78 auto rakp1Size = sizeof(RAKP1request) - 79 (userNameMaxLen - request->user_name_len); 80 81 std::string message = "Invalid login attempted via RCMPP interface "; 82 // Validate user name length in the message 83 if (request->user_name_len > userNameMaxLen || 84 inPayload.size() != rakp1Size) 85 { 86 response->rmcpStatusCode = 87 static_cast<uint8_t>(RAKP_ReturnCode::INVALID_NAME_LENGTH); 88 logInvalidLoginRedfishEvent(message); 89 return outPayload; 90 } 91 92 session->userName.assign(request->user_name, request->user_name_len); 93 94 // Update transaction time 95 session->updateLastTransactionTime(); 96 97 auto rcSessionID = endian::to_ipmi(session->getRCSessionID()); 98 auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID()); 99 auto authAlgo = session->getAuthAlgo(); 100 101 /* 102 * Generate Key Authentication Code - RAKP 2 103 * 104 * 1) Remote Console Session ID - 4 bytes 105 * 2) Managed System Session ID - 4 bytes 106 * 3) Remote Console Random Number - 16 bytes 107 * 4) Managed System Random Number - 16 bytes 108 * 5) Managed System GUID - 16 bytes 109 * 6) Requested Privilege Level - 1 byte 110 * 7) User Name Length Byte - 1 byte (0 for 'null' username) 111 * 8) User Name - variable (absent for 'null' username) 112 */ 113 114 std::vector<uint8_t> input; 115 input.resize(sizeof(rcSessionID) + sizeof(bmcSessionID) + 116 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN + 117 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN + BMC_GUID_LEN + 118 sizeof(request->req_max_privilege_level) + 119 sizeof(request->user_name_len) + session->userName.size()); 120 121 auto iter = input.begin(); 122 123 // Remote Console Session ID 124 std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID), 125 iter); 126 std::advance(iter, sizeof(rcSessionID)); 127 128 // Managed System Session ID 129 std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID), 130 iter); 131 std::advance(iter, sizeof(bmcSessionID)); 132 133 // Copy the Remote Console Random Number from the RAKP1 request to the 134 // Authentication Algorithm 135 std::copy_n( 136 reinterpret_cast<const uint8_t*>(request->remote_console_random_number), 137 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN, 138 authAlgo->rcRandomNum.begin()); 139 140 std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter); 141 std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN); 142 143 // Generate the Managed System Random Number 144 if (!RAND_bytes(input.data() + sizeof(rcSessionID) + sizeof(bmcSessionID) + 145 cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN, 146 cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN)) 147 { 148 response->rmcpStatusCode = 149 static_cast<uint8_t>(RAKP_ReturnCode::INSUFFICIENT_RESOURCE); 150 return outPayload; 151 } 152 // As stated in Set Session Privilege Level command in IPMI Spec, when 153 // creating a session through Activate command / RAKP 1 message, it must 154 // be established with USER privilege as well as all other sessions are 155 // initially set to USER privilege, regardless of the requested maximum 156 // privilege. 157 if (!(static_cast<session::Privilege>(request->req_max_privilege_level & 158 session::reqMaxPrivMask) > 159 session::Privilege::CALLBACK)) 160 { 161 response->rmcpStatusCode = 162 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_ROLE_PRIV); 163 return outPayload; 164 } 165 session->currentPrivilege(static_cast<uint8_t>(session::Privilege::USER)); 166 167 session->reqMaxPrivLevel = 168 static_cast<session::Privilege>(request->req_max_privilege_level); 169 if (request->user_name_len == 0) 170 { 171 // Bail out, if user name is not specified. 172 // Yes, NULL user name is not supported for security reasons. 173 response->rmcpStatusCode = 174 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME); 175 logInvalidLoginRedfishEvent(message); 176 return outPayload; 177 } 178 179 // Perform user name based lookup 180 std::string userName(request->user_name, request->user_name_len); 181 ipmi::SecureString passwd; 182 uint8_t userId = ipmi::ipmiUserGetUserId(userName); 183 if (userId == ipmi::invalidUserId) 184 { 185 response->rmcpStatusCode = 186 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME); 187 logInvalidLoginRedfishEvent(message); 188 return outPayload; 189 } 190 // check user is enabled before proceeding. 191 bool userEnabled = false; 192 ipmi::ipmiUserCheckEnabled(userId, userEnabled); 193 if (!userEnabled) 194 { 195 response->rmcpStatusCode = 196 static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE); 197 logInvalidLoginRedfishEvent(message); 198 return outPayload; 199 } 200 // Get the user password for RAKP message authenticate 201 passwd = ipmi::ipmiUserGetPassword(userName); 202 if (passwd.empty()) 203 { 204 response->rmcpStatusCode = 205 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME); 206 logInvalidLoginRedfishEvent(message); 207 return outPayload; 208 } 209 #ifdef PAM_AUTHENTICATE 210 // Check whether user is already locked for failed attempts 211 if (!ipmi::ipmiUserPamAuthenticate(userName, passwd)) 212 { 213 lg2::error( 214 "Authentication failed - user already locked out, user id: {ID}", 215 "ID", userId); 216 217 response->rmcpStatusCode = 218 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME); 219 logInvalidLoginRedfishEvent(message); 220 return outPayload; 221 } 222 #endif 223 224 uint8_t chNum = static_cast<uint8_t>(getInterfaceIndex()); 225 // Get channel based access information 226 if ((ipmi::ipmiUserGetPrivilegeAccess( 227 userId, chNum, session->sessionUserPrivAccess) != IPMI_CC_OK) || 228 (ipmi::getChannelAccessData(chNum, session->sessionChannelAccess) != 229 IPMI_CC_OK)) 230 { 231 response->rmcpStatusCode = 232 static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE); 233 logInvalidLoginRedfishEvent(message); 234 return outPayload; 235 } 236 if (!isChannelAccessModeEnabled(session->sessionChannelAccess.accessMode)) 237 { 238 lg2::error("Channel access mode disabled."); 239 response->rmcpStatusCode = 240 static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE); 241 logInvalidLoginRedfishEvent(message); 242 return outPayload; 243 } 244 if (session->sessionUserPrivAccess.privilege > 245 static_cast<uint8_t>(session::Privilege::OEM)) 246 { 247 response->rmcpStatusCode = 248 static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE); 249 logInvalidLoginRedfishEvent(message); 250 return outPayload; 251 } 252 session->channelNum(chNum); 253 session->userID(userId); 254 // minimum privilege of Channel / User / session::privilege::USER 255 // has to be used as session current privilege level 256 uint8_t minPriv = 0; 257 if (session->sessionChannelAccess.privLimit < 258 session->sessionUserPrivAccess.privilege) 259 { 260 minPriv = session->sessionChannelAccess.privLimit; 261 } 262 else 263 { 264 minPriv = session->sessionUserPrivAccess.privilege; 265 } 266 if (session->currentPrivilege() > minPriv) 267 { 268 session->currentPrivilege(static_cast<uint8_t>(minPriv)); 269 } 270 // For username / privilege lookup, fail with UNAUTH_NAME, if requested 271 // max privilege does not match user privilege 272 if (((request->req_max_privilege_level & userNameOnlyLookupMask) == 273 userNamePrivLookup) && 274 ((request->req_max_privilege_level & session::reqMaxPrivMask) != 275 session->sessionUserPrivAccess.privilege)) 276 { 277 lg2::info("Username/Privilege lookup failed for requested privilege"); 278 response->rmcpStatusCode = 279 static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME); 280 281 logInvalidLoginRedfishEvent(message); 282 return outPayload; 283 } 284 285 std::fill(authAlgo->userKey.data(), 286 authAlgo->userKey.data() + authAlgo->userKey.size(), 0); 287 std::copy_n(passwd.c_str(), passwd.size(), authAlgo->userKey.data()); 288 289 // Copy the Managed System Random Number to the Authentication Algorithm 290 std::copy_n(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN, 291 authAlgo->bmcRandomNum.begin()); 292 std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN); 293 294 // Managed System GUID 295 const Guid& guid = command::getSystemGUID(); 296 std::copy_n(guid.data(), guid.size(), iter); 297 std::advance(iter, BMC_GUID_LEN); 298 299 // Requested Privilege Level 300 std::copy_n(&(request->req_max_privilege_level), 301 sizeof(request->req_max_privilege_level), iter); 302 std::advance(iter, sizeof(request->req_max_privilege_level)); 303 304 // User Name Length Byte 305 std::copy_n(&(request->user_name_len), sizeof(request->user_name_len), 306 iter); 307 std::advance(iter, sizeof(request->user_name_len)); 308 309 std::copy_n(session->userName.data(), session->userName.size(), iter); 310 311 // Generate Key Exchange Authentication Code - RAKP2 312 auto output = authAlgo->generateHMAC(input); 313 314 response->messageTag = request->messageTag; 315 response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR); 316 response->reserved = 0; 317 response->remoteConsoleSessionID = rcSessionID; 318 319 // Copy Managed System Random Number to the Response 320 std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(), 321 response->managed_system_random_number); 322 323 // Copy System GUID to the Response 324 std::copy_n(guid.data(), guid.size(), response->managed_system_guid); 325 326 // Insert the HMAC output into the payload 327 outPayload.insert(outPayload.end(), output.begin(), output.end()); 328 return outPayload; 329 } 330 331 } // namespace command 332