1 /*
2  * Copyright (c) 2024-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 <fstream>
17 #include <filesystem>
18 
19 #include "constant.h"
20 #include "file_utils.h"
21 #include "sign_head.h"
22 #include "block_head.h"
23 #include "verify_hap.h"
24 #include "verify_code_signature.h"
25 #include "hash_utils.h"
26 #include "sign_content_info.h"
27 #include "signature_block_tags.h"
28 #include "verify_elf.h"
29 
30 namespace OHOS {
31 namespace SignatureTools {
32 
33 const int8_t VerifyElf::SIGNATURE_BLOCK = 0;
34 const int8_t VerifyElf::PROFILE_NOSIGNED_BLOCK = 1;
35 const int8_t VerifyElf::PROFILE_SIGNED_BLOCK = 2;
36 const int8_t VerifyElf::KEY_ROTATION_BLOCK = 3;
37 const int8_t VerifyElf::CODESIGNING_BLOCK_TYPE = 3;
38 
Verify(Options* options)39 bool VerifyElf::Verify(Options* options)
40 {
41     // check param
42     if (options == nullptr) {
43         PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Param options is null.");
44         return false;
45     }
46     if (!CheckParams(options)) {
47         SIGNATURE_TOOLS_LOGE("verify elf check params failed!");
48         return false;
49     }
50     std::string filePath = options->GetString(Options::IN_FILE);
51     bool checkSignFileFlag = CheckSignFile(filePath);
52     if (!checkSignFileFlag) {
53         SIGNATURE_TOOLS_LOGE("check input elf file %s failed!", filePath.c_str());
54         return false;
55     }
56     // verify elf
57     std::vector<int8_t> profileVec;
58     Pkcs7Context pkcs7Context;
59     bool verifyElfFileFlag = VerifyElfFile(filePath, profileVec, options, pkcs7Context);
60     if (!verifyElfFileFlag) {
61         SIGNATURE_TOOLS_LOGE("verify elf file %s failed!", filePath.c_str());
62         return false;
63     }
64     // write certificate and p7b file
65     VerifyHap hapVerify(false);
66     int32_t writeVerifyOutputFlag = hapVerify.WriteVerifyOutput(pkcs7Context, profileVec, options);
67     if (writeVerifyOutputFlag != RET_OK) {
68         SIGNATURE_TOOLS_LOGE("write elf output failed on verify elf!");
69         return false;
70     }
71     return true;
72 }
73 
VerifyElfFile(const std::string& elfFile, std::vector<int8_t>& profileVec, Options* options, Pkcs7Context& pkcs7Context)74 bool VerifyElf::VerifyElfFile(const std::string& elfFile, std::vector<int8_t>& profileVec,
75                               Options* options, Pkcs7Context& pkcs7Context)
76 {
77     SignBlockInfo signBlockInfo(false);
78     bool getSignBlockInfoFlag = GetSignBlockInfo(elfFile, signBlockInfo, ELF);
79     if (!getSignBlockInfoFlag) {
80         SIGNATURE_TOOLS_LOGE("get signBlockInfo failed on verify elf %s", elfFile.c_str());
81         return false;
82     }
83     // verify profile
84     std::string profileJson;
85     bool verifyP7b = VerifyP7b(signBlockInfo.GetSignBlockMap(), options, pkcs7Context, profileVec, profileJson);
86     if (!verifyP7b) {
87         SIGNATURE_TOOLS_LOGE("verify profile failed on verify elf %s", elfFile.c_str());
88         return false;
89     }
90     // verify code sign
91     bool findFlag =
92         signBlockInfo.GetSignBlockMap().find(CODESIGNING_BLOCK_TYPE) != signBlockInfo.GetSignBlockMap().end();
93     if (findFlag) {
94         SigningBlock codesign = signBlockInfo.GetSignBlockMap().find(CODESIGNING_BLOCK_TYPE)->second;
95         bool verifyElfFlag = VerifyCodeSignature::VerifyElf(elfFile, codesign.GetOffset(), codesign.GetLength(),
96                                                             ELF, profileJson);
97         if (!verifyElfFlag) {
98             SIGNATURE_TOOLS_LOGE("code signing failed on verify elf %s", elfFile.c_str());
99             return false;
100         }
101     }
102     return true;
103 }
104 
VerifyP7b(std::unordered_map<int8_t, SigningBlock>& signBlockMap, Options* options, Pkcs7Context& pkcs7Context, std::vector<int8_t>& profileVec, std::string& profileJson)105 bool VerifyElf::VerifyP7b(std::unordered_map<int8_t, SigningBlock>& signBlockMap,
106                           Options* options, Pkcs7Context& pkcs7Context,
107                           std::vector<int8_t>& profileVec, std::string& profileJson)
108 {
109     if (signBlockMap.find(PROFILE_NOSIGNED_BLOCK) != signBlockMap.end()) {
110         // verify unsigned profile
111         const std::vector<int8_t>& profileByte = signBlockMap.find(PROFILE_NOSIGNED_BLOCK)->second.GetValue();
112         std::string fromByteStr(profileByte.begin(), profileByte.end());
113         profileJson = fromByteStr;
114         profileVec = profileByte;
115         SIGNATURE_TOOLS_LOGW("profile is not signed.");
116     } else if (signBlockMap.find(PROFILE_SIGNED_BLOCK) != signBlockMap.end()) {
117         // verify signed profile
118         SigningBlock profileSign = signBlockMap.find(PROFILE_SIGNED_BLOCK)->second;
119         const std::vector<int8_t>& profileByte = profileSign.GetValue();
120         bool getRawContentFlag = GetRawContent(profileByte, profileJson);
121         if (!getRawContentFlag) {
122             SIGNATURE_TOOLS_LOGE("get profile content failed on verify elf!");
123             return false;
124         }
125         VerifyHap hapVerify(false);
126         std::unique_ptr<ByteBuffer> profileBuffer =
127             std::make_unique<ByteBuffer>((char*)profileByte.data(), profileByte.size());
128         bool resultFlag = hapVerify.VerifyAppPkcs7(pkcs7Context, *profileBuffer);
129         if (!resultFlag) {
130             SIGNATURE_TOOLS_LOGE("verify elf profile failed on verify elf!");
131             return false;
132         }
133         profileVec = profileByte;
134         SIGNATURE_TOOLS_LOGI("verify profile success.");
135     } else {
136         SIGNATURE_TOOLS_LOGW("can not found profile sign block.");
137     }
138     return true;
139 }
140 
GetSignBlockInfo(const std::string& file, SignBlockInfo& signBlockInfo, const std::string fileType)141 bool VerifyElf::GetSignBlockInfo(const std::string& file, SignBlockInfo& signBlockInfo,
142                                  const std::string fileType)
143 {
144     // read file
145     std::uintmax_t fileSize = std::filesystem::file_size(file);
146     std::ifstream fileStream(file, std::ios::binary);
147     if (!fileStream.is_open()) {
148         PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed");
149         return false;
150     }
151     std::vector<char>* fileBytes = new std::vector<char>(fileSize, 0);
152     fileStream.read(fileBytes->data(), fileBytes->size());
153     if (fileStream.fail() && !fileStream.eof()) {
154         PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "Error occurred while reading data");
155         fileStream.close();
156         delete fileBytes;
157         return false;
158     }
159     fileStream.close();
160     // get BlockData
161     BlockData blockData(0, 0);
162     bool getSignBlockData = GetSignBlockData(*((std::vector<int8_t>*)fileBytes), blockData, fileType);
163     if (!getSignBlockData) {
164         SIGNATURE_TOOLS_LOGE("get signBlockData failed on verify elf/bin file %s", file.c_str());
165         delete fileBytes;
166         return false;
167     }
168     // get SignBlockMap
169     if (fileType == ELF) {
170         GetElfSignBlock(*((std::vector<int8_t>*)fileBytes), blockData, signBlockInfo.GetSignBlockMap());
171     } else {
172         GetBinSignBlock(*((std::vector<int8_t>*)fileBytes), blockData, signBlockInfo.GetSignBlockMap());
173     }
174     // get bin file digest
175     bool needGenerateDigest = signBlockInfo.GetNeedGenerateDigest();
176     if (needGenerateDigest) {
177         const std::vector<int8_t>& signatrue = signBlockInfo.GetSignBlockMap().find(0)->second.GetValue();
178         bool getFileDigest = GetFileDigest(*((std::vector<int8_t>*)fileBytes), signatrue, signBlockInfo);
179         if (!getFileDigest) {
180             SIGNATURE_TOOLS_LOGE("getFileDigest failed on verify bin file %s", file.c_str());
181             delete fileBytes;
182             return false;
183         }
184     }
185     delete fileBytes;
186     return true;
187 }
188 
GetFileDigest(std::vector<int8_t>& fileBytes, const std::vector<int8_t>& signatrue, SignBlockInfo& signBlockInfo)189 bool VerifyElf::GetFileDigest(std::vector<int8_t>& fileBytes, const std::vector<int8_t>& signatrue,
190                               SignBlockInfo& signBlockInfo)
191 {
192     std::string binDigest;
193     bool getRawContentFlag = GetRawContent(signatrue, binDigest);
194     if (!getRawContentFlag) {
195         SIGNATURE_TOOLS_LOGE("getBinDigest failed on verify bin digest!");
196         return false;
197     }
198     std::vector<int8_t> rawDigest(binDigest.begin(), binDigest.end());
199     signBlockInfo.SetRawDigest(rawDigest);
200     GenerateFileDigest(fileBytes, signBlockInfo);
201     return true;
202 }
203 
GenerateFileDigest(std::vector<int8_t>& fileBytes, SignBlockInfo& signBlockInfo)204 bool VerifyElf::GenerateFileDigest(std::vector<int8_t>& fileBytes, SignBlockInfo& signBlockInfo)
205 {
206     // get algId
207     std::vector<int8_t>& rawDigest = signBlockInfo.GetRawDigest();
208     std::unique_ptr<ByteBuffer> digBuffer = std::make_unique<ByteBuffer>(rawDigest.size());
209     digBuffer->PutData(rawDigest.data(), rawDigest.size());
210     digBuffer->Flip();
211     int32_t algOffset = 10;
212     int16_t algId = 0;
213     const char* bufferPtr = digBuffer->GetBufferPtr();
214     algId = static_cast<int16_t>(be16toh(*reinterpret_cast<const int16_t*>(bufferPtr + algOffset)));
215     // generate digest
216     int32_t fileLength = signBlockInfo.GetSignBlockMap().find(0)->second.GetOffset();
217     std::string digAlg = HashUtils::GetHashAlgName(algId);
218     std::vector<int8_t> generatedDig = HashUtils::GetDigestFromBytes(fileBytes, fileLength, digAlg);
219     if (generatedDig.empty()) {
220         SIGNATURE_TOOLS_LOGE("generate bin file digest failed on verify bin");
221         return false;
222     }
223     SignContentInfo contentInfo;
224     contentInfo.AddContentHashData(0, SignatureBlockTags::HASH_ROOT_4K, algId, generatedDig.size(), generatedDig);
225     std::vector<int8_t> dig = contentInfo.GetByteContent();
226     if (dig.empty()) {
227         SIGNATURE_TOOLS_LOGE("generate file digest is null on verify bin");
228         return false;
229     }
230     signBlockInfo.SetFileDigest(dig);
231     return true;
232 }
233 
GetSignBlockData(std::vector<int8_t>& bytes, BlockData& blockData, const std::string fileType)234 bool VerifyElf::GetSignBlockData(std::vector<int8_t>& bytes, BlockData& blockData,
235                                  const std::string fileType)
236 {
237     int64_t offset = 0;
238     bool checkMagicAndVersionFlag = CheckMagicAndVersion(bytes, offset, fileType);
239     if (!checkMagicAndVersionFlag) {
240         SIGNATURE_TOOLS_LOGE("check magic and version failed, file type: %s", fileType.c_str());
241         return false;
242     }
243     int32_t intByteLength = 4;
244     std::vector<int8_t> blockSizeByte(bytes.begin() + offset, bytes.begin() + offset + intByteLength);
245     offset += intByteLength;
246     std::vector<int8_t> blockNumByte(bytes.begin() + offset, bytes.begin() + offset + intByteLength);
247     if (fileType == BIN) {
248         std::reverse(blockSizeByte.begin(), blockSizeByte.end());
249         std::reverse(blockNumByte.begin(), blockNumByte.end());
250     }
251     std::unique_ptr<ByteBuffer> blockNumBf = std::make_unique<ByteBuffer>(blockNumByte.size());
252     blockNumBf->PutData(blockNumByte.data(), blockNumByte.size());
253     blockNumBf->Flip();
254     int32_t blockNum = 0;
255     blockNumBf->GetInt32(blockNum);
256     std::unique_ptr<ByteBuffer> blockSizeBf = std::make_unique<ByteBuffer>(blockSizeByte.size());
257     blockSizeBf->PutData(blockSizeByte.data(), blockSizeByte.size());
258     blockSizeBf->Flip();
259     int32_t blockSize = 0;
260     blockSizeBf->GetInt32(blockSize);
261     int64_t blockStart = 0;
262     if (fileType == BIN) {
263         blockStart = bytes.size() - blockSize;
264     } else {
265         blockStart = bytes.size() - SignHead::SIGN_HEAD_LEN - blockSize;
266     }
267     blockData.SetBlockNum(blockNum);
268     blockData.SetBlockStart(blockStart);
269     return true;
270 }
271 
CheckMagicAndVersion(std::vector<int8_t>& bytes, int64_t& offset, const std::string fileType)272 bool VerifyElf::CheckMagicAndVersion(std::vector<int8_t>& bytes, int64_t& offset, const std::string fileType)
273 {
274     std::string magicStr = (fileType == ELF ? SignHead::ELF_MAGIC : SignHead::MAGIC);
275     offset = bytes.size() - SignHead::SIGN_HEAD_LEN;
276     std::vector<int8_t> magicByte(bytes.begin() + offset, bytes.begin() + offset + magicStr.size());
277     offset += magicStr.size();
278     std::vector<int8_t> versionByte(bytes.begin() + offset, bytes.begin() + offset + SignHead::VERSION.size());
279     offset += SignHead::VERSION.size();
280     std::vector<int8_t> magicVec(magicStr.begin(), magicStr.end());
281     for (int i = 0; i < magicStr.size(); i++) {
282         if (magicVec[i] != magicByte[i]) {
283             PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "magic verify failed!");
284             return false;
285         }
286     }
287     std::vector<int8_t> versionVec(SignHead::VERSION.begin(), SignHead::VERSION.end());
288     for (int i = 0; i < SignHead::VERSION.size(); i++) {
289         if (versionVec[i] != versionByte[i]) {
290             PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "sign version verify failed!");
291             return false;
292         }
293     }
294     return true;
295 }
296 
GetElfSignBlock(std::vector<int8_t>& bytes, BlockData& blockData, std::unordered_map<int8_t, SigningBlock>& signBlockMap)297 void VerifyElf::GetElfSignBlock(std::vector<int8_t>& bytes, BlockData& blockData,
298                                 std::unordered_map<int8_t, SigningBlock>& signBlockMap)
299 {
300     int32_t headBlockLen = SignHead::ELF_BLOCK_LEN;
301     int64_t offset = blockData.GetBlockStart();
302     for (int i = 0; i < blockData.GetBlockNum(); i++) {
303         std::vector<int8_t> blockByte(bytes.begin() + offset, bytes.begin() + offset + headBlockLen);
304         std::unique_ptr<ByteBuffer> blockBuffer = std::make_unique<ByteBuffer>(blockByte.size());
305         blockBuffer->PutData(blockByte.data(), blockByte.size());
306         blockBuffer->Flip();
307         int8_t type = 0;
308         int8_t tag = 0;
309         int16_t empValue = 0;
310         int32_t length = 0;
311         int32_t blockOffset = 0;
312         blockBuffer->GetByte((int8_t*)&type, sizeof(int8_t));
313         blockBuffer->GetByte((int8_t*)&tag, sizeof(int8_t));
314         blockBuffer->GetInt16(empValue);
315         blockBuffer->GetInt32(length);
316         blockBuffer->GetInt32(blockOffset);
317         std::vector<int8_t> value(bytes.begin() + blockData.GetBlockStart() + blockOffset,
318                                   bytes.begin() + blockData.GetBlockStart() + blockOffset + length);
319         SigningBlock signingBlock(type, value, blockData.GetBlockStart() + blockOffset);
320         signBlockMap.insert(std::make_pair(type, signingBlock));
321         offset += headBlockLen;
322     }
323 }
324 
GetBinSignBlock(std::vector<int8_t>& bytes, BlockData& blockData, std::unordered_map<int8_t, SigningBlock>& signBlockMap)325 void VerifyElf::GetBinSignBlock(std::vector<int8_t>& bytes, BlockData& blockData,
326                                 std::unordered_map<int8_t, SigningBlock>& signBlockMap)
327 {
328     int32_t headBlockLen = SignHead::BIN_BLOCK_LEN;
329     int32_t offset = blockData.GetBlockStart();
330     for (int i = 0; i < blockData.GetBlockNum(); i++) {
331         std::vector<int8_t> blockByte(bytes.begin() + offset, bytes.begin() + offset + headBlockLen);
332         std::unique_ptr<ByteBuffer> blockBuffer = std::make_unique<ByteBuffer>(blockByte.size());
333         blockBuffer->PutData(blockByte.data(), blockByte.size());
334         blockBuffer->Flip();
335         int8_t type = 0;
336         int8_t tag = 0;
337         int16_t length = 0;
338         int32_t blockOffset = 0;
339         blockBuffer->GetByte((int8_t*)&type, sizeof(int8_t));
340         blockBuffer->GetByte((int8_t*)&tag, sizeof(int8_t));
341         const char* bufferPtr = blockBuffer->GetBufferPtr();
342         int bfLengthIdx = 2;
343         int bfBlockIdx = 4;
344         length = static_cast<int16_t>(be16toh(*reinterpret_cast<const int16_t*>(bufferPtr + bfLengthIdx)));
345         blockOffset = static_cast<int32_t>(be32toh(*reinterpret_cast<const int32_t*>(bufferPtr + bfBlockIdx)));
346         if (length == 0) {
347             length = bytes.size() - SignHead::SIGN_HEAD_LEN - blockOffset;
348         }
349         std::vector<int8_t> value(bytes.begin() + blockOffset, bytes.begin() + blockOffset + length);
350         SigningBlock signingBlock(type, value, blockOffset);
351         signBlockMap.insert(std::make_pair(type, signingBlock));
352         offset += headBlockLen;
353     }
354 }
355 
CheckParams(Options* options)356 bool VerifyElf::CheckParams(Options* options)
357 {
358     bool certEmpty = options->GetString(Options::OUT_CERT_CHAIN).empty();
359     if (certEmpty) {
360         PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Missing parameter: " + Options::OUT_CERT_CHAIN + "s.");
361         return false;
362     }
363     bool profileEmpty = options->GetString(Options::OUT_PROFILE).empty();
364     if (profileEmpty) {
365         PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Missing parameter: " + Options::OUT_PROFILE + "s.");
366         return false;
367     }
368     bool proofEmpty = options->GetString(Options::PROOF_FILE).empty();
369     if (proofEmpty) {
370         SIGNATURE_TOOLS_LOGW("Missing parameter: %s.",
371                              Options::PROOF_FILE.c_str());
372     }
373     return true;
374 }
375 
CheckSignFile(const std::string& signedFile)376 bool VerifyElf::CheckSignFile(const std::string& signedFile)
377 {
378     if (signedFile.empty()) {
379         PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Not found verify file path " + signedFile);
380         return false;
381     }
382     bool validFlag = FileUtils::IsValidFile(signedFile);
383     if (!validFlag) {
384         SIGNATURE_TOOLS_LOGE("signed file is invalid.");
385         return false;
386     }
387     return true;
388 }
389 
GetRawContent(const std::vector<int8_t>& contentVec, std::string& rawContent)390 bool VerifyElf::GetRawContent(const std::vector<int8_t>& contentVec, std::string& rawContent)
391 {
392     PKCS7Data p7Data;
393     int parseFlag = p7Data.Parse(contentVec);
394     if (parseFlag < 0) {
395         SIGNATURE_TOOLS_LOGE("parse content failed!");
396         return false;
397     }
398     int verifyFlag = p7Data.Verify();
399     if (verifyFlag < 0) {
400         SIGNATURE_TOOLS_LOGE("verify content failed!");
401         return false;
402     }
403     int getContentFlag = p7Data.GetContent(rawContent);
404     if (getContentFlag < 0) {
405         SIGNATURE_TOOLS_LOGE("get p7Data raw content failed!");
406         return false;
407     }
408     return true;
409 }
410 
411 } // namespace SignatureTools
412 } // namespace OHOS