blob: a4ed842dbbd799fe97dbcf605756103a1704c4a2 [file] [log] [blame]
Prithvi Pai6b580c72025-06-05 11:13:34 +05301#include "config.h"
2
3#include "oemcommands.hpp"
4
5#include <openssl/evp.h>
6#include <openssl/rand.h>
7#include <openssl/sha.h>
8
9#include <ipmid/api.hpp>
10#include <ipmid/types.hpp>
11#include <nlohmann/json.hpp>
12#include <phosphor-logging/lg2.hpp>
13
14#include <array>
15#include <cstdint>
16#include <fstream>
17#include <string>
18#include <vector>
19
20constexpr char biosPasswordFilePath[] =
21 "/var/lib/bios-settings-manager/seedData";
22constexpr int biosPasswordIter = 1000;
23constexpr uint8_t biosPasswordSaltSize = 32;
24constexpr uint8_t biosPasswordMaxHashSize = 64;
25constexpr uint8_t biosPasswordTypeNoChange = 0x00;
26constexpr uint8_t biosPasswordSelectorAdmin = 0x01;
27constexpr uint8_t biosPasswordTypeNoPassowrd = 0x01;
28constexpr uint8_t biosPasswordTypePbkdf2Sha256 = 0x02;
29constexpr uint8_t biosPasswordTypePbkdf2Sha384 = 0x03;
30
31void registerBiosConfigCommands() __attribute__((constructor));
32
33namespace ipmi
34{
35ipmi::RspType<> ipmiSetBiosPassword(
36 uint8_t id, uint8_t type, std::array<uint8_t, biosPasswordSaltSize> salt,
37 std::array<uint8_t, biosPasswordMaxHashSize> hash)
38{
39 nlohmann::json json;
40
41 if (id != biosPasswordSelectorAdmin)
42 {
43 return ipmi::responseInvalidFieldRequest();
44 }
45 // key names for json object
46 constexpr char keyHashAlgo[] = "HashAlgo";
47 constexpr char keySeed[] = "Seed";
48 constexpr char keyAdminPwdHash[] = "AdminPwdHash";
49 constexpr char keyIsAdminPwdChanged[] = "IsAdminPwdChanged";
50 constexpr char keyIsUserPwdChanged[] = "IsUserPwdChanged";
51 constexpr char keyUserPwdHash[] = "UserPwdHash";
52
53 switch (type)
54 {
55 case biosPasswordTypeNoPassowrd:
56 json[keyHashAlgo] = "SHA256";
57 RAND_bytes(salt.data(), salt.size());
58 // password is only Null-terminated character
59 PKCS5_PBKDF2_HMAC("", 1, salt.data(), salt.size(), biosPasswordIter,
60 EVP_sha256(), SHA256_DIGEST_LENGTH, hash.data());
61 json[keySeed] = salt;
62 json[keyAdminPwdHash] = hash;
63 break;
64 case biosPasswordTypePbkdf2Sha256:
65 json[keyHashAlgo] = "SHA256";
66 json[keySeed] = salt;
67 json[keyAdminPwdHash] = hash;
68 break;
69 case biosPasswordTypePbkdf2Sha384:
70 json[keyHashAlgo] = "SHA384";
71 json[keySeed] = salt;
72 json[keyAdminPwdHash] = hash;
73 break;
74 default:
75 return ipmi::responseInvalidFieldRequest();
76 }
77
78 json[keyIsAdminPwdChanged] = false;
79 json[keyIsUserPwdChanged] = false;
80
81 // initializing with 0 as user password hash field
82 // is not used presently
83 constexpr std::array<uint8_t, biosPasswordMaxHashSize> userPwdHash = {0};
84 json[keyUserPwdHash] = userPwdHash;
85
86 try
87 {
88 std::ofstream ofs(biosPasswordFilePath, std::ios::out);
89 const auto& writeData = json.dump();
90 ofs << writeData;
91 ofs.close();
92 }
93 catch (std::exception& e)
94 {
95 lg2::error("Failed to save BIOS Password information: {ERROR}", "ERROR",
96 e.what());
97 return ipmi::responseUnspecifiedError();
98 }
99 return ipmi::responseSuccess();
100}
101
102ipmi::RspType<uint8_t, // action
103 std::array<uint8_t, biosPasswordSaltSize>, // salt
104 std::array<uint8_t, biosPasswordMaxHashSize> // hash
105 >
106 ipmiGetBiosPassword(uint8_t id)
107{
108 uint8_t action = biosPasswordTypeNoChange;
109 std::array<uint8_t, biosPasswordSaltSize> salt = {0};
110 std::array<uint8_t, biosPasswordMaxHashSize> hash = {0};
111
112 if (id != biosPasswordSelectorAdmin)
113 {
114 return ipmi::responseParmOutOfRange();
115 }
116
117 std::ifstream ifs(biosPasswordFilePath);
118 if (!ifs.is_open())
119 {
120 // return No change if no file
121 return ipmi::responseSuccess(action, salt, hash);
122 }
123
124 // key names for json object
125 constexpr char keyIsAdminPwdChanged[] = "IsAdminPwdChanged";
126 constexpr char keyHashAlgo[] = "HashAlgo";
127 constexpr char keySeed[] = "Seed";
128 constexpr char keyAdminPwdHash[] = "AdminPwdHash";
129
130 nlohmann::json json = nlohmann::json::parse(ifs, nullptr, false);
131 if (json.is_discarded() || !json.contains(keyIsAdminPwdChanged) ||
132 !json.contains(keyHashAlgo) || !json.contains(keySeed) ||
133 !json.contains(keyAdminPwdHash))
134 {
135 return ipmi::responseResponseError();
136 }
137 bool IsAdminPwdChanged = json[keyIsAdminPwdChanged];
138 if (IsAdminPwdChanged == false)
139 {
140 return ipmi::responseSuccess(action, salt, hash);
141 }
142
143 salt = json[keySeed];
144 hash = json[keyAdminPwdHash];
145
146 std::string HashAlgo = json[keyHashAlgo];
147 auto digest = EVP_sha256();
148 int keylen = SHA256_DIGEST_LENGTH;
149
150 if (HashAlgo == "SHA256")
151 {
152 action = biosPasswordTypePbkdf2Sha256;
153 }
154 else if (HashAlgo == "SHA384")
155 {
156 action = biosPasswordTypePbkdf2Sha384;
157 digest = EVP_sha384();
158 keylen = SHA384_DIGEST_LENGTH;
159 }
160
161 std::array<uint8_t, biosPasswordMaxHashSize> nullHash = {0};
162 PKCS5_PBKDF2_HMAC("", 1, salt.data(), salt.size(), biosPasswordIter, digest,
163 keylen, nullHash.data());
164 if (hash == nullHash)
165 {
166 action = biosPasswordTypeNoPassowrd;
167 salt.fill(0x00);
168 hash.fill(0x00);
169 }
170
171 return ipmi::responseSuccess(action, salt, hash);
172}
173} // namespace ipmi
174
175void registerBiosConfigCommands()
176{
177 ipmi::registerHandler(ipmi::prioOemBase, ipmi::groupNvidia,
178 ipmi::bios_password::cmdSetBiosPassword,
179 ipmi::Privilege::Admin, ipmi::ipmiSetBiosPassword);
180 ipmi::registerHandler(ipmi::prioOemBase, ipmi::groupNvidia,
181 ipmi::bios_password::cmdGetBiosPassword,
182 ipmi::Privilege::Admin, ipmi::ipmiGetBiosPassword);
183}