blob: 0e348cee77f607005e2d3fdd5ace8c180ff1ead5 [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
yes8c22d072023-03-22 15:11:26 +0530123bool Password::verifyIntegrityCheck(std::string& newPassword,
124 std::array<uint8_t, maxSeedSize>& seed,
125 unsigned int mdLen,
126 const EVP_MD* digestFunc)
127{
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