xref: /openbmc/phosphor-host-ipmid/user_channel/passwd_mgr.cpp (revision 82844ef677e97757881b43052e7c67691e8d377c)
14654d99fSRichard Marian Thomaiyar /*
24654d99fSRichard Marian Thomaiyar // Copyright (c) 2018 Intel Corporation
34654d99fSRichard Marian Thomaiyar //
44654d99fSRichard Marian Thomaiyar // Licensed under the Apache License, Version 2.0 (the "License");
54654d99fSRichard Marian Thomaiyar // you may not use this file except in compliance with the License.
64654d99fSRichard Marian Thomaiyar // You may obtain a copy of the License at
74654d99fSRichard Marian Thomaiyar //
84654d99fSRichard Marian Thomaiyar //      http://www.apache.org/licenses/LICENSE-2.0
94654d99fSRichard Marian Thomaiyar //
104654d99fSRichard Marian Thomaiyar // Unless required by applicable law or agreed to in writing, software
114654d99fSRichard Marian Thomaiyar // distributed under the License is distributed on an "AS IS" BASIS,
124654d99fSRichard Marian Thomaiyar // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134654d99fSRichard Marian Thomaiyar // See the License for the specific language governing permissions and
144654d99fSRichard Marian Thomaiyar // limitations under the License.
154654d99fSRichard Marian Thomaiyar */
164654d99fSRichard Marian Thomaiyar 
174654d99fSRichard Marian Thomaiyar #include "passwd_mgr.hpp"
184654d99fSRichard Marian Thomaiyar 
19b29b5ab3SAppaRao Puli #include "file.hpp"
204654d99fSRichard Marian Thomaiyar #include "shadowlock.hpp"
214654d99fSRichard Marian Thomaiyar 
224654d99fSRichard Marian Thomaiyar #include <openssl/hmac.h>
23b29b5ab3SAppaRao Puli #include <openssl/rand.h>
244654d99fSRichard Marian Thomaiyar #include <openssl/sha.h>
254654d99fSRichard Marian Thomaiyar #include <string.h>
264654d99fSRichard Marian Thomaiyar #include <sys/stat.h>
27b29b5ab3SAppaRao Puli #include <unistd.h>
284654d99fSRichard Marian Thomaiyar 
29*82844ef6SGeorge Liu #include <phosphor-logging/lg2.hpp>
30fbc6c9d7SPatrick Williams 
31b29b5ab3SAppaRao Puli #include <cerrno>
324654d99fSRichard Marian Thomaiyar #include <cstring>
334654d99fSRichard Marian Thomaiyar #include <fstream>
34b29b5ab3SAppaRao Puli #include <iomanip>
354654d99fSRichard Marian Thomaiyar 
364654d99fSRichard Marian Thomaiyar namespace ipmi
374654d99fSRichard Marian Thomaiyar {
384654d99fSRichard Marian Thomaiyar 
394654d99fSRichard Marian Thomaiyar static const char* passwdFileName = "/etc/ipmi_pass";
404654d99fSRichard Marian Thomaiyar static const char* encryptKeyFileName = "/etc/key_file";
414654d99fSRichard Marian Thomaiyar static const size_t maxKeySize = 8;
424654d99fSRichard Marian Thomaiyar 
436ba8d315SRichard Marian Thomaiyar constexpr mode_t modeMask =
446ba8d315SRichard Marian Thomaiyar     (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
456ba8d315SRichard Marian Thomaiyar 
46b29b5ab3SAppaRao Puli #define META_PASSWD_SIG "=OPENBMC="
47b29b5ab3SAppaRao Puli 
484654d99fSRichard Marian Thomaiyar /*
494654d99fSRichard Marian Thomaiyar  * Meta data struct for encrypted password file
504654d99fSRichard Marian Thomaiyar  */
5148e55585SRichard Marian Thomaiyar struct MetaPassStruct
524654d99fSRichard Marian Thomaiyar {
534654d99fSRichard Marian Thomaiyar     char signature[10];
544654d99fSRichard Marian Thomaiyar     unsigned char reseved[2];
5565a9168cSTim Lee     size_t hashSize;
5665a9168cSTim Lee     size_t ivSize;
5765a9168cSTim Lee     size_t dataSize;
5865a9168cSTim Lee     size_t padSize;
5965a9168cSTim Lee     size_t macSize;
604654d99fSRichard Marian Thomaiyar };
614654d99fSRichard Marian Thomaiyar 
624654d99fSRichard Marian Thomaiyar PasswdMgr::PasswdMgr()
634654d99fSRichard Marian Thomaiyar {
646ba8d315SRichard Marian Thomaiyar     restrictFilesPermission();
654654d99fSRichard Marian Thomaiyar     initPasswordMap();
664654d99fSRichard Marian Thomaiyar }
674654d99fSRichard Marian Thomaiyar 
686ba8d315SRichard Marian Thomaiyar void PasswdMgr::restrictFilesPermission(void)
696ba8d315SRichard Marian Thomaiyar {
706ba8d315SRichard Marian Thomaiyar     struct stat st = {};
716ba8d315SRichard Marian Thomaiyar     // Restrict file permission to owner read & write
726ba8d315SRichard Marian Thomaiyar     if (stat(passwdFileName, &st) == 0)
736ba8d315SRichard Marian Thomaiyar     {
746ba8d315SRichard Marian Thomaiyar         if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
756ba8d315SRichard Marian Thomaiyar         {
763771f5f2SPavanKumarIntel             if (chmod(passwdFileName, S_IRUSR | S_IWUSR) == -1)
773771f5f2SPavanKumarIntel             {
78*82844ef6SGeorge Liu                 lg2::debug("Error setting chmod for ipmi_pass file");
793771f5f2SPavanKumarIntel             }
806ba8d315SRichard Marian Thomaiyar         }
816ba8d315SRichard Marian Thomaiyar     }
826ba8d315SRichard Marian Thomaiyar 
836ba8d315SRichard Marian Thomaiyar     if (stat(encryptKeyFileName, &st) == 0)
846ba8d315SRichard Marian Thomaiyar     {
856ba8d315SRichard Marian Thomaiyar         if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
866ba8d315SRichard Marian Thomaiyar         {
873771f5f2SPavanKumarIntel             if (chmod(encryptKeyFileName, S_IRUSR | S_IWUSR) == -1)
883771f5f2SPavanKumarIntel             {
89*82844ef6SGeorge Liu                 lg2::debug("Error setting chmod for ipmi_pass file");
903771f5f2SPavanKumarIntel             }
916ba8d315SRichard Marian Thomaiyar         }
926ba8d315SRichard Marian Thomaiyar     }
936ba8d315SRichard Marian Thomaiyar }
946ba8d315SRichard Marian Thomaiyar 
951e22a0f1SVernon Mauery SecureString PasswdMgr::getPasswdByUserName(const std::string& userName)
964654d99fSRichard Marian Thomaiyar {
974654d99fSRichard Marian Thomaiyar     checkAndReload();
984654d99fSRichard Marian Thomaiyar     auto iter = passwdMapList.find(userName);
994654d99fSRichard Marian Thomaiyar     if (iter == passwdMapList.end())
1004654d99fSRichard Marian Thomaiyar     {
1011e22a0f1SVernon Mauery         return SecureString();
1024654d99fSRichard Marian Thomaiyar     }
1034654d99fSRichard Marian Thomaiyar     return iter->second;
1044654d99fSRichard Marian Thomaiyar }
1054654d99fSRichard Marian Thomaiyar 
10642bed64dSRichard Marian Thomaiyar int PasswdMgr::updateUserEntry(const std::string& userName,
10742bed64dSRichard Marian Thomaiyar                                const std::string& newUserName)
108b29b5ab3SAppaRao Puli {
109b29b5ab3SAppaRao Puli     std::time_t updatedTime = getUpdatedFileTime();
110b29b5ab3SAppaRao Puli     // Check file time stamp to know passwdMapList is up-to-date.
111b29b5ab3SAppaRao Puli     // If not up-to-date, then updatePasswdSpecialFile will read and
112b29b5ab3SAppaRao Puli     // check the user entry existance.
113b29b5ab3SAppaRao Puli     if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
114b29b5ab3SAppaRao Puli     {
115b29b5ab3SAppaRao Puli         if (passwdMapList.find(userName) == passwdMapList.end())
116b29b5ab3SAppaRao Puli         {
117*82844ef6SGeorge Liu             lg2::debug("User not found");
118b29b5ab3SAppaRao Puli             return 0;
119b29b5ab3SAppaRao Puli         }
120b29b5ab3SAppaRao Puli     }
121b29b5ab3SAppaRao Puli 
122b29b5ab3SAppaRao Puli     // Write passwdMap to Encryted file
12342bed64dSRichard Marian Thomaiyar     if (updatePasswdSpecialFile(userName, newUserName) != 0)
124b29b5ab3SAppaRao Puli     {
125*82844ef6SGeorge Liu         lg2::debug("Passwd file update failed");
126b29b5ab3SAppaRao Puli         return -EIO;
127b29b5ab3SAppaRao Puli     }
128b29b5ab3SAppaRao Puli 
129*82844ef6SGeorge Liu     lg2::debug("Passwd file updated successfully");
130b29b5ab3SAppaRao Puli     return 0;
131b29b5ab3SAppaRao Puli }
132b29b5ab3SAppaRao Puli 
1334654d99fSRichard Marian Thomaiyar void PasswdMgr::checkAndReload(void)
1344654d99fSRichard Marian Thomaiyar {
135b29b5ab3SAppaRao Puli     std::time_t updatedTime = getUpdatedFileTime();
136b29b5ab3SAppaRao Puli     if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
1374654d99fSRichard Marian Thomaiyar     {
138*82844ef6SGeorge Liu         lg2::debug("Reloading password map list");
1394654d99fSRichard Marian Thomaiyar         passwdMapList.clear();
1404654d99fSRichard Marian Thomaiyar         initPasswordMap();
1414654d99fSRichard Marian Thomaiyar     }
1424654d99fSRichard Marian Thomaiyar }
1434654d99fSRichard Marian Thomaiyar 
144b29b5ab3SAppaRao Puli int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher,
145b29b5ab3SAppaRao Puli                                   uint8_t* key, size_t keyLen, uint8_t* iv,
146b29b5ab3SAppaRao Puli                                   size_t ivLen, uint8_t* inBytes,
147b29b5ab3SAppaRao Puli                                   size_t inBytesLen, uint8_t* mac,
148b29b5ab3SAppaRao Puli                                   size_t* macLen, unsigned char* outBytes,
149b29b5ab3SAppaRao Puli                                   size_t* outBytesLen)
1504654d99fSRichard Marian Thomaiyar {
1514654d99fSRichard Marian Thomaiyar     if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
1524654d99fSRichard Marian Thomaiyar         outBytes == NULL || mac == NULL || inBytesLen == 0 ||
1534654d99fSRichard Marian Thomaiyar         (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
1544654d99fSRichard Marian Thomaiyar         (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
1554654d99fSRichard Marian Thomaiyar     {
156*82844ef6SGeorge Liu         lg2::debug("Error Invalid Inputs");
157b29b5ab3SAppaRao Puli         return -EINVAL;
1584654d99fSRichard Marian Thomaiyar     }
1594654d99fSRichard Marian Thomaiyar 
160b29b5ab3SAppaRao Puli     if (!doEncrypt)
161b29b5ab3SAppaRao Puli     {
162b29b5ab3SAppaRao Puli         // verify MAC before decrypting the data.
1634654d99fSRichard Marian Thomaiyar         std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
1644654d99fSRichard Marian Thomaiyar         size_t calMacLen = calMac.size();
1654654d99fSRichard Marian Thomaiyar         // calculate MAC for the encrypted message.
1664654d99fSRichard Marian Thomaiyar         if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen,
1674654d99fSRichard Marian Thomaiyar                          calMac.data(),
1684654d99fSRichard Marian Thomaiyar                          reinterpret_cast<unsigned int*>(&calMacLen)))
1694654d99fSRichard Marian Thomaiyar         {
170*82844ef6SGeorge Liu             lg2::debug("Error: Failed to calculate MAC");
171b29b5ab3SAppaRao Puli             return -EIO;
1724654d99fSRichard Marian Thomaiyar         }
173b29b5ab3SAppaRao Puli         if (!((calMacLen == *macLen) &&
1744654d99fSRichard Marian Thomaiyar               (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
1754654d99fSRichard Marian Thomaiyar         {
176*82844ef6SGeorge Liu             lg2::debug("Authenticated message doesn't match");
177b29b5ab3SAppaRao Puli             return -EBADMSG;
178b29b5ab3SAppaRao Puli         }
1794654d99fSRichard Marian Thomaiyar     }
1804654d99fSRichard Marian Thomaiyar 
1814654d99fSRichard Marian Thomaiyar     std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
1824654d99fSRichard Marian Thomaiyar         EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
1834654d99fSRichard Marian Thomaiyar 
184bf30c8d3SP Dheeraj Srujan Kumar     if (!ctx)
185bf30c8d3SP Dheeraj Srujan Kumar     {
186*82844ef6SGeorge Liu         lg2::debug("Error: EVP_CIPHER_CTX is NULL");
187bf30c8d3SP Dheeraj Srujan Kumar         return -ENOMEM;
188bf30c8d3SP Dheeraj Srujan Kumar     }
189bf30c8d3SP Dheeraj Srujan Kumar 
190a67caed7SP Dheeraj Srujan Kumar     EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
191a67caed7SP Dheeraj Srujan Kumar 
192b29b5ab3SAppaRao Puli     // Set key & IV
193b29b5ab3SAppaRao Puli     int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
194b29b5ab3SAppaRao Puli                                    static_cast<int>(doEncrypt));
1954654d99fSRichard Marian Thomaiyar     if (!retval)
1964654d99fSRichard Marian Thomaiyar     {
197*82844ef6SGeorge Liu         lg2::debug("EVP_CipherInit_ex failed: {RET_VAL}", "RET_VAL", retval);
198b29b5ab3SAppaRao Puli         return -EIO;
1994654d99fSRichard Marian Thomaiyar     }
2004654d99fSRichard Marian Thomaiyar 
2014654d99fSRichard Marian Thomaiyar     int outLen = 0, outEVPLen = 0;
2024654d99fSRichard Marian Thomaiyar     if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
2034654d99fSRichard Marian Thomaiyar                                    inBytes, inBytesLen)))
2044654d99fSRichard Marian Thomaiyar     {
2054654d99fSRichard Marian Thomaiyar         outLen += outEVPLen;
206fbc6c9d7SPatrick Williams         if ((retval = EVP_CipherFinal(ctx.get(), outBytes + outLen,
207fbc6c9d7SPatrick Williams                                       &outEVPLen)))
2084654d99fSRichard Marian Thomaiyar         {
2094654d99fSRichard Marian Thomaiyar             outLen += outEVPLen;
2104654d99fSRichard Marian Thomaiyar             *outBytesLen = outLen;
2114654d99fSRichard Marian Thomaiyar         }
2124654d99fSRichard Marian Thomaiyar         else
2134654d99fSRichard Marian Thomaiyar         {
214*82844ef6SGeorge Liu             lg2::debug("EVP_CipherFinal fails: {RET_VAL}", "RET_VAL", retval);
215b29b5ab3SAppaRao Puli             return -EIO;
2164654d99fSRichard Marian Thomaiyar         }
2174654d99fSRichard Marian Thomaiyar     }
2184654d99fSRichard Marian Thomaiyar     else
2194654d99fSRichard Marian Thomaiyar     {
220*82844ef6SGeorge Liu         lg2::debug("EVP_CipherUpdate fails: {RET_VAL}", "RET_VAL", retval);
221b29b5ab3SAppaRao Puli         return -EIO;
222b29b5ab3SAppaRao Puli     }
223b29b5ab3SAppaRao Puli 
224b29b5ab3SAppaRao Puli     if (doEncrypt)
225b29b5ab3SAppaRao Puli     {
226b29b5ab3SAppaRao Puli         // Create MAC for the encrypted message
227b29b5ab3SAppaRao Puli         if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
228b29b5ab3SAppaRao Puli                          reinterpret_cast<unsigned int*>(macLen)))
229b29b5ab3SAppaRao Puli         {
230*82844ef6SGeorge Liu             lg2::debug("Failed to create authentication");
231b29b5ab3SAppaRao Puli             return -EIO;
232b29b5ab3SAppaRao Puli         }
2334654d99fSRichard Marian Thomaiyar     }
2344654d99fSRichard Marian Thomaiyar     return 0;
2354654d99fSRichard Marian Thomaiyar }
2364654d99fSRichard Marian Thomaiyar 
2374654d99fSRichard Marian Thomaiyar void PasswdMgr::initPasswordMap(void)
2384654d99fSRichard Marian Thomaiyar {
2392f0ad74dSAndrew Geissler     // TODO  phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
2401e22a0f1SVernon Mauery     SecureString dataBuf;
2414654d99fSRichard Marian Thomaiyar 
242b29b5ab3SAppaRao Puli     if (readPasswdFileData(dataBuf) != 0)
2434654d99fSRichard Marian Thomaiyar     {
244*82844ef6SGeorge Liu         lg2::debug("Error in reading the encrypted pass file");
2454654d99fSRichard Marian Thomaiyar         return;
2464654d99fSRichard Marian Thomaiyar     }
2474654d99fSRichard Marian Thomaiyar 
248b29b5ab3SAppaRao Puli     if (dataBuf.size() != 0)
2494654d99fSRichard Marian Thomaiyar     {
2504654d99fSRichard Marian Thomaiyar         // populate the user list with password
2511e22a0f1SVernon Mauery         char* outPtr = dataBuf.data();
2524654d99fSRichard Marian Thomaiyar         char* nToken = NULL;
2534654d99fSRichard Marian Thomaiyar         char* linePtr = strtok_r(outPtr, "\n", &nToken);
25451d0c40aSPatrick Venture         size_t lineSize = 0;
2554654d99fSRichard Marian Thomaiyar         while (linePtr != NULL)
2564654d99fSRichard Marian Thomaiyar         {
25751d0c40aSPatrick Venture             size_t userEPos = 0;
2581e22a0f1SVernon Mauery             SecureString lineStr(linePtr);
2594654d99fSRichard Marian Thomaiyar             if ((userEPos = lineStr.find(":")) != std::string::npos)
2604654d99fSRichard Marian Thomaiyar             {
2614654d99fSRichard Marian Thomaiyar                 lineSize = lineStr.size();
2624654d99fSRichard Marian Thomaiyar                 passwdMapList.emplace(
2634654d99fSRichard Marian Thomaiyar                     lineStr.substr(0, userEPos),
2644654d99fSRichard Marian Thomaiyar                     lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
2654654d99fSRichard Marian Thomaiyar             }
2664654d99fSRichard Marian Thomaiyar             linePtr = strtok_r(NULL, "\n", &nToken);
2674654d99fSRichard Marian Thomaiyar         }
268b29b5ab3SAppaRao Puli     }
269b29b5ab3SAppaRao Puli 
2704654d99fSRichard Marian Thomaiyar     // Update the timestamp
271b29b5ab3SAppaRao Puli     fileLastUpdatedTime = getUpdatedFileTime();
272b29b5ab3SAppaRao Puli     return;
273b29b5ab3SAppaRao Puli }
274b29b5ab3SAppaRao Puli 
2751e22a0f1SVernon Mauery int PasswdMgr::readPasswdFileData(SecureString& outBytes)
276b29b5ab3SAppaRao Puli {
277b29b5ab3SAppaRao Puli     std::array<uint8_t, maxKeySize> keyBuff;
278b29b5ab3SAppaRao Puli     std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
279b29b5ab3SAppaRao Puli     if (!keyFile.is_open())
280b29b5ab3SAppaRao Puli     {
281*82844ef6SGeorge Liu         lg2::debug("Error in opening encryption key file");
282b29b5ab3SAppaRao Puli         return -EIO;
283b29b5ab3SAppaRao Puli     }
284b29b5ab3SAppaRao Puli     keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
285b29b5ab3SAppaRao Puli     if (keyFile.fail())
286b29b5ab3SAppaRao Puli     {
287*82844ef6SGeorge Liu         lg2::debug("Error in reading encryption key file");
288b29b5ab3SAppaRao Puli         return -EIO;
289b29b5ab3SAppaRao Puli     }
290b29b5ab3SAppaRao Puli 
291b29b5ab3SAppaRao Puli     std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
292b29b5ab3SAppaRao Puli     if (!passwdFile.is_open())
293b29b5ab3SAppaRao Puli     {
294*82844ef6SGeorge Liu         lg2::debug("Error in opening ipmi password file");
295b29b5ab3SAppaRao Puli         return -EIO;
296b29b5ab3SAppaRao Puli     }
297b29b5ab3SAppaRao Puli 
298b29b5ab3SAppaRao Puli     // calculate file size and read the data
299b29b5ab3SAppaRao Puli     passwdFile.seekg(0, std::ios::end);
300b29b5ab3SAppaRao Puli     ssize_t fileSize = passwdFile.tellg();
301b29b5ab3SAppaRao Puli     passwdFile.seekg(0, std::ios::beg);
302b29b5ab3SAppaRao Puli     std::vector<uint8_t> input(fileSize);
303b29b5ab3SAppaRao Puli     passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
304b29b5ab3SAppaRao Puli     if (passwdFile.fail())
305b29b5ab3SAppaRao Puli     {
306*82844ef6SGeorge Liu         lg2::debug("Error in reading encryption key file");
307b29b5ab3SAppaRao Puli         return -EIO;
308b29b5ab3SAppaRao Puli     }
309b29b5ab3SAppaRao Puli 
310b29b5ab3SAppaRao Puli     // verify the signature first
31148e55585SRichard Marian Thomaiyar     MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
312b29b5ab3SAppaRao Puli     if (std::strncmp(metaData->signature, META_PASSWD_SIG,
313b29b5ab3SAppaRao Puli                      sizeof(metaData->signature)))
314b29b5ab3SAppaRao Puli     {
315*82844ef6SGeorge Liu         lg2::debug("Error signature mismatch in password file");
316b29b5ab3SAppaRao Puli         return -EBADMSG;
317b29b5ab3SAppaRao Puli     }
318b29b5ab3SAppaRao Puli 
319b29b5ab3SAppaRao Puli     size_t inBytesLen = metaData->dataSize + metaData->padSize;
320b29b5ab3SAppaRao Puli     // If data is empty i.e no password map then return success
321b29b5ab3SAppaRao Puli     if (inBytesLen == 0)
322b29b5ab3SAppaRao Puli     {
323*82844ef6SGeorge Liu         lg2::debug("Empty password file");
324b29b5ab3SAppaRao Puli         return 0;
325b29b5ab3SAppaRao Puli     }
326b29b5ab3SAppaRao Puli 
327b29b5ab3SAppaRao Puli     // compute the key needed to decrypt
328b29b5ab3SAppaRao Puli     std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
329b29b5ab3SAppaRao Puli     auto keyLen = key.size();
330b29b5ab3SAppaRao Puli     if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
331b29b5ab3SAppaRao Puli                      input.data() + sizeof(*metaData), metaData->hashSize,
332b29b5ab3SAppaRao Puli                      key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
333b29b5ab3SAppaRao Puli     {
334*82844ef6SGeorge Liu         lg2::debug("Failed to create MAC for authentication");
335b29b5ab3SAppaRao Puli         return -EIO;
336b29b5ab3SAppaRao Puli     }
337b29b5ab3SAppaRao Puli 
338b29b5ab3SAppaRao Puli     // decrypt the data
339b29b5ab3SAppaRao Puli     uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
340b29b5ab3SAppaRao Puli     size_t ivLen = metaData->ivSize;
341b29b5ab3SAppaRao Puli     uint8_t* inBytes = iv + ivLen;
342b29b5ab3SAppaRao Puli     uint8_t* mac = inBytes + inBytesLen;
343b29b5ab3SAppaRao Puli     size_t macLen = metaData->macSize;
344b29b5ab3SAppaRao Puli 
345b29b5ab3SAppaRao Puli     size_t outBytesLen = 0;
346b29b5ab3SAppaRao Puli     // Resize to actual data size
3471e22a0f1SVernon Mauery     outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH, '\0');
348b29b5ab3SAppaRao Puli     if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
349b29b5ab3SAppaRao Puli                            ivLen, inBytes, inBytesLen, mac, &macLen,
3501e22a0f1SVernon Mauery                            reinterpret_cast<unsigned char*>(outBytes.data()),
3511e22a0f1SVernon Mauery                            &outBytesLen) != 0)
352b29b5ab3SAppaRao Puli     {
353*82844ef6SGeorge Liu         lg2::debug("Error in decryption");
354b29b5ab3SAppaRao Puli         return -EIO;
355b29b5ab3SAppaRao Puli     }
356b29b5ab3SAppaRao Puli     // Resize the vector to outBytesLen
357b29b5ab3SAppaRao Puli     outBytes.resize(outBytesLen);
358b29b5ab3SAppaRao Puli 
359b29b5ab3SAppaRao Puli     OPENSSL_cleanse(key.data(), keyLen);
360b29b5ab3SAppaRao Puli     OPENSSL_cleanse(iv, ivLen);
361b29b5ab3SAppaRao Puli 
362b29b5ab3SAppaRao Puli     return 0;
363b29b5ab3SAppaRao Puli }
364b29b5ab3SAppaRao Puli 
36542bed64dSRichard Marian Thomaiyar int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
36642bed64dSRichard Marian Thomaiyar                                        const std::string& newUserName)
367b29b5ab3SAppaRao Puli {
3682f0ad74dSAndrew Geissler     // TODO  phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
369b29b5ab3SAppaRao Puli 
370b29b5ab3SAppaRao Puli     size_t bytesWritten = 0;
371b29b5ab3SAppaRao Puli     size_t inBytesLen = 0;
372b29b5ab3SAppaRao Puli     size_t isUsrFound = false;
373b29b5ab3SAppaRao Puli     const EVP_CIPHER* cipher = EVP_aes_128_cbc();
3741e22a0f1SVernon Mauery     SecureString dataBuf;
375b29b5ab3SAppaRao Puli 
376b29b5ab3SAppaRao Puli     // Read the encrypted file and get the file data
377b29b5ab3SAppaRao Puli     // Check user existance and return if not exist.
378b29b5ab3SAppaRao Puli     if (readPasswdFileData(dataBuf) != 0)
379b29b5ab3SAppaRao Puli     {
380*82844ef6SGeorge Liu         lg2::debug("Error in reading the encrypted pass file");
381b29b5ab3SAppaRao Puli         return -EIO;
382b29b5ab3SAppaRao Puli     }
383b29b5ab3SAppaRao Puli 
384b29b5ab3SAppaRao Puli     if (dataBuf.size() != 0)
385b29b5ab3SAppaRao Puli     {
386fbc6c9d7SPatrick Williams         inBytesLen = dataBuf.size() + newUserName.size() +
387fbc6c9d7SPatrick Williams                      EVP_CIPHER_block_size(cipher);
388b29b5ab3SAppaRao Puli     }
389b29b5ab3SAppaRao Puli 
3901e22a0f1SVernon Mauery     SecureString inBytes(inBytesLen, '\0');
391b29b5ab3SAppaRao Puli     if (inBytesLen != 0)
392b29b5ab3SAppaRao Puli     {
393b29b5ab3SAppaRao Puli         char* outPtr = reinterpret_cast<char*>(dataBuf.data());
394b29b5ab3SAppaRao Puli         char* nToken = NULL;
395b29b5ab3SAppaRao Puli         char* linePtr = strtok_r(outPtr, "\n", &nToken);
396b29b5ab3SAppaRao Puli         while (linePtr != NULL)
397b29b5ab3SAppaRao Puli         {
39851d0c40aSPatrick Venture             size_t userEPos = 0;
39951d0c40aSPatrick Venture 
4001e22a0f1SVernon Mauery             SecureString lineStr(linePtr);
401b29b5ab3SAppaRao Puli             if ((userEPos = lineStr.find(":")) != std::string::npos)
402b29b5ab3SAppaRao Puli             {
403b29b5ab3SAppaRao Puli                 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
404b29b5ab3SAppaRao Puli                 {
405b29b5ab3SAppaRao Puli                     isUsrFound = true;
40642bed64dSRichard Marian Thomaiyar                     if (!newUserName.empty())
40742bed64dSRichard Marian Thomaiyar                     {
40842bed64dSRichard Marian Thomaiyar                         bytesWritten += std::snprintf(
4091e22a0f1SVernon Mauery                             &inBytes[0] + bytesWritten,
41042bed64dSRichard Marian Thomaiyar                             (inBytesLen - bytesWritten), "%s%s\n",
41142bed64dSRichard Marian Thomaiyar                             newUserName.c_str(),
41242bed64dSRichard Marian Thomaiyar                             lineStr.substr(userEPos, lineStr.size()).data());
41342bed64dSRichard Marian Thomaiyar                     }
414b29b5ab3SAppaRao Puli                 }
415b29b5ab3SAppaRao Puli                 else
416b29b5ab3SAppaRao Puli                 {
4171e22a0f1SVernon Mauery                     bytesWritten += std::snprintf(&inBytes[0] + bytesWritten,
4181e22a0f1SVernon Mauery                                                   (inBytesLen - bytesWritten),
4191e22a0f1SVernon Mauery                                                   "%s\n", lineStr.data());
420b29b5ab3SAppaRao Puli                 }
421b29b5ab3SAppaRao Puli             }
422b29b5ab3SAppaRao Puli             linePtr = strtok_r(NULL, "\n", &nToken);
423b29b5ab3SAppaRao Puli         }
424161f20d5SRichard Marian Thomaiyar         inBytesLen = bytesWritten;
425b29b5ab3SAppaRao Puli     }
426b29b5ab3SAppaRao Puli     if (!isUsrFound)
427b29b5ab3SAppaRao Puli     {
428*82844ef6SGeorge Liu         lg2::debug("User doesn't exist");
429b29b5ab3SAppaRao Puli         return 0;
430b29b5ab3SAppaRao Puli     }
431b29b5ab3SAppaRao Puli 
432b29b5ab3SAppaRao Puli     // Read the key buff from key file
433b29b5ab3SAppaRao Puli     std::array<uint8_t, maxKeySize> keyBuff;
434b29b5ab3SAppaRao Puli     std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
435b29b5ab3SAppaRao Puli     if (!keyFile.good())
436b29b5ab3SAppaRao Puli     {
437*82844ef6SGeorge Liu         lg2::debug("Error in opening encryption key file");
438b29b5ab3SAppaRao Puli         return -EIO;
439b29b5ab3SAppaRao Puli     }
440b29b5ab3SAppaRao Puli     keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
441b29b5ab3SAppaRao Puli     if (keyFile.fail())
442b29b5ab3SAppaRao Puli     {
443*82844ef6SGeorge Liu         lg2::debug("Error in reading encryption key file");
444b29b5ab3SAppaRao Puli         return -EIO;
445b29b5ab3SAppaRao Puli     }
446b29b5ab3SAppaRao Puli     keyFile.close();
447b29b5ab3SAppaRao Puli 
448b29b5ab3SAppaRao Puli     // Read the original passwd file mode
449b29b5ab3SAppaRao Puli     struct stat st = {};
450b29b5ab3SAppaRao Puli     if (stat(passwdFileName, &st) != 0)
451b29b5ab3SAppaRao Puli     {
452*82844ef6SGeorge Liu         lg2::debug("Error in getting password file fstat()");
453b29b5ab3SAppaRao Puli         return -EIO;
454b29b5ab3SAppaRao Puli     }
455b29b5ab3SAppaRao Puli 
456b29b5ab3SAppaRao Puli     // Create temporary file for write
457b29b5ab3SAppaRao Puli     std::string pwdFile(passwdFileName);
458b29b5ab3SAppaRao Puli     std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
459b29b5ab3SAppaRao Puli     std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
460b29b5ab3SAppaRao Puli                                       'X', 'X', 'X', '\0'};
461b29b5ab3SAppaRao Puli     tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
462b29b5ab3SAppaRao Puli                         fileTemplate.end());
463b29b5ab3SAppaRao Puli     int fd = mkstemp((char*)tempFileName.data());
464b29b5ab3SAppaRao Puli     if (fd == -1)
465b29b5ab3SAppaRao Puli     {
466*82844ef6SGeorge Liu         lg2::debug("Error creating temp file");
467b29b5ab3SAppaRao Puli         return -EIO;
468b29b5ab3SAppaRao Puli     }
469b29b5ab3SAppaRao Puli 
470b29b5ab3SAppaRao Puli     std::string strTempFileName(tempFileName.data());
471b29b5ab3SAppaRao Puli     // Open the temp file for writing from provided fd
472b29b5ab3SAppaRao Puli     // By "true", remove it at exit if still there.
473b29b5ab3SAppaRao Puli     // This is needed to cleanup the temp file at exception
474b29b5ab3SAppaRao Puli     phosphor::user::File temp(fd, strTempFileName, "w", true);
475b29b5ab3SAppaRao Puli     if ((temp)() == NULL)
476b29b5ab3SAppaRao Puli     {
477b29b5ab3SAppaRao Puli         close(fd);
478*82844ef6SGeorge Liu         lg2::debug("Error creating temp file");
479b29b5ab3SAppaRao Puli         return -EIO;
480b29b5ab3SAppaRao Puli     }
481b29b5ab3SAppaRao Puli 
482b265455aSVernon Mauery     // Set the file mode as read-write for owner only
483b265455aSVernon Mauery     if (fchmod(fileno((temp)()), S_IRUSR | S_IWUSR) < 0)
484b29b5ab3SAppaRao Puli     {
485*82844ef6SGeorge Liu         lg2::debug("Error setting fchmod for temp file");
486b29b5ab3SAppaRao Puli         return -EIO;
487b29b5ab3SAppaRao Puli     }
488b29b5ab3SAppaRao Puli 
489b29b5ab3SAppaRao Puli     const EVP_MD* digest = EVP_sha256();
490b29b5ab3SAppaRao Puli     size_t hashLen = EVP_MD_block_size(digest);
491b29b5ab3SAppaRao Puli     std::vector<uint8_t> hash(hashLen);
492b29b5ab3SAppaRao Puli     size_t ivLen = EVP_CIPHER_iv_length(cipher);
493b29b5ab3SAppaRao Puli     std::vector<uint8_t> iv(ivLen);
494b29b5ab3SAppaRao Puli     std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
495b29b5ab3SAppaRao Puli     size_t keyLen = key.size();
496b29b5ab3SAppaRao Puli     std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
497b29b5ab3SAppaRao Puli     size_t macLen = mac.size();
498b29b5ab3SAppaRao Puli 
499b29b5ab3SAppaRao Puli     // Create random hash and generate hash key which will be used for
500b29b5ab3SAppaRao Puli     // encryption.
501b29b5ab3SAppaRao Puli     if (RAND_bytes(hash.data(), hashLen) != 1)
502b29b5ab3SAppaRao Puli     {
503*82844ef6SGeorge Liu         lg2::debug("Hash genertion failed, bailing out");
504b29b5ab3SAppaRao Puli         return -EIO;
505b29b5ab3SAppaRao Puli     }
506b29b5ab3SAppaRao Puli     if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(),
507b29b5ab3SAppaRao Puli                      hashLen, key.data(),
508b29b5ab3SAppaRao Puli                      reinterpret_cast<unsigned int*>(&keyLen)))
509b29b5ab3SAppaRao Puli     {
510*82844ef6SGeorge Liu         lg2::debug("Failed to create MAC for authentication");
511b29b5ab3SAppaRao Puli         return -EIO;
512b29b5ab3SAppaRao Puli     }
513b29b5ab3SAppaRao Puli 
514b29b5ab3SAppaRao Puli     // Generate IV values
515b29b5ab3SAppaRao Puli     if (RAND_bytes(iv.data(), ivLen) != 1)
516b29b5ab3SAppaRao Puli     {
517*82844ef6SGeorge Liu         lg2::debug("UV genertion failed, bailing out");
518b29b5ab3SAppaRao Puli         return -EIO;
519b29b5ab3SAppaRao Puli     }
520b29b5ab3SAppaRao Puli 
521b29b5ab3SAppaRao Puli     // Encrypt the input data
522b29b5ab3SAppaRao Puli     std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
523b29b5ab3SAppaRao Puli     size_t outBytesLen = 0;
524b29b5ab3SAppaRao Puli     if (inBytesLen != 0)
525b29b5ab3SAppaRao Puli     {
5261e22a0f1SVernon Mauery         if (encryptDecryptData(
5271e22a0f1SVernon Mauery                 true, EVP_aes_128_cbc(), key.data(), keyLen, iv.data(), ivLen,
5281e22a0f1SVernon Mauery                 reinterpret_cast<unsigned char*>(inBytes.data()), inBytesLen,
5291e22a0f1SVernon Mauery                 mac.data(), &macLen, outBytes.data(), &outBytesLen) != 0)
530b29b5ab3SAppaRao Puli         {
531*82844ef6SGeorge Liu             lg2::debug("Error while encrypting the data");
532b29b5ab3SAppaRao Puli             return -EIO;
533b29b5ab3SAppaRao Puli         }
534b29b5ab3SAppaRao Puli         outBytes[outBytesLen] = 0;
535b29b5ab3SAppaRao Puli     }
536b29b5ab3SAppaRao Puli     OPENSSL_cleanse(key.data(), keyLen);
537b29b5ab3SAppaRao Puli 
538b29b5ab3SAppaRao Puli     // Update the meta password structure.
53948e55585SRichard Marian Thomaiyar     MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
540b29b5ab3SAppaRao Puli     metaData.hashSize = hashLen;
541b29b5ab3SAppaRao Puli     metaData.ivSize = ivLen;
542b29b5ab3SAppaRao Puli     metaData.dataSize = bytesWritten;
543b29b5ab3SAppaRao Puli     metaData.padSize = outBytesLen - bytesWritten;
544b29b5ab3SAppaRao Puli     metaData.macSize = macLen;
545b29b5ab3SAppaRao Puli 
546b29b5ab3SAppaRao Puli     if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
547b29b5ab3SAppaRao Puli     {
548*82844ef6SGeorge Liu         lg2::debug("Error in writing meta data");
549b29b5ab3SAppaRao Puli         return -EIO;
550b29b5ab3SAppaRao Puli     }
551b29b5ab3SAppaRao Puli 
552b29b5ab3SAppaRao Puli     if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
553b29b5ab3SAppaRao Puli     {
554*82844ef6SGeorge Liu         lg2::debug("Error in writing hash data");
555b29b5ab3SAppaRao Puli         return -EIO;
556b29b5ab3SAppaRao Puli     }
557b29b5ab3SAppaRao Puli 
558b29b5ab3SAppaRao Puli     if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
559b29b5ab3SAppaRao Puli     {
560*82844ef6SGeorge Liu         lg2::debug("Error in writing IV data");
561b29b5ab3SAppaRao Puli         return -EIO;
562b29b5ab3SAppaRao Puli     }
563b29b5ab3SAppaRao Puli 
564b29b5ab3SAppaRao Puli     if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
565b29b5ab3SAppaRao Puli     {
566*82844ef6SGeorge Liu         lg2::debug("Error in writing encrypted data");
567b29b5ab3SAppaRao Puli         return -EIO;
568b29b5ab3SAppaRao Puli     }
569b29b5ab3SAppaRao Puli 
570b29b5ab3SAppaRao Puli     if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
571b29b5ab3SAppaRao Puli     {
572*82844ef6SGeorge Liu         lg2::debug("Error in writing MAC data");
573b29b5ab3SAppaRao Puli         return -EIO;
574b29b5ab3SAppaRao Puli     }
575b29b5ab3SAppaRao Puli 
576b29b5ab3SAppaRao Puli     if (fflush((temp)()))
577b29b5ab3SAppaRao Puli     {
578*82844ef6SGeorge Liu         lg2::debug("File fflush error while writing entries to special file");
579b29b5ab3SAppaRao Puli         return -EIO;
580b29b5ab3SAppaRao Puli     }
581b29b5ab3SAppaRao Puli 
582b29b5ab3SAppaRao Puli     OPENSSL_cleanse(iv.data(), ivLen);
583b29b5ab3SAppaRao Puli 
584b29b5ab3SAppaRao Puli     // Rename the tmp  file to actual file
585b29b5ab3SAppaRao Puli     if (std::rename(strTempFileName.data(), passwdFileName) != 0)
586b29b5ab3SAppaRao Puli     {
587*82844ef6SGeorge Liu         lg2::debug("Failed to rename tmp file to ipmi-pass");
588b29b5ab3SAppaRao Puli         return -EIO;
589b29b5ab3SAppaRao Puli     }
590b29b5ab3SAppaRao Puli 
591b29b5ab3SAppaRao Puli     return 0;
592b29b5ab3SAppaRao Puli }
593b29b5ab3SAppaRao Puli 
594b29b5ab3SAppaRao Puli std::time_t PasswdMgr::getUpdatedFileTime()
595b29b5ab3SAppaRao Puli {
5964654d99fSRichard Marian Thomaiyar     struct stat fileStat = {};
5974654d99fSRichard Marian Thomaiyar     if (stat(passwdFileName, &fileStat) != 0)
5984654d99fSRichard Marian Thomaiyar     {
599*82844ef6SGeorge Liu         lg2::debug("Error - Getting passwd file time stamp");
600b29b5ab3SAppaRao Puli         return -EIO;
6014654d99fSRichard Marian Thomaiyar     }
602b29b5ab3SAppaRao Puli     return fileStat.st_mtime;
6034654d99fSRichard Marian Thomaiyar }
6044654d99fSRichard Marian Thomaiyar 
6054654d99fSRichard Marian Thomaiyar } // namespace ipmi
606