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 30namespace OHOS { 31namespace SignatureTools { 32 33const int8_t VerifyElf::SIGNATURE_BLOCK = 0; 34const int8_t VerifyElf::PROFILE_NOSIGNED_BLOCK = 1; 35const int8_t VerifyElf::PROFILE_SIGNED_BLOCK = 2; 36const int8_t VerifyElf::KEY_ROTATION_BLOCK = 3; 37const int8_t VerifyElf::CODESIGNING_BLOCK_TYPE = 3; 38 39bool 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 74bool 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 105bool 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 141bool 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 189bool 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 204bool 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 234bool 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 272bool 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 297void 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 325void 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 356bool 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 376bool 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 390bool 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