xref: /openbmc/phosphor-host-ipmid/oem/nvidia/biosconfigcommands.cpp (revision 6b580c7ceb0a5073c3ff3d264ab52e2a726dc9d5)
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