1/* 2 * Copyright (c) 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 17#include <climits> 18#include <cstdlib> 19#include <fcntl.h> 20#include <filesystem> 21#include <fstream> 22#include <openssl/pem.h> 23#include <openssl/sha.h> 24#include <sstream> 25#include <unistd.h> 26#include "i18n_hilog.h" 27#include "signature_verifier.h" 28#include "utils.h" 29 30namespace OHOS { 31namespace Global { 32namespace I18n { 33namespace { 34 const int32_t BASE64_ENCODE_PACKET_LEN = 3; 35 const int32_t BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA = 4; 36} 37 38const int SignatureVerifier::HASH_BUFFER_SIZE = 4096; 39const int SignatureVerifier::MIN_SIZE = 2; 40const int SignatureVerifier::VERSION_SIZE = 4; 41 42 43std::string SignatureVerifier::LoadFileVersion(const std::string& versionPath) 44{ 45 std::string version; 46 if (!FileExist(versionPath.c_str())) { 47 return version; 48 } 49 std::ifstream file(versionPath); 50 std::string line; 51 std::vector<std::string> strs; 52 while (std::getline(file, line)) { 53 Split(line, "=", strs); 54 if (strs.size() < MIN_SIZE) { 55 continue; 56 } 57 if (strs[0] == "version") { 58 version = trim(strs[1]); 59 break; 60 } 61 } 62 file.close(); 63 return version; 64} 65 66// compare version 67int SignatureVerifier::CompareVersion(std::string& preVersion, std::string& curVersion) 68{ 69 std::vector<std::string> preVersionstr; 70 std::vector<std::string> curVersionstr; 71 Split(preVersion, ".", preVersionstr); 72 Split(curVersion, ".", curVersionstr); 73 if (curVersionstr.size() != VERSION_SIZE || preVersionstr.size() != VERSION_SIZE) { 74 return -1; 75 } 76 for (int i = 0; i < VERSION_SIZE; i++) { 77 if (atoi(preVersionstr.at(i).c_str()) < atoi(curVersionstr.at(i).c_str())) { 78 return 1; 79 } else if (atoi(preVersionstr.at(i).c_str()) > atoi(curVersionstr.at(i).c_str())) { 80 return -1; 81 } 82 } 83 return 0; 84} 85 86// verify certificate file 87bool SignatureVerifier::VerifyCertFile(const std::string& certPath, const std::string& verifyPath, 88 const std::string& pubkeyPath, const std::string& manifestPath) 89{ 90 if (!VerifyFileSign(pubkeyPath, certPath, verifyPath)) { 91 return false; 92 } 93 std::ifstream file(verifyPath); 94 if (!file.good()) { 95 return false; 96 } 97 std::string line; 98 std::string sha256Digest; 99 std::getline(file, line); 100 file.close(); 101 std::vector<std::string> strs; 102 Split(line, ":", strs); 103 if (strs.size() < MIN_SIZE) { 104 return false; 105 } 106 sha256Digest = strs[1]; 107 sha256Digest = trim(sha256Digest); 108 // std::string manifestPath = CFG_PATH + MANIFEST_FILE; 109 std::string manifestDigest = CalcFileSha256Digest(manifestPath); 110 if (sha256Digest == manifestDigest) { 111 return true; 112 } 113 return false; 114} 115 116 117// verify param file digest 118bool SignatureVerifier::VerifyParamFile(const std::string& fileName, const std::string& filePath, 119 const std::string& manifestPath) 120{ 121 std::ifstream file(manifestPath); 122 if (!file.good()) { 123 return false; 124 } 125 std::string absFilePath = filePath + fileName; 126 if (!CheckTzDataFilePath(absFilePath)) { 127 return false; 128 } 129 std::string sha256Digest; 130 std::string line; 131 while (std::getline(file, line)) { 132 if (line.find("Name: " + fileName) != std::string::npos) { 133 std::string nextLine; 134 std::getline(file, nextLine); 135 std::vector<std::string> strs; 136 Split(nextLine, ":", strs); 137 if (strs.size() < MIN_SIZE) { 138 return false; 139 } 140 sha256Digest = strs[1]; 141 sha256Digest = trim(sha256Digest); 142 break; 143 } 144 } 145 if (sha256Digest.empty()) { 146 return false; 147 } 148 std::string fileDigest = CalcFileSha256Digest(absFilePath); 149 if (fileDigest == sha256Digest) { 150 return true; 151 } 152 return false; 153} 154 155 156// verify cert file sign 157bool SignatureVerifier::VerifyFileSign(const std::string& pubkeyPath, const std::string& signPath, 158 const std::string& digestPath) 159{ 160 if (!FileExist(pubkeyPath.c_str())) { 161 return false; 162 } 163 164 if (!FileExist(signPath.c_str())) { 165 return false; 166 } 167 168 if (!FileExist(digestPath.c_str())) { 169 return false; 170 } 171 std::string signStr = GetFileStream(signPath); 172 std::string digestStr = GetFileStream(digestPath); 173 RSA* pubkey = RSA_new(); 174 bool verify = false; 175 if (pubkey != nullptr && !signStr.empty() && !digestStr.empty()) { 176 BIO* bio = BIO_new_file(pubkeyPath.c_str(), "r"); 177 if (PEM_read_bio_RSA_PUBKEY(bio, &pubkey, nullptr, nullptr) == nullptr) { 178 BIO_free(bio); 179 return false; 180 } 181 verify = VerifyRsa(pubkey, digestStr, signStr); 182 BIO_free(bio); 183 } 184 RSA_free(pubkey); 185 return verify; 186} 187 188bool SignatureVerifier::VerifyRsa(RSA* pubkey, const std::string& digest, const std::string& sign) 189{ 190 EVP_PKEY* evpKey = EVP_PKEY_new(); 191 if (evpKey == nullptr) { 192 return false; 193 } 194 if (EVP_PKEY_set1_RSA(evpKey, pubkey) != 1) { 195 return false; 196 } 197 EVP_MD_CTX* ctx = EVP_MD_CTX_new(); 198 EVP_MD_CTX_init(ctx); 199 if (ctx == nullptr) { 200 EVP_PKEY_free(evpKey); 201 return false; 202 } 203 if (EVP_VerifyInit_ex(ctx, EVP_sha256(), nullptr) != 1) { 204 EVP_PKEY_free(evpKey); 205 EVP_MD_CTX_free(ctx); 206 return false; 207 } 208 if (EVP_VerifyUpdate(ctx, digest.c_str(), digest.size()) != 1) { 209 EVP_PKEY_free(evpKey); 210 EVP_MD_CTX_free(ctx); 211 return false; 212 } 213 char* signArr = const_cast<char*>(sign.c_str()); 214 if (EVP_VerifyFinal(ctx, reinterpret_cast<unsigned char *>(signArr), sign.size(), evpKey) != 1) { 215 EVP_PKEY_free(evpKey); 216 EVP_MD_CTX_free(ctx); 217 return false; 218 } 219 EVP_PKEY_free(evpKey); 220 EVP_MD_CTX_free(ctx); 221 return true; 222} 223 224std::string SignatureVerifier::CalcFileSha256Digest(const std::string& path) 225{ 226 unsigned char res[SHA256_DIGEST_LENGTH] = {0}; 227 CalcFileShaOriginal(path, res); 228 std::string dist; 229 CalcBase64(res, SHA256_DIGEST_LENGTH, dist); 230 return dist; 231} 232 233void SignatureVerifier::CalcBase64(uint8_t* input, uint32_t inputLen, std::string& encodedStr) 234{ 235 size_t base64Len = static_cast<size_t>(ceil(static_cast<long double>(inputLen) / BASE64_ENCODE_PACKET_LEN) * 236 BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA + 1); 237 std::unique_ptr<unsigned char[]> base64Str = std::make_unique<unsigned char[]>(base64Len); 238 int encodeLen = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64Str.get()), input, inputLen); 239 size_t outLen = static_cast<size_t>(encodeLen); 240 encodedStr = std::string(reinterpret_cast<char*>(base64Str.get()), outLen); 241} 242 243int SignatureVerifier::CalcFileShaOriginal(const std::string& filePath, unsigned char* hash) 244{ 245 if (filePath.empty() || hash == nullptr || !IsLegalPath(filePath)) { 246 return -1; 247 } 248 FILE* fp = fopen(filePath.c_str(), "rb"); 249 if (fp == nullptr) { 250 return -1; 251 } 252 size_t n; 253 char buffer[HASH_BUFFER_SIZE] = {0}; 254 SHA256_CTX ctx; 255 SHA256_Init(&ctx); 256 while ((n = fread(buffer, 1, sizeof(buffer), fp))) { 257 SHA256_Update(&ctx, reinterpret_cast<unsigned char*>(buffer), n); 258 } 259 SHA256_Final(hash, &ctx); 260 if (fclose(fp) == -1) { 261 return -1; 262 } 263 return 0; 264} 265 266// load file content 267std::string SignatureVerifier::GetFileStream(const std::string& filePath) 268{ 269 if (filePath.length() > PATH_MAX) { 270 return ""; 271 } 272 char* resolvedPath = new char[PATH_MAX + 1]; 273 if (realpath(filePath.c_str(), resolvedPath) == nullptr) { 274 delete[] resolvedPath; 275 return ""; 276 } 277 const std::string newFilePath = resolvedPath; 278 std::ifstream file(newFilePath, std::ios::in | std::ios::binary); 279 if (!file.good()) { 280 delete[] resolvedPath; 281 return ""; 282 } 283 std::stringstream inFile; 284 inFile << file.rdbuf(); 285 delete[] resolvedPath; 286 return inFile.str(); 287} 288 289} 290} 291}