19596a2c1Sopenharmony_ci/* 29596a2c1Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 39596a2c1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 49596a2c1Sopenharmony_ci * you may not use this file except in compliance with the License. 59596a2c1Sopenharmony_ci * You may obtain a copy of the License at 69596a2c1Sopenharmony_ci * 79596a2c1Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 89596a2c1Sopenharmony_ci * 99596a2c1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 109596a2c1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 119596a2c1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129596a2c1Sopenharmony_ci * See the License for the specific language governing permissions and 139596a2c1Sopenharmony_ci * limitations under the License. 149596a2c1Sopenharmony_ci */ 159596a2c1Sopenharmony_ci 169596a2c1Sopenharmony_ci 179596a2c1Sopenharmony_ci#include <climits> 189596a2c1Sopenharmony_ci#include <cstdlib> 199596a2c1Sopenharmony_ci#include <fcntl.h> 209596a2c1Sopenharmony_ci#include <filesystem> 219596a2c1Sopenharmony_ci#include <fstream> 229596a2c1Sopenharmony_ci#include <openssl/pem.h> 239596a2c1Sopenharmony_ci#include <openssl/sha.h> 249596a2c1Sopenharmony_ci#include <sstream> 259596a2c1Sopenharmony_ci#include <unistd.h> 269596a2c1Sopenharmony_ci#include "i18n_hilog.h" 279596a2c1Sopenharmony_ci#include "signature_verifier.h" 289596a2c1Sopenharmony_ci#include "utils.h" 299596a2c1Sopenharmony_ci 309596a2c1Sopenharmony_cinamespace OHOS { 319596a2c1Sopenharmony_cinamespace Global { 329596a2c1Sopenharmony_cinamespace I18n { 339596a2c1Sopenharmony_cinamespace { 349596a2c1Sopenharmony_ci const int32_t BASE64_ENCODE_PACKET_LEN = 3; 359596a2c1Sopenharmony_ci const int32_t BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA = 4; 369596a2c1Sopenharmony_ci} 379596a2c1Sopenharmony_ci 389596a2c1Sopenharmony_ciconst int SignatureVerifier::HASH_BUFFER_SIZE = 4096; 399596a2c1Sopenharmony_ciconst int SignatureVerifier::MIN_SIZE = 2; 409596a2c1Sopenharmony_ciconst int SignatureVerifier::VERSION_SIZE = 4; 419596a2c1Sopenharmony_ci 429596a2c1Sopenharmony_ci 439596a2c1Sopenharmony_cistd::string SignatureVerifier::LoadFileVersion(const std::string& versionPath) 449596a2c1Sopenharmony_ci{ 459596a2c1Sopenharmony_ci std::string version; 469596a2c1Sopenharmony_ci if (!FileExist(versionPath.c_str())) { 479596a2c1Sopenharmony_ci return version; 489596a2c1Sopenharmony_ci } 499596a2c1Sopenharmony_ci std::ifstream file(versionPath); 509596a2c1Sopenharmony_ci std::string line; 519596a2c1Sopenharmony_ci std::vector<std::string> strs; 529596a2c1Sopenharmony_ci while (std::getline(file, line)) { 539596a2c1Sopenharmony_ci Split(line, "=", strs); 549596a2c1Sopenharmony_ci if (strs.size() < MIN_SIZE) { 559596a2c1Sopenharmony_ci continue; 569596a2c1Sopenharmony_ci } 579596a2c1Sopenharmony_ci if (strs[0] == "version") { 589596a2c1Sopenharmony_ci version = trim(strs[1]); 599596a2c1Sopenharmony_ci break; 609596a2c1Sopenharmony_ci } 619596a2c1Sopenharmony_ci } 629596a2c1Sopenharmony_ci file.close(); 639596a2c1Sopenharmony_ci return version; 649596a2c1Sopenharmony_ci} 659596a2c1Sopenharmony_ci 669596a2c1Sopenharmony_ci// compare version 679596a2c1Sopenharmony_ciint SignatureVerifier::CompareVersion(std::string& preVersion, std::string& curVersion) 689596a2c1Sopenharmony_ci{ 699596a2c1Sopenharmony_ci std::vector<std::string> preVersionstr; 709596a2c1Sopenharmony_ci std::vector<std::string> curVersionstr; 719596a2c1Sopenharmony_ci Split(preVersion, ".", preVersionstr); 729596a2c1Sopenharmony_ci Split(curVersion, ".", curVersionstr); 739596a2c1Sopenharmony_ci if (curVersionstr.size() != VERSION_SIZE || preVersionstr.size() != VERSION_SIZE) { 749596a2c1Sopenharmony_ci return -1; 759596a2c1Sopenharmony_ci } 769596a2c1Sopenharmony_ci for (int i = 0; i < VERSION_SIZE; i++) { 779596a2c1Sopenharmony_ci if (atoi(preVersionstr.at(i).c_str()) < atoi(curVersionstr.at(i).c_str())) { 789596a2c1Sopenharmony_ci return 1; 799596a2c1Sopenharmony_ci } else if (atoi(preVersionstr.at(i).c_str()) > atoi(curVersionstr.at(i).c_str())) { 809596a2c1Sopenharmony_ci return -1; 819596a2c1Sopenharmony_ci } 829596a2c1Sopenharmony_ci } 839596a2c1Sopenharmony_ci return 0; 849596a2c1Sopenharmony_ci} 859596a2c1Sopenharmony_ci 869596a2c1Sopenharmony_ci// verify certificate file 879596a2c1Sopenharmony_cibool SignatureVerifier::VerifyCertFile(const std::string& certPath, const std::string& verifyPath, 889596a2c1Sopenharmony_ci const std::string& pubkeyPath, const std::string& manifestPath) 899596a2c1Sopenharmony_ci{ 909596a2c1Sopenharmony_ci if (!VerifyFileSign(pubkeyPath, certPath, verifyPath)) { 919596a2c1Sopenharmony_ci return false; 929596a2c1Sopenharmony_ci } 939596a2c1Sopenharmony_ci std::ifstream file(verifyPath); 949596a2c1Sopenharmony_ci if (!file.good()) { 959596a2c1Sopenharmony_ci return false; 969596a2c1Sopenharmony_ci } 979596a2c1Sopenharmony_ci std::string line; 989596a2c1Sopenharmony_ci std::string sha256Digest; 999596a2c1Sopenharmony_ci std::getline(file, line); 1009596a2c1Sopenharmony_ci file.close(); 1019596a2c1Sopenharmony_ci std::vector<std::string> strs; 1029596a2c1Sopenharmony_ci Split(line, ":", strs); 1039596a2c1Sopenharmony_ci if (strs.size() < MIN_SIZE) { 1049596a2c1Sopenharmony_ci return false; 1059596a2c1Sopenharmony_ci } 1069596a2c1Sopenharmony_ci sha256Digest = strs[1]; 1079596a2c1Sopenharmony_ci sha256Digest = trim(sha256Digest); 1089596a2c1Sopenharmony_ci // std::string manifestPath = CFG_PATH + MANIFEST_FILE; 1099596a2c1Sopenharmony_ci std::string manifestDigest = CalcFileSha256Digest(manifestPath); 1109596a2c1Sopenharmony_ci if (sha256Digest == manifestDigest) { 1119596a2c1Sopenharmony_ci return true; 1129596a2c1Sopenharmony_ci } 1139596a2c1Sopenharmony_ci return false; 1149596a2c1Sopenharmony_ci} 1159596a2c1Sopenharmony_ci 1169596a2c1Sopenharmony_ci 1179596a2c1Sopenharmony_ci// verify param file digest 1189596a2c1Sopenharmony_cibool SignatureVerifier::VerifyParamFile(const std::string& fileName, const std::string& filePath, 1199596a2c1Sopenharmony_ci const std::string& manifestPath) 1209596a2c1Sopenharmony_ci{ 1219596a2c1Sopenharmony_ci std::ifstream file(manifestPath); 1229596a2c1Sopenharmony_ci if (!file.good()) { 1239596a2c1Sopenharmony_ci return false; 1249596a2c1Sopenharmony_ci } 1259596a2c1Sopenharmony_ci std::string absFilePath = filePath + fileName; 1269596a2c1Sopenharmony_ci if (!CheckTzDataFilePath(absFilePath)) { 1279596a2c1Sopenharmony_ci return false; 1289596a2c1Sopenharmony_ci } 1299596a2c1Sopenharmony_ci std::string sha256Digest; 1309596a2c1Sopenharmony_ci std::string line; 1319596a2c1Sopenharmony_ci while (std::getline(file, line)) { 1329596a2c1Sopenharmony_ci if (line.find("Name: " + fileName) != std::string::npos) { 1339596a2c1Sopenharmony_ci std::string nextLine; 1349596a2c1Sopenharmony_ci std::getline(file, nextLine); 1359596a2c1Sopenharmony_ci std::vector<std::string> strs; 1369596a2c1Sopenharmony_ci Split(nextLine, ":", strs); 1379596a2c1Sopenharmony_ci if (strs.size() < MIN_SIZE) { 1389596a2c1Sopenharmony_ci return false; 1399596a2c1Sopenharmony_ci } 1409596a2c1Sopenharmony_ci sha256Digest = strs[1]; 1419596a2c1Sopenharmony_ci sha256Digest = trim(sha256Digest); 1429596a2c1Sopenharmony_ci break; 1439596a2c1Sopenharmony_ci } 1449596a2c1Sopenharmony_ci } 1459596a2c1Sopenharmony_ci if (sha256Digest.empty()) { 1469596a2c1Sopenharmony_ci return false; 1479596a2c1Sopenharmony_ci } 1489596a2c1Sopenharmony_ci std::string fileDigest = CalcFileSha256Digest(absFilePath); 1499596a2c1Sopenharmony_ci if (fileDigest == sha256Digest) { 1509596a2c1Sopenharmony_ci return true; 1519596a2c1Sopenharmony_ci } 1529596a2c1Sopenharmony_ci return false; 1539596a2c1Sopenharmony_ci} 1549596a2c1Sopenharmony_ci 1559596a2c1Sopenharmony_ci 1569596a2c1Sopenharmony_ci// verify cert file sign 1579596a2c1Sopenharmony_cibool SignatureVerifier::VerifyFileSign(const std::string& pubkeyPath, const std::string& signPath, 1589596a2c1Sopenharmony_ci const std::string& digestPath) 1599596a2c1Sopenharmony_ci{ 1609596a2c1Sopenharmony_ci if (!FileExist(pubkeyPath.c_str())) { 1619596a2c1Sopenharmony_ci return false; 1629596a2c1Sopenharmony_ci } 1639596a2c1Sopenharmony_ci 1649596a2c1Sopenharmony_ci if (!FileExist(signPath.c_str())) { 1659596a2c1Sopenharmony_ci return false; 1669596a2c1Sopenharmony_ci } 1679596a2c1Sopenharmony_ci 1689596a2c1Sopenharmony_ci if (!FileExist(digestPath.c_str())) { 1699596a2c1Sopenharmony_ci return false; 1709596a2c1Sopenharmony_ci } 1719596a2c1Sopenharmony_ci std::string signStr = GetFileStream(signPath); 1729596a2c1Sopenharmony_ci std::string digestStr = GetFileStream(digestPath); 1739596a2c1Sopenharmony_ci RSA* pubkey = RSA_new(); 1749596a2c1Sopenharmony_ci bool verify = false; 1759596a2c1Sopenharmony_ci if (pubkey != nullptr && !signStr.empty() && !digestStr.empty()) { 1769596a2c1Sopenharmony_ci BIO* bio = BIO_new_file(pubkeyPath.c_str(), "r"); 1779596a2c1Sopenharmony_ci if (PEM_read_bio_RSA_PUBKEY(bio, &pubkey, nullptr, nullptr) == nullptr) { 1789596a2c1Sopenharmony_ci BIO_free(bio); 1799596a2c1Sopenharmony_ci return false; 1809596a2c1Sopenharmony_ci } 1819596a2c1Sopenharmony_ci verify = VerifyRsa(pubkey, digestStr, signStr); 1829596a2c1Sopenharmony_ci BIO_free(bio); 1839596a2c1Sopenharmony_ci } 1849596a2c1Sopenharmony_ci RSA_free(pubkey); 1859596a2c1Sopenharmony_ci return verify; 1869596a2c1Sopenharmony_ci} 1879596a2c1Sopenharmony_ci 1889596a2c1Sopenharmony_cibool SignatureVerifier::VerifyRsa(RSA* pubkey, const std::string& digest, const std::string& sign) 1899596a2c1Sopenharmony_ci{ 1909596a2c1Sopenharmony_ci EVP_PKEY* evpKey = EVP_PKEY_new(); 1919596a2c1Sopenharmony_ci if (evpKey == nullptr) { 1929596a2c1Sopenharmony_ci return false; 1939596a2c1Sopenharmony_ci } 1949596a2c1Sopenharmony_ci if (EVP_PKEY_set1_RSA(evpKey, pubkey) != 1) { 1959596a2c1Sopenharmony_ci return false; 1969596a2c1Sopenharmony_ci } 1979596a2c1Sopenharmony_ci EVP_MD_CTX* ctx = EVP_MD_CTX_new(); 1989596a2c1Sopenharmony_ci EVP_MD_CTX_init(ctx); 1999596a2c1Sopenharmony_ci if (ctx == nullptr) { 2009596a2c1Sopenharmony_ci EVP_PKEY_free(evpKey); 2019596a2c1Sopenharmony_ci return false; 2029596a2c1Sopenharmony_ci } 2039596a2c1Sopenharmony_ci if (EVP_VerifyInit_ex(ctx, EVP_sha256(), nullptr) != 1) { 2049596a2c1Sopenharmony_ci EVP_PKEY_free(evpKey); 2059596a2c1Sopenharmony_ci EVP_MD_CTX_free(ctx); 2069596a2c1Sopenharmony_ci return false; 2079596a2c1Sopenharmony_ci } 2089596a2c1Sopenharmony_ci if (EVP_VerifyUpdate(ctx, digest.c_str(), digest.size()) != 1) { 2099596a2c1Sopenharmony_ci EVP_PKEY_free(evpKey); 2109596a2c1Sopenharmony_ci EVP_MD_CTX_free(ctx); 2119596a2c1Sopenharmony_ci return false; 2129596a2c1Sopenharmony_ci } 2139596a2c1Sopenharmony_ci char* signArr = const_cast<char*>(sign.c_str()); 2149596a2c1Sopenharmony_ci if (EVP_VerifyFinal(ctx, reinterpret_cast<unsigned char *>(signArr), sign.size(), evpKey) != 1) { 2159596a2c1Sopenharmony_ci EVP_PKEY_free(evpKey); 2169596a2c1Sopenharmony_ci EVP_MD_CTX_free(ctx); 2179596a2c1Sopenharmony_ci return false; 2189596a2c1Sopenharmony_ci } 2199596a2c1Sopenharmony_ci EVP_PKEY_free(evpKey); 2209596a2c1Sopenharmony_ci EVP_MD_CTX_free(ctx); 2219596a2c1Sopenharmony_ci return true; 2229596a2c1Sopenharmony_ci} 2239596a2c1Sopenharmony_ci 2249596a2c1Sopenharmony_cistd::string SignatureVerifier::CalcFileSha256Digest(const std::string& path) 2259596a2c1Sopenharmony_ci{ 2269596a2c1Sopenharmony_ci unsigned char res[SHA256_DIGEST_LENGTH] = {0}; 2279596a2c1Sopenharmony_ci CalcFileShaOriginal(path, res); 2289596a2c1Sopenharmony_ci std::string dist; 2299596a2c1Sopenharmony_ci CalcBase64(res, SHA256_DIGEST_LENGTH, dist); 2309596a2c1Sopenharmony_ci return dist; 2319596a2c1Sopenharmony_ci} 2329596a2c1Sopenharmony_ci 2339596a2c1Sopenharmony_civoid SignatureVerifier::CalcBase64(uint8_t* input, uint32_t inputLen, std::string& encodedStr) 2349596a2c1Sopenharmony_ci{ 2359596a2c1Sopenharmony_ci size_t base64Len = static_cast<size_t>(ceil(static_cast<long double>(inputLen) / BASE64_ENCODE_PACKET_LEN) * 2369596a2c1Sopenharmony_ci BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA + 1); 2379596a2c1Sopenharmony_ci std::unique_ptr<unsigned char[]> base64Str = std::make_unique<unsigned char[]>(base64Len); 2389596a2c1Sopenharmony_ci int encodeLen = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64Str.get()), input, inputLen); 2399596a2c1Sopenharmony_ci size_t outLen = static_cast<size_t>(encodeLen); 2409596a2c1Sopenharmony_ci encodedStr = std::string(reinterpret_cast<char*>(base64Str.get()), outLen); 2419596a2c1Sopenharmony_ci} 2429596a2c1Sopenharmony_ci 2439596a2c1Sopenharmony_ciint SignatureVerifier::CalcFileShaOriginal(const std::string& filePath, unsigned char* hash) 2449596a2c1Sopenharmony_ci{ 2459596a2c1Sopenharmony_ci if (filePath.empty() || hash == nullptr || !IsLegalPath(filePath)) { 2469596a2c1Sopenharmony_ci return -1; 2479596a2c1Sopenharmony_ci } 2489596a2c1Sopenharmony_ci FILE* fp = fopen(filePath.c_str(), "rb"); 2499596a2c1Sopenharmony_ci if (fp == nullptr) { 2509596a2c1Sopenharmony_ci return -1; 2519596a2c1Sopenharmony_ci } 2529596a2c1Sopenharmony_ci size_t n; 2539596a2c1Sopenharmony_ci char buffer[HASH_BUFFER_SIZE] = {0}; 2549596a2c1Sopenharmony_ci SHA256_CTX ctx; 2559596a2c1Sopenharmony_ci SHA256_Init(&ctx); 2569596a2c1Sopenharmony_ci while ((n = fread(buffer, 1, sizeof(buffer), fp))) { 2579596a2c1Sopenharmony_ci SHA256_Update(&ctx, reinterpret_cast<unsigned char*>(buffer), n); 2589596a2c1Sopenharmony_ci } 2599596a2c1Sopenharmony_ci SHA256_Final(hash, &ctx); 2609596a2c1Sopenharmony_ci if (fclose(fp) == -1) { 2619596a2c1Sopenharmony_ci return -1; 2629596a2c1Sopenharmony_ci } 2639596a2c1Sopenharmony_ci return 0; 2649596a2c1Sopenharmony_ci} 2659596a2c1Sopenharmony_ci 2669596a2c1Sopenharmony_ci// load file content 2679596a2c1Sopenharmony_cistd::string SignatureVerifier::GetFileStream(const std::string& filePath) 2689596a2c1Sopenharmony_ci{ 2699596a2c1Sopenharmony_ci if (filePath.length() > PATH_MAX) { 2709596a2c1Sopenharmony_ci return ""; 2719596a2c1Sopenharmony_ci } 2729596a2c1Sopenharmony_ci char* resolvedPath = new char[PATH_MAX + 1]; 2739596a2c1Sopenharmony_ci if (realpath(filePath.c_str(), resolvedPath) == nullptr) { 2749596a2c1Sopenharmony_ci delete[] resolvedPath; 2759596a2c1Sopenharmony_ci return ""; 2769596a2c1Sopenharmony_ci } 2779596a2c1Sopenharmony_ci const std::string newFilePath = resolvedPath; 2789596a2c1Sopenharmony_ci std::ifstream file(newFilePath, std::ios::in | std::ios::binary); 2799596a2c1Sopenharmony_ci if (!file.good()) { 2809596a2c1Sopenharmony_ci delete[] resolvedPath; 2819596a2c1Sopenharmony_ci return ""; 2829596a2c1Sopenharmony_ci } 2839596a2c1Sopenharmony_ci std::stringstream inFile; 2849596a2c1Sopenharmony_ci inFile << file.rdbuf(); 2859596a2c1Sopenharmony_ci delete[] resolvedPath; 2869596a2c1Sopenharmony_ci return inFile.str(); 2879596a2c1Sopenharmony_ci} 2889596a2c1Sopenharmony_ci 2899596a2c1Sopenharmony_ci} 2909596a2c1Sopenharmony_ci} 2919596a2c1Sopenharmony_ci}