blob: acf7c7482cd351017527cd809e63b238ee62caad [file] [log] [blame]
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +05301/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "passwd_mgr.hpp"
18
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053019#include "file.hpp"
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053020#include "shadowlock.hpp"
21
22#include <openssl/hmac.h>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053023#include <openssl/rand.h>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053024#include <openssl/sha.h>
25#include <string.h>
26#include <sys/stat.h>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053027#include <unistd.h>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053028
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050029#include <phosphor-logging/log.hpp>
30
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053031#include <cerrno>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053032#include <cstring>
33#include <fstream>
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053034#include <iomanip>
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053035
36namespace ipmi
37{
38
39static const char* passwdFileName = "/etc/ipmi_pass";
40static const char* encryptKeyFileName = "/etc/key_file";
41static const size_t maxKeySize = 8;
42
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053043constexpr mode_t modeMask =
44 (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
45
AppaRao Pulib29b5ab2018-05-17 10:28:48 +053046#define META_PASSWD_SIG "=OPENBMC="
47
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053048/*
49 * Meta data struct for encrypted password file
50 */
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +053051struct MetaPassStruct
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053052{
53 char signature[10];
54 unsigned char reseved[2];
Tim Lee65a91682022-11-30 17:14:13 +080055 size_t hashSize;
56 size_t ivSize;
57 size_t dataSize;
58 size_t padSize;
59 size_t macSize;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053060};
61
62using namespace phosphor::logging;
63
64PasswdMgr::PasswdMgr()
65{
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053066 restrictFilesPermission();
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053067 initPasswordMap();
68}
69
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053070void PasswdMgr::restrictFilesPermission(void)
71{
72 struct stat st = {};
73 // Restrict file permission to owner read & write
74 if (stat(passwdFileName, &st) == 0)
75 {
76 if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
77 {
PavanKumarIntel3771f5f2023-11-02 06:26:42 +000078 if (chmod(passwdFileName, S_IRUSR | S_IWUSR) == -1)
79 {
80 log<level::DEBUG>("Error setting chmod for ipmi_pass file");
81 }
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053082 }
83 }
84
85 if (stat(encryptKeyFileName, &st) == 0)
86 {
87 if ((st.st_mode & modeMask) != (S_IRUSR | S_IWUSR))
88 {
PavanKumarIntel3771f5f2023-11-02 06:26:42 +000089 if (chmod(encryptKeyFileName, S_IRUSR | S_IWUSR) == -1)
90 {
91 log<level::DEBUG>("Error setting chmod for ipmi_pass file");
92 }
Richard Marian Thomaiyar6ba8d312020-04-10 23:52:50 +053093 }
94 }
95}
96
Vernon Mauery1e22a0f2021-07-30 13:36:54 -070097SecureString PasswdMgr::getPasswdByUserName(const std::string& userName)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +053098{
99 checkAndReload();
100 auto iter = passwdMapList.find(userName);
101 if (iter == passwdMapList.end())
102 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700103 return SecureString();
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530104 }
105 return iter->second;
106}
107
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530108int PasswdMgr::updateUserEntry(const std::string& userName,
109 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530110{
111 std::time_t updatedTime = getUpdatedFileTime();
112 // Check file time stamp to know passwdMapList is up-to-date.
113 // If not up-to-date, then updatePasswdSpecialFile will read and
114 // check the user entry existance.
115 if (fileLastUpdatedTime == updatedTime && updatedTime != -EIO)
116 {
117 if (passwdMapList.find(userName) == passwdMapList.end())
118 {
119 log<level::DEBUG>("User not found");
120 return 0;
121 }
122 }
123
124 // Write passwdMap to Encryted file
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530125 if (updatePasswdSpecialFile(userName, newUserName) != 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530126 {
127 log<level::DEBUG>("Passwd file update failed");
128 return -EIO;
129 }
130
131 log<level::DEBUG>("Passwd file updated successfully");
132 return 0;
133}
134
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530135void PasswdMgr::checkAndReload(void)
136{
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530137 std::time_t updatedTime = getUpdatedFileTime();
138 if (fileLastUpdatedTime != updatedTime && updatedTime != -1)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530139 {
140 log<level::DEBUG>("Reloading password map list");
141 passwdMapList.clear();
142 initPasswordMap();
143 }
144}
145
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530146int PasswdMgr::encryptDecryptData(bool doEncrypt, const EVP_CIPHER* cipher,
147 uint8_t* key, size_t keyLen, uint8_t* iv,
148 size_t ivLen, uint8_t* inBytes,
149 size_t inBytesLen, uint8_t* mac,
150 size_t* macLen, unsigned char* outBytes,
151 size_t* outBytesLen)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530152{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530153 if (cipher == NULL || key == NULL || iv == NULL || inBytes == NULL ||
154 outBytes == NULL || mac == NULL || inBytesLen == 0 ||
155 (size_t)EVP_CIPHER_key_length(cipher) > keyLen ||
156 (size_t)EVP_CIPHER_iv_length(cipher) > ivLen)
157 {
158 log<level::DEBUG>("Error Invalid Inputs");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530159 return -EINVAL;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530160 }
161
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530162 if (!doEncrypt)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530163 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530164 // verify MAC before decrypting the data.
165 std::array<uint8_t, EVP_MAX_MD_SIZE> calMac;
166 size_t calMacLen = calMac.size();
167 // calculate MAC for the encrypted message.
168 if (NULL == HMAC(EVP_sha256(), key, keyLen, inBytes, inBytesLen,
169 calMac.data(),
170 reinterpret_cast<unsigned int*>(&calMacLen)))
171 {
172 log<level::DEBUG>("Error: Failed to calculate MAC");
173 return -EIO;
174 }
175 if (!((calMacLen == *macLen) &&
176 (std::memcmp(calMac.data(), mac, calMacLen) == 0)))
177 {
178 log<level::DEBUG>("Authenticated message doesn't match");
179 return -EBADMSG;
180 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530181 }
182
183 std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(
184 EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530185
P Dheeraj Srujan Kumarbf30c8d2021-07-20 04:06:37 +0530186 if (!ctx)
187 {
188 log<level::DEBUG>("Error: EVP_CIPHER_CTX is NULL");
189 return -ENOMEM;
190 }
191
P Dheeraj Srujan Kumara67caed2021-08-25 21:55:09 +0530192 EVP_CIPHER_CTX_set_padding(ctx.get(), 1);
193
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530194 // Set key & IV
195 int retval = EVP_CipherInit_ex(ctx.get(), cipher, NULL, key, iv,
196 static_cast<int>(doEncrypt));
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530197 if (!retval)
198 {
199 log<level::DEBUG>("EVP_CipherInit_ex failed",
200 entry("RET_VAL=%d", retval));
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530201 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530202 }
203
204 int outLen = 0, outEVPLen = 0;
205 if ((retval = EVP_CipherUpdate(ctx.get(), outBytes + outLen, &outEVPLen,
206 inBytes, inBytesLen)))
207 {
208 outLen += outEVPLen;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500209 if ((retval = EVP_CipherFinal(ctx.get(), outBytes + outLen,
210 &outEVPLen)))
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530211 {
212 outLen += outEVPLen;
213 *outBytesLen = outLen;
214 }
215 else
216 {
217 log<level::DEBUG>("EVP_CipherFinal fails",
218 entry("RET_VAL=%d", retval));
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530219 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530220 }
221 }
222 else
223 {
224 log<level::DEBUG>("EVP_CipherUpdate fails",
225 entry("RET_VAL=%d", retval));
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530226 return -EIO;
227 }
228
229 if (doEncrypt)
230 {
231 // Create MAC for the encrypted message
232 if (NULL == HMAC(EVP_sha256(), key, keyLen, outBytes, *outBytesLen, mac,
233 reinterpret_cast<unsigned int*>(macLen)))
234 {
235 log<level::DEBUG>("Failed to create authentication");
236 return -EIO;
237 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530238 }
239 return 0;
240}
241
242void PasswdMgr::initPasswordMap(void)
243{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500244 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700245 SecureString dataBuf;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530246
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530247 if (readPasswdFileData(dataBuf) != 0)
248 {
249 log<level::DEBUG>("Error in reading the encrypted pass file");
250 return;
251 }
252
253 if (dataBuf.size() != 0)
254 {
255 // populate the user list with password
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700256 char* outPtr = dataBuf.data();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530257 char* nToken = NULL;
258 char* linePtr = strtok_r(outPtr, "\n", &nToken);
Patrick Venture51d0c402019-08-19 11:19:19 -0700259 size_t lineSize = 0;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530260 while (linePtr != NULL)
261 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700262 size_t userEPos = 0;
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700263 SecureString lineStr(linePtr);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530264 if ((userEPos = lineStr.find(":")) != std::string::npos)
265 {
266 lineSize = lineStr.size();
267 passwdMapList.emplace(
268 lineStr.substr(0, userEPos),
269 lineStr.substr(userEPos + 1, lineSize - (userEPos + 1)));
270 }
271 linePtr = strtok_r(NULL, "\n", &nToken);
272 }
273 }
274
275 // Update the timestamp
276 fileLastUpdatedTime = getUpdatedFileTime();
277 return;
278}
279
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700280int PasswdMgr::readPasswdFileData(SecureString& outBytes)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530281{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530282 std::array<uint8_t, maxKeySize> keyBuff;
283 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
284 if (!keyFile.is_open())
285 {
286 log<level::DEBUG>("Error in opening encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530287 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530288 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530289 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530290 if (keyFile.fail())
291 {
292 log<level::DEBUG>("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530293 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530294 }
295
296 std::ifstream passwdFile(passwdFileName, std::ios::in | std::ios::binary);
297 if (!passwdFile.is_open())
298 {
299 log<level::DEBUG>("Error in opening ipmi password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530300 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530301 }
302
303 // calculate file size and read the data
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530304 passwdFile.seekg(0, std::ios::end);
305 ssize_t fileSize = passwdFile.tellg();
306 passwdFile.seekg(0, std::ios::beg);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530307 std::vector<uint8_t> input(fileSize);
308 passwdFile.read(reinterpret_cast<char*>(input.data()), fileSize);
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530309 if (passwdFile.fail())
310 {
311 log<level::DEBUG>("Error in reading encryption key file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530312 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530313 }
314
315 // verify the signature first
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530316 MetaPassStruct* metaData = reinterpret_cast<MetaPassStruct*>(input.data());
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530317 if (std::strncmp(metaData->signature, META_PASSWD_SIG,
318 sizeof(metaData->signature)))
319 {
320 log<level::DEBUG>("Error signature mismatch in password file");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530321 return -EBADMSG;
322 }
323
324 size_t inBytesLen = metaData->dataSize + metaData->padSize;
325 // If data is empty i.e no password map then return success
326 if (inBytesLen == 0)
327 {
328 log<level::DEBUG>("Empty password file");
329 return 0;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530330 }
331
332 // compute the key needed to decrypt
333 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
334 auto keyLen = key.size();
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530335 if (NULL == HMAC(EVP_sha256(), keyBuff.data(), keyBuff.size(),
336 input.data() + sizeof(*metaData), metaData->hashSize,
337 key.data(), reinterpret_cast<unsigned int*>(&keyLen)))
338 {
339 log<level::DEBUG>("Failed to create MAC for authentication");
340 return -EIO;
341 }
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530342
343 // decrypt the data
344 uint8_t* iv = input.data() + sizeof(*metaData) + metaData->hashSize;
345 size_t ivLen = metaData->ivSize;
346 uint8_t* inBytes = iv + ivLen;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530347 uint8_t* mac = inBytes + inBytesLen;
348 size_t macLen = metaData->macSize;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530349
350 size_t outBytesLen = 0;
351 // Resize to actual data size
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700352 outBytes.resize(inBytesLen + EVP_MAX_BLOCK_LENGTH, '\0');
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530353 if (encryptDecryptData(false, EVP_aes_128_cbc(), key.data(), keyLen, iv,
354 ivLen, inBytes, inBytesLen, mac, &macLen,
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700355 reinterpret_cast<unsigned char*>(outBytes.data()),
356 &outBytesLen) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530357 {
358 log<level::DEBUG>("Error in decryption");
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530359 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530360 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530361 // Resize the vector to outBytesLen
362 outBytes.resize(outBytesLen);
363
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530364 OPENSSL_cleanse(key.data(), keyLen);
365 OPENSSL_cleanse(iv, ivLen);
366
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530367 return 0;
368}
369
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530370int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
371 const std::string& newUserName)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530372{
Andrew Geissler2f0ad742021-05-14 13:39:15 -0500373 // TODO phosphor-host-ipmid#170 phosphor::user::shadow::Lock lock{};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530374
375 size_t bytesWritten = 0;
376 size_t inBytesLen = 0;
377 size_t isUsrFound = false;
378 const EVP_CIPHER* cipher = EVP_aes_128_cbc();
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700379 SecureString dataBuf;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530380
381 // Read the encrypted file and get the file data
382 // Check user existance and return if not exist.
383 if (readPasswdFileData(dataBuf) != 0)
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530384 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530385 log<level::DEBUG>("Error in reading the encrypted pass file");
386 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530387 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530388
389 if (dataBuf.size() != 0)
390 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500391 inBytesLen = dataBuf.size() + newUserName.size() +
392 EVP_CIPHER_block_size(cipher);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530393 }
394
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700395 SecureString inBytes(inBytesLen, '\0');
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530396 if (inBytesLen != 0)
397 {
398 char* outPtr = reinterpret_cast<char*>(dataBuf.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530399 char* nToken = NULL;
400 char* linePtr = strtok_r(outPtr, "\n", &nToken);
401 while (linePtr != NULL)
402 {
Patrick Venture51d0c402019-08-19 11:19:19 -0700403 size_t userEPos = 0;
404
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700405 SecureString lineStr(linePtr);
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530406 if ((userEPos = lineStr.find(":")) != std::string::npos)
407 {
408 if (userName.compare(lineStr.substr(0, userEPos)) == 0)
409 {
410 isUsrFound = true;
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530411 if (!newUserName.empty())
412 {
413 bytesWritten += std::snprintf(
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700414 &inBytes[0] + bytesWritten,
Richard Marian Thomaiyar42bed642018-09-21 12:28:57 +0530415 (inBytesLen - bytesWritten), "%s%s\n",
416 newUserName.c_str(),
417 lineStr.substr(userEPos, lineStr.size()).data());
418 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530419 }
420 else
421 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700422 bytesWritten += std::snprintf(&inBytes[0] + bytesWritten,
423 (inBytesLen - bytesWritten),
424 "%s\n", lineStr.data());
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530425 }
426 }
427 linePtr = strtok_r(NULL, "\n", &nToken);
428 }
Richard Marian Thomaiyar161f20d2019-01-28 20:33:16 +0530429 inBytesLen = bytesWritten;
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530430 }
431 if (!isUsrFound)
432 {
433 log<level::DEBUG>("User doesn't exist");
434 return 0;
435 }
436
437 // Read the key buff from key file
438 std::array<uint8_t, maxKeySize> keyBuff;
439 std::ifstream keyFile(encryptKeyFileName, std::ios::in | std::ios::binary);
440 if (!keyFile.good())
441 {
442 log<level::DEBUG>("Error in opening encryption key file");
443 return -EIO;
444 }
445 keyFile.read(reinterpret_cast<char*>(keyBuff.data()), keyBuff.size());
446 if (keyFile.fail())
447 {
448 log<level::DEBUG>("Error in reading encryption key file");
449 return -EIO;
450 }
451 keyFile.close();
452
453 // Read the original passwd file mode
454 struct stat st = {};
455 if (stat(passwdFileName, &st) != 0)
456 {
457 log<level::DEBUG>("Error in getting password file fstat()");
458 return -EIO;
459 }
460
461 // Create temporary file for write
462 std::string pwdFile(passwdFileName);
463 std::vector<char> tempFileName(pwdFile.begin(), pwdFile.end());
464 std::vector<char> fileTemplate = {'_', '_', 'X', 'X', 'X',
465 'X', 'X', 'X', '\0'};
466 tempFileName.insert(tempFileName.end(), fileTemplate.begin(),
467 fileTemplate.end());
468 int fd = mkstemp((char*)tempFileName.data());
469 if (fd == -1)
470 {
471 log<level::DEBUG>("Error creating temp file");
472 return -EIO;
473 }
474
475 std::string strTempFileName(tempFileName.data());
476 // Open the temp file for writing from provided fd
477 // By "true", remove it at exit if still there.
478 // This is needed to cleanup the temp file at exception
479 phosphor::user::File temp(fd, strTempFileName, "w", true);
480 if ((temp)() == NULL)
481 {
482 close(fd);
483 log<level::DEBUG>("Error creating temp file");
484 return -EIO;
485 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530486
Vernon Maueryb2654552020-04-03 14:28:53 -0700487 // Set the file mode as read-write for owner only
488 if (fchmod(fileno((temp)()), S_IRUSR | S_IWUSR) < 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530489 {
490 log<level::DEBUG>("Error setting fchmod for temp file");
491 return -EIO;
492 }
493
494 const EVP_MD* digest = EVP_sha256();
495 size_t hashLen = EVP_MD_block_size(digest);
496 std::vector<uint8_t> hash(hashLen);
497 size_t ivLen = EVP_CIPHER_iv_length(cipher);
498 std::vector<uint8_t> iv(ivLen);
499 std::array<uint8_t, EVP_MAX_KEY_LENGTH> key;
500 size_t keyLen = key.size();
501 std::array<uint8_t, EVP_MAX_MD_SIZE> mac;
502 size_t macLen = mac.size();
503
504 // Create random hash and generate hash key which will be used for
505 // encryption.
506 if (RAND_bytes(hash.data(), hashLen) != 1)
507 {
508 log<level::DEBUG>("Hash genertion failed, bailing out");
509 return -EIO;
510 }
511 if (NULL == HMAC(digest, keyBuff.data(), keyBuff.size(), hash.data(),
512 hashLen, key.data(),
513 reinterpret_cast<unsigned int*>(&keyLen)))
514 {
515 log<level::DEBUG>("Failed to create MAC for authentication");
516 return -EIO;
517 }
518
519 // Generate IV values
520 if (RAND_bytes(iv.data(), ivLen) != 1)
521 {
522 log<level::DEBUG>("UV genertion failed, bailing out");
523 return -EIO;
524 }
525
526 // Encrypt the input data
527 std::vector<uint8_t> outBytes(inBytesLen + EVP_MAX_BLOCK_LENGTH);
528 size_t outBytesLen = 0;
529 if (inBytesLen != 0)
530 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700531 if (encryptDecryptData(
532 true, EVP_aes_128_cbc(), key.data(), keyLen, iv.data(), ivLen,
533 reinterpret_cast<unsigned char*>(inBytes.data()), inBytesLen,
534 mac.data(), &macLen, outBytes.data(), &outBytesLen) != 0)
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530535 {
536 log<level::DEBUG>("Error while encrypting the data");
537 return -EIO;
538 }
539 outBytes[outBytesLen] = 0;
540 }
541 OPENSSL_cleanse(key.data(), keyLen);
542
543 // Update the meta password structure.
Richard Marian Thomaiyar48e55582018-12-20 15:58:04 +0530544 MetaPassStruct metaData = {META_PASSWD_SIG, {0, 0}, 0, 0, 0, 0, 0};
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530545 metaData.hashSize = hashLen;
546 metaData.ivSize = ivLen;
547 metaData.dataSize = bytesWritten;
548 metaData.padSize = outBytesLen - bytesWritten;
549 metaData.macSize = macLen;
550
551 if (fwrite(&metaData, 1, sizeof(metaData), (temp)()) != sizeof(metaData))
552 {
553 log<level::DEBUG>("Error in writing meta data");
554 return -EIO;
555 }
556
557 if (fwrite(&hash[0], 1, hashLen, (temp)()) != hashLen)
558 {
559 log<level::DEBUG>("Error in writing hash data");
560 return -EIO;
561 }
562
563 if (fwrite(&iv[0], 1, ivLen, (temp)()) != ivLen)
564 {
565 log<level::DEBUG>("Error in writing IV data");
566 return -EIO;
567 }
568
569 if (fwrite(&outBytes[0], 1, outBytesLen, (temp)()) != outBytesLen)
570 {
571 log<level::DEBUG>("Error in writing encrypted data");
572 return -EIO;
573 }
574
575 if (fwrite(&mac[0], 1, macLen, (temp)()) != macLen)
576 {
577 log<level::DEBUG>("Error in writing MAC data");
578 return -EIO;
579 }
580
581 if (fflush((temp)()))
582 {
583 log<level::DEBUG>(
584 "File fflush error while writing entries to special file");
585 return -EIO;
586 }
587
588 OPENSSL_cleanse(iv.data(), ivLen);
589
590 // Rename the tmp file to actual file
591 if (std::rename(strTempFileName.data(), passwdFileName) != 0)
592 {
593 log<level::DEBUG>("Failed to rename tmp file to ipmi-pass");
594 return -EIO;
595 }
596
597 return 0;
598}
599
600std::time_t PasswdMgr::getUpdatedFileTime()
601{
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530602 struct stat fileStat = {};
603 if (stat(passwdFileName, &fileStat) != 0)
604 {
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530605 log<level::DEBUG>("Error - Getting passwd file time stamp");
606 return -EIO;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530607 }
AppaRao Pulib29b5ab2018-05-17 10:28:48 +0530608 return fileStat.st_mtime;
Richard Marian Thomaiyar4654d992018-04-19 05:38:37 +0530609}
610
611} // namespace ipmi