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
30 namespace OHOS {
31 namespace Global {
32 namespace I18n {
33 namespace {
34 const int32_t BASE64_ENCODE_PACKET_LEN = 3;
35 const int32_t BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA = 4;
36 }
37
38 const int SignatureVerifier::HASH_BUFFER_SIZE = 4096;
39 const int SignatureVerifier::MIN_SIZE = 2;
40 const int SignatureVerifier::VERSION_SIZE = 4;
41
42
LoadFileVersion(const std::string & versionPath)43 std::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
CompareVersion(std::string & preVersion,std::string & curVersion)67 int 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
VerifyCertFile(const std::string & certPath,const std::string & verifyPath,const std::string & pubkeyPath,const std::string & manifestPath)87 bool 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
VerifyParamFile(const std::string & fileName,const std::string & filePath,const std::string & manifestPath)118 bool 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
VerifyFileSign(const std::string & pubkeyPath,const std::string & signPath,const std::string & digestPath)157 bool 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
VerifyRsa(RSA * pubkey,const std::string & digest,const std::string & sign)188 bool 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
CalcFileSha256Digest(const std::string & path)224 std::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
CalcBase64(uint8_t * input,uint32_t inputLen,std::string & encodedStr)233 void 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
CalcFileShaOriginal(const std::string & filePath,unsigned char * hash)243 int 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
GetFileStream(const std::string & filePath)267 std::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 }