1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <cstdlib>
17 #include <gtest/gtest.h>
18 #include <string>
19 
20 #include <openssl/asn1.h>
21 #include <openssl/pkcs7.h>
22 #include <openssl/x509v3.h>
23 #include "access_token_setter.h"
24 #include "byte_buffer.h"
25 #include "code_sign_utils.h"
26 #include "local_code_sign_kit.h"
27 #include "local_key_helper.h"
28 #include "log.h"
29 
30 using namespace OHOS::Security::CodeSign;
31 using namespace testing::ext;
32 using namespace std;
33 
34 namespace OHOS {
35 namespace Security {
36 namespace CodeSign {
37 static const std::string AN_BASE_PATH = "/data/local/ark-cache/tmp/";
38 static const std::string DEMO_AN_PATH = AN_BASE_PATH + "demo.an";
39 static const std::string DEMO_TAMPER_AN_PATH = AN_BASE_PATH + "fake_demo.an";
40 
41 static const char *VALID_CALLER = "compiler_service";
42 
43 static const std::string FAKE_SERIAL_NUMBER = "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
44 static const std::string FAKE_CONTENT = "FAKE";
45 
46 static const int MAX_TEST_BUF_LEN = 1024;
47 
ModifySignatureFormat(ByteBuffer & pkcs7Data)48 static void ModifySignatureFormat(ByteBuffer &pkcs7Data)
49 {
50     uint8_t *data = pkcs7Data.GetBuffer();
51     (void) memcpy_s(data, pkcs7Data.GetSize(), FAKE_CONTENT.c_str(), FAKE_CONTENT.length());
52 }
53 
ModifySignatureValue(PKCS7_SIGNER_INFO * p7info)54 static void ModifySignatureValue(PKCS7_SIGNER_INFO *p7info)
55 {
56     const uint8_t *data = ASN1_STRING_get0_data(p7info->enc_digest);
57     int len = ASN1_STRING_length(p7info->enc_digest);
58     if (len <= 0 || len > MAX_TEST_BUF_LEN) {
59         return;
60     }
61     uint8_t *fdata = static_cast<uint8_t *>(malloc(len));
62     if (fdata == nullptr) {
63         return;
64     }
65     (void)memcpy_s(fdata, len, data, len);
66     (void)memcpy_s(fdata, len, FAKE_CONTENT.c_str(), FAKE_CONTENT.length());
67     ASN1_STRING_set0(p7info->enc_digest, fdata, len);
68 }
69 
ModifySignatureSigner(PKCS7_SIGNER_INFO * p7info)70 static void ModifySignatureSigner(PKCS7_SIGNER_INFO *p7info)
71 {
72     ASN1_INTEGER *serial = s2i_ASN1_INTEGER(nullptr, FAKE_SERIAL_NUMBER.c_str());
73     ASN1_INTEGER_free(p7info->issuer_and_serial->serial);
74     p7info->issuer_and_serial->serial = ASN1_INTEGER_dup(serial);
75 }
76 
GetSignerInfo(PKCS7 * p7)77 static PKCS7_SIGNER_INFO *GetSignerInfo(PKCS7 *p7)
78 {
79     STACK_OF(PKCS7_SIGNER_INFO) *signInfos = PKCS7_get_signer_info(p7);
80     // only one signer
81     if (sk_PKCS7_SIGNER_INFO_num(signInfos) < 1) {
82         return nullptr;
83     }
84     return sk_PKCS7_SIGNER_INFO_value(signInfos, 0);
85 }
86 
LoadPKCS7Data(ByteBuffer & pkcs7Data)87 static PKCS7 *LoadPKCS7Data(ByteBuffer &pkcs7Data)
88 {
89     BIO *mem = BIO_new_mem_buf(pkcs7Data.GetBuffer(), pkcs7Data.GetSize());
90     return d2i_PKCS7_bio(mem, nullptr);
91 }
92 
DumpPKCS7Data(PKCS7 * p7,ByteBuffer & pkcs7Data)93 static bool DumpPKCS7Data(PKCS7 *p7, ByteBuffer &pkcs7Data)
94 {
95     BIO *bio = BIO_new(BIO_s_mem());
96     bool ret = false;
97     do {
98         if (bio == nullptr) {
99             break;
100         }
101         if (!i2d_PKCS7_bio(bio, p7)) {
102             break;
103         }
104         uint8_t *tmp = nullptr;
105         long tmpSize = BIO_get_mem_data(bio, &tmp);
106         if ((tmpSize < 0) || (tmpSize > UINT32_MAX)) {
107             break;
108         }
109         if (!pkcs7Data.CopyFrom(tmp, static_cast<uint32_t>(tmpSize))) {
110             break;
111         }
112         ret = true;
113     } while (0);
114     BIO_free(bio);
115     return ret;
116 }
117 
ModifyPkcs7SignerwithTargetFunc(ByteBuffer & src,ByteBuffer & dst,void (* modifyFunc)(PKCS7_SIGNER_INFO * p7))118 static bool ModifyPkcs7SignerwithTargetFunc(ByteBuffer &src, ByteBuffer &dst,
119     void (*modifyFunc)(PKCS7_SIGNER_INFO *p7))
120 {
121     PKCS7 *p7 = LoadPKCS7Data(src);
122     if (p7 == nullptr) {
123         return false;
124     }
125     PKCS7_SIGNER_INFO *signer = GetSignerInfo(p7);
126     if (signer == nullptr) {
127         return false;
128     }
129     modifyFunc(signer);
130     if (!DumpPKCS7Data(p7, dst)) {
131         return false;
132     }
133     PKCS7_free(p7);
134     return true;
135 }
136 
InvokeLocalCodeSign(const std::string & filePath,ByteBuffer & sig)137 static void InvokeLocalCodeSign(const std::string &filePath, ByteBuffer &sig)
138 {
139     uint64_t selfTokenId = NativeTokenSet(VALID_CALLER);
140     int ret = LocalCodeSignKit::SignLocalCode(filePath, sig);
141     NativeTokenReset(selfTokenId);
142     EXPECT_EQ(ret, CS_SUCCESS);
143 }
144 
145 class SignAndEnforceTest : public testing::Test {
146 public:
SignAndEnforceTest()147     SignAndEnforceTest() {};
~SignAndEnforceTest()148     virtual ~SignAndEnforceTest() {};
SetUpTestCase()149     static void SetUpTestCase() {};
TearDownTestCase()150     static void TearDownTestCase() {};
SetUp()151     void SetUp() {};
TearDown()152     void TearDown() {};
153 };
154 
155 /**
156  * @tc.name: SignAndEnforceTest_0001
157  * @tc.desc: sign AN file and enforce with null
158  * @tc.type: Func
159  * @tc.require:
160  */
161 HWTEST_F(SignAndEnforceTest, SignAndEnforceTest_0001, TestSize.Level0)
162 {
163     ByteBuffer sig;
164     InvokeLocalCodeSign(DEMO_AN_PATH, sig);
165     ByteBuffer empty;
166     int32_t ret = CodeSignUtils::EnforceCodeSignForFile(DEMO_AN_PATH, empty);
167     EXPECT_EQ(ret, CS_ERR_NO_SIGNATURE);
168 }
169 
170 /**
171  * @tc.name: SignAndEnforceTest_0002
172  * @tc.desc: sign AN file and enforce tampered one
173  * @tc.type: Func
174  * @tc.require:
175  */
176 HWTEST_F(SignAndEnforceTest, SignAndEnforceTest_0002, TestSize.Level0)
177 {
178     ByteBuffer sig;
179     InvokeLocalCodeSign(DEMO_AN_PATH, sig);
180     int32_t ret = CodeSignUtils::EnforceCodeSignForFile(DEMO_TAMPER_AN_PATH, sig);
181     EXPECT_EQ(ret, CS_ERR_ENABLE);
182 }
183 
184 /**
185  * @tc.name: SignAndEnforceTest_0003
186  * @tc.desc: sign AN file and enforce it with wrong signature fromat
187  * @tc.type: Func
188  * @tc.require:
189  */
190 HWTEST_F(SignAndEnforceTest, SignAndEnforceTest_0003, TestSize.Level0)
191 {
192     ByteBuffer sig;
193     InvokeLocalCodeSign(DEMO_AN_PATH, sig);
194     ModifySignatureFormat(sig);
195     int32_t ret = CodeSignUtils::EnforceCodeSignForFile(DEMO_AN_PATH, sig);
196     EXPECT_EQ(ret, CS_ERR_ENABLE);
197 }
198 
199 /**
200  * @tc.name: SignAndEnforceTest_0004
201  * @tc.desc: sign AN file and enforce it with wrong signature value
202  * @tc.type: Func
203  * @tc.require:
204  */
205 HWTEST_F(SignAndEnforceTest, SignAndEnforceTest_0004, TestSize.Level0)
206 {
207     ByteBuffer sig;
208     InvokeLocalCodeSign(DEMO_AN_PATH, sig);;
209     ByteBuffer wrongSig;
210     EXPECT_EQ(ModifyPkcs7SignerwithTargetFunc(sig, wrongSig, ModifySignatureValue), true);
211     int32_t ret = CodeSignUtils::EnforceCodeSignForFile(DEMO_AN_PATH, wrongSig);
212     EXPECT_EQ(ret, CS_ERR_ENABLE);
213 }
214 
215 /**
216  * @tc.name: SignAndEnforceTest_0005
217  * @tc.desc: sign AN file and enforce it using signature with wrong signer
218  * @tc.type: Func
219  * @tc.require:
220  */
221 HWTEST_F(SignAndEnforceTest, SignAndEnforceTest_0005, TestSize.Level0)
222 {
223     ByteBuffer sig;
224     InvokeLocalCodeSign(DEMO_AN_PATH, sig);
225     ByteBuffer wrongSig;
226     EXPECT_EQ(ModifyPkcs7SignerwithTargetFunc(sig, wrongSig, ModifySignatureSigner), true);
227     int32_t ret = CodeSignUtils::EnforceCodeSignForFile(DEMO_AN_PATH, wrongSig);
228     EXPECT_EQ(ret, CS_ERR_ENABLE);
229 }
230 
231 /**
232  * @tc.name: SignAndEnforceTest_0006
233  * @tc.desc: sign AN file and enforce it
234  * @tc.type: Func
235  * @tc.require:
236  */
237 HWTEST_F(SignAndEnforceTest, SignAndEnforceTest_0006, TestSize.Level0)
238 {
239     ByteBuffer sig;
240     InvokeLocalCodeSign(DEMO_AN_PATH, sig);
241     int32_t ret = CodeSignUtils::EnforceCodeSignForFile(DEMO_AN_PATH, sig);
242     EXPECT_EQ(ret, GetEnforceFileResult());
243 }
244 } // namespace CodeSign
245 } // namespace Security
246 } // namespace OHOS