1 /*
2 * Copyright (c) 2025-2025 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 "feature/param_update/sign_tools.h"
17
18 #include <unistd.h>
19 #include <fstream> // for ifstream
20 #include <openssl/bio.h> // bio
21 #include <openssl/evp.h> // evp
22 #include <openssl/pem.h> // PEM_read_bio_RSA_PUBKEY
23 #include <openssl/rsa.h> // rsa
24 #include <sstream> // stringstream
25 #include <cstdlib>
26 #include <climits>
27
28 #include "common/util/file_utils.h"
29 #include "fms_log_wrapper.h"
30
31 namespace OHOS {
32 namespace AppExecFwk {
VerifyFileSign(const std::string & pubKeyPath,const std::string & singPath,const std::string & digestPath)33 bool SignTools::VerifyFileSign(const std::string &pubKeyPath, const std::string &singPath,
34 const std::string &digestPath)
35 {
36 if (!(FileUtils::IsFileExists(pubKeyPath) && FileUtils::IsFileExists(singPath) &&
37 FileUtils::IsFileExists(digestPath))) {
38 HILOG_ERROR("file not exist");
39 return false;
40 }
41
42 const std::string signStr = GetfileStream(singPath);
43 const std::string digeststr = GetfileStream(digestPath);
44
45 BIO *bio = BIO_new_file(pubKeyPath.c_str(), "r");
46
47 RSA *pubKey = RSA_new();
48
49 if (PEM_read_bio_RSA_PUBKEY(bio, &pubKey, NULL, NULL) == NULL) {
50 HILOG_ERROR("get pubKey is failed");
51 BIO_free(bio);
52 RSA_free(pubKey);
53 return false;
54 }
55
56 bool verify = false;
57 if (!(pubKey == NULL || signStr.empty() || digeststr.empty())) {
58 verify = VerifyRsa(pubKey, digeststr, signStr);
59 } else {
60 HILOG_ERROR("param is null");
61 }
62 BIO_free(bio);
63 RSA_free(pubKey);
64 return verify;
65 }
66
VerifyRsa(RSA * pubKey,const std::string & digest,const std::string & sign)67 bool SignTools::VerifyRsa(RSA *pubKey, const std::string &digest, const std::string &sign)
68 {
69 EVP_PKEY *evpKey = NULL;
70 EVP_MD_CTX *ctx = NULL;
71 evpKey = EVP_PKEY_new();
72 if (evpKey == nullptr) {
73 HILOG_ERROR("evpKey is nullptr");
74 return false;
75 }
76 if (EVP_PKEY_set1_RSA(evpKey, pubKey) != 1) {
77 HILOG_ERROR("EVP_PKEY_set1_RSA fail");
78 EVP_PKEY_free(evpKey);
79 return false;
80 }
81 ctx = EVP_MD_CTX_new();
82 EVP_MD_CTX_init(ctx);
83 if (ctx == nullptr) {
84 HILOG_ERROR("ctx is nullptr");
85 EVP_PKEY_free(evpKey);
86 return false;
87 }
88 if (EVP_VerifyInit_ex(ctx, EVP_sha256(), NULL) != 1) {
89 HILOG_ERROR("EVP_VerifyInit_ex fail");
90 EVP_PKEY_free(evpKey);
91 EVP_MD_CTX_free(ctx);
92 return false;
93 }
94 if (EVP_VerifyUpdate(ctx, digest.c_str(), digest.size()) != 1) {
95 HILOG_ERROR("EVP_VerifyUpdate fail");
96 EVP_PKEY_free(evpKey);
97 EVP_MD_CTX_free(ctx);
98 return false;
99 }
100 if (EVP_VerifyFinal(ctx, (unsigned char *)sign.c_str(), sign.size(), evpKey) != 1) {
101 HILOG_ERROR("EVP_VerifyFinal fail)");
102 EVP_PKEY_free(evpKey);
103 EVP_MD_CTX_free(ctx);
104 return false;
105 }
106
107 EVP_PKEY_free(evpKey);
108 EVP_MD_CTX_free(ctx);
109 return true;
110 }
111
GetfileStream(const std::string & filepath)112 std::string SignTools::GetfileStream(const std::string &filepath)
113 {
114 std::string fileString;
115 char canonicalPath[PATH_MAX] = { '\0' };
116 if (realpath(filepath.c_str(), canonicalPath) == nullptr) {
117 HILOG_ERROR("canonicalPath is null");
118 return fileString;
119 }
120 canonicalPath[PATH_MAX - 1] = '\0';
121 std::ifstream file(canonicalPath, std::ios::in | std::ios::binary);
122 if (!file.good()) {
123 HILOG_ERROR("Failed to open the file!");
124 return fileString;
125 }
126 std::stringstream infile;
127 infile << file.rdbuf();
128 fileString = infile.str();
129 file.close();
130 return fileString;
131 }
132
133
CalcFileSha256Digest(const std::string & fpath)134 std::tuple<int, std::string> SignTools::CalcFileSha256Digest(const std::string &fpath)
135 {
136 auto res = std::make_unique<unsigned char[]>(SHA256_DIGEST_LENGTH);
137 SHA256_CTX ctx;
138 SHA256_Init(&ctx);
139 auto sha256Update = [ctx = &ctx](char *buf, size_t len) { SHA256_Update(ctx, buf, len); };
140 int err = ForEachFileSegment(fpath, sha256Update);
141 SHA256_Final(res.get(), &ctx);
142 if (err) {
143 return { err, "" };
144 }
145 std::string dist;
146 CalcBase64(res.get(), SHA256_DIGEST_LENGTH, dist);
147 return { err, dist };
148 };
149
ForEachFileSegment(const std::string & fpath,std::function<void (char *,size_t)> executor)150 int SignTools::ForEachFileSegment(const std::string &fpath, std::function<void(char *, size_t)> executor)
151 {
152 char canonicalPath[PATH_MAX] = { '\0' };
153 if (realpath(fpath.c_str(), canonicalPath) == nullptr) {
154 HILOG_ERROR("canonicalPath is null");
155 return errno;
156 }
157 canonicalPath[PATH_MAX - 1] = '\0';
158 std::unique_ptr<FILE, decltype(&fclose)> filp = { fopen(canonicalPath, "r"), fclose };
159 if (!filp) {
160 return errno;
161 }
162 const size_t pageSize { getpagesize() };
163 auto buf = std::make_unique<char[]>(pageSize);
164 size_t actLen;
165 do {
166 actLen = fread(buf.get(), 1, pageSize, filp.get());
167 if (actLen > 0) {
168 executor(buf.get(), actLen);
169 }
170 } while (actLen == pageSize);
171
172 return ferror(filp.get()) ? errno : 0;
173 }
174
CalcBase64(uint8_t * input,uint32_t inputLen,std::string & encodedStr)175 void SignTools::CalcBase64(uint8_t *input, uint32_t inputLen, std::string &encodedStr)
176 {
177 size_t expectedLength = 4 * ((inputLen + 2) / 3);
178 encodedStr.resize(expectedLength);
179 int actualLength = EVP_EncodeBlock(reinterpret_cast<uint8_t *>(&encodedStr[0]), input, inputLen);
180 encodedStr.resize(actualLength);
181 HILOG_INFO("expectedLength = %{public}zu, actualLength = %{public}d", expectedLength, actualLength);
182 }
183 } // namespace AppExecFwk
184 } // namespace OHOS