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