blob: 1c0c803ef2e5e7acb6db3f61accc9a5e21ee68c5 [file] [log] [blame]
Gunnar Mills01d55c32017-04-20 10:52:15 -05001#include "version.hpp"
2#include <gtest/gtest.h>
3#include <experimental/filesystem>
4#include <stdlib.h>
5#include <fstream>
6#include <iostream>
7#include <sstream>
8#include <string>
Saqib Khan26a960d2017-09-19 14:23:28 -05009#include <openssl/sha.h>
Jayanth Othayoth6be275b2018-02-27 08:36:38 -060010#include "image_verify.hpp"
Gunnar Mills01d55c32017-04-20 10:52:15 -050011
12using namespace phosphor::software::manager;
Jayanth Othayoth6be275b2018-02-27 08:36:38 -060013using namespace phosphor::software::image;
Gunnar Mills01d55c32017-04-20 10:52:15 -050014
Gunnar Mills01d55c32017-04-20 10:52:15 -050015class VersionTest : public testing::Test
16{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060017 protected:
18 virtual void SetUp()
19 {
20 char versionDir[] = "./versionXXXXXX";
21 _directory = mkdtemp(versionDir);
Gunnar Mills01d55c32017-04-20 10:52:15 -050022
Adriana Kobylak2285fe02018-02-27 15:36:59 -060023 if (_directory.empty())
Gunnar Mills01d55c32017-04-20 10:52:15 -050024 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -060025 throw std::bad_alloc();
Gunnar Mills01d55c32017-04-20 10:52:15 -050026 }
Adriana Kobylak2285fe02018-02-27 15:36:59 -060027 }
Gunnar Mills01d55c32017-04-20 10:52:15 -050028
Adriana Kobylak2285fe02018-02-27 15:36:59 -060029 virtual void TearDown()
30 {
31 fs::remove_all(_directory);
32 }
Gunnar Mills01d55c32017-04-20 10:52:15 -050033
Adriana Kobylak2285fe02018-02-27 15:36:59 -060034 std::string _directory;
Gunnar Mills01d55c32017-04-20 10:52:15 -050035};
36
37/** @brief Make sure we correctly get the version and purpose from getValue()*/
38TEST_F(VersionTest, TestGetValue)
39{
40 auto manifestFilePath = _directory + "/" + "MANIFEST";
41 auto version = "test-version";
42 auto purpose = "BMC";
43
44 std::ofstream file;
45 file.open(manifestFilePath, std::ofstream::out);
46 ASSERT_TRUE(file.is_open());
47
48 file << "version=" << version << std::endl;
49 file << "purpose=" << purpose << std::endl;
50 file.close();
51
52 EXPECT_EQ(Version::getValue(manifestFilePath, "version"), version);
53 EXPECT_EQ(Version::getValue(manifestFilePath, "purpose"), purpose);
54}
55
56/** @brief Make sure we correctly get the Id from getId()*/
57TEST_F(VersionTest, TestGetId)
58{
Gunnar Mills01d55c32017-04-20 10:52:15 -050059 auto version = "test-id";
Saqib Khan26a960d2017-09-19 14:23:28 -050060 unsigned char digest[SHA512_DIGEST_LENGTH];
61 SHA512_CTX ctx;
62 SHA512_Init(&ctx);
63 SHA512_Update(&ctx, version, strlen(version));
64 SHA512_Final(digest, &ctx);
Adriana Kobylak2285fe02018-02-27 15:36:59 -060065 char mdString[SHA512_DIGEST_LENGTH * 2 + 1];
Saqib Khan26a960d2017-09-19 14:23:28 -050066 for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
67 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -060068 snprintf(&mdString[i * 2], 3, "%02x", (unsigned int)digest[i]);
Saqib Khan26a960d2017-09-19 14:23:28 -050069 }
70 std::string hexId = std::string(mdString);
71 hexId = hexId.substr(0, 8);
72 EXPECT_EQ(Version::getId(version), hexId);
Gunnar Mills01d55c32017-04-20 10:52:15 -050073}
Jayanth Othayoth6be275b2018-02-27 08:36:38 -060074
75class SignatureTest : public testing::Test
76{
77 static constexpr auto opensslCmd = "openssl dgst -sha256 -sign ";
78 static constexpr auto testPath = "/tmp/_testSig";
79
80 protected:
81 void command(const std::string& cmd)
82 {
83 auto val = std::system(cmd.c_str());
84 if (val)
85 {
86 std::cout << "COMMAND Error: " << val << std::endl;
87 }
88 }
89 virtual void SetUp()
90 {
91 // Create test base directory.
92 fs::create_directories(testPath);
93
94 // Create unique temporary path for images
95 std::string tmpDir(testPath);
96 tmpDir += "/extractXXXXXX";
97 std::string imageDir = mkdtemp(const_cast<char*>(tmpDir.c_str()));
98
99 // Create unique temporary configuration path
100 std::string tmpConfDir(testPath);
101 tmpConfDir += "/confXXXXXX";
102 std::string confDir = mkdtemp(const_cast<char*>(tmpConfDir.c_str()));
103
104 extractPath = imageDir;
105 extractPath /= "images";
106
107 signedConfPath = confDir;
108 signedConfPath /= "conf";
109
110 signedConfOpenBMCPath = confDir;
111 signedConfOpenBMCPath /= "conf";
112 signedConfOpenBMCPath /= "OpenBMC";
113
114 std::cout << "SETUP " << std::endl;
115
116 command("mkdir " + extractPath.string());
117 command("mkdir " + signedConfPath.string());
118 command("mkdir " + signedConfOpenBMCPath.string());
119
120 std::string hashFile = signedConfOpenBMCPath.string() + "/hashfunc";
121 command("echo \"HashType=RSA-SHA256\" > " + hashFile);
122
123 std::string manifestFile = extractPath.string() + "/" + "MANIFEST";
124 command("echo \"HashType=RSA-SHA256\" > " + manifestFile);
125 command("echo \"KeyType=OpenBMC\" >> " + manifestFile);
126
127 std::string kernelFile = extractPath.string() + "/" + "image-kernel";
128 command("echo \"image-kernel file \" > " + kernelFile);
129
130 std::string rofsFile = extractPath.string() + "/" + "image-rofs";
131 command("echo \"image-rofs file \" > " + rofsFile);
132
133 std::string rwfsFile = extractPath.string() + "/" + "image-rwfs";
134 command("echo \"image-rwfs file \" > " + rwfsFile);
135
136 std::string ubootFile = extractPath.string() + "/" + "image-u-boot";
137 command("echo \"image-u-boot file \" > " + ubootFile);
138
139 std::string pkeyFile = extractPath.string() + "/" + "private.pem";
140 command("openssl genrsa -out " + pkeyFile + " 2048");
141
142 std::string pubkeyFile = extractPath.string() + "/" + "publickey";
143 command("openssl rsa -in " + pkeyFile + " -outform PEM " +
144 "-pubout -out " + pubkeyFile);
145
146 std::string pubKeyConfFile =
147 signedConfOpenBMCPath.string() + "/" + "publickey";
148 command("cp " + pubkeyFile + " " + signedConfOpenBMCPath.string());
149 command(opensslCmd + pkeyFile + " -out " + kernelFile + ".sig " +
150 kernelFile);
151
152 command(opensslCmd + pkeyFile + " -out " + manifestFile + ".sig " +
153 manifestFile);
154 command(opensslCmd + pkeyFile + " -out " + rofsFile + ".sig " +
155 rofsFile);
156 command(opensslCmd + pkeyFile + " -out " + rwfsFile + ".sig " +
157 rwfsFile);
158 command(opensslCmd + pkeyFile + " -out " + ubootFile + ".sig " +
159 ubootFile);
160 command(opensslCmd + pkeyFile + " -out " + pubkeyFile + ".sig " +
161 pubkeyFile);
162
163 signature = std::make_unique<Signature>(extractPath, signedConfPath);
164 }
165 virtual void TearDown()
166 {
167 command("rm -rf " + std::string(testPath));
168 }
169
170 std::unique_ptr<Signature> signature;
171 fs::path extractPath;
172 fs::path signedConfPath;
173 fs::path signedConfOpenBMCPath;
174};
175
176/** @brief Test for sucess scenario*/
177TEST_F(SignatureTest, TestSignatureVerify)
178{
179 EXPECT_TRUE(signature->verify());
180}
181
182/** @brief Test failure scenario with corrupted signature file*/
183TEST_F(SignatureTest, TestCorruptSignatureFile)
184{
185 // corrupt the image-kernel.sig file and ensure that verification fails
186 std::string kernelFile = extractPath.string() + "/" + "image-kernel";
187 command("echo \"dummy data\" > " + kernelFile + ".sig ");
188 EXPECT_FALSE(signature->verify());
189}
190
191/** @brief Test failure scenario with no public key in the image*/
192TEST_F(SignatureTest, TestNoPublicKeyInImage)
193{
194 // Remove publickey file from the image and ensure that verify fails
195 std::string pubkeyFile = extractPath.string() + "/" + "publickey";
196 command("rm " + pubkeyFile);
197 EXPECT_FALSE(signature->verify());
198}
199
200/** @brief Test failure scenario with invalid hash function value*/
201TEST_F(SignatureTest, TestInvalidHashValue)
202{
203 // Change the hashfunc value and ensure that verification fails
204 std::string hashFile = signedConfOpenBMCPath.string() + "/hashfunc";
205 command("echo \"HashType=md5\" > " + hashFile);
206 EXPECT_FALSE(signature->verify());
207}
208
209/** @brief Test for failure scenario with no config file in system*/
210TEST_F(SignatureTest, TestNoConfigFileInSystem)
211{
212 // Remove the conf folder in the system and ensure that verify fails
213 command("rm -rf " + signedConfOpenBMCPath.string());
214 EXPECT_FALSE(signature->verify());
215}