blob: c5d9d6e2d311575e8cd9afb008479391622bf038 [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
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,
237 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
238 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
239 *systemBus, objectPathPwd),
240 objServer(objectServer), systemBus(systemBus)
241{
yes8de46ff2023-03-22 14:51:28 +0530242 lg2::debug("BIOS config password is running");
Kuiying Wang8f706212020-12-16 18:59:24 +0800243 try
244 {
245 fs::path biosDir(BIOS_PERSIST_PATH);
246 fs::create_directories(biosDir);
Kuiying Wang8f706212020-12-16 18:59:24 +0800247 seedFile = biosDir / biosSeedFile;
248 }
249 catch (const fs::filesystem_error& e)
250 {
George Liu567a3cf2021-12-08 10:36:03 +0800251 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800252 throw InternalFailure();
253 }
254}
255
256} // namespace bios_config_pwd