blob: abde4b512e2e15bc4504e4a5d95457a5b8f4c592 [file] [log] [blame]
Kuiying Wang8f706212020-12-16 18:59:24 +08001/*
Manojkiran Edafae57322024-11-12 12:58:11 +05302 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.
Kuiying Wang8f706212020-12-16 18:59:24 +080015*/
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
yesd0f034a2022-12-29 18:35:37 +053036bool Password::compareDigest(const EVP_MD* digestFunc, size_t digestLen,
37 const std::array<uint8_t, maxHashSize>& expected,
38 const std::array<uint8_t, maxSeedSize>& seed,
39 const std::string& rawData)
40{
41 std::vector<uint8_t> output(digestLen);
42 unsigned int hashLen = digestLen;
43
44 if (!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(rawData.c_str()),
45 rawData.length() + 1,
46 reinterpret_cast<const unsigned char*>(seed.data()),
47 seed.size(), iterValue, digestFunc, hashLen,
48 output.data()))
49 {
50 lg2::error("Generate PKCS5_PBKDF2_HMAC Integrity Check Value failed");
51 throw InternalFailure();
52 }
53
54 if (std::memcmp(output.data(), expected.data(),
55 output.size() * sizeof(uint8_t)) == 0)
56 {
57 return true;
58 }
59
60 return false;
61}
62
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053063bool Password::isMatch(const std::array<uint8_t, maxHashSize>& expected,
64 const std::array<uint8_t, maxSeedSize>& seed,
George Liu616f9222021-12-29 14:25:39 +080065 const std::string& rawData, const std::string& algo)
Kuiying Wang8f706212020-12-16 18:59:24 +080066{
George Liu567a3cf2021-12-08 10:36:03 +080067 lg2::error("isMatch");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053068
69 if (algo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +080070 {
yesd0f034a2022-12-29 18:35:37 +053071 return compareDigest(EVP_sha256(), SHA256_DIGEST_LENGTH, expected, seed,
72 rawData);
Kuiying Wang8f706212020-12-16 18:59:24 +080073 }
yesd0f034a2022-12-29 18:35:37 +053074
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053075 if (algo == "SHA384")
76 {
yesd0f034a2022-12-29 18:35:37 +053077 return compareDigest(EVP_sha384(), SHA384_DIGEST_LENGTH, expected, seed,
78 rawData);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053079 }
80
Kuiying Wang8f706212020-12-16 18:59:24 +080081 return false;
82}
83
Smriti-Ayushib3f7a792023-05-09 15:03:24 +053084bool Password::getParam(std::array<uint8_t, maxHashSize>& orgUsrPwdHash,
85 std::array<uint8_t, maxHashSize>& orgAdminPwdHash,
86 std::array<uint8_t, maxSeedSize>& seed,
87 std::string& hashAlgo)
88{
89 try
90 {
91 nlohmann::json json = nullptr;
92 std::ifstream ifs(seedFile.c_str());
93 if (ifs.is_open())
94 {
95 try
96 {
97 json = nlohmann::json::parse(ifs, nullptr, false);
98 }
99 catch (const nlohmann::json::parse_error& e)
100 {
101 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
102 return false;
103 }
104
105 if (!json.is_discarded())
106 {
107 orgUsrPwdHash = json["UserPwdHash"];
108 orgAdminPwdHash = json["AdminPwdHash"];
109 seed = json["Seed"];
110 hashAlgo = json["HashAlgo"];
111 }
112 }
113 }
114 catch (nlohmann::detail::exception& e)
115 {
116 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
117 return false;
118 }
119
120 return true;
121}
122
Patrick Williamsea6a65f2024-08-16 15:19:44 -0400123bool Password::verifyIntegrityCheck(
124 std::string& newPassword, std::array<uint8_t, maxSeedSize>& seed,
125 unsigned int mdLen, const EVP_MD* digestFunc)
yes8c22d072023-03-22 15:11:26 +0530126{
127 mNewPwdHash.fill(0);
128
129 if (!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(newPassword.c_str()),
130 newPassword.length() + 1,
131 reinterpret_cast<const unsigned char*>(seed.data()),
132 seed.size(), iterValue, digestFunc, mdLen,
133 mNewPwdHash.data()))
134 {
135 lg2::error("Verify PKCS5_PBKDF2_HMAC Integrity Check failed");
136 return false;
137 }
138
139 return true;
140}
141
Kuiying Wang8f706212020-12-16 18:59:24 +0800142void Password::verifyPassword(std::string userName, std::string currentPassword,
143 std::string newPassword)
144{
145 if (fs::exists(seedFile.c_str()))
146 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530147 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
148 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
149 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +0800150 std::string hashAlgo = "";
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530151
Smriti-Ayushib3f7a792023-05-09 15:03:24 +0530152 if (getParam(orgUsrPwdHash, orgAdminPwdHash, seed, hashAlgo))
153 {
154 if (orgUsrPwdHash.empty() || orgAdminPwdHash.empty() ||
155 seed.empty() || hashAlgo.empty())
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530156 {
157 return;
158 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800159 }
Smriti-Ayushib3f7a792023-05-09 15:03:24 +0530160 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800161 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800162 throw InternalFailure();
163 }
Smriti-Ayushib3f7a792023-05-09 15:03:24 +0530164
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530165 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800166 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530167 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800168 {
169 throw InvalidCurrentPassword();
170 }
171 }
172 else
173 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530174 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800175 {
176 throw InvalidCurrentPassword();
177 }
178 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530179 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800180 {
yes8c22d072023-03-22 15:11:26 +0530181 if (!verifyIntegrityCheck(newPassword, seed, 32, EVP_sha256()))
Kuiying Wang8f706212020-12-16 18:59:24 +0800182 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800183 throw InternalFailure();
184 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800185 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530186 if (hashAlgo == "SHA384")
187 {
yes8c22d072023-03-22 15:11:26 +0530188 if (!verifyIntegrityCheck(newPassword, seed, 48, EVP_sha384()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530189 {
190 throw InternalFailure();
191 }
192 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800193 return;
194 }
195 throw InternalFailure();
196}
197void Password::changePassword(std::string userName, std::string currentPassword,
198 std::string newPassword)
199{
George Liu567a3cf2021-12-08 10:36:03 +0800200 lg2::debug("BIOS config changePassword");
Kuiying Wang8f706212020-12-16 18:59:24 +0800201 verifyPassword(userName, currentPassword, newPassword);
202
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530203 std::ifstream fs(seedFile.c_str());
204 nlohmann::json json = nullptr;
205
206 if (fs.is_open())
Kuiying Wang8f706212020-12-16 18:59:24 +0800207 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530208 try
Kuiying Wang8f706212020-12-16 18:59:24 +0800209 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530210 json = nlohmann::json::parse(fs, nullptr, false);
Kuiying Wang8f706212020-12-16 18:59:24 +0800211 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530212 catch (const nlohmann::json::parse_error& e)
Kuiying Wang8f706212020-12-16 18:59:24 +0800213 {
George Liu567a3cf2021-12-08 10:36:03 +0800214 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530215 throw InternalFailure();
Kuiying Wang8f706212020-12-16 18:59:24 +0800216 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530217
218 if (json.is_discarded())
219 {
220 throw InternalFailure();
221 }
222 json["AdminPwdHash"] = mNewPwdHash;
223 json["IsAdminPwdChanged"] = true;
224
225 std::ofstream ofs(seedFile.c_str(), std::ios::out);
226 const auto& writeData = json.dump();
227 ofs << writeData;
228 ofs.close();
Kuiying Wang8f706212020-12-16 18:59:24 +0800229 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530230 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800231 {
George Liu567a3cf2021-12-08 10:36:03 +0800232 lg2::debug("Cannot open file stream");
Kuiying Wang8f706212020-12-16 18:59:24 +0800233 throw InternalFailure();
234 }
235}
236Password::Password(sdbusplus::asio::object_server& objectServer,
Patrick Williams773c9222024-10-18 21:39:55 -0400237 std::shared_ptr<sdbusplus::asio::connection>& systemBus,
238 std::string persistPath) :
Kuiying Wang8f706212020-12-16 18:59:24 +0800239 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 {
Patrick Williams773c9222024-10-18 21:39:55 -0400246 fs::path biosDir(persistPath);
Kuiying Wang8f706212020-12-16 18:59:24 +0800247 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