blob: 3aacc45e0597d0086747734b1a0b253895feccc1 [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>
24#include <sdbusplus/asio/connection.hpp>
25#include <sdbusplus/asio/object_server.hpp>
26
27#include <fstream>
28#include <iostream>
29
30namespace bios_config_pwd
31{
32using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
34
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053035bool Password::isMatch(const std::array<uint8_t, maxHashSize>& expected,
36 const std::array<uint8_t, maxSeedSize>& seed,
Kuiying Wang8f706212020-12-16 18:59:24 +080037 const std::string rawData, const std::string algo)
38{
39 phosphor::logging::log<phosphor::logging::level::ERR>("isMatch");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053040
41 if (algo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +080042 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053043 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000044 unsigned int hashLen = SHA256_DIGEST_LENGTH;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053045
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000046 if (!PKCS5_PBKDF2_HMAC(
47 reinterpret_cast<const char*>(rawData.c_str()),
48 rawData.length() + 1,
49 reinterpret_cast<const unsigned char*>(seed.data()),
50 seed.size(), iterValue, EVP_sha256(), hashLen, output.data()))
Kuiying Wang8f706212020-12-16 18:59:24 +080051 {
52 phosphor::logging::log<phosphor::logging::level::ERR>(
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000053 "Generate PKCS5_PBKDF2_HMAC_SHA256 Integrity Check Value "
54 "failed");
Kuiying Wang8f706212020-12-16 18:59:24 +080055 throw InternalFailure();
56 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053057
58 int cmp;
59 cmp = std::memcmp(output.data(), expected.data(),
60 output.size() * sizeof(uint8_t));
61 if (cmp == 0)
Kuiying Wang8f706212020-12-16 18:59:24 +080062 {
63 return true;
64 }
65 else
66 {
67 return false;
68 }
69 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053070 if (algo == "SHA384")
71 {
72 std::array<uint8_t, SHA384_DIGEST_LENGTH> output;
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000073 unsigned int hashLen = SHA384_DIGEST_LENGTH;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053074
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000075 if (!PKCS5_PBKDF2_HMAC(
76 reinterpret_cast<const char*>(rawData.c_str()),
77 rawData.length() + 1,
78 reinterpret_cast<const unsigned char*>(seed.data()),
79 seed.size(), iterValue, EVP_sha384(), hashLen, output.data()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053080 {
81 phosphor::logging::log<phosphor::logging::level::ERR>(
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +000082 "Generate PKCS5_PBKDF2_HMAC_SHA384 Integrity Check Value "
83 "failed");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +053084 throw InternalFailure();
85 }
86
87 int cmp;
88 cmp = std::memcmp(output.data(), expected.data(),
89 output.size() * sizeof(uint8_t));
90 if (cmp == 0)
91 {
92 return true;
93 }
94 else
95 {
96 return false;
97 }
98 }
99
Kuiying Wang8f706212020-12-16 18:59:24 +0800100 return false;
101}
102
103void Password::verifyPassword(std::string userName, std::string currentPassword,
104 std::string newPassword)
105{
106 if (fs::exists(seedFile.c_str()))
107 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530108 std::array<uint8_t, maxHashSize> orgUsrPwdHash;
109 std::array<uint8_t, maxHashSize> orgAdminPwdHash;
110 std::array<uint8_t, maxSeedSize> seed;
Kuiying Wang8f706212020-12-16 18:59:24 +0800111 std::string hashAlgo = "";
112 try
113 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530114 nlohmann::json json = nullptr;
Kuiying Wang8f706212020-12-16 18:59:24 +0800115 std::ifstream ifs(seedFile.c_str());
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530116 if (ifs.is_open())
117 {
118 try
119 {
120 json = nlohmann::json::parse(ifs, nullptr, false);
121 }
122 catch (const nlohmann::json::parse_error& e)
123 {
124 phosphor::logging::log<phosphor::logging::level::ERR>(
125 e.what());
126 throw InternalFailure();
127 }
128
129 if (json.is_discarded())
130 {
131 return;
132 }
133 orgUsrPwdHash = json["UserPwdHash"];
134 orgAdminPwdHash = json["AdminPwdHash"];
135 seed = json["Seed"];
136 hashAlgo = json["HashAlgo"];
137 }
138 else
139 {
140 return;
141 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800142 }
143 catch (nlohmann::detail::exception& e)
144 {
145 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
146 throw InternalFailure();
147 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530148 if (userName == "AdminPassword")
Kuiying Wang8f706212020-12-16 18:59:24 +0800149 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530150 if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800151 {
152 throw InvalidCurrentPassword();
153 }
154 }
155 else
156 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530157 if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo))
Kuiying Wang8f706212020-12-16 18:59:24 +0800158 {
159 throw InvalidCurrentPassword();
160 }
161 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530162 if (hashAlgo == "SHA256")
Kuiying Wang8f706212020-12-16 18:59:24 +0800163 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000164 unsigned int mdLen = 32;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530165 mNewPwdHash.fill(0);
166
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000167 if (!PKCS5_PBKDF2_HMAC(
168 reinterpret_cast<const char*>(newPassword.c_str()),
169 newPassword.length() + 1,
170 reinterpret_cast<const unsigned char*>(seed.data()),
171 seed.size(), iterValue, EVP_sha256(), mdLen,
172 mNewPwdHash.data()))
Kuiying Wang8f706212020-12-16 18:59:24 +0800173 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000174 phosphor::logging::log<phosphor::logging::level::ERR>(
175 "Verify PKCS5_PBKDF2_HMAC_SHA256 Integrity Check failed");
Kuiying Wang8f706212020-12-16 18:59:24 +0800176 throw InternalFailure();
177 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800178 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530179 if (hashAlgo == "SHA384")
180 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000181 unsigned int mdLen = 48;
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530182 mNewPwdHash.fill(0);
Kuiying Wang8f706212020-12-16 18:59:24 +0800183
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000184 if (!PKCS5_PBKDF2_HMAC(
185 reinterpret_cast<const char*>(newPassword.c_str()),
186 newPassword.length() + 1,
187 reinterpret_cast<const unsigned char*>(seed.data()),
188 seed.size(), iterValue, EVP_sha384(), mdLen,
189 mNewPwdHash.data()))
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530190 {
Snehalatha Venkatesh2f7ba732021-09-30 10:25:32 +0000191 phosphor::logging::log<phosphor::logging::level::ERR>(
192 "Verify PKCS5_PBKDF2_HMAC_SHA384 Integrity Check failed");
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530193 throw InternalFailure();
194 }
195 }
Kuiying Wang8f706212020-12-16 18:59:24 +0800196 return;
197 }
198 throw InternalFailure();
199}
200void Password::changePassword(std::string userName, std::string currentPassword,
201 std::string newPassword)
202{
203 phosphor::logging::log<phosphor::logging::level::DEBUG>(
204 "BIOS config changePassword");
205 verifyPassword(userName, currentPassword, newPassword);
206
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530207 std::ifstream fs(seedFile.c_str());
208 nlohmann::json json = nullptr;
209
210 if (fs.is_open())
Kuiying Wang8f706212020-12-16 18:59:24 +0800211 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530212 try
Kuiying Wang8f706212020-12-16 18:59:24 +0800213 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530214 json = nlohmann::json::parse(fs, nullptr, false);
Kuiying Wang8f706212020-12-16 18:59:24 +0800215 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530216 catch (const nlohmann::json::parse_error& e)
Kuiying Wang8f706212020-12-16 18:59:24 +0800217 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530218 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
219 throw InternalFailure();
Kuiying Wang8f706212020-12-16 18:59:24 +0800220 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530221
222 if (json.is_discarded())
223 {
224 throw InternalFailure();
225 }
226 json["AdminPwdHash"] = mNewPwdHash;
227 json["IsAdminPwdChanged"] = true;
228
229 std::ofstream ofs(seedFile.c_str(), std::ios::out);
230 const auto& writeData = json.dump();
231 ofs << writeData;
232 ofs.close();
Kuiying Wang8f706212020-12-16 18:59:24 +0800233 }
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530234 else
Kuiying Wang8f706212020-12-16 18:59:24 +0800235 {
Ayushi Smriti96e72ec2021-05-20 13:44:12 +0530236 phosphor::logging::log<phosphor::logging::level::DEBUG>(
237 "Cannot open file stream");
Kuiying Wang8f706212020-12-16 18:59:24 +0800238 throw InternalFailure();
239 }
240}
241Password::Password(sdbusplus::asio::object_server& objectServer,
242 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
243 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
244 *systemBus, objectPathPwd),
245 objServer(objectServer), systemBus(systemBus)
246{
247 phosphor::logging::log<phosphor::logging::level::DEBUG>(
248 "BIOS config password is runing");
249 try
250 {
251 fs::path biosDir(BIOS_PERSIST_PATH);
252 fs::create_directories(biosDir);
Kuiying Wang8f706212020-12-16 18:59:24 +0800253 seedFile = biosDir / biosSeedFile;
254 }
255 catch (const fs::filesystem_error& e)
256 {
257 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
258 throw InternalFailure();
259 }
260}
261
262} // namespace bios_config_pwd
263
264int main()
265{
266 boost::asio::io_service io;
267 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
268
269 systemBus->request_name(bios_config_pwd::servicePwd);
270 sdbusplus::asio::object_server objectServer(systemBus);
271 bios_config_pwd::Password password(objectServer, systemBus);
272
273 io.run();
274 return 0;
275}