blob: d942d8592fe7c3c79da0270a227e8e7b849a704d [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
yes8c22d072023-03-22 15:11:26 +053084bool Password::verifyIntegrityCheck(std::string& newPassword,
85 std::array<uint8_t, maxSeedSize>& seed,
86 unsigned int mdLen,
87 const EVP_MD* digestFunc)
88{
89 mNewPwdHash.fill(0);
90
91 if (!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(newPassword.c_str()),
92 newPassword.length() + 1,
93 reinterpret_cast<const unsigned char*>(seed.data()),
94 seed.size(), iterValue, digestFunc, mdLen,
95 mNewPwdHash.data()))
96 {
97 lg2::error("Verify PKCS5_PBKDF2_HMAC Integrity Check failed");
98 return false;
99 }
100
101 return true;
102}
103
Kuiying Wang8f706212020-12-16 18:59:24 +0800104void Password::verifyPassword(std::string userName, std::string currentPassword,
105 std::string newPassword)
106{
107 if (fs::exists(seedFile.c_str()))
108 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530109 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
110 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
111 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +0800112 std::string hashAlgo = "";
113 try
114 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530115 nlohmann::json json = nullptr;
Kuiying Wang8f706212020-12-16 18:59:24 +0800116 std::ifstream ifs(seedFile.c_str());
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530117 if (ifs.is_open())
118 {
119 try
120 {
121 json = nlohmann::json::parse(ifs, nullptr, false);
122 }
123 catch (const nlohmann::json::parse_error& e)
124 {
George Liu567a3cf2021-12-08 10:36:03 +0800125 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR",
126 e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530127 throw InternalFailure();
128 }
129
130 if (json.is_discarded())
131 {
132 return;
133 }
134 orgUsrPwdHash = json["UserPwdHash"];
135 orgAdminPwdHash = json["AdminPwdHash"];
136 seed = json["Seed"];
137 hashAlgo = json["HashAlgo"];
138 }
139 else
140 {
141 return;
142 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800143 }
144 catch (nlohmann::detail::exception& e)
145 {
George Liu567a3cf2021-12-08 10:36:03 +0800146 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800147 throw InternalFailure();
148 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530149 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800150 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530151 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800152 {
153 throw InvalidCurrentPassword();
154 }
155 }
156 else
157 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530158 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800159 {
160 throw InvalidCurrentPassword();
161 }
162 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530163 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800164 {
yes8c22d072023-03-22 15:11:26 +0530165 if (!verifyIntegrityCheck(newPassword, seed, 32, EVP_sha256()))
Kuiying Wang8f706212020-12-16 18:59:24 +0800166 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800167 throw InternalFailure();
168 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800169 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530170 if (hashAlgo == "SHA384")
171 {
yes8c22d072023-03-22 15:11:26 +0530172 if (!verifyIntegrityCheck(newPassword, seed, 48, EVP_sha384()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530173 {
174 throw InternalFailure();
175 }
176 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800177 return;
178 }
179 throw InternalFailure();
180}
181void Password::changePassword(std::string userName, std::string currentPassword,
182 std::string newPassword)
183{
George Liu567a3cf2021-12-08 10:36:03 +0800184 lg2::debug("BIOS config changePassword");
Kuiying Wang8f706212020-12-16 18:59:24 +0800185 verifyPassword(userName, currentPassword, newPassword);
186
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530187 std::ifstream fs(seedFile.c_str());
188 nlohmann::json json = nullptr;
189
190 if (fs.is_open())
Kuiying Wang8f706212020-12-16 18:59:24 +0800191 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530192 try
Kuiying Wang8f706212020-12-16 18:59:24 +0800193 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530194 json = nlohmann::json::parse(fs, nullptr, false);
Kuiying Wang8f706212020-12-16 18:59:24 +0800195 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530196 catch (const nlohmann::json::parse_error& e)
Kuiying Wang8f706212020-12-16 18:59:24 +0800197 {
George Liu567a3cf2021-12-08 10:36:03 +0800198 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530199 throw InternalFailure();
Kuiying Wang8f706212020-12-16 18:59:24 +0800200 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530201
202 if (json.is_discarded())
203 {
204 throw InternalFailure();
205 }
206 json["AdminPwdHash"] = mNewPwdHash;
207 json["IsAdminPwdChanged"] = true;
208
209 std::ofstream ofs(seedFile.c_str(), std::ios::out);
210 const auto& writeData = json.dump();
211 ofs << writeData;
212 ofs.close();
Kuiying Wang8f706212020-12-16 18:59:24 +0800213 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530214 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800215 {
George Liu567a3cf2021-12-08 10:36:03 +0800216 lg2::debug("Cannot open file stream");
Kuiying Wang8f706212020-12-16 18:59:24 +0800217 throw InternalFailure();
218 }
219}
220Password::Password(sdbusplus::asio::object_server& objectServer,
221 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
222 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
223 *systemBus, objectPathPwd),
224 objServer(objectServer), systemBus(systemBus)
225{
yes8de46ff2023-03-22 14:51:28 +0530226 lg2::debug("BIOS config password is running");
Kuiying Wang8f706212020-12-16 18:59:24 +0800227 try
228 {
229 fs::path biosDir(BIOS_PERSIST_PATH);
230 fs::create_directories(biosDir);
Kuiying Wang8f706212020-12-16 18:59:24 +0800231 seedFile = biosDir / biosSeedFile;
232 }
233 catch (const fs::filesystem_error& e)
234 {
George Liu567a3cf2021-12-08 10:36:03 +0800235 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800236 throw InternalFailure();
237 }
238}
239
240} // namespace bios_config_pwd