1 /* 2 // Copyright (c) 2020 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #include "password.hpp" 17 18 #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp" 19 #include "xyz/openbmc_project/Common/error.hpp" 20 21 #include <boost/algorithm/hex.hpp> 22 #include <boost/asio.hpp> 23 #include <phosphor-logging/elog-errors.hpp> 24 #include <sdbusplus/asio/connection.hpp> 25 #include <sdbusplus/asio/object_server.hpp> 26 27 #include <fstream> 28 #include <iostream> 29 30 namespace bios_config_pwd 31 { 32 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 33 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; 34 35 bool Password::isMatch(const std::string expected, const std::string seed, 36 const std::string rawData, const std::string algo) 37 { 38 phosphor::logging::log<phosphor::logging::level::ERR>("isMatch"); 39 if (algo == "SHA384") 40 { 41 phosphor::logging::log<phosphor::logging::level::ERR>("SHA384"); 42 std::vector<uint8_t> output(SHA384_DIGEST_LENGTH); 43 unsigned int mdLen = 0; 44 if (HMAC(EVP_sha384(), seed.c_str(), seed.length(), 45 reinterpret_cast<const unsigned char*>(rawData.c_str()), 46 rawData.length(), output.data(), &mdLen) == NULL) 47 { 48 phosphor::logging::log<phosphor::logging::level::ERR>( 49 "Generate HMAC_SHA384 Integrity Check Value failed"); 50 output.resize(0); 51 throw InternalFailure(); 52 } 53 phosphor::logging::log<phosphor::logging::level::ERR>(expected.c_str()); 54 std::string strOutput; 55 boost::algorithm::hex(output.begin(), output.end(), 56 std::back_inserter(strOutput)); 57 phosphor::logging::log<phosphor::logging::level::ERR>( 58 strOutput.c_str()); 59 if (expected == strOutput) 60 { 61 return true; 62 } 63 else 64 { 65 return false; 66 } 67 } 68 return false; 69 } 70 71 void Password::verifyPassword(std::string userName, std::string currentPassword, 72 std::string newPassword) 73 { 74 if (fs::exists(seedFile.c_str())) 75 { 76 std::string userPassword = ""; 77 std::string adminPassword = ""; 78 std::string seed = ""; 79 std::string hashAlgo = ""; 80 try 81 { 82 std::ifstream ifs(seedFile.c_str()); 83 nlohmann::json json; 84 ifs >> json; 85 userPassword = json["UserPwdHash"]; 86 adminPassword = json["AdminPwdHash"]; 87 seed = json["Seed"]; 88 hashAlgo = json["HashAlgo"]; 89 } 90 catch (nlohmann::detail::exception& e) 91 { 92 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 93 throw InternalFailure(); 94 } 95 if (userName == "Administrator") 96 { 97 if (!isMatch(adminPassword, seed, currentPassword, hashAlgo)) 98 { 99 throw InvalidCurrentPassword(); 100 } 101 } 102 else 103 { 104 if (!isMatch(userPassword, seed, currentPassword, hashAlgo)) 105 { 106 throw InvalidCurrentPassword(); 107 } 108 } 109 if (hashAlgo == "SHA384") 110 { 111 std::vector<uint8_t> output(SHA384_DIGEST_LENGTH); 112 unsigned int mdLen = 0; 113 if (HMAC( 114 EVP_sha384(), seed.c_str(), seed.length(), 115 reinterpret_cast<const unsigned char*>(newPassword.c_str()), 116 newPassword.length(), output.data(), &mdLen) == NULL) 117 { 118 phosphor::logging::log<phosphor::logging::level::ERR>( 119 "Generate HMAC_SHA384 Integrity Check Value failed"); 120 output.resize(0); 121 throw InternalFailure(); 122 } 123 std::string strOutput; 124 boost::algorithm::hex(output.begin(), output.end(), 125 std::back_inserter(strOutput)); 126 phosphor::logging::log<phosphor::logging::level::ERR>( 127 strOutput.c_str()); 128 mNewPassword = strOutput; 129 } 130 131 return; 132 } 133 throw InternalFailure(); 134 } 135 void Password::changePassword(std::string userName, std::string currentPassword, 136 std::string newPassword) 137 { 138 phosphor::logging::log<phosphor::logging::level::DEBUG>( 139 "BIOS config changePassword"); 140 verifyPassword(userName, currentPassword, newPassword); 141 142 try 143 { 144 nlohmann::json json; 145 json["UserName"] = userName; 146 json["CurrentPassword"] = currentPassword; 147 json["NewPassword"] = mNewPassword; 148 if (userName == "Administrator") 149 { 150 json["IsAdminPwdChanged"] = 1; 151 json["IsUserPwdChanged"] = 0; 152 } 153 else 154 { 155 json["IsAdminPwdChanged"] = 0; 156 json["IsUserPwdChanged"] = 1; 157 } 158 std::ofstream ofs(passwordFile.c_str(), std::ios::out); 159 ofs << std::setw(4) << json << std::endl; 160 } 161 catch (nlohmann::detail::exception& e) 162 { 163 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 164 throw InternalFailure(); 165 } 166 } 167 Password::Password(sdbusplus::asio::object_server& objectServer, 168 std::shared_ptr<sdbusplus::asio::connection>& systemBus) : 169 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password( 170 *systemBus, objectPathPwd), 171 objServer(objectServer), systemBus(systemBus) 172 { 173 phosphor::logging::log<phosphor::logging::level::DEBUG>( 174 "BIOS config password is runing"); 175 try 176 { 177 fs::path biosDir(BIOS_PERSIST_PATH); 178 fs::create_directories(biosDir); 179 passwordFile = biosDir / biosPasswordFile; 180 seedFile = biosDir / biosSeedFile; 181 } 182 catch (const fs::filesystem_error& e) 183 { 184 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 185 throw InternalFailure(); 186 } 187 } 188 189 } // namespace bios_config_pwd 190 191 int main() 192 { 193 boost::asio::io_service io; 194 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 195 196 systemBus->request_name(bios_config_pwd::servicePwd); 197 sdbusplus::asio::object_server objectServer(systemBus); 198 bios_config_pwd::Password password(objectServer, systemBus); 199 200 io.run(); 201 return 0; 202 } 203