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