1*cab87e9cSJagpal Singh Gill #include "config.h"
2*cab87e9cSJagpal Singh Gill
3*cab87e9cSJagpal Singh Gill #include "image_verify.hpp"
4*cab87e9cSJagpal Singh Gill
5*cab87e9cSJagpal Singh Gill #include "images.hpp"
6*cab87e9cSJagpal Singh Gill #include "utils.hpp"
7*cab87e9cSJagpal Singh Gill #include "version.hpp"
8*cab87e9cSJagpal Singh Gill
9*cab87e9cSJagpal Singh Gill #include <fcntl.h>
10*cab87e9cSJagpal Singh Gill #include <openssl/err.h>
11*cab87e9cSJagpal Singh Gill #include <sys/stat.h>
12*cab87e9cSJagpal Singh Gill
13*cab87e9cSJagpal Singh Gill #include <phosphor-logging/elog-errors.hpp>
14*cab87e9cSJagpal Singh Gill #include <phosphor-logging/elog.hpp>
15*cab87e9cSJagpal Singh Gill #include <phosphor-logging/lg2.hpp>
16*cab87e9cSJagpal Singh Gill #include <xyz/openbmc_project/Common/error.hpp>
17*cab87e9cSJagpal Singh Gill
18*cab87e9cSJagpal Singh Gill #include <cassert>
19*cab87e9cSJagpal Singh Gill #include <fstream>
20*cab87e9cSJagpal Singh Gill #include <set>
21*cab87e9cSJagpal Singh Gill #include <system_error>
22*cab87e9cSJagpal Singh Gill
23*cab87e9cSJagpal Singh Gill namespace phosphor
24*cab87e9cSJagpal Singh Gill {
25*cab87e9cSJagpal Singh Gill namespace software
26*cab87e9cSJagpal Singh Gill {
27*cab87e9cSJagpal Singh Gill namespace image
28*cab87e9cSJagpal Singh Gill {
29*cab87e9cSJagpal Singh Gill
30*cab87e9cSJagpal Singh Gill PHOSPHOR_LOG2_USING;
31*cab87e9cSJagpal Singh Gill using namespace phosphor::logging;
32*cab87e9cSJagpal Singh Gill using namespace phosphor::software::manager;
33*cab87e9cSJagpal Singh Gill using InternalFailure =
34*cab87e9cSJagpal Singh Gill sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
35*cab87e9cSJagpal Singh Gill
36*cab87e9cSJagpal Singh Gill constexpr auto keyTypeTag = "KeyType";
37*cab87e9cSJagpal Singh Gill constexpr auto hashFunctionTag = "HashType";
38*cab87e9cSJagpal Singh Gill
Signature(const fs::path & imageDirPath,const fs::path & signedConfPath)39*cab87e9cSJagpal Singh Gill Signature::Signature(const fs::path& imageDirPath,
40*cab87e9cSJagpal Singh Gill const fs::path& signedConfPath) :
41*cab87e9cSJagpal Singh Gill imageDirPath(imageDirPath), signedConfPath(signedConfPath)
42*cab87e9cSJagpal Singh Gill {
43*cab87e9cSJagpal Singh Gill fs::path file(imageDirPath / MANIFEST_FILE_NAME);
44*cab87e9cSJagpal Singh Gill
45*cab87e9cSJagpal Singh Gill keyType = Version::getValue(file, keyTypeTag);
46*cab87e9cSJagpal Singh Gill hashType = Version::getValue(file, hashFunctionTag);
47*cab87e9cSJagpal Singh Gill
48*cab87e9cSJagpal Singh Gill // Get purpose
49*cab87e9cSJagpal Singh Gill auto purposeString = Version::getValue(file, "purpose");
50*cab87e9cSJagpal Singh Gill auto convertedPurpose =
51*cab87e9cSJagpal Singh Gill sdbusplus::message::convert_from_string<VersionPurpose>(purposeString);
52*cab87e9cSJagpal Singh Gill purpose = convertedPurpose.value_or(Version::VersionPurpose::Unknown);
53*cab87e9cSJagpal Singh Gill }
54*cab87e9cSJagpal Singh Gill
getAvailableKeyTypesFromSystem() const55*cab87e9cSJagpal Singh Gill AvailableKeyTypes Signature::getAvailableKeyTypesFromSystem() const
56*cab87e9cSJagpal Singh Gill {
57*cab87e9cSJagpal Singh Gill AvailableKeyTypes keyTypes{};
58*cab87e9cSJagpal Singh Gill
59*cab87e9cSJagpal Singh Gill // Find the path of all the files
60*cab87e9cSJagpal Singh Gill std::error_code ec;
61*cab87e9cSJagpal Singh Gill if (!fs::is_directory(signedConfPath, ec))
62*cab87e9cSJagpal Singh Gill {
63*cab87e9cSJagpal Singh Gill error("Signed configuration path not found in the system: {ERROR_MSG}",
64*cab87e9cSJagpal Singh Gill "ERROR_MSG", ec.message());
65*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
66*cab87e9cSJagpal Singh Gill }
67*cab87e9cSJagpal Singh Gill
68*cab87e9cSJagpal Singh Gill // Look for all the hash and public key file names get the key value
69*cab87e9cSJagpal Singh Gill // For example:
70*cab87e9cSJagpal Singh Gill // /etc/activationdata/OpenBMC/publickey
71*cab87e9cSJagpal Singh Gill // /etc/activationdata/OpenBMC/hashfunc
72*cab87e9cSJagpal Singh Gill // /etc/activationdata/GA/publickey
73*cab87e9cSJagpal Singh Gill // /etc/activationdata/GA/hashfunc
74*cab87e9cSJagpal Singh Gill // Set will have OpenBMC, GA
75*cab87e9cSJagpal Singh Gill
76*cab87e9cSJagpal Singh Gill for (const auto& p : fs::recursive_directory_iterator(signedConfPath))
77*cab87e9cSJagpal Singh Gill {
78*cab87e9cSJagpal Singh Gill if ((p.path().filename() == HASH_FILE_NAME) ||
79*cab87e9cSJagpal Singh Gill (p.path().filename() == PUBLICKEY_FILE_NAME))
80*cab87e9cSJagpal Singh Gill {
81*cab87e9cSJagpal Singh Gill // extract the key types
82*cab87e9cSJagpal Singh Gill // /etc/activationdata/OpenBMC/ -> get OpenBMC from the path
83*cab87e9cSJagpal Singh Gill auto key = p.path().parent_path();
84*cab87e9cSJagpal Singh Gill keyTypes.insert(key.filename());
85*cab87e9cSJagpal Singh Gill }
86*cab87e9cSJagpal Singh Gill }
87*cab87e9cSJagpal Singh Gill
88*cab87e9cSJagpal Singh Gill return keyTypes;
89*cab87e9cSJagpal Singh Gill }
90*cab87e9cSJagpal Singh Gill
getKeyHashFileNames(const Key_t & key) const91*cab87e9cSJagpal Singh Gill inline KeyHashPathPair Signature::getKeyHashFileNames(const Key_t& key) const
92*cab87e9cSJagpal Singh Gill {
93*cab87e9cSJagpal Singh Gill fs::path hashpath(signedConfPath / key / HASH_FILE_NAME);
94*cab87e9cSJagpal Singh Gill fs::path keyPath(signedConfPath / key / PUBLICKEY_FILE_NAME);
95*cab87e9cSJagpal Singh Gill
96*cab87e9cSJagpal Singh Gill return std::make_pair(std::move(hashpath), std::move(keyPath));
97*cab87e9cSJagpal Singh Gill }
98*cab87e9cSJagpal Singh Gill
verifyFullImage()99*cab87e9cSJagpal Singh Gill bool Signature::verifyFullImage()
100*cab87e9cSJagpal Singh Gill {
101*cab87e9cSJagpal Singh Gill bool ret = true;
102*cab87e9cSJagpal Singh Gill #ifdef WANT_SIGNATURE_VERIFY
103*cab87e9cSJagpal Singh Gill // Only verify full image for BMC
104*cab87e9cSJagpal Singh Gill if (purpose != VersionPurpose::BMC)
105*cab87e9cSJagpal Singh Gill {
106*cab87e9cSJagpal Singh Gill return ret;
107*cab87e9cSJagpal Singh Gill }
108*cab87e9cSJagpal Singh Gill
109*cab87e9cSJagpal Singh Gill std::vector<std::string> fullImages = {
110*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "image-bmc.sig",
111*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "image-hostfw.sig",
112*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "image-kernel.sig",
113*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "image-rofs.sig",
114*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "image-rwfs.sig",
115*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "image-u-boot.sig",
116*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "MANIFEST.sig",
117*cab87e9cSJagpal Singh Gill fs::path(imageDirPath) / "publickey.sig"};
118*cab87e9cSJagpal Singh Gill
119*cab87e9cSJagpal Singh Gill // Merge files
120*cab87e9cSJagpal Singh Gill std::string tmpFullFile = "/tmp/image-full";
121*cab87e9cSJagpal Singh Gill utils::mergeFiles(fullImages, tmpFullFile);
122*cab87e9cSJagpal Singh Gill
123*cab87e9cSJagpal Singh Gill // Validate the full image files
124*cab87e9cSJagpal Singh Gill fs::path pkeyFullFile(tmpFullFile);
125*cab87e9cSJagpal Singh Gill
126*cab87e9cSJagpal Singh Gill std::string imageFullSig = "image-full.sig";
127*cab87e9cSJagpal Singh Gill fs::path pkeyFullFileSig(imageDirPath / imageFullSig);
128*cab87e9cSJagpal Singh Gill pkeyFullFileSig.replace_extension(SIGNATURE_FILE_EXT);
129*cab87e9cSJagpal Singh Gill
130*cab87e9cSJagpal Singh Gill // image specific publickey file name.
131*cab87e9cSJagpal Singh Gill fs::path publicKeyFile(imageDirPath / PUBLICKEY_FILE_NAME);
132*cab87e9cSJagpal Singh Gill
133*cab87e9cSJagpal Singh Gill ret = verifyFile(pkeyFullFile, pkeyFullFileSig, publicKeyFile, hashType);
134*cab87e9cSJagpal Singh Gill
135*cab87e9cSJagpal Singh Gill std::error_code ec;
136*cab87e9cSJagpal Singh Gill fs::remove(tmpFullFile, ec);
137*cab87e9cSJagpal Singh Gill #endif
138*cab87e9cSJagpal Singh Gill
139*cab87e9cSJagpal Singh Gill return ret;
140*cab87e9cSJagpal Singh Gill }
141*cab87e9cSJagpal Singh Gill
verify()142*cab87e9cSJagpal Singh Gill bool Signature::verify()
143*cab87e9cSJagpal Singh Gill {
144*cab87e9cSJagpal Singh Gill try
145*cab87e9cSJagpal Singh Gill {
146*cab87e9cSJagpal Singh Gill bool valid;
147*cab87e9cSJagpal Singh Gill // Verify the MANIFEST and publickey file using available
148*cab87e9cSJagpal Singh Gill // public keys and hash on the system.
149*cab87e9cSJagpal Singh Gill if (!systemLevelVerify())
150*cab87e9cSJagpal Singh Gill {
151*cab87e9cSJagpal Singh Gill error("System level Signature Validation failed");
152*cab87e9cSJagpal Singh Gill return false;
153*cab87e9cSJagpal Singh Gill }
154*cab87e9cSJagpal Singh Gill
155*cab87e9cSJagpal Singh Gill bool bmcFilesFound = false;
156*cab87e9cSJagpal Singh Gill // image specific publickey file name.
157*cab87e9cSJagpal Singh Gill fs::path publicKeyFile(imageDirPath / PUBLICKEY_FILE_NAME);
158*cab87e9cSJagpal Singh Gill
159*cab87e9cSJagpal Singh Gill // Record the images which are being updated
160*cab87e9cSJagpal Singh Gill // First check and Validate for the fullimage, then check and Validate
161*cab87e9cSJagpal Singh Gill // for images with partitions
162*cab87e9cSJagpal Singh Gill std::vector<std::string> imageUpdateList = {bmcFullImages};
163*cab87e9cSJagpal Singh Gill valid = checkAndVerifyImage(imageDirPath, publicKeyFile,
164*cab87e9cSJagpal Singh Gill imageUpdateList, bmcFilesFound);
165*cab87e9cSJagpal Singh Gill if (bmcFilesFound && !valid)
166*cab87e9cSJagpal Singh Gill {
167*cab87e9cSJagpal Singh Gill return false;
168*cab87e9cSJagpal Singh Gill }
169*cab87e9cSJagpal Singh Gill
170*cab87e9cSJagpal Singh Gill if (!valid)
171*cab87e9cSJagpal Singh Gill {
172*cab87e9cSJagpal Singh Gill // Validate bmcImages
173*cab87e9cSJagpal Singh Gill imageUpdateList.clear();
174*cab87e9cSJagpal Singh Gill imageUpdateList.assign(bmcImages.begin(), bmcImages.end());
175*cab87e9cSJagpal Singh Gill valid = checkAndVerifyImage(imageDirPath, publicKeyFile,
176*cab87e9cSJagpal Singh Gill imageUpdateList, bmcFilesFound);
177*cab87e9cSJagpal Singh Gill if (bmcFilesFound && !valid)
178*cab87e9cSJagpal Singh Gill {
179*cab87e9cSJagpal Singh Gill return false;
180*cab87e9cSJagpal Singh Gill }
181*cab87e9cSJagpal Singh Gill }
182*cab87e9cSJagpal Singh Gill
183*cab87e9cSJagpal Singh Gill // Validate the optional image files.
184*cab87e9cSJagpal Singh Gill auto optionalImages = getOptionalImages();
185*cab87e9cSJagpal Singh Gill bool optionalFilesFound = false;
186*cab87e9cSJagpal Singh Gill bool optionalImagesValid = false;
187*cab87e9cSJagpal Singh Gill for (const auto& optionalImage : optionalImages)
188*cab87e9cSJagpal Singh Gill {
189*cab87e9cSJagpal Singh Gill // Build Image File name
190*cab87e9cSJagpal Singh Gill fs::path file(imageDirPath);
191*cab87e9cSJagpal Singh Gill file /= optionalImage;
192*cab87e9cSJagpal Singh Gill
193*cab87e9cSJagpal Singh Gill std::error_code ec;
194*cab87e9cSJagpal Singh Gill if (fs::exists(file, ec))
195*cab87e9cSJagpal Singh Gill {
196*cab87e9cSJagpal Singh Gill optionalFilesFound = true;
197*cab87e9cSJagpal Singh Gill // Build Signature File name
198*cab87e9cSJagpal Singh Gill fs::path sigFile(file);
199*cab87e9cSJagpal Singh Gill sigFile += SIGNATURE_FILE_EXT;
200*cab87e9cSJagpal Singh Gill
201*cab87e9cSJagpal Singh Gill // Verify the signature.
202*cab87e9cSJagpal Singh Gill optionalImagesValid =
203*cab87e9cSJagpal Singh Gill verifyFile(file, sigFile, publicKeyFile, hashType);
204*cab87e9cSJagpal Singh Gill if (!optionalImagesValid)
205*cab87e9cSJagpal Singh Gill {
206*cab87e9cSJagpal Singh Gill error("Image file Signature Validation failed on {IMAGE}",
207*cab87e9cSJagpal Singh Gill "IMAGE", optionalImage);
208*cab87e9cSJagpal Singh Gill return false;
209*cab87e9cSJagpal Singh Gill }
210*cab87e9cSJagpal Singh Gill }
211*cab87e9cSJagpal Singh Gill }
212*cab87e9cSJagpal Singh Gill
213*cab87e9cSJagpal Singh Gill if (!verifyFullImage())
214*cab87e9cSJagpal Singh Gill {
215*cab87e9cSJagpal Singh Gill error("Image full file Signature Validation failed");
216*cab87e9cSJagpal Singh Gill return false;
217*cab87e9cSJagpal Singh Gill }
218*cab87e9cSJagpal Singh Gill
219*cab87e9cSJagpal Singh Gill if (!bmcFilesFound && !optionalFilesFound)
220*cab87e9cSJagpal Singh Gill {
221*cab87e9cSJagpal Singh Gill error("Unable to find files to verify");
222*cab87e9cSJagpal Singh Gill return false;
223*cab87e9cSJagpal Singh Gill }
224*cab87e9cSJagpal Singh Gill
225*cab87e9cSJagpal Singh Gill // Either BMC images or optional images shall be valid
226*cab87e9cSJagpal Singh Gill assert(valid || optionalImagesValid);
227*cab87e9cSJagpal Singh Gill
228*cab87e9cSJagpal Singh Gill debug("Successfully completed Signature validation.");
229*cab87e9cSJagpal Singh Gill return true;
230*cab87e9cSJagpal Singh Gill }
231*cab87e9cSJagpal Singh Gill catch (const InternalFailure& e)
232*cab87e9cSJagpal Singh Gill {
233*cab87e9cSJagpal Singh Gill return false;
234*cab87e9cSJagpal Singh Gill }
235*cab87e9cSJagpal Singh Gill catch (const std::exception& e)
236*cab87e9cSJagpal Singh Gill {
237*cab87e9cSJagpal Singh Gill error("Error during processing: {ERROR}", "ERROR", e);
238*cab87e9cSJagpal Singh Gill return false;
239*cab87e9cSJagpal Singh Gill }
240*cab87e9cSJagpal Singh Gill }
241*cab87e9cSJagpal Singh Gill
systemLevelVerify()242*cab87e9cSJagpal Singh Gill bool Signature::systemLevelVerify()
243*cab87e9cSJagpal Singh Gill {
244*cab87e9cSJagpal Singh Gill // Get available key types from the system.
245*cab87e9cSJagpal Singh Gill auto keyTypes = getAvailableKeyTypesFromSystem();
246*cab87e9cSJagpal Singh Gill if (keyTypes.empty())
247*cab87e9cSJagpal Singh Gill {
248*cab87e9cSJagpal Singh Gill error("Missing Signature configuration data in system");
249*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
250*cab87e9cSJagpal Singh Gill }
251*cab87e9cSJagpal Singh Gill
252*cab87e9cSJagpal Singh Gill // Build publickey and its signature file name.
253*cab87e9cSJagpal Singh Gill fs::path pkeyFile(imageDirPath / PUBLICKEY_FILE_NAME);
254*cab87e9cSJagpal Singh Gill fs::path pkeyFileSig(pkeyFile);
255*cab87e9cSJagpal Singh Gill pkeyFileSig.replace_extension(SIGNATURE_FILE_EXT);
256*cab87e9cSJagpal Singh Gill
257*cab87e9cSJagpal Singh Gill // Build manifest and its signature file name.
258*cab87e9cSJagpal Singh Gill fs::path manifestFile(imageDirPath / MANIFEST_FILE_NAME);
259*cab87e9cSJagpal Singh Gill fs::path manifestFileSig(manifestFile);
260*cab87e9cSJagpal Singh Gill manifestFileSig.replace_extension(SIGNATURE_FILE_EXT);
261*cab87e9cSJagpal Singh Gill
262*cab87e9cSJagpal Singh Gill auto valid = false;
263*cab87e9cSJagpal Singh Gill
264*cab87e9cSJagpal Singh Gill // Verify the file signature with available key types
265*cab87e9cSJagpal Singh Gill // public keys and hash function.
266*cab87e9cSJagpal Singh Gill // For any internal failure during the key/hash pair specific
267*cab87e9cSJagpal Singh Gill // validation, should continue the validation with next
268*cab87e9cSJagpal Singh Gill // available Key/hash pair.
269*cab87e9cSJagpal Singh Gill for (const auto& keyType : keyTypes)
270*cab87e9cSJagpal Singh Gill {
271*cab87e9cSJagpal Singh Gill auto keyHashPair = getKeyHashFileNames(keyType);
272*cab87e9cSJagpal Singh Gill
273*cab87e9cSJagpal Singh Gill auto hashFunc = Version::getValue(keyHashPair.first, hashFunctionTag);
274*cab87e9cSJagpal Singh Gill
275*cab87e9cSJagpal Singh Gill try
276*cab87e9cSJagpal Singh Gill {
277*cab87e9cSJagpal Singh Gill // Verify manifest file signature
278*cab87e9cSJagpal Singh Gill valid = verifyFile(manifestFile, manifestFileSig,
279*cab87e9cSJagpal Singh Gill keyHashPair.second, hashFunc);
280*cab87e9cSJagpal Singh Gill if (valid)
281*cab87e9cSJagpal Singh Gill {
282*cab87e9cSJagpal Singh Gill // Verify publickey file signature.
283*cab87e9cSJagpal Singh Gill valid = verifyFile(pkeyFile, pkeyFileSig, keyHashPair.second,
284*cab87e9cSJagpal Singh Gill hashFunc);
285*cab87e9cSJagpal Singh Gill if (valid)
286*cab87e9cSJagpal Singh Gill {
287*cab87e9cSJagpal Singh Gill break;
288*cab87e9cSJagpal Singh Gill }
289*cab87e9cSJagpal Singh Gill }
290*cab87e9cSJagpal Singh Gill }
291*cab87e9cSJagpal Singh Gill catch (const InternalFailure& e)
292*cab87e9cSJagpal Singh Gill {
293*cab87e9cSJagpal Singh Gill valid = false;
294*cab87e9cSJagpal Singh Gill }
295*cab87e9cSJagpal Singh Gill }
296*cab87e9cSJagpal Singh Gill return valid;
297*cab87e9cSJagpal Singh Gill }
298*cab87e9cSJagpal Singh Gill
verifyFile(const fs::path & file,const fs::path & sigFile,const fs::path & publicKey,const std::string & hashFunc)299*cab87e9cSJagpal Singh Gill bool Signature::verifyFile(const fs::path& file, const fs::path& sigFile,
300*cab87e9cSJagpal Singh Gill const fs::path& publicKey,
301*cab87e9cSJagpal Singh Gill const std::string& hashFunc)
302*cab87e9cSJagpal Singh Gill {
303*cab87e9cSJagpal Singh Gill // Check existence of the files in the system.
304*cab87e9cSJagpal Singh Gill std::error_code ec;
305*cab87e9cSJagpal Singh Gill if (!(fs::exists(file, ec) && fs::exists(sigFile, ec)))
306*cab87e9cSJagpal Singh Gill {
307*cab87e9cSJagpal Singh Gill error("Failed to find the Data or signature file {PATH}", "PATH", file);
308*cab87e9cSJagpal Singh Gill if (ec)
309*cab87e9cSJagpal Singh Gill {
310*cab87e9cSJagpal Singh Gill error("Error message: {ERROR_MSG}", "ERROR_MSG", ec.message());
311*cab87e9cSJagpal Singh Gill }
312*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
313*cab87e9cSJagpal Singh Gill }
314*cab87e9cSJagpal Singh Gill
315*cab87e9cSJagpal Singh Gill // Create RSA.
316*cab87e9cSJagpal Singh Gill auto publicRSA = createPublicRSA(publicKey);
317*cab87e9cSJagpal Singh Gill if (!publicRSA)
318*cab87e9cSJagpal Singh Gill {
319*cab87e9cSJagpal Singh Gill error("Failed to create RSA from {PATH}", "PATH", publicKey);
320*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
321*cab87e9cSJagpal Singh Gill }
322*cab87e9cSJagpal Singh Gill
323*cab87e9cSJagpal Singh Gill // Initializes a digest context.
324*cab87e9cSJagpal Singh Gill EVP_MD_CTX_Ptr rsaVerifyCtx(EVP_MD_CTX_new(), ::EVP_MD_CTX_free);
325*cab87e9cSJagpal Singh Gill
326*cab87e9cSJagpal Singh Gill // Adds all digest algorithms to the internal table
327*cab87e9cSJagpal Singh Gill OpenSSL_add_all_digests();
328*cab87e9cSJagpal Singh Gill
329*cab87e9cSJagpal Singh Gill // Create Hash structure.
330*cab87e9cSJagpal Singh Gill auto hashStruct = EVP_get_digestbyname(hashFunc.c_str());
331*cab87e9cSJagpal Singh Gill if (!hashStruct)
332*cab87e9cSJagpal Singh Gill {
333*cab87e9cSJagpal Singh Gill error("EVP_get_digestbynam: Unknown message digest: {HASH}", "HASH",
334*cab87e9cSJagpal Singh Gill hashFunc);
335*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
336*cab87e9cSJagpal Singh Gill }
337*cab87e9cSJagpal Singh Gill
338*cab87e9cSJagpal Singh Gill auto result = EVP_DigestVerifyInit(rsaVerifyCtx.get(), nullptr, hashStruct,
339*cab87e9cSJagpal Singh Gill nullptr, publicRSA.get());
340*cab87e9cSJagpal Singh Gill
341*cab87e9cSJagpal Singh Gill if (result <= 0)
342*cab87e9cSJagpal Singh Gill {
343*cab87e9cSJagpal Singh Gill error("Error ({RC}) occurred during EVP_DigestVerifyInit", "RC",
344*cab87e9cSJagpal Singh Gill ERR_get_error());
345*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
346*cab87e9cSJagpal Singh Gill }
347*cab87e9cSJagpal Singh Gill
348*cab87e9cSJagpal Singh Gill // Hash the data file and update the verification context
349*cab87e9cSJagpal Singh Gill auto size = fs::file_size(file, ec);
350*cab87e9cSJagpal Singh Gill auto dataPtr = mapFile(file, size);
351*cab87e9cSJagpal Singh Gill
352*cab87e9cSJagpal Singh Gill result = EVP_DigestVerifyUpdate(rsaVerifyCtx.get(), dataPtr(), size);
353*cab87e9cSJagpal Singh Gill if (result <= 0)
354*cab87e9cSJagpal Singh Gill {
355*cab87e9cSJagpal Singh Gill error("Error ({RC}) occurred during EVP_DigestVerifyUpdate", "RC",
356*cab87e9cSJagpal Singh Gill ERR_get_error());
357*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
358*cab87e9cSJagpal Singh Gill }
359*cab87e9cSJagpal Singh Gill
360*cab87e9cSJagpal Singh Gill // Verify the data with signature.
361*cab87e9cSJagpal Singh Gill size = fs::file_size(sigFile, ec);
362*cab87e9cSJagpal Singh Gill auto signature = mapFile(sigFile, size);
363*cab87e9cSJagpal Singh Gill
364*cab87e9cSJagpal Singh Gill result = EVP_DigestVerifyFinal(
365*cab87e9cSJagpal Singh Gill rsaVerifyCtx.get(), reinterpret_cast<unsigned char*>(signature()),
366*cab87e9cSJagpal Singh Gill size);
367*cab87e9cSJagpal Singh Gill
368*cab87e9cSJagpal Singh Gill // Check the verification result.
369*cab87e9cSJagpal Singh Gill if (result < 0)
370*cab87e9cSJagpal Singh Gill {
371*cab87e9cSJagpal Singh Gill error("Error ({RC}) occurred during EVP_DigestVerifyFinal", "RC",
372*cab87e9cSJagpal Singh Gill ERR_get_error());
373*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
374*cab87e9cSJagpal Singh Gill }
375*cab87e9cSJagpal Singh Gill
376*cab87e9cSJagpal Singh Gill if (result == 0)
377*cab87e9cSJagpal Singh Gill {
378*cab87e9cSJagpal Singh Gill error("EVP_DigestVerifyFinal:Signature validation failed on {PATH}",
379*cab87e9cSJagpal Singh Gill "PATH", sigFile);
380*cab87e9cSJagpal Singh Gill return false;
381*cab87e9cSJagpal Singh Gill }
382*cab87e9cSJagpal Singh Gill return true;
383*cab87e9cSJagpal Singh Gill }
384*cab87e9cSJagpal Singh Gill
createPublicRSA(const fs::path & publicKey)385*cab87e9cSJagpal Singh Gill inline EVP_PKEY_Ptr Signature::createPublicRSA(const fs::path& publicKey)
386*cab87e9cSJagpal Singh Gill {
387*cab87e9cSJagpal Singh Gill std::error_code ec;
388*cab87e9cSJagpal Singh Gill auto size = fs::file_size(publicKey, ec);
389*cab87e9cSJagpal Singh Gill
390*cab87e9cSJagpal Singh Gill // Read public key file
391*cab87e9cSJagpal Singh Gill auto data = mapFile(publicKey, size);
392*cab87e9cSJagpal Singh Gill
393*cab87e9cSJagpal Singh Gill BIO_MEM_Ptr keyBio(BIO_new_mem_buf(data(), -1), &::BIO_free);
394*cab87e9cSJagpal Singh Gill if (keyBio.get() == nullptr)
395*cab87e9cSJagpal Singh Gill {
396*cab87e9cSJagpal Singh Gill error("Failed to create new BIO Memory buffer");
397*cab87e9cSJagpal Singh Gill elog<InternalFailure>();
398*cab87e9cSJagpal Singh Gill }
399*cab87e9cSJagpal Singh Gill
400*cab87e9cSJagpal Singh Gill return {PEM_read_bio_PUBKEY(keyBio.get(), nullptr, nullptr, nullptr),
401*cab87e9cSJagpal Singh Gill &::EVP_PKEY_free};
402*cab87e9cSJagpal Singh Gill }
403*cab87e9cSJagpal Singh Gill
mapFile(const fs::path & path,size_t size)404*cab87e9cSJagpal Singh Gill CustomMap Signature::mapFile(const fs::path& path, size_t size)
405*cab87e9cSJagpal Singh Gill {
406*cab87e9cSJagpal Singh Gill CustomFd fd(open(path.c_str(), O_RDONLY));
407*cab87e9cSJagpal Singh Gill
408*cab87e9cSJagpal Singh Gill return CustomMap(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd(), 0),
409*cab87e9cSJagpal Singh Gill size);
410*cab87e9cSJagpal Singh Gill }
411*cab87e9cSJagpal Singh Gill
checkAndVerifyImage(const std::string & filePath,const std::string & publicKeyPath,const std::vector<std::string> & imageList,bool & fileFound)412*cab87e9cSJagpal Singh Gill bool Signature::checkAndVerifyImage(
413*cab87e9cSJagpal Singh Gill const std::string& filePath, const std::string& publicKeyPath,
414*cab87e9cSJagpal Singh Gill const std::vector<std::string>& imageList, bool& fileFound)
415*cab87e9cSJagpal Singh Gill {
416*cab87e9cSJagpal Singh Gill bool valid = true;
417*cab87e9cSJagpal Singh Gill
418*cab87e9cSJagpal Singh Gill fileFound = false;
419*cab87e9cSJagpal Singh Gill for (auto& bmcImage : imageList)
420*cab87e9cSJagpal Singh Gill {
421*cab87e9cSJagpal Singh Gill fs::path file(filePath);
422*cab87e9cSJagpal Singh Gill file /= bmcImage;
423*cab87e9cSJagpal Singh Gill
424*cab87e9cSJagpal Singh Gill std::error_code ec;
425*cab87e9cSJagpal Singh Gill if (!fs::exists(file, ec))
426*cab87e9cSJagpal Singh Gill {
427*cab87e9cSJagpal Singh Gill valid = false;
428*cab87e9cSJagpal Singh Gill break;
429*cab87e9cSJagpal Singh Gill }
430*cab87e9cSJagpal Singh Gill fileFound = true;
431*cab87e9cSJagpal Singh Gill
432*cab87e9cSJagpal Singh Gill fs::path sigFile(file);
433*cab87e9cSJagpal Singh Gill sigFile += SIGNATURE_FILE_EXT;
434*cab87e9cSJagpal Singh Gill
435*cab87e9cSJagpal Singh Gill // Verify the signature.
436*cab87e9cSJagpal Singh Gill valid = verifyFile(file, sigFile, publicKeyPath, hashType);
437*cab87e9cSJagpal Singh Gill if (!valid)
438*cab87e9cSJagpal Singh Gill {
439*cab87e9cSJagpal Singh Gill error("Image file Signature Validation failed on {PATH}", "PATH",
440*cab87e9cSJagpal Singh Gill bmcImage);
441*cab87e9cSJagpal Singh Gill return false;
442*cab87e9cSJagpal Singh Gill }
443*cab87e9cSJagpal Singh Gill }
444*cab87e9cSJagpal Singh Gill
445*cab87e9cSJagpal Singh Gill return valid;
446*cab87e9cSJagpal Singh Gill }
447*cab87e9cSJagpal Singh Gill } // namespace image
448*cab87e9cSJagpal Singh Gill } // namespace software
449*cab87e9cSJagpal Singh Gill } // namespace phosphor
450