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}