blob: 724b98f8fcafd05e7df9cb80acb81211c2718cf5 [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
84void Password::verifyPassword(std::string userName, std::string currentPassword,
85 std::string newPassword)
86{
87 if (fs::exists(seedFile.c_str()))
88 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053089 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
90 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
91 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +080092 std::string hashAlgo = "";
93 try
94 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053095 nlohmann::json json = nullptr;
Kuiying Wang8f706212020-12-16 18:59:24 +080096 std::ifstream ifs(seedFile.c_str());
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053097 if (ifs.is_open())
98 {
99 try
100 {
101 json = nlohmann::json::parse(ifs, nullptr, false);
102 }
103 catch (const nlohmann::json::parse_error& e)
104 {
George Liu567a3cf2021-12-08 10:36:03 +0800105 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR",
106 e);
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530107 throw InternalFailure();
108 }
109
110 if (json.is_discarded())
111 {
112 return;
113 }
114 orgUsrPwdHash = json["UserPwdHash"];
115 orgAdminPwdHash = json["AdminPwdHash"];
116 seed = json["Seed"];
117 hashAlgo = json["HashAlgo"];
118 }
119 else
120 {
121 return;
122 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800123 }
124 catch (nlohmann::detail::exception& e)
125 {
George Liu567a3cf2021-12-08 10:36:03 +0800126 lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e);
Kuiying Wang8f706212020-12-16 18:59:24 +0800127 throw InternalFailure();
128 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530129 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800130 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530131 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800132 {
133 throw InvalidCurrentPassword();
134 }
135 }
136 else
137 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530138 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800139 {
140 throw InvalidCurrentPassword();
141 }
142 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530143 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800144 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000145 unsigned int mdLen = 32;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530146 mNewPwdHash.fill(0);
147
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000148 if (!PKCS5_PBKDF2_HMAC(
149 reinterpret_cast<const char*>(newPassword.c_str()),
150 newPassword.length() + 1,
151 reinterpret_cast<const unsigned char*>(seed.data()),
152 seed.size(), iterValue, EVP_sha256(), mdLen,
153 mNewPwdHash.data()))
Kuiying Wang8f706212020-12-16 18:59:24 +0800154 {
George Liu567a3cf2021-12-08 10:36:03 +0800155 lg2::error(
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000156 "Verify PKCS5_PBKDF2_HMAC_SHA256 Integrity Check failed");
Kuiying Wang8f706212020-12-16 18:59:24 +0800157 throw InternalFailure();
158 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800159 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530160 if (hashAlgo == "SHA384")
161 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000162 unsigned int mdLen = 48;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530163 mNewPwdHash.fill(0);
Kuiying Wang8f706212020-12-16 18:59:24 +0800164
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000165 if (!PKCS5_PBKDF2_HMAC(
166 reinterpret_cast<const char*>(newPassword.c_str()),
167 newPassword.length() + 1,
168 reinterpret_cast<const unsigned char*>(seed.data()),
169 seed.size(), iterValue, EVP_sha384(), mdLen,
170 mNewPwdHash.data()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530171 {
George Liu567a3cf2021-12-08 10:36:03 +0800172 lg2::error(
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000173 "Verify PKCS5_PBKDF2_HMAC_SHA384 Integrity Check failed");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530174 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