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