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 #include "sign_provider.h"
16 #include <openssl/pem.h>
17 #include <openssl/bio.h>
18 #include <openssl/x509.h>
19 #include <cstdio>
20 #include <cinttypes>
21 #include <algorithm>
22
23 #include "nlohmann/json.hpp"
24 #include "string_utils.h"
25 #include "file_utils.h"
26 #include "sign_elf.h"
27 #include "params.h"
28 #include "constant.h"
29
30 using namespace nlohmann;
31 namespace OHOS {
32 namespace SignatureTools {
33 std::vector<std::string> SignProvider::VALID_SIGN_ALG_NAME = {
34 ParamConstants::HAP_SIG_ALGORITHM_SHA256_ECDSA,
35 ParamConstants::HAP_SIG_ALGORITHM_SHA384_ECDSA,
36 ParamConstants::HAP_SIG_ALGORITHM_SHA512_ECDSA
37 };
38
InitSigerConfig(SignerConfig & signerConfig,STACK_OF (X509)* publicCerts,Options * options)39 bool SignProvider::InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options)
40 {
41 std::optional<X509_CRL*> crl = GetCrl();
42 if (!CreateSignerConfigs(publicCerts, crl, options, signerConfig)) {
43 SIGNATURE_TOOLS_LOGE("[Sign] create Signer Configs failed");
44 return false;
45 }
46 return true;
47 }
48
SignElf(Options * options)49 bool SignProvider::SignElf(Options* options)
50 {
51 // 1.check the parameters
52 if (!CheckParams(options)) {
53 SIGNATURE_TOOLS_LOGE("Check Params failed please check");
54 return false;
55 }
56 if (!CheckSignatureAlg()) {
57 SIGNATURE_TOOLS_LOGE("signAlg Parameter is not support");
58 return false;
59 }
60 STACK_OF(X509)* publicCerts = nullptr;
61 int ret = GetX509Certificates(options, &publicCerts);
62 if (ret != RET_OK) {
63 sk_X509_pop_free(publicCerts, X509_free);
64 SIGNATURE_TOOLS_LOGE("[SignElf] get X509 Certificates failed! errorCode:%d", ret);
65 return false;
66 }
67 SignerConfig signerConfig;
68 if (!InitSigerConfig(signerConfig, publicCerts, options)) {
69 SIGNATURE_TOOLS_LOGE("SignElf] create Signer Configs failed");
70 return false;
71 }
72
73 if (!profileContent.empty()) {
74 signParams.insert(std::make_pair(ParamConstants::PARAM_PROFILE_JSON_CONTENT, profileContent));
75 }
76 if (!SignElf::Sign(signerConfig, signParams)) {
77 SIGNATURE_TOOLS_LOGE("[SignElf] sign elf failed");
78 return false;
79 }
80
81 return true;
82 }
83
CreateSignerConfigs(STACK_OF (X509)* certificates,const std::optional<X509_CRL * > & crl,Options * options,SignerConfig & inOut)84 bool SignProvider::CreateSignerConfigs(STACK_OF(X509)* certificates, const std::optional<X509_CRL*>& crl,
85 Options* options, SignerConfig& inOut)
86 {
87 inOut.FillParameters(signParams);
88 inOut.SetCertificates(certificates);
89 inOut.SetOptions(options);
90 std::vector<SignatureAlgorithmHelper> signatureAlgorithms;
91 SignatureAlgorithmHelper alg;
92 // Since CheckParmaAndInitConfig has already validated all parameters, it is possible to directly use at
93 if (!Params::GetSignatureAlgorithm(signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG), alg)) {
94 SIGNATURE_TOOLS_LOGE("[Sign] get Signature Algorithm failed");
95 return false;
96 }
97 signatureAlgorithms.push_back(alg);
98 inOut.SetSignatureAlgorithms(signatureAlgorithms);
99 if (crl.has_value()) {
100 SIGNATURE_TOOLS_LOGE("not support crl");
101 return false;
102 }
103 return true;
104 }
105
GetCrl()106 std::optional<X509_CRL*> SignProvider::GetCrl()
107 {
108 return std::nullopt;
109 }
110
GetX509Certificates(Options * options,STACK_OF (X509)** X509Vec)111 int SignProvider::GetX509Certificates(Options* options, STACK_OF(X509)** X509Vec)
112 {
113 int ret = RET_OK;
114 // 2.get x509 verify certificate
115 ret = GetPublicCerts(options, X509Vec);
116 if (ret != RET_OK) {
117 SIGNATURE_TOOLS_LOGE("Get Public Certs please check");
118 return ret;
119 }
120 std::string profileFile = options->GetString(Options::PROFILE_FILE);
121 if (FileUtils::IsEmpty(profileFile)) {
122 return ret;
123 }
124 // 3. check Profile Valid
125 if ((ret = CheckProfileValid(*X509Vec, profileFile)) < 0) {
126 SIGNATURE_TOOLS_LOGE("profile check error");
127 sk_X509_pop_free(*X509Vec, X509_free);
128 *X509Vec = nullptr;
129 return ret;
130 }
131 return ret;
132 }
133
GetPublicCerts(Options * options,STACK_OF (X509)** ret)134 int SignProvider::GetPublicCerts(Options* options, STACK_OF(X509)** ret)
135 {
136 std::string appCertFileName = options->GetString(Options::APP_CERT_FILE);
137 if (appCertFileName.empty()) {
138 SIGNATURE_TOOLS_LOGI("appCertFile param can not find,may be is RemoteSigner");
139 return RET_OK;
140 }
141 return GetCertificateChainFromFile(appCertFileName, ret);
142 }
143
GetCertificateChainFromFile(const std::string & certChianFile,STACK_OF (X509)** ret)144 int SignProvider::GetCertificateChainFromFile(const std::string& certChianFile, STACK_OF(X509)** ret)
145 {
146 return GetCertListFromFile(certChianFile, ret);
147 }
148
GetCertListFromFile(const std::string & certsFile,STACK_OF (X509)** ret)149 int SignProvider::GetCertListFromFile(const std::string& certsFile, STACK_OF(X509)** ret)
150 {
151 X509* cert = nullptr;
152 *ret = sk_X509_new(nullptr);
153 if (*ret == nullptr) {
154 PrintErrorNumberMsg("RET_FAILED", RET_FAILED, "get CertList FromFile [sk_X509_new] failed");
155 return RET_FAILED;
156 }
157 BIO* certBio = BIO_new_file(certsFile.c_str(), "rb");
158 if (!certBio) {
159 PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
160 std::string("get CertList from file ") + certsFile + " failed");
161 sk_X509_free(*ret);
162 return IO_ERROR;
163 }
164 while (1) {
165 cert = PEM_read_bio_X509(certBio, NULL, NULL, NULL);
166 if (cert == nullptr)
167 break;
168 sk_X509_push(*ret, cert);
169 }
170 BIO_free(certBio);
171 return RET_OK;
172 }
173
SetSignParams(Options * options,std::unordered_set<std::string> & paramSet)174 bool SignProvider::SetSignParams(Options* options, std::unordered_set<std::string>& paramSet)
175 {
176 for (auto it = options->begin(); it != options->end(); it++) {
177 if (paramSet.find(it->first) != paramSet.end()) {
178 size_t size = it->first.size();
179 std::string str = it->first.substr(size - 3);
180 if (str != "Pwd") {
181 this->signParams.insert(std::make_pair(it->first, options->GetString(it->first)));
182 }
183 }
184 }
185 return true;
186 }
187
CheckParams(Options * options)188 bool SignProvider::CheckParams(Options* options)
189 {
190 std::vector<std::string> paramFileds;
191 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_ALIGNMENT);
192 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_SIGANTURE_ALG);
193 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_INPUT_FILE);
194 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_OUTPUT_FILE);
195 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PRIVATE_KEY);
196 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROFILE);
197 paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_SERVER);
198 paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
199 paramFileds.emplace_back(ParamConstants::PARAM_LOCAL_PUBLIC_CERT);
200 paramFileds.emplace_back(ParamConstants::PARAM_SIGN_CODE);
201 paramFileds.emplace_back(ParamConstants::PARAM_MODULE_FILE);
202 paramFileds.emplace_back(ParamConstants::PARAM_SELF_SIGN);
203
204 std::unordered_set<std::string> paramSet = Params::InitParamField(paramFileds);
205 for (auto it = options->begin(); it != options->end(); it++) {
206 if (paramSet.find(it->first) != paramSet.end()) {
207 signParams.insert(std::make_pair(it->first, options->GetString(it->first)));
208 }
209 }
210
211 if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE_SIGNED) == signParams.end()
212 || signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED).empty()) {
213 signParams[ParamConstants::PARAM_BASIC_PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1;
214 }
215 if (signParams.find(ParamConstants::PARAM_SELF_SIGN) == signParams.end()
216 || signParams.at(ParamConstants::PARAM_SELF_SIGN).empty()) {
217 signParams[ParamConstants::PARAM_SELF_SIGN] = ParamConstants::SELF_SIGN_TYPE_0;
218 }
219 return true;
220 }
221
CheckSignatureAlg()222 bool SignProvider::CheckSignatureAlg()
223 {
224 std::string signAlg = signParams[ParamConstants::PARAM_BASIC_SIGANTURE_ALG];
225 // Remove leading spaces
226 size_t start = signAlg.find_first_not_of(" ");
227 if (start != std::string::npos) {
228 signAlg = signAlg.substr(start);
229 }
230 // Remove trailing spaces
231 size_t end = signAlg.find_last_not_of(" ");
232 if (end != std::string::npos) {
233 signAlg.resize(end + 1);
234 }
235 for (auto it = VALID_SIGN_ALG_NAME.begin(); it != VALID_SIGN_ALG_NAME.end(); it++) {
236 if (StringUtils::CaseCompare(*it, signAlg)) {
237 return true;
238 }
239 }
240 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
241 "signAlg Parameter is only support [SHA256withECDSA / SHA384withECDSA]");
242 return false;
243 }
244
CheckSignAlignment()245 void SignProvider::CheckSignAlignment()
246 {
247 if (signParams.find(ParamConstants::PARAM_BASIC_ALIGNMENT) == signParams.end()) {
248 signParams.insert(std::make_pair(ParamConstants::PARAM_BASIC_ALIGNMENT, ParamConstants::ALIGNMENT));
249 }
250 }
251
GetCertificate(const std::string & certificate) const252 X509* SignProvider::GetCertificate(const std::string& certificate)const
253 {
254 BIO* in = BIO_new_mem_buf(certificate.data(), certificate.size());
255 if (!in) {
256 PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR,
257 "bio new error ,get ceritificate from base64 certificate failed");
258 return NULL;
259 }
260 X509* cert = NULL;
261 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
262 if (!cert) {
263 BIO_free(in);
264 PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR,
265 "read no cert from base64 certificate failed");
266 return NULL;
267 }
268 BIO_free(in);
269 return cert;
270 }
271
GetCertificateCN(X509 * cert) const272 std::string SignProvider::GetCertificateCN(X509* cert)const
273 {
274 X509_NAME* name = NULL;
275 int len = 0;
276 std::string ret;
277 if (cert == NULL) {
278 return "";
279 }
280 name = X509_get_subject_name(cert);
281 if (!name) {
282 SIGNATURE_TOOLS_LOGE("name is NULL,get X509_NAME from cert failed");
283 }
284 len = X509_NAME_get_text_by_NID(name, NID_countryName, NULL, 0);
285 if (len <= 0) {
286 return "";
287 }
288 ret.resize(len + 1);
289 if (X509_NAME_get_text_by_NID(name, NID_countryName, &ret[0], len + 1) != len) {
290 return "";
291 }
292 return ret;
293 }
294
CheckProfileValid(STACK_OF (X509)* inputCerts,const std::string & file)295 int SignProvider::CheckProfileValid(STACK_OF(X509)* inputCerts, const std::string& file)
296 {
297 std::string profile;
298 if (FileUtils::ReadFile(file, profile) < 0) {
299 SIGNATURE_TOOLS_LOGE("profile read faild!");
300 return IO_ERROR;
301 }
302 std::map<std::string, std::string>::const_iterator ite =
303 signParams.find(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
304 if (ite == signParams.end()) {
305 PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
306 "find PARAM_BASIC_PROFILE_SIGNED failed");
307 return INVALIDPARAM_ERROR;
308 }
309 bool isProfileWithoutSign = (DEFAULT_PROFILE_SIGNED_0 == ite->second);
310 if (!isProfileWithoutSign) {
311 PKCS7Data p7Data;
312 if (p7Data.Parse(profile) < 0) {
313 SIGNATURE_TOOLS_LOGE("Parse profile error.");
314 return PARSE_ERROR;
315 }
316 if (p7Data.Verify() < 0) {
317 SIGNATURE_TOOLS_LOGE("Verify profile pkcs7 failed! Profile is invalid.");
318 return VERIFY_ERROR;
319 }
320 profileContent.clear();
321 if (p7Data.GetContent(profileContent) < 0) {
322 SIGNATURE_TOOLS_LOGE("get content data failed");
323 return INVALIDPARAM_ERROR;
324 }
325 } else {
326 profileContent = profile;
327 }
328
329 ProfileInfo info;
330 if (ParseProvision(profileContent, info) != PROVISION_OK) {
331 SIGNATURE_TOOLS_LOGE("parse provision error");
332 return PARSE_ERROR;
333 }
334 if (CheckProfileInfo(info, inputCerts) < 0) {
335 SIGNATURE_TOOLS_LOGE("Check Profile Info error");
336 return RET_FAILED;
337 }
338 return 0;
339 }
340
CheckProfileInfo(const ProfileInfo & info,STACK_OF (X509)* inputCerts) const341 int SignProvider::CheckProfileInfo(const ProfileInfo& info, STACK_OF(X509)* inputCerts)const
342 {
343 X509* certInProfile = NULL;
344 if (info.type == ProvisionType::RELEASE) {
345 certInProfile = GetCertificate(info.bundleInfo.distributionCertificate);
346 } else if (info.type == ProvisionType::DEBUG) {
347 certInProfile = GetCertificate(info.bundleInfo.developmentCertificate);
348 } else {
349 PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "Unsupported profile type!");
350 return NOT_SUPPORT_ERROR;
351 }
352 if (sk_X509_num(inputCerts) > 0 && !CheckInputCertMatchWithProfile(sk_X509_value(inputCerts, 0),
353 certInProfile)) {
354 X509_free(certInProfile);
355 SIGNATURE_TOOLS_LOGE("input certificates do not match with profile!");
356 return RET_FAILED;
357 }
358 std::string cn = GetCertificateCN(certInProfile);
359 X509_free(certInProfile);
360 SIGNATURE_TOOLS_LOGI("certificate in profile: %s", cn.c_str());
361 if (cn.empty()) {
362 PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "Common name of certificate is empty!");
363 return CERTIFICATE_ERROR;
364 }
365 return 0;
366 }
367
CheckInputCertMatchWithProfile(X509 * inputCert,X509 * certInProfile) const368 bool SignProvider::CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile)const
369 {
370 return true;
371 }
372 } // namespace SignatureTools
373 } // namespace OHOS