blob: 5b50f390dd355639c11f9b5334f3605177dca539 [file] [log] [blame]
Jayanth Othayoth2ab9b102018-02-21 05:27:47 -06001#include <set>
2
Jayanth Othayoth9d7cd832018-02-21 05:12:39 -06003#include "image_verify.hpp"
Jayanth Othayoth2ab9b102018-02-21 05:27:47 -06004#include "config.h"
5#include "version.hpp"
6
7#include <phosphor-logging/log.hpp>
8#include <phosphor-logging/elog.hpp>
9#include <phosphor-logging/elog-errors.hpp>
10#include <xyz/openbmc_project/Common/error.hpp>
Jayanth Othayoth9d7cd832018-02-21 05:12:39 -060011
12namespace phosphor
13{
14namespace software
15{
16namespace image
17{
18
Jayanth Othayoth2ab9b102018-02-21 05:27:47 -060019using namespace phosphor::logging;
20using namespace phosphor::software::manager;
21using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23
24constexpr auto keyTypeTag = "KeyType";
25constexpr auto hashFunctionTag = "HashType";
26
27Signature::Signature(const fs::path& imageDirPath,
28 const fs::path& signedConfPath) :
29 imageDirPath(imageDirPath),
30 signedConfPath(signedConfPath)
31{
32 fs::path file(imageDirPath / MANIFEST_FILE_NAME);
33
34 keyType = Version::getValue(file, keyTypeTag);
35 hashType = Version::getValue(file, hashFunctionTag);
36}
37
38AvailableKeyTypes Signature::getAvailableKeyTypesFromSystem() const
39{
40 AvailableKeyTypes keyTypes{};
41
42 // Find the path of all the files
43 if (!fs::is_directory(signedConfPath))
44 {
45 log<level::ERR>("Signed configuration path not found in the system");
46 elog<InternalFailure>();
47 }
48
49 // Look for all the hash and public key file names get the key value
50 // For example:
51 // /etc/activationdata/OpenBMC/publickey
52 // /etc/activationdata/OpenBMC/hashfunc
53 // /etc/activationdata/GA/publickey
54 // /etc/activationdata/GA/hashfunc
55 // Set will have OpenBMC, GA
56
57 for (const auto& p : fs::recursive_directory_iterator(signedConfPath))
58 {
59 if ((p.path().filename() == HASH_FILE_NAME) ||
60 (p.path().filename() == PUBLICKEY_FILE_NAME))
61 {
62 // extract the key types
63 // /etc/activationdata/OpenBMC/ -> get OpenBMC from the path
64 auto key = p.path().parent_path();
65 keyTypes.insert(key.filename());
66 }
67 }
68
69 return keyTypes;
70}
71
72inline KeyHashPathPair Signature::getKeyHashFileNames(const Key_t& key) const
73{
74 fs::path hashpath(signedConfPath / key / HASH_FILE_NAME);
75 fs::path keyPath(signedConfPath / key / PUBLICKEY_FILE_NAME);
76
77 return std::make_pair(std::move(hashpath), std::move(keyPath));
78}
79
Jayanth Othayoth9d7cd832018-02-21 05:12:39 -060080bool Signature::verify()
81{
Jayanth Othayoth2ab9b102018-02-21 05:27:47 -060082 try
83 {
84 // Verify the MANIFEST and publickey file using available
85 // public keys and hash on the system.
86 if (false == systemLevelVerify())
87 {
88 log<level::ERR>("System level Signature Validation failed");
89 return false;
90 }
91
92 // image specfic publickey file name.
93 fs::path publicKeyFile(imageDirPath / PUBLICKEY_FILE_NAME);
94
95 // Validate the BMC image files.
96 for (const auto& bmcImage : bmcImages)
97 {
98 // Build Image File name
99 fs::path file(imageDirPath);
100 file /= bmcImage;
101
102 // Build Signature File name
103 fs::path sigFile(file);
104 sigFile.replace_extension(SIGNATURE_FILE_EXT);
105
106 // Verify the signature.
107 auto valid = verifyFile(file, sigFile, publicKeyFile, hashType);
108 if (valid == false)
109 {
110 log<level::ERR>("Image file Signature Validation failed",
111 entry("IMAGE=%s", bmcImage.c_str()));
112 return false;
113 }
114 }
115
116 log<level::DEBUG>("Sucessfully completed Signature vaildation.");
117
118 return true;
119 }
120 catch (const InternalFailure& e)
121 {
122 return false;
123 }
124 catch (const std::exception& e)
125 {
126 log<level::ERR>(e.what());
127 return false;
128 }
129}
130
131bool Signature::systemLevelVerify()
132{
133 // Get available key types from the system.
134 auto keyTypes = getAvailableKeyTypesFromSystem();
135 if (keyTypes.empty())
136 {
137 log<level::ERR>("Missing Signature configuration data in system");
138 elog<InternalFailure>();
139 }
140
141 // Build publickey and its signature file name.
142 fs::path pkeyFile(imageDirPath / PUBLICKEY_FILE_NAME);
143 fs::path pkeyFileSig(pkeyFile);
144 pkeyFileSig.replace_extension(SIGNATURE_FILE_EXT);
145
146 // Build manifest and its signature file name.
147 fs::path manifestFile(imageDirPath / MANIFEST_FILE_NAME);
148 fs::path manifestFileSig(manifestFile);
149 manifestFileSig.replace_extension(SIGNATURE_FILE_EXT);
150
151 auto valid = false;
152
153 // Verify the file signature with available key types
154 // public keys and hash function.
155 for (const auto& keyType : keyTypes)
156 {
157 auto keyHashPair = getKeyHashFileNames(keyType);
158
159 auto hashFunc = Version::getValue(keyHashPair.first, hashFunctionTag);
160
161 // Verify manifest file signature
162 valid = verifyFile(manifestFile, manifestFileSig, keyHashPair.second,
163 hashFunc);
164 if (valid)
165 {
166 // Verify publickey file signature.
167 valid =
168 verifyFile(pkeyFile, pkeyFileSig, keyHashPair.second, hashFunc);
169 if (valid)
170 {
171 break;
172 }
173 }
174 }
175 return valid;
176}
177
178bool Signature::verifyFile(const fs::path& file, const fs::path& sigFile,
179 const fs::path& publicKey,
180 const std::string& hashFunc)
181{
Jayanth Othayoth9d7cd832018-02-21 05:12:39 -0600182 return true;
183}
184
185} // namespace image
186} // namespace software
187} // namespace phosphor