blob: 03aeb793431cde21e1c0a2a771b8f642e7f30a78 [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
Patrick Williams5c7e80d2024-10-18 21:24:12 -040018#include "config.hpp"
Kuiying Wang8f706212020-12-16 18:59:24 +080019#include "xyz/openbmc_project/BIOSConfig/Common/error.hpp"
20#include "xyz/openbmc_project/Common/error.hpp"
21
22#include <boost/algorithm/hex.hpp>
23#include <boost/asio.hpp>
24#include <phosphor-logging/elog-errors.hpp>
George Liu567a3cf2021-12-08 10:36:03 +080025#include <phosphor-logging/lg2.hpp>
Kuiying Wang8f706212020-12-16 18:59:24 +080026#include <sdbusplus/asio/connection.hpp>
27#include <sdbusplus/asio/object_server.hpp>
28
29#include <fstream>
30#include <iostream>
31
32namespace bios_config_pwd
33{
34using namespace sdbusplus::xyz::openbmc_project::Common::Error;
35using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
36
yesd0f034a2022-12-29 18:35:37 +053037bool Password::compareDigest(const EVP_MD* digestFunc, size_t digestLen,
38 const std::array<uint8_t, maxHashSize>& expected,
39 const std::array<uint8_t, maxSeedSize>& seed,
40 const std::string& rawData)
41{
42 std::vector<uint8_t> output(digestLen);
43 unsigned int hashLen = digestLen;
44
45 if (!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(rawData.c_str()),
46 rawData.length() + 1,
47 reinterpret_cast<const unsigned char*>(seed.data()),
48 seed.size(), iterValue, digestFunc, hashLen,
49 output.data()))
50 {
51 lg2::error("Generate PKCS5_PBKDF2_HMAC Integrity Check Value failed");
52 throw InternalFailure();
53 }
54
55 if (std::memcmp(output.data(), expected.data(),
56 output.size() * sizeof(uint8_t)) == 0)
57 {
58 return true;
59 }
60
61 return false;
62}
63
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053064bool Password::isMatch(const std::array<uint8_t, maxHashSize>& expected,
65 const std::array<uint8_t, maxSeedSize>& seed,
George Liu616f9222021-12-29 14:25:39 +080066 const std::string& rawData, const std::string& algo)
Kuiying Wang8f706212020-12-16 18:59:24 +080067{
George Liu567a3cf2021-12-08 10:36:03 +080068 lg2::error("isMatch");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053069
70 if (algo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +080071 {
yesd0f034a2022-12-29 18:35:37 +053072 return compareDigest(EVP_sha256(), SHA256_DIGEST_LENGTH, expected, seed,
73 rawData);
Kuiying Wang8f706212020-12-16 18:59:24 +080074 }
yesd0f034a2022-12-29 18:35:37 +053075
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053076 if (algo == "SHA384")
77 {
yesd0f034a2022-12-29 18:35:37 +053078 return compareDigest(EVP_sha384(), SHA384_DIGEST_LENGTH, expected, seed,
79 rawData);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053080 }
81
Kuiying Wang8f706212020-12-16 18:59:24 +080082 return false;
83}
84
Smriti-Ayushib3f7a792023-05-09 15:03:24 +053085bool Password::getParam(std::array<uint8_t, maxHashSize>& orgUsrPwdHash,
86 std::array<uint8_t, maxHashSize>& orgAdminPwdHash,
87 std::array<uint8_t, maxSeedSize>& seed,
88 std::string& hashAlgo)
89{
90 try
91 {
92 nlohmann::json json = nullptr;
93 std::ifstream ifs(seedFile.c_str());
94 if (ifs.is_open())
95 {
96 try
97 {
98 json = nlohmann::json::parse(ifs, nullptr, false);
99 }
100 catch (const nlohmann::json::parse_error& e)
101 {
102 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
103 return false;
104 }
105
106 if (!json.is_discarded())
107 {
108 orgUsrPwdHash = json["UserPwdHash"];
109 orgAdminPwdHash = json["AdminPwdHash"];
110 seed = json["Seed"];
111 hashAlgo = json["HashAlgo"];
112 }
113 }
114 }
115 catch (nlohmann::detail::exception& e)
116 {
117 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
118 return false;
119 }
120
121 return true;
122}
123
Patrick Williamsea6a65f2024-08-16 15:19:44 -0400124bool Password::verifyIntegrityCheck(
125 std::string& newPassword, std::array<uint8_t, maxSeedSize>& seed,
126 unsigned int mdLen, const EVP_MD* digestFunc)
yes8c22d072023-03-22 15:11:26 +0530127{
128 mNewPwdHash.fill(0);
129
130 if (!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(newPassword.c_str()),
131 newPassword.length() + 1,
132 reinterpret_cast<const unsigned char*>(seed.data()),
133 seed.size(), iterValue, digestFunc, mdLen,
134 mNewPwdHash.data()))
135 {
136 lg2::error("Verify PKCS5_PBKDF2_HMAC Integrity Check failed");
137 return false;
138 }
139
140 return true;
141}
142
Kuiying Wang8f706212020-12-16 18:59:24 +0800143void Password::verifyPassword(std::string userName, std::string currentPassword,
144 std::string newPassword)
145{
146 if (fs::exists(seedFile.c_str()))
147 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530148 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
149 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
150 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +0800151 std::string hashAlgo = "";
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530152
Smriti-Ayushib3f7a792023-05-09 15:03:24 +0530153 if (getParam(orgUsrPwdHash, orgAdminPwdHash, seed, hashAlgo))
154 {
155 if (orgUsrPwdHash.empty() || orgAdminPwdHash.empty() ||
156 seed.empty() || hashAlgo.empty())
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530157 {
158 return;
159 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800160 }
Smriti-Ayushib3f7a792023-05-09 15:03:24 +0530161 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800162 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800163 throw InternalFailure();
164 }
Smriti-Ayushib3f7a792023-05-09 15:03:24 +0530165
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530166 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800167 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530168 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800169 {
170 throw InvalidCurrentPassword();
171 }
172 }
173 else
174 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530175 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800176 {
177 throw InvalidCurrentPassword();
178 }
179 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530180 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800181 {
yes8c22d072023-03-22 15:11:26 +0530182 if (!verifyIntegrityCheck(newPassword, seed, 32, EVP_sha256()))
Kuiying Wang8f706212020-12-16 18:59:24 +0800183 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800184 throw InternalFailure();
185 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800186 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530187 if (hashAlgo == "SHA384")
188 {
yes8c22d072023-03-22 15:11:26 +0530189 if (!verifyIntegrityCheck(newPassword, seed, 48, EVP_sha384()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530190 {
191 throw InternalFailure();
192 }
193 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800194 return;
195 }
196 throw InternalFailure();
197}
198void Password::changePassword(std::string userName, std::string currentPassword,
199 std::string newPassword)
200{
George Liu567a3cf2021-12-08 10:36:03 +0800201 lg2::debug("BIOS config changePassword");
Kuiying Wang8f706212020-12-16 18:59:24 +0800202 verifyPassword(userName, currentPassword, newPassword);
203
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530204 std::ifstream fs(seedFile.c_str());
205 nlohmann::json json = nullptr;
206
207 if (fs.is_open())
Kuiying Wang8f706212020-12-16 18:59:24 +0800208 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530209 try
Kuiying Wang8f706212020-12-16 18:59:24 +0800210 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530211 json = nlohmann::json::parse(fs, nullptr, false);
Kuiying Wang8f706212020-12-16 18:59:24 +0800212 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530213 catch (const nlohmann::json::parse_error& e)
Kuiying Wang8f706212020-12-16 18:59:24 +0800214 {
George Liu567a3cf2021-12-08 10:36:03 +0800215 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530216 throw InternalFailure();
Kuiying Wang8f706212020-12-16 18:59:24 +0800217 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530218
219 if (json.is_discarded())
220 {
221 throw InternalFailure();
222 }
223 json["AdminPwdHash"] = mNewPwdHash;
224 json["IsAdminPwdChanged"] = true;
225
226 std::ofstream ofs(seedFile.c_str(), std::ios::out);
227 const auto& writeData = json.dump();
228 ofs << writeData;
229 ofs.close();
Kuiying Wang8f706212020-12-16 18:59:24 +0800230 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530231 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800232 {
George Liu567a3cf2021-12-08 10:36:03 +0800233 lg2::debug("Cannot open file stream");
Kuiying Wang8f706212020-12-16 18:59:24 +0800234 throw InternalFailure();
235 }
236}
237Password::Password(sdbusplus::asio::object_server& objectServer,
238 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
239 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
240 *systemBus, objectPathPwd),
241 objServer(objectServer), systemBus(systemBus)
242{
yes8de46ff2023-03-22 14:51:28 +0530243 lg2::debug("BIOS config password is running");
Kuiying Wang8f706212020-12-16 18:59:24 +0800244 try
245 {
246 fs::path biosDir(BIOS_PERSIST_PATH);
247 fs::create_directories(biosDir);
Kuiying Wang8f706212020-12-16 18:59:24 +0800248 seedFile = biosDir / biosSeedFile;
249 }
250 catch (const fs::filesystem_error& e)
251 {
George Liu567a3cf2021-12-08 10:36:03 +0800252 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800253 throw InternalFailure();
254 }
255}
256
257} // namespace bios_config_pwd