blob: f780cc50fa0d6acfe5d4bf21717cc736666e3efa [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>
George Liu567a3cf2021-12-08 10:36:03 +080024#include <phosphor-logging/lg2.hpp>
Kuiying Wang8f706212020-12-16 18:59:24 +080025#include <sdbusplus/asio/connection.hpp>
26#include <sdbusplus/asio/object_server.hpp>
27
28#include <fstream>
29#include <iostream>
30
31namespace bios_config_pwd
32{
33using namespace sdbusplus::xyz::openbmc_project::Common::Error;
34using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
35
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053036bool Password::isMatch(const std::array<uint8_t, maxHashSize>& expected,
37 const std::array<uint8_t, maxSeedSize>& seed,
George Liu616f9222021-12-29 14:25:39 +080038 const std::string& rawData, const std::string& algo)
Kuiying Wang8f706212020-12-16 18:59:24 +080039{
George Liu567a3cf2021-12-08 10:36:03 +080040 lg2::error("isMatch");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053041
42 if (algo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +080043 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053044 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000045 unsigned int hashLen = SHA256_DIGEST_LENGTH;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053046
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000047 if (!PKCS5_PBKDF2_HMAC(
48 reinterpret_cast<const char*>(rawData.c_str()),
49 rawData.length() + 1,
50 reinterpret_cast<const unsigned char*>(seed.data()),
51 seed.size(), iterValue, EVP_sha256(), hashLen, output.data()))
Kuiying Wang8f706212020-12-16 18:59:24 +080052 {
George Liu567a3cf2021-12-08 10:36:03 +080053 lg2::error(
54 "Generate PKCS5_PBKDF2_HMAC_SHA256 Integrity Check Value failed");
Kuiying Wang8f706212020-12-16 18:59:24 +080055 throw InternalFailure();
56 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053057
58 int cmp;
59 cmp = std::memcmp(output.data(), expected.data(),
60 output.size() * sizeof(uint8_t));
61 if (cmp == 0)
Kuiying Wang8f706212020-12-16 18:59:24 +080062 {
63 return true;
64 }
65 else
66 {
67 return false;
68 }
69 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053070 if (algo == "SHA384")
71 {
72 std::array<uint8_t, SHA384_DIGEST_LENGTH> output;
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000073 unsigned int hashLen = SHA384_DIGEST_LENGTH;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053074
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000075 if (!PKCS5_PBKDF2_HMAC(
76 reinterpret_cast<const char*>(rawData.c_str()),
77 rawData.length() + 1,
78 reinterpret_cast<const unsigned char*>(seed.data()),
79 seed.size(), iterValue, EVP_sha384(), hashLen, output.data()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053080 {
George Liu567a3cf2021-12-08 10:36:03 +080081 lg2::error(
82 "Generate PKCS5_PBKDF2_HMAC_SHA384 Integrity Check Value failed");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053083 throw InternalFailure();
84 }
85
86 int cmp;
87 cmp = std::memcmp(output.data(), expected.data(),
88 output.size() * sizeof(uint8_t));
89 if (cmp == 0)
90 {
91 return true;
92 }
93 else
94 {
95 return false;
96 }
97 }
98
Kuiying Wang8f706212020-12-16 18:59:24 +080099 return false;
100}
101
102void Password::verifyPassword(std::string userName, std::string currentPassword,
103 std::string newPassword)
104{
105 if (fs::exists(seedFile.c_str()))
106 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530107 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
108 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
109 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +0800110 std::string hashAlgo = "";
111 try
112 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530113 nlohmann::json json = nullptr;
Kuiying Wang8f706212020-12-16 18:59:24 +0800114 std::ifstream ifs(seedFile.c_str());
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530115 if (ifs.is_open())
116 {
117 try
118 {
119 json = nlohmann::json::parse(ifs, nullptr, false);
120 }
121 catch (const nlohmann::json::parse_error& e)
122 {
George Liu567a3cf2021-12-08 10:36:03 +0800123 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR",
124 e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530125 throw InternalFailure();
126 }
127
128 if (json.is_discarded())
129 {
130 return;
131 }
132 orgUsrPwdHash = json["UserPwdHash"];
133 orgAdminPwdHash = json["AdminPwdHash"];
134 seed = json["Seed"];
135 hashAlgo = json["HashAlgo"];
136 }
137 else
138 {
139 return;
140 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800141 }
142 catch (nlohmann::detail::exception& e)
143 {
George Liu567a3cf2021-12-08 10:36:03 +0800144 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800145 throw InternalFailure();
146 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530147 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800148 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530149 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800150 {
151 throw InvalidCurrentPassword();
152 }
153 }
154 else
155 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530156 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800157 {
158 throw InvalidCurrentPassword();
159 }
160 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530161 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800162 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000163 unsigned int mdLen = 32;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530164 mNewPwdHash.fill(0);
165
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000166 if (!PKCS5_PBKDF2_HMAC(
167 reinterpret_cast<const char*>(newPassword.c_str()),
168 newPassword.length() + 1,
169 reinterpret_cast<const unsigned char*>(seed.data()),
170 seed.size(), iterValue, EVP_sha256(), mdLen,
171 mNewPwdHash.data()))
Kuiying Wang8f706212020-12-16 18:59:24 +0800172 {
George Liu567a3cf2021-12-08 10:36:03 +0800173 lg2::error(
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000174 "Verify PKCS5_PBKDF2_HMAC_SHA256 Integrity Check failed");
Kuiying Wang8f706212020-12-16 18:59:24 +0800175 throw InternalFailure();
176 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800177 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530178 if (hashAlgo == "SHA384")
179 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000180 unsigned int mdLen = 48;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530181 mNewPwdHash.fill(0);
Kuiying Wang8f706212020-12-16 18:59:24 +0800182
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000183 if (!PKCS5_PBKDF2_HMAC(
184 reinterpret_cast<const char*>(newPassword.c_str()),
185 newPassword.length() + 1,
186 reinterpret_cast<const unsigned char*>(seed.data()),
187 seed.size(), iterValue, EVP_sha384(), mdLen,
188 mNewPwdHash.data()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530189 {
George Liu567a3cf2021-12-08 10:36:03 +0800190 lg2::error(
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000191 "Verify PKCS5_PBKDF2_HMAC_SHA384 Integrity Check failed");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530192 throw InternalFailure();
193 }
194 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800195 return;
196 }
197 throw InternalFailure();
198}
199void Password::changePassword(std::string userName, std::string currentPassword,
200 std::string newPassword)
201{
George Liu567a3cf2021-12-08 10:36:03 +0800202 lg2::debug("BIOS config changePassword");
Kuiying Wang8f706212020-12-16 18:59:24 +0800203 verifyPassword(userName, currentPassword, newPassword);
204
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530205 std::ifstream fs(seedFile.c_str());
206 nlohmann::json json = nullptr;
207
208 if (fs.is_open())
Kuiying Wang8f706212020-12-16 18:59:24 +0800209 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530210 try
Kuiying Wang8f706212020-12-16 18:59:24 +0800211 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530212 json = nlohmann::json::parse(fs, nullptr, false);
Kuiying Wang8f706212020-12-16 18:59:24 +0800213 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530214 catch (const nlohmann::json::parse_error& e)
Kuiying Wang8f706212020-12-16 18:59:24 +0800215 {
George Liu567a3cf2021-12-08 10:36:03 +0800216 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530217 throw InternalFailure();
Kuiying Wang8f706212020-12-16 18:59:24 +0800218 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530219
220 if (json.is_discarded())
221 {
222 throw InternalFailure();
223 }
224 json["AdminPwdHash"] = mNewPwdHash;
225 json["IsAdminPwdChanged"] = true;
226
227 std::ofstream ofs(seedFile.c_str(), std::ios::out);
228 const auto& writeData = json.dump();
229 ofs << writeData;
230 ofs.close();
Kuiying Wang8f706212020-12-16 18:59:24 +0800231 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530232 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800233 {
George Liu567a3cf2021-12-08 10:36:03 +0800234 lg2::debug("Cannot open file stream");
Kuiying Wang8f706212020-12-16 18:59:24 +0800235 throw InternalFailure();
236 }
237}
238Password::Password(sdbusplus::asio::object_server& objectServer,
239 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
240 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
241 *systemBus, objectPathPwd),
242 objServer(objectServer), systemBus(systemBus)
243{
George Liu567a3cf2021-12-08 10:36:03 +0800244 lg2::debug("BIOS config password is runing");
Kuiying Wang8f706212020-12-16 18:59:24 +0800245 try
246 {
247 fs::path biosDir(BIOS_PERSIST_PATH);
248 fs::create_directories(biosDir);
Kuiying Wang8f706212020-12-16 18:59:24 +0800249 seedFile = biosDir / biosSeedFile;
250 }
251 catch (const fs::filesystem_error& e)
252 {
George Liu567a3cf2021-12-08 10:36:03 +0800253 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800254 throw InternalFailure();
255 }
256}
257
258} // namespace bios_config_pwd
259
260int main()
261{
262 boost::asio::io_service io;
263 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
264
265 systemBus->request_name(bios_config_pwd::servicePwd);
266 sdbusplus::asio::object_server objectServer(systemBus);
267 bios_config_pwd::Password password(objectServer, systemBus);
268
269 io.run();
270 return 0;
271}