xref: /openbmc/bios-settings-mgr/src/password.cpp (revision 8f706213ccc2900e1a02fedb26073065897b02c3)
1 /*
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 
30 namespace bios_config_pwd
31 {
32 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
34 
35 bool Password::isMatch(const std::string expected, const std::string seed,
36                        const std::string rawData, const std::string algo)
37 {
38     phosphor::logging::log<phosphor::logging::level::ERR>("isMatch");
39     if (algo == "SHA384")
40     {
41         phosphor::logging::log<phosphor::logging::level::ERR>("SHA384");
42         std::vector<uint8_t> output(SHA384_DIGEST_LENGTH);
43         unsigned int mdLen = 0;
44         if (HMAC(EVP_sha384(), seed.c_str(), seed.length(),
45                  reinterpret_cast<const unsigned char*>(rawData.c_str()),
46                  rawData.length(), output.data(), &mdLen) == NULL)
47         {
48             phosphor::logging::log<phosphor::logging::level::ERR>(
49                 "Generate HMAC_SHA384 Integrity Check Value failed");
50             output.resize(0);
51             throw InternalFailure();
52         }
53         phosphor::logging::log<phosphor::logging::level::ERR>(expected.c_str());
54         std::string strOutput;
55         boost::algorithm::hex(output.begin(), output.end(),
56                               std::back_inserter(strOutput));
57         phosphor::logging::log<phosphor::logging::level::ERR>(
58             strOutput.c_str());
59         if (expected == strOutput)
60         {
61             return true;
62         }
63         else
64         {
65             return false;
66         }
67     }
68     return false;
69 }
70 
71 void Password::verifyPassword(std::string userName, std::string currentPassword,
72                               std::string newPassword)
73 {
74     if (fs::exists(seedFile.c_str()))
75     {
76         std::string userPassword = "";
77         std::string adminPassword = "";
78         std::string seed = "";
79         std::string hashAlgo = "";
80         try
81         {
82             std::ifstream ifs(seedFile.c_str());
83             nlohmann::json json;
84             ifs >> json;
85             userPassword = json["UserPwdHash"];
86             adminPassword = json["AdminPwdHash"];
87             seed = json["Seed"];
88             hashAlgo = json["HashAlgo"];
89         }
90         catch (nlohmann::detail::exception& e)
91         {
92             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
93             throw InternalFailure();
94         }
95         if (userName == "Administrator")
96         {
97             if (!isMatch(adminPassword, seed, currentPassword, hashAlgo))
98             {
99                 throw InvalidCurrentPassword();
100             }
101         }
102         else
103         {
104             if (!isMatch(userPassword, seed, currentPassword, hashAlgo))
105             {
106                 throw InvalidCurrentPassword();
107             }
108         }
109         if (hashAlgo == "SHA384")
110         {
111             std::vector<uint8_t> output(SHA384_DIGEST_LENGTH);
112             unsigned int mdLen = 0;
113             if (HMAC(
114                     EVP_sha384(), seed.c_str(), seed.length(),
115                     reinterpret_cast<const unsigned char*>(newPassword.c_str()),
116                     newPassword.length(), output.data(), &mdLen) == NULL)
117             {
118                 phosphor::logging::log<phosphor::logging::level::ERR>(
119                     "Generate HMAC_SHA384 Integrity Check Value failed");
120                 output.resize(0);
121                 throw InternalFailure();
122             }
123             std::string strOutput;
124             boost::algorithm::hex(output.begin(), output.end(),
125                                   std::back_inserter(strOutput));
126             phosphor::logging::log<phosphor::logging::level::ERR>(
127                 strOutput.c_str());
128             mNewPassword = strOutput;
129         }
130 
131         return;
132     }
133     throw InternalFailure();
134 }
135 void Password::changePassword(std::string userName, std::string currentPassword,
136                               std::string newPassword)
137 {
138     phosphor::logging::log<phosphor::logging::level::DEBUG>(
139         "BIOS config changePassword");
140     verifyPassword(userName, currentPassword, newPassword);
141 
142     try
143     {
144         nlohmann::json json;
145         json["UserName"] = userName;
146         json["CurrentPassword"] = currentPassword;
147         json["NewPassword"] = mNewPassword;
148         if (userName == "Administrator")
149         {
150             json["IsAdminPwdChanged"] = 1;
151             json["IsUserPwdChanged"] = 0;
152         }
153         else
154         {
155             json["IsAdminPwdChanged"] = 0;
156             json["IsUserPwdChanged"] = 1;
157         }
158         std::ofstream ofs(passwordFile.c_str(), std::ios::out);
159         ofs << std::setw(4) << json << std::endl;
160     }
161     catch (nlohmann::detail::exception& e)
162     {
163         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
164         throw InternalFailure();
165     }
166 }
167 Password::Password(sdbusplus::asio::object_server& objectServer,
168                    std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
169     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
170         *systemBus, objectPathPwd),
171     objServer(objectServer), systemBus(systemBus)
172 {
173     phosphor::logging::log<phosphor::logging::level::DEBUG>(
174         "BIOS config password is runing");
175     try
176     {
177         fs::path biosDir(BIOS_PERSIST_PATH);
178         fs::create_directories(biosDir);
179         passwordFile = biosDir / biosPasswordFile;
180         seedFile = biosDir / biosSeedFile;
181     }
182     catch (const fs::filesystem_error& e)
183     {
184         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
185         throw InternalFailure();
186     }
187 }
188 
189 } // namespace bios_config_pwd
190 
191 int main()
192 {
193     boost::asio::io_service io;
194     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
195 
196     systemBus->request_name(bios_config_pwd::servicePwd);
197     sdbusplus::asio::object_server objectServer(systemBus);
198     bios_config_pwd::Password password(objectServer, systemBus);
199 
200     io.run();
201     return 0;
202 }
203