blob: a4ed842dbbd799fe97dbcf605756103a1704c4a2 [file] [log] [blame]
#include "config.h"
#include "oemcommands.hpp"
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <ipmid/api.hpp>
#include <ipmid/types.hpp>
#include <nlohmann/json.hpp>
#include <phosphor-logging/lg2.hpp>
#include <array>
#include <cstdint>
#include <fstream>
#include <string>
#include <vector>
constexpr char biosPasswordFilePath[] =
"/var/lib/bios-settings-manager/seedData";
constexpr int biosPasswordIter = 1000;
constexpr uint8_t biosPasswordSaltSize = 32;
constexpr uint8_t biosPasswordMaxHashSize = 64;
constexpr uint8_t biosPasswordTypeNoChange = 0x00;
constexpr uint8_t biosPasswordSelectorAdmin = 0x01;
constexpr uint8_t biosPasswordTypeNoPassowrd = 0x01;
constexpr uint8_t biosPasswordTypePbkdf2Sha256 = 0x02;
constexpr uint8_t biosPasswordTypePbkdf2Sha384 = 0x03;
void registerBiosConfigCommands() __attribute__((constructor));
namespace ipmi
{
ipmi::RspType<> ipmiSetBiosPassword(
uint8_t id, uint8_t type, std::array<uint8_t, biosPasswordSaltSize> salt,
std::array<uint8_t, biosPasswordMaxHashSize> hash)
{
nlohmann::json json;
if (id != biosPasswordSelectorAdmin)
{
return ipmi::responseInvalidFieldRequest();
}
// key names for json object
constexpr char keyHashAlgo[] = "HashAlgo";
constexpr char keySeed[] = "Seed";
constexpr char keyAdminPwdHash[] = "AdminPwdHash";
constexpr char keyIsAdminPwdChanged[] = "IsAdminPwdChanged";
constexpr char keyIsUserPwdChanged[] = "IsUserPwdChanged";
constexpr char keyUserPwdHash[] = "UserPwdHash";
switch (type)
{
case biosPasswordTypeNoPassowrd:
json[keyHashAlgo] = "SHA256";
RAND_bytes(salt.data(), salt.size());
// password is only Null-terminated character
PKCS5_PBKDF2_HMAC("", 1, salt.data(), salt.size(), biosPasswordIter,
EVP_sha256(), SHA256_DIGEST_LENGTH, hash.data());
json[keySeed] = salt;
json[keyAdminPwdHash] = hash;
break;
case biosPasswordTypePbkdf2Sha256:
json[keyHashAlgo] = "SHA256";
json[keySeed] = salt;
json[keyAdminPwdHash] = hash;
break;
case biosPasswordTypePbkdf2Sha384:
json[keyHashAlgo] = "SHA384";
json[keySeed] = salt;
json[keyAdminPwdHash] = hash;
break;
default:
return ipmi::responseInvalidFieldRequest();
}
json[keyIsAdminPwdChanged] = false;
json[keyIsUserPwdChanged] = false;
// initializing with 0 as user password hash field
// is not used presently
constexpr std::array<uint8_t, biosPasswordMaxHashSize> userPwdHash = {0};
json[keyUserPwdHash] = userPwdHash;
try
{
std::ofstream ofs(biosPasswordFilePath, std::ios::out);
const auto& writeData = json.dump();
ofs << writeData;
ofs.close();
}
catch (std::exception& e)
{
lg2::error("Failed to save BIOS Password information: {ERROR}", "ERROR",
e.what());
return ipmi::responseUnspecifiedError();
}
return ipmi::responseSuccess();
}
ipmi::RspType<uint8_t, // action
std::array<uint8_t, biosPasswordSaltSize>, // salt
std::array<uint8_t, biosPasswordMaxHashSize> // hash
>
ipmiGetBiosPassword(uint8_t id)
{
uint8_t action = biosPasswordTypeNoChange;
std::array<uint8_t, biosPasswordSaltSize> salt = {0};
std::array<uint8_t, biosPasswordMaxHashSize> hash = {0};
if (id != biosPasswordSelectorAdmin)
{
return ipmi::responseParmOutOfRange();
}
std::ifstream ifs(biosPasswordFilePath);
if (!ifs.is_open())
{
// return No change if no file
return ipmi::responseSuccess(action, salt, hash);
}
// key names for json object
constexpr char keyIsAdminPwdChanged[] = "IsAdminPwdChanged";
constexpr char keyHashAlgo[] = "HashAlgo";
constexpr char keySeed[] = "Seed";
constexpr char keyAdminPwdHash[] = "AdminPwdHash";
nlohmann::json json = nlohmann::json::parse(ifs, nullptr, false);
if (json.is_discarded() || !json.contains(keyIsAdminPwdChanged) ||
!json.contains(keyHashAlgo) || !json.contains(keySeed) ||
!json.contains(keyAdminPwdHash))
{
return ipmi::responseResponseError();
}
bool IsAdminPwdChanged = json[keyIsAdminPwdChanged];
if (IsAdminPwdChanged == false)
{
return ipmi::responseSuccess(action, salt, hash);
}
salt = json[keySeed];
hash = json[keyAdminPwdHash];
std::string HashAlgo = json[keyHashAlgo];
auto digest = EVP_sha256();
int keylen = SHA256_DIGEST_LENGTH;
if (HashAlgo == "SHA256")
{
action = biosPasswordTypePbkdf2Sha256;
}
else if (HashAlgo == "SHA384")
{
action = biosPasswordTypePbkdf2Sha384;
digest = EVP_sha384();
keylen = SHA384_DIGEST_LENGTH;
}
std::array<uint8_t, biosPasswordMaxHashSize> nullHash = {0};
PKCS5_PBKDF2_HMAC("", 1, salt.data(), salt.size(), biosPasswordIter, digest,
keylen, nullHash.data());
if (hash == nullHash)
{
action = biosPasswordTypeNoPassowrd;
salt.fill(0x00);
hash.fill(0x00);
}
return ipmi::responseSuccess(action, salt, hash);
}
} // namespace ipmi
void registerBiosConfigCommands()
{
ipmi::registerHandler(ipmi::prioOemBase, ipmi::groupNvidia,
ipmi::bios_password::cmdSetBiosPassword,
ipmi::Privilege::Admin, ipmi::ipmiSetBiosPassword);
ipmi::registerHandler(ipmi::prioOemBase, ipmi::groupNvidia,
ipmi::bios_password::cmdGetBiosPassword,
ipmi::Privilege::Admin, ipmi::ipmiGetBiosPassword);
}