• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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