oob bios config password and bios reset

Tested:
1. Bios reset flag can be modified throw redfish
POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios
{
    "ResetFlag": "Factory"
}
root@intel-obmc:~# busctl call xyz.openbmc_project.BIOSConfigManager /xyz/openbmc_project/bios_config/manager org.freedesktop.DBus.Properties Get ss xyz.openbmc_project.BIOSConfig.Manager ResetBIOSSettings
v s "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.FactoryDefaults"

2. Bios change password:
root@intel-obmc:~# cat /var/lib/bios-settings-manager/seedData
{
"UserPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
"AdminPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
"Seed": "123456",
"HashAlgo": "SHA384"
}
POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword
{
    "NewPassword": "12345678",
    "OldPassword": "1234567890",
    "PasswordName": "Administrator"
}
root@intel-obmc:~# cat /var/lib/bios-settings-manager/passwordData
{
    "CurrentPassword": "1234567890",
    "IsAdminPwdChanged": 1,
    "IsUserPwdChanged": 0,
    "NewPassword": "2DD65D57EB60B1D92C5F3D2DC84724FCEE7BC02E57AA75E834712266ED94CAC704047B2FF7CEC1C36BED280B36BB5AC6",
    "UserName": "Administrator"
}

Change-Id: Ib54b36819e49c891c6169c95d9cdaebd5bcb06f3
Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
diff --git a/src/manager.cpp b/src/manager.cpp
index c173ee4..c92205f 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -20,6 +20,7 @@
 #include "xyz/openbmc_project/Common/error.hpp"
 
 #include <boost/asio.hpp>
+#include <phosphor-logging/elog-errors.hpp>
 #include <sdbusplus/asio/connection.hpp>
 #include <sdbusplus/asio/object_server.hpp>
 
@@ -117,12 +118,16 @@
         // BIOS attribute not found in the BaseBIOSTable
         if (iter == biosTable.end())
         {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "BIOS attribute not found in the BaseBIOSTable");
             throw AttributeNotFound();
         }
 
         // BIOS attribute is read only
         if (std::get<static_cast<uint8_t>(Index::readOnly)>(iter->second))
         {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "BIOS attribute is read only");
             throw AttributeReadOnly();
         }
 
@@ -130,15 +135,19 @@
             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
         if (attributeType != std::get<0>(pair.second))
         {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "attributeType is not same with bios base table");
             throw InvalidArgument();
         }
 
         // Validate enumeration BIOS attributes
         if (attributeType == AttributeType::Enumeration)
         {
-            // For enumeration the expected variant types is std::string
+            // For enumeration the expected variant types is Enumeration
             if (std::get<1>(pair.second).index() == 0)
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "Enumeration property value is not enum");
                 throw InvalidArgument();
             }
 
@@ -161,6 +170,8 @@
 
             if (!found)
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "No valid attribute");
                 throw InvalidArgument();
             }
         }
@@ -170,6 +181,8 @@
             // For enumeration the expected variant types is std::string
             if (std::get<1>(pair.second).index() == 0)
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "String property value is not string");
                 throw InvalidArgument();
             }
 
@@ -198,15 +211,19 @@
             if ((attrValue.length() < static_cast<size_t>(minStringLength)) ||
                 (attrValue.length() > static_cast<size_t>(maxStringLength)))
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "std::string, length is invalid");
                 throw InvalidArgument();
             }
         }
 
         if (attributeType == AttributeType::Integer)
         {
-            // For enumeration the expected variant types is std::string
+            // For enumeration the expected variant types is Integer
             if (std::get<1>(pair.second).index() == 1)
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "Enumeration property value is not int");
                 throw InvalidArgument();
             }
 
@@ -237,11 +254,16 @@
 
             if ((attrValue < lowerBound) || (attrValue > upperBound))
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "Integer, bound is invalid");
                 throw InvalidArgument();
             }
 
             if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "((std::abs(attrValue - lowerBound)) % scalarIncrement) != "
+                    "0");
                 throw InvalidArgument();
             }
         }
diff --git a/src/password.cpp b/src/password.cpp
new file mode 100644
index 0000000..0c24347
--- /dev/null
+++ b/src/password.cpp
@@ -0,0 +1,202 @@
+/*
+// Copyright (c) 2020 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "password.hpp"
+
+#include "xyz/openbmc_project/BIOSConfig/Common/error.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <boost/algorithm/hex.hpp>
+#include <boost/asio.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <fstream>
+#include <iostream>
+
+namespace bios_config_pwd
+{
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
+
+bool Password::isMatch(const std::string expected, const std::string seed,
+                       const std::string rawData, const std::string algo)
+{
+    phosphor::logging::log<phosphor::logging::level::ERR>("isMatch");
+    if (algo == "SHA384")
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>("SHA384");
+        std::vector<uint8_t> output(SHA384_DIGEST_LENGTH);
+        unsigned int mdLen = 0;
+        if (HMAC(EVP_sha384(), seed.c_str(), seed.length(),
+                 reinterpret_cast<const unsigned char*>(rawData.c_str()),
+                 rawData.length(), output.data(), &mdLen) == NULL)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "Generate HMAC_SHA384 Integrity Check Value failed");
+            output.resize(0);
+            throw InternalFailure();
+        }
+        phosphor::logging::log<phosphor::logging::level::ERR>(expected.c_str());
+        std::string strOutput;
+        boost::algorithm::hex(output.begin(), output.end(),
+                              std::back_inserter(strOutput));
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            strOutput.c_str());
+        if (expected == strOutput)
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    return false;
+}
+
+void Password::verifyPassword(std::string userName, std::string currentPassword,
+                              std::string newPassword)
+{
+    if (fs::exists(seedFile.c_str()))
+    {
+        std::string userPassword = "";
+        std::string adminPassword = "";
+        std::string seed = "";
+        std::string hashAlgo = "";
+        try
+        {
+            std::ifstream ifs(seedFile.c_str());
+            nlohmann::json json;
+            ifs >> json;
+            userPassword = json["UserPwdHash"];
+            adminPassword = json["AdminPwdHash"];
+            seed = json["Seed"];
+            hashAlgo = json["HashAlgo"];
+        }
+        catch (nlohmann::detail::exception& e)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
+            throw InternalFailure();
+        }
+        if (userName == "Administrator")
+        {
+            if (!isMatch(adminPassword, seed, currentPassword, hashAlgo))
+            {
+                throw InvalidCurrentPassword();
+            }
+        }
+        else
+        {
+            if (!isMatch(userPassword, seed, currentPassword, hashAlgo))
+            {
+                throw InvalidCurrentPassword();
+            }
+        }
+        if (hashAlgo == "SHA384")
+        {
+            std::vector<uint8_t> output(SHA384_DIGEST_LENGTH);
+            unsigned int mdLen = 0;
+            if (HMAC(
+                    EVP_sha384(), seed.c_str(), seed.length(),
+                    reinterpret_cast<const unsigned char*>(newPassword.c_str()),
+                    newPassword.length(), output.data(), &mdLen) == NULL)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "Generate HMAC_SHA384 Integrity Check Value failed");
+                output.resize(0);
+                throw InternalFailure();
+            }
+            std::string strOutput;
+            boost::algorithm::hex(output.begin(), output.end(),
+                                  std::back_inserter(strOutput));
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                strOutput.c_str());
+            mNewPassword = strOutput;
+        }
+
+        return;
+    }
+    throw InternalFailure();
+}
+void Password::changePassword(std::string userName, std::string currentPassword,
+                              std::string newPassword)
+{
+    phosphor::logging::log<phosphor::logging::level::DEBUG>(
+        "BIOS config changePassword");
+    verifyPassword(userName, currentPassword, newPassword);
+
+    try
+    {
+        nlohmann::json json;
+        json["UserName"] = userName;
+        json["CurrentPassword"] = currentPassword;
+        json["NewPassword"] = mNewPassword;
+        if (userName == "Administrator")
+        {
+            json["IsAdminPwdChanged"] = 1;
+            json["IsUserPwdChanged"] = 0;
+        }
+        else
+        {
+            json["IsAdminPwdChanged"] = 0;
+            json["IsUserPwdChanged"] = 1;
+        }
+        std::ofstream ofs(passwordFile.c_str(), std::ios::out);
+        ofs << std::setw(4) << json << std::endl;
+    }
+    catch (nlohmann::detail::exception& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
+        throw InternalFailure();
+    }
+}
+Password::Password(sdbusplus::asio::object_server& objectServer,
+                   std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
+    sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password(
+        *systemBus, objectPathPwd),
+    objServer(objectServer), systemBus(systemBus)
+{
+    phosphor::logging::log<phosphor::logging::level::DEBUG>(
+        "BIOS config password is runing");
+    try
+    {
+        fs::path biosDir(BIOS_PERSIST_PATH);
+        fs::create_directories(biosDir);
+        passwordFile = biosDir / biosPasswordFile;
+        seedFile = biosDir / biosSeedFile;
+    }
+    catch (const fs::filesystem_error& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
+        throw InternalFailure();
+    }
+}
+
+} // namespace bios_config_pwd
+
+int main()
+{
+    boost::asio::io_service io;
+    auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
+
+    systemBus->request_name(bios_config_pwd::servicePwd);
+    sdbusplus::asio::object_server objectServer(systemBus);
+    bios_config_pwd::Password password(objectServer, systemBus);
+
+    io.run();
+    return 0;
+}