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