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