blob: d29582221e7a2235f53a4f087a76497f95e63114 [file] [log] [blame]
Kuiying Wang8f706212020-12-16 18:59:24 +08001/*
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
30namespace bios_config_pwd
31{
32using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
34
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053035uint8_t
36 Password::convertUnicode(const std::string& pwd,
37 std::array<uint16_t, maxPasswordLen>& unicodePwd)
38{
39 if (pwd.size() > unicodePwd.size())
40 {
41 phosphor::logging::log<phosphor::logging::level::DEBUG>(
42 "password size exceeds unicodePwd array size");
43 throw InternalFailure();
44 }
45
46 for (std::string::size_type i = 0; i < pwd.size(); i++)
47 {
48 unicodePwd[i] = pwd[i];
49 }
50 unicodePwd[pwd.size()] = 0;
51
52 return (pwd.size() * sizeof(uint16_t) + sizeof(uint16_t));
53}
54
55bool Password::isMatch(const std::array<uint8_t, maxHashSize>& expected,
56 const std::array<uint8_t, maxSeedSize>& seed,
Kuiying Wang8f706212020-12-16 18:59:24 +080057 const std::string rawData, const std::string algo)
58{
59 phosphor::logging::log<phosphor::logging::level::ERR>("isMatch");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053060
61 if (algo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +080062 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053063 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
64 unsigned int hashLen = 0;
65
66 std::array<uint16_t, maxPasswordLen> unicodePwd = {0};
67 uint8_t unicodePwdLength = convertUnicode(rawData, unicodePwd);
68
69 if (HMAC(EVP_sha256(), seed.data(), seed.size(),
70 reinterpret_cast<const unsigned char*>(unicodePwd.data()),
71 unicodePwdLength, output.data(), &hashLen) == NULL)
Kuiying Wang8f706212020-12-16 18:59:24 +080072 {
73 phosphor::logging::log<phosphor::logging::level::ERR>(
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053074 "Generate HMAC_SHA256 Integrity Check Value failed");
Kuiying Wang8f706212020-12-16 18:59:24 +080075 throw InternalFailure();
76 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053077
78 int cmp;
79 cmp = std::memcmp(output.data(), expected.data(),
80 output.size() * sizeof(uint8_t));
81 if (cmp == 0)
Kuiying Wang8f706212020-12-16 18:59:24 +080082 {
83 return true;
84 }
85 else
86 {
87 return false;
88 }
89 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053090 if (algo == "SHA384")
91 {
92 std::array<uint8_t, SHA384_DIGEST_LENGTH> output;
93 unsigned int hashLen = 0;
94
95 std::array<uint16_t, maxPasswordLen> unicodePwd = {0};
96 uint8_t unicodePwdLength = convertUnicode(rawData, unicodePwd);
97
98 if (HMAC(EVP_sha384(), seed.data(), seed.size(),
99 reinterpret_cast<const unsigned char*>(unicodePwd.data()),
100 unicodePwdLength, output.data(), &hashLen) == NULL)
101 {
102 phosphor::logging::log<phosphor::logging::level::ERR>(
103 "Generate HMAC_SHA384 Integrity Check Value failed");
104 throw InternalFailure();
105 }
106
107 int cmp;
108 cmp = std::memcmp(output.data(), expected.data(),
109 output.size() * sizeof(uint8_t));
110 if (cmp == 0)
111 {
112 return true;
113 }
114 else
115 {
116 return false;
117 }
118 }
119
Kuiying Wang8f706212020-12-16 18:59:24 +0800120 return false;
121}
122
123void Password::verifyPassword(std::string userName, std::string currentPassword,
124 std::string newPassword)
125{
126 if (fs::exists(seedFile.c_str()))
127 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530128 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
129 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
130 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +0800131 std::string hashAlgo = "";
132 try
133 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530134 nlohmann::json json = nullptr;
Kuiying Wang8f706212020-12-16 18:59:24 +0800135 std::ifstream ifs(seedFile.c_str());
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530136 if (ifs.is_open())
137 {
138 try
139 {
140 json = nlohmann::json::parse(ifs, nullptr, false);
141 }
142 catch (const nlohmann::json::parse_error& e)
143 {
144 phosphor::logging::log<phosphor::logging::level::ERR>(
145 e.what());
146 throw InternalFailure();
147 }
148
149 if (json.is_discarded())
150 {
151 return;
152 }
153 orgUsrPwdHash = json["UserPwdHash"];
154 orgAdminPwdHash = json["AdminPwdHash"];
155 seed = json["Seed"];
156 hashAlgo = json["HashAlgo"];
157 }
158 else
159 {
160 return;
161 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800162 }
163 catch (nlohmann::detail::exception& e)
164 {
165 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
166 throw InternalFailure();
167 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530168 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800169 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530170 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800171 {
172 throw InvalidCurrentPassword();
173 }
174 }
175 else
176 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530177 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800178 {
179 throw InvalidCurrentPassword();
180 }
181 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530182 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800183 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530184 std::array<uint16_t, maxPasswordLen> unicodePwd;
185 uint8_t unicodePwdlength = 0;
Kuiying Wang8f706212020-12-16 18:59:24 +0800186 unsigned int mdLen = 0;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530187 unicodePwdlength = convertUnicode(newPassword, unicodePwd);
188 mNewPwdHash.fill(0);
189
190 if (HMAC(EVP_sha256(), seed.data(), seed.size(),
191 reinterpret_cast<const unsigned char*>(unicodePwd.data()),
192 unicodePwdlength, mNewPwdHash.data(), &mdLen) == NULL)
Kuiying Wang8f706212020-12-16 18:59:24 +0800193 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800194 throw InternalFailure();
195 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800196 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530197 if (hashAlgo == "SHA384")
198 {
199 std::array<uint16_t, maxPasswordLen> unicodePwd;
200 uint8_t unicodePwdlength = 0;
201 unsigned int mdLen = 0;
202 unicodePwdlength = convertUnicode(newPassword, unicodePwd);
203 mNewPwdHash.fill(0);
Kuiying Wang8f706212020-12-16 18:59:24 +0800204
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530205 if (HMAC(EVP_sha384(), seed.data(), seed.size(),
206 reinterpret_cast<const unsigned char*>(unicodePwd.data()),
207 unicodePwdlength, mNewPwdHash.data(), &mdLen) == NULL)
208 {
209 throw InternalFailure();
210 }
211 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800212 return;
213 }
214 throw InternalFailure();
215}
216void Password::changePassword(std::string userName, std::string currentPassword,
217 std::string newPassword)
218{
219 phosphor::logging::log<phosphor::logging::level::DEBUG>(
220 "BIOS config changePassword");
221 verifyPassword(userName, currentPassword, newPassword);
222
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530223 std::ifstream fs(seedFile.c_str());
224 nlohmann::json json = nullptr;
225
226 if (fs.is_open())
Kuiying Wang8f706212020-12-16 18:59:24 +0800227 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530228 try
Kuiying Wang8f706212020-12-16 18:59:24 +0800229 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530230 json = nlohmann::json::parse(fs, nullptr, false);
Kuiying Wang8f706212020-12-16 18:59:24 +0800231 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530232 catch (const nlohmann::json::parse_error& e)
Kuiying Wang8f706212020-12-16 18:59:24 +0800233 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530234 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
235 throw InternalFailure();
Kuiying Wang8f706212020-12-16 18:59:24 +0800236 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530237
238 if (json.is_discarded())
239 {
240 throw InternalFailure();
241 }
242 json["AdminPwdHash"] = mNewPwdHash;
243 json["IsAdminPwdChanged"] = true;
244
245 std::ofstream ofs(seedFile.c_str(), std::ios::out);
246 const auto& writeData = json.dump();
247 ofs << writeData;
248 ofs.close();
Kuiying Wang8f706212020-12-16 18:59:24 +0800249 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530250 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800251 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530252 phosphor::logging::log<phosphor::logging::level::DEBUG>(
253 "Cannot open file stream");
Kuiying Wang8f706212020-12-16 18:59:24 +0800254 throw InternalFailure();
255 }
256}
257Password::Password(sdbusplus::asio::object_server& objectServer,
258 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
259 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
260 *systemBus, objectPathPwd),
261 objServer(objectServer), systemBus(systemBus)
262{
263 phosphor::logging::log<phosphor::logging::level::DEBUG>(
264 "BIOS config password is runing");
265 try
266 {
267 fs::path biosDir(BIOS_PERSIST_PATH);
268 fs::create_directories(biosDir);
Kuiying Wang8f706212020-12-16 18:59:24 +0800269 seedFile = biosDir / biosSeedFile;
270 }
271 catch (const fs::filesystem_error& e)
272 {
273 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
274 throw InternalFailure();
275 }
276}
277
278} // namespace bios_config_pwd
279
280int main()
281{
282 boost::asio::io_service io;
283 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
284
285 systemBus->request_name(bios_config_pwd::servicePwd);
286 sdbusplus::asio::object_server objectServer(systemBus);
287 bios_config_pwd::Password password(objectServer, systemBus);
288
289 io.run();
290 return 0;
291}