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