1 #include "image_verify.hpp"
2 
3 #include <openssl/sha.h>
4 
5 #include <filesystem>
6 #include <string>
7 
8 #include <gtest/gtest.h>
9 
10 using namespace openpower::software::image;
11 
12 class SignatureTest : public testing::Test
13 {
14     static constexpr auto opensslCmd = "openssl dgst -sha256 -sign ";
15     static constexpr auto testPath = "/tmp/_testSig";
16 
17   protected:
command(const std::string & cmd)18     void command(const std::string& cmd)
19     {
20         auto val = std::system(cmd.c_str());
21         if (val)
22         {
23             std::cout << "COMMAND Error: " << val << std::endl;
24         }
25     }
SetUp()26     virtual void SetUp()
27     {
28         // Create test base directory.
29         std::filesystem::create_directories(testPath);
30 
31         // Create unique temporary path for images.
32         std::string tmpDir(testPath);
33         tmpDir += "/extractXXXXXX";
34         std::string imageDir = mkdtemp(const_cast<char*>(tmpDir.c_str()));
35 
36         // Create unique temporary configuration path
37         std::string tmpConfDir(testPath);
38         tmpConfDir += "/confXXXXXX";
39         std::string confDir = mkdtemp(const_cast<char*>(tmpConfDir.c_str()));
40 
41         extractPath = imageDir;
42         extractPath /= "images";
43 
44         signedConfPath = confDir;
45         signedConfPath /= "conf";
46 
47         signedConfPNORPath = confDir;
48         signedConfPNORPath /= "conf";
49         signedConfPNORPath /= "OpenBMC";
50 
51         std::cout << "SETUP " << std::endl;
52 
53         command("mkdir " + extractPath.string());
54         command("mkdir " + signedConfPath.string());
55         command("mkdir " + signedConfPNORPath.string());
56 
57         std::string hashFile = signedConfPNORPath.string() + "/hashfunc";
58         command("echo \"HashType=RSA-SHA256\" > " + hashFile);
59 
60         std::string manifestFile = extractPath.string() + "/" + "MANIFEST";
61         command("echo \"HashType=RSA-SHA256\" > " + manifestFile);
62         command("echo \"KeyType=OpenBMC\" >> " + manifestFile);
63 
64         std::string pnorFile = extractPath.string() + "/" + "pnor.xz.squashfs";
65         command("echo \"pnor.xz.squashfs file \" > " + pnorFile);
66 
67         std::string pkeyFile = extractPath.string() + "/" + "private.pem";
68         command("openssl genrsa  -out " + pkeyFile + " 4096");
69 
70         std::string pubkeyFile = extractPath.string() + "/" + "publickey";
71         command("openssl rsa -in " + pkeyFile + " -outform PEM " +
72                 "-pubout -out " + pubkeyFile);
73 
74         std::string pubKeyConfFile =
75             signedConfPNORPath.string() + "/" + "publickey";
76         command("cp " + pubkeyFile + " " + signedConfPNORPath.string());
77         command(opensslCmd + pkeyFile + " -out " + pnorFile + ".sig " +
78                 pnorFile);
79 
80         command(opensslCmd + pkeyFile + " -out " + manifestFile + ".sig " +
81                 manifestFile);
82         command(opensslCmd + pkeyFile + " -out " + pubkeyFile + ".sig " +
83                 pubkeyFile);
84 
85         signature = std::make_unique<Signature>(extractPath, "pnor.xz.squashfs",
86                                                 signedConfPath);
87     }
TearDown()88     virtual void TearDown()
89     {
90         command("rm -rf " + std::string(testPath));
91     }
92     std::unique_ptr<Signature> signature;
93     std::filesystem::path extractPath;
94     std::filesystem::path signedConfPath;
95     std::filesystem::path signedConfPNORPath;
96 };
97 
98 /** @brief Test for success scenario*/
TEST_F(SignatureTest,TestSignatureVerify)99 TEST_F(SignatureTest, TestSignatureVerify)
100 {
101     EXPECT_TRUE(signature->verify());
102 }
103 
104 /** @brief Test failure scenario with corrupted signature file*/
TEST_F(SignatureTest,TestCorruptSignatureFile)105 TEST_F(SignatureTest, TestCorruptSignatureFile)
106 {
107     // corrupt the image-kernel.sig file and ensure that verification fails
108     std::string kernelFile = extractPath.string() + "/" + "pnor.xz.squashfs";
109     command("echo \"dummy data\" > " + kernelFile + ".sig ");
110     EXPECT_FALSE(signature->verify());
111 }
112 
113 /** @brief Test failure scenario with no public key in the image*/
TEST_F(SignatureTest,TestNoPublicKeyInImage)114 TEST_F(SignatureTest, TestNoPublicKeyInImage)
115 {
116     // Remove publickey file from the image and ensure that verify fails
117     std::string pubkeyFile = extractPath.string() + "/" + "publickey";
118     command("rm " + pubkeyFile);
119     EXPECT_FALSE(signature->verify());
120 }
121 
122 /** @brief Test failure scenario with invalid hash function value*/
TEST_F(SignatureTest,TestInvalidHashValue)123 TEST_F(SignatureTest, TestInvalidHashValue)
124 {
125     // Change the hashfunc value and ensure that verification fails
126     std::string hashFile = signedConfPNORPath.string() + "/hashfunc";
127     command("echo \"HashType=md5\" > " + hashFile);
128     EXPECT_FALSE(signature->verify());
129 }
130 
131 /** @brief Test for failure scenario with no config file in system*/
TEST_F(SignatureTest,TestNoConfigFileInSystem)132 TEST_F(SignatureTest, TestNoConfigFileInSystem)
133 {
134     // Remove the conf folder in the system and ensure that verify fails
135     command("rm -rf " + signedConfPNORPath.string());
136     EXPECT_FALSE(signature->verify());
137 }
138