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