1 /*
2  * Copyright (c) 2024-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 #include "sign_provider.h"
16 
17 #include <openssl/pem.h>
18 #include <openssl/bio.h>
19 #include <openssl/x509.h>
20 #include <cstdio>
21 #include <cinttypes>
22 #include <filesystem>
23 #include <algorithm>
24 
25 #include "nlohmann/json.hpp"
26 #include "string_utils.h"
27 #include "file_utils.h"
28 #include "sign_elf.h"
29 #include "sign_bin.h"
30 #include "params.h"
31 #include "constant.h"
32 
33 using namespace nlohmann;
34 namespace OHOS {
35 namespace SignatureTools {
36 std::vector<std::string> SignProvider::VALID_SIGN_ALG_NAME = {
37     ParamConstants::HAP_SIG_ALGORITHM_SHA256_ECDSA,
38     ParamConstants::HAP_SIG_ALGORITHM_SHA384_ECDSA,
39     ParamConstants::HAP_SIG_ALGORITHM_SHA512_ECDSA
40 };
41 
PrintErrorLog(const std::string& log, const int& errorCode, std::string path)42 bool SignProvider::PrintErrorLog(const std::string& log, const int& errorCode, std::string path)
43 {
44     SIGNATURE_TOOLS_LOGE("%s", std::string("(Error Code: " + std::to_string(errorCode) + ")" + log).c_str());
45     if (path != "") {
46         remove(path.c_str());
47     }
48     return false;
49 }
50 
InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options)51 bool SignProvider::InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options)
52 {
53     std::optional<X509_CRL*> crl = GetCrl();
54     if (!CreateSignerConfigs(publicCerts, crl, options, signerConfig)) {
55         SIGNATURE_TOOLS_LOGE("[SignHap] create Signer Configs failed");
56         return false;
57     }
58     int CompatibleVersion;
59     if (!StringUtils::CheckStringToint(signParams.at(ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION),
60         CompatibleVersion)) {
61         SIGNATURE_TOOLS_LOGE("[SignHap] CompatibleVersion String To int failed");
62         return false;
63     }
64     signerConfig.SetCompatibleVersion(CompatibleVersion);
65     return true;
66 }
67 
CheckParmaAndInitConfig(SignerConfig& signerConfig, Options* options, std::string& suffix)68 int SignProvider::CheckParmaAndInitConfig(SignerConfig& signerConfig, Options* options, std::string& suffix)
69 {
70     STACK_OF(X509)* publicCerts = nullptr;
71     int ret = GetX509Certificates(options, &publicCerts);
72     if (ret != RET_OK) {
73         sk_X509_pop_free(publicCerts, X509_free);
74         SIGNATURE_TOOLS_LOGE("SIGNHAP_ERROR get X509 Certificates failed");
75         return ret;
76     }
77     if (!CheckCompatibleVersion()) {
78         sk_X509_pop_free(publicCerts, X509_free);
79         SIGNATURE_TOOLS_LOGE("check Compatible Version failed!!");
80         return COMMAND_PARAM_ERROR;
81     }
82     if (!InitSigerConfig(signerConfig, publicCerts, options)) {
83         SIGNATURE_TOOLS_LOGE("create Signer Configs failed");
84         return COMMAND_PARAM_ERROR;
85     }
86     std::string inputFilePath = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
87     suffix = FileUtils::GetSuffix(inputFilePath);
88     if (suffix == "") {
89         SIGNATURE_TOOLS_LOGE("hap format error pleass check!!");
90         return COMMAND_PARAM_ERROR;
91     }
92     return RET_OK;
93 }
94 
PrepareIOStreams(const std::string& inputPath, const std::string& outputPath, bool& ret)95 fileIOTuple SignProvider::PrepareIOStreams(const std::string& inputPath,
96                                            const std::string& outputPath, bool& ret)
97 {
98     std::shared_ptr<std::ifstream> inputFile = nullptr;
99     std::shared_ptr<std::ofstream> outputFile = nullptr;
100     std::string tmpOutputFilePath;
101     ret = false;
102     inputFile = std::make_shared<std::ifstream>(inputPath, std::ios::binary);
103     if (!inputFile->good()) {
104         PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
105                             inputPath + " open failed");
106         return {nullptr, nullptr, ""};
107     }
108     if (inputPath == outputPath) {
109         std::filesystem::path filePath = outputPath;
110         std::filesystem::path directory = filePath.parent_path();
111         std::string strDirectory = directory;
112         tmpOutputFilePath = strDirectory + '/' + std::string("signedHap") + "." + "hap";
113         outputFile = std::make_shared<std::ofstream>(tmpOutputFilePath, std::ios::binary | std::ios::trunc);
114         if (!outputFile->good()) {
115             PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
116                                 tmpOutputFilePath + " open failed");
117             return {nullptr, nullptr, ""};
118         }
119         ret = true;
120     } else {
121         outputFile = std::make_shared<std::ofstream>(outputPath, std::ios::binary | std::ios::trunc);
122         if (!outputFile->good()) {
123             PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
124                                 outputPath + " open failed");
125             return {nullptr, nullptr, ""};
126         }
127         tmpOutputFilePath = outputPath;
128     }
129     return {inputFile, outputFile, tmpOutputFilePath};
130 }
131 
InitZipOutput(std::shared_ptr<RandomAccessFile> outputHap, std::shared_ptr<ZipSigner> zip, std::shared_ptr<std::ifstream> inputStream, std::shared_ptr<std::ofstream>tmpOutput, const std::string& Path)132 bool SignProvider::InitZipOutput(std::shared_ptr<RandomAccessFile> outputHap,
133                                  std::shared_ptr<ZipSigner> zip,
134                                  std::shared_ptr<std::ifstream> inputStream,
135                                  std::shared_ptr<std::ofstream>tmpOutput,
136                                  const std::string& Path)
137 {
138     int alignment;
139     if (!StringUtils::CheckStringToint(signParams.at(ParamConstants::PARAM_BASIC_ALIGNMENT), alignment)) {
140         SIGNATURE_TOOLS_LOGE("[signHap] alignment String To int failed");
141         inputStream->close();
142         tmpOutput->close();
143         remove(Path.c_str());
144         return false;
145     }
146 
147     if (!CopyFileAndAlignment(*inputStream, *tmpOutput, alignment, *zip)) {
148         SIGNATURE_TOOLS_LOGE("[signHap] copy File And Alignment failed");
149         inputStream->close();
150         tmpOutput->close();
151         remove(Path.c_str());
152         return false;
153     }
154 
155     inputStream->close();
156     tmpOutput->flush();
157     tmpOutput->close();
158     if (!outputHap->Init(Path)) {
159         SIGNATURE_TOOLS_LOGE("[signHap] init outputFile failed %s", Path.c_str());
160         remove(Path.c_str());
161         return false;
162     }
163     return true;
164 }
165 
InitDataSourceContents(RandomAccessFile& outputHap, DataSourceContents& dataSrcContents)166 bool SignProvider::InitDataSourceContents(RandomAccessFile& outputHap, DataSourceContents& dataSrcContents)
167 {
168     std::shared_ptr<ZipDataInput> outputHapIn = std::make_shared<RandomAccessFileInput>(outputHap);
169     // get eocd bytebuffer and eocd offset
170     if (!HapSignerBlockUtils::FindEocdInHap(outputHap, dataSrcContents.eocdPair)) {
171         PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "eocd is not found in hap");
172         return false;
173     }
174     dataSrcContents.endOfCentralDir = new ByteBufferDataSource(dataSrcContents.eocdPair.first);
175     if (!dataSrcContents.endOfCentralDir) {
176         return false;
177     }
178 
179     // get cd offset
180     if (!HapSignerBlockUtils::GetCentralDirectoryOffset(dataSrcContents.eocdPair.first,
181                                                         dataSrcContents.eocdPair.second, dataSrcContents.cDOffset)) {
182         PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "get central directory offset failed");
183         return false;
184     }
185 
186     SIGNATURE_TOOLS_LOGI("Central Directory Offset is %" PRId64, dataSrcContents.cDOffset);
187 
188     // get beforeCentralDir
189     dataSrcContents.beforeCentralDir = outputHapIn->Slice(0, dataSrcContents.cDOffset);
190     if (!dataSrcContents.beforeCentralDir) {
191         return false;
192     }
193 
194     // get cd size
195     long cDSize;
196     if (!HapSignerBlockUtils::GetCentralDirectorySize(dataSrcContents.eocdPair.first, cDSize)) {
197         PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "get central directory size failed");
198         return false;
199     }
200 
201     // get cd buffer
202     dataSrcContents.cDByteBuffer = outputHapIn->CreateByteBuffer(dataSrcContents.cDOffset, cDSize);
203     if (dataSrcContents.cDByteBuffer.GetCapacity() == 0) {
204         return false;
205     }
206     dataSrcContents.centralDir = new ByteBufferDataSource(dataSrcContents.cDByteBuffer);
207     if (!dataSrcContents.centralDir) {
208         return false;
209     }
210     return true;
211 }
212 
Sign(Options* options)213 bool SignProvider::Sign(Options* options)
214 {
215     bool isPathOverlap = false;
216     SignerConfig signerConfig;
217     std::string suffix;
218     if (CheckParmaAndInitConfig(signerConfig, options, suffix) != RET_OK) {
219         return PrintErrorLog("Check Parma And Init Config failed", COMMAND_PARAM_ERROR);
220     }
221     // Since CheckParmaAndInitConfig has already validated all parameters, it is possible to directly use at
222     std::string inputFilePath = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
223     auto [inputStream, tmpOutput, tmpOutputFilePath] = PrepareIOStreams(
224         inputFilePath,
225         signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE), isPathOverlap);
226 
227     if (!inputStream || !tmpOutput) {
228         return PrintErrorLog("[signHap] Prepare IO Streams failed", IO_ERROR);
229     }
230 
231     std::shared_ptr<ZipSigner> zip = std::make_shared<ZipSigner>();
232     std::shared_ptr<RandomAccessFile> outputHap = std::make_shared<RandomAccessFile>();
233     if (!InitZipOutput(outputHap, zip, inputStream, tmpOutput, tmpOutputFilePath)) {
234         return PrintErrorLog("[signHap] Init Zip Output failed", IO_ERROR);
235     }
236 
237     DataSourceContents dataSrcContents;
238     if (!InitDataSourceContents(*outputHap, dataSrcContents)) {
239         return PrintErrorLog("[signHap] Init Data Source Contents failed", ZIP_ERROR, tmpOutputFilePath);
240     }
241 
242     DataSource* contents[] = {dataSrcContents.beforeCentralDir,
243         dataSrcContents.centralDir, dataSrcContents.endOfCentralDir
244     };
245     if (!AppendCodeSignBlock(&signerConfig, tmpOutputFilePath, suffix, dataSrcContents.cDOffset, *zip)) {
246         return PrintErrorLog("[SignCode] AppendCodeSignBlock failed", SIGN_ERROR, tmpOutputFilePath);
247     }
248 
249     ByteBuffer signingBlock;
250     if (!SignHap::Sign(contents, sizeof(contents) / sizeof(contents[0]), signerConfig, optionalBlocks,
251                        signingBlock)) {
252         return PrintErrorLog("[SignHap] SignHap Sign failed.", SIGN_ERROR, tmpOutputFilePath);
253     }
254 
255     int64_t newCentralDirectoryOffset = dataSrcContents.cDOffset + signingBlock.GetCapacity();
256     SIGNATURE_TOOLS_LOGI("new Central Directory Offset is %" PRId64, newCentralDirectoryOffset);
257     dataSrcContents.eocdPair.first.SetPosition(0);
258     if (!ZipUtils::SetCentralDirectoryOffset(dataSrcContents.eocdPair.first, newCentralDirectoryOffset)) {
259         return PrintErrorLog("[SignHap] Set Central Directory Offset.", ZIP_ERROR, tmpOutputFilePath);
260     }
261 
262     if (!OutputSignedFile(outputHap.get(), dataSrcContents.cDOffset, signingBlock, dataSrcContents.centralDir,
263                           dataSrcContents.eocdPair.first)) {
264         return PrintErrorLog("[SignHap] write output signed file failed.", ZIP_ERROR, tmpOutputFilePath);
265     }
266     return DoAfterSign(isPathOverlap, tmpOutputFilePath, inputFilePath);
267 }
268 
SignElf(Options* options)269 bool SignProvider::SignElf(Options* options)
270 {
271     bool isPathOverlap = false;
272     STACK_OF(X509)* publicCerts = nullptr;
273     int ret = GetX509Certificates(options, &publicCerts);
274     if (ret != RET_OK) {
275         sk_X509_pop_free(publicCerts, X509_free);
276         SIGNATURE_TOOLS_LOGE("[SignElf] get X509 Certificates failed! errorCode:%d", ret);
277         return false;
278     }
279     if (!CheckCompatibleVersion()) {
280         sk_X509_pop_free(publicCerts, X509_free);
281         SIGNATURE_TOOLS_LOGE("[SignElf] check Compatible Version failed!!");
282         return false;
283     }
284 
285     std::string inputFilePath = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
286 
287     auto [inputStream, tmpOutput, tmpOutputFilePath] =
288         PrepareIOStreams(inputFilePath,
289                          signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE),
290                          isPathOverlap);
291 
292     if (!inputStream || !tmpOutput) {
293         sk_X509_pop_free(publicCerts, X509_free);
294         SIGNATURE_TOOLS_LOGE("[signElf] Prepare IO Streams failed");
295         return false;
296     }
297 
298     SignerConfig signerConfig;
299     if (!InitSigerConfig(signerConfig, publicCerts, options)) {
300         SIGNATURE_TOOLS_LOGE("SignElf] create Signer Configs failed");
301         return false;
302     }
303 
304     if (!profileContent.empty()) {
305         signParams.insert(std::make_pair(ParamConstants::PARAM_PROFILE_JSON_CONTENT, profileContent));
306     }
307 
308     if (!SignElf::Sign(signerConfig, signParams)) {
309         SIGNATURE_TOOLS_LOGE("[SignElf] sign elf failed");
310         return false;
311     }
312 
313     return true;
314 }
315 
SignBin(Options* options)316 bool SignProvider::SignBin(Options* options)
317 {
318     STACK_OF(X509)* x509Certificates = nullptr;
319     int ret = GetX509Certificates(options, &x509Certificates);
320     if (ret != RET_OK) {
321         sk_X509_pop_free(x509Certificates, X509_free);
322         SIGNATURE_TOOLS_LOGE("[SignBin] get X509 Certificates failed! errorCode:%d", ret);
323         return false;
324     }
325     if (!CheckCompatibleVersion()) {
326         sk_X509_pop_free(x509Certificates, X509_free);
327         SIGNATURE_TOOLS_LOGE("check Compatible Version failed!");
328         return false;
329     }
330 
331     SignerConfig signerConfig;
332     if (!InitSigerConfig(signerConfig, x509Certificates, options)) {
333         SIGNATURE_TOOLS_LOGE("[SignBin] create Signer Configs failed");
334         return false;
335     }
336 
337     bool signFlag = SignBin::Sign(signerConfig, signParams);
338     if (!signFlag) {
339         SIGNATURE_TOOLS_LOGE("sign bin internal failed");
340         return false;
341     }
342 
343     SIGNATURE_TOOLS_LOGI("sign bin success");
344     return true;
345 }
346 
AppendCodeSignBlock(SignerConfig* signerConfig, std::string outputFilePath, const std::string& suffix, int64_t centralDirectoryOffset, ZipSigner& zip)347 bool SignProvider::AppendCodeSignBlock(SignerConfig* signerConfig, std::string outputFilePath,
348                                        const std::string& suffix, int64_t centralDirectoryOffset, ZipSigner& zip)
349 {
350     if (signParams.at(ParamConstants::PARAM_SIGN_CODE) == CodeSigning::ENABLE_SIGN_CODE_VALUE) {
351         SIGNATURE_TOOLS_LOGI("start code signing.");
352         std::string suffixTmp = suffix;
353         std::transform(suffixTmp.begin(), suffixTmp.end(), suffixTmp.begin(), ::tolower);
354         if (std::find(CodeSigning::SUPPORT_FILE_FORM.begin(), CodeSigning::SUPPORT_FILE_FORM.end(),
355                       suffixTmp) == CodeSigning::SUPPORT_FILE_FORM.end()) {
356             SIGNATURE_TOOLS_LOGI("no need to sign code for %s", suffixTmp.c_str());
357             return true;
358         }
359         // 4 means hap format occupy 4 byte storage location,2 means optional blocks reserve 2 storage location
360         int64_t codeSignOffset = centralDirectoryOffset + ((4 + 4 + 4) * (optionalBlocks.size() + 2 + 1));
361         // create CodeSigning Object
362         CodeSigning codeSigning(signerConfig);
363         std::vector<int8_t> codeSignArray;
364         if (!codeSigning.GetCodeSignBlock(outputFilePath, codeSignOffset, suffixTmp, profileContent, zip,
365                                           codeSignArray)) {
366             SIGNATURE_TOOLS_LOGE("Codesigning getCodeSignBlock Fail.");
367             return false;
368         }
369         SIGNATURE_TOOLS_LOGI("generate codeSignArray finished.");
370         std::unique_ptr<ByteBuffer> result =
371             std::make_unique<ByteBuffer>(codeSignArray.size()
372                                          + (FOUR_BYTE + FOUR_BYTE + FOUR_BYTE));
373         result->PutInt32(HapUtils::HAP_CODE_SIGN_BLOCK_ID);
374         result->PutInt32(codeSignArray.size()); // length
375         result->PutInt32((int32_t)codeSignOffset); // offset
376         result->PutData(codeSignArray.data(), codeSignArray.size());
377 
378         OptionalBlock tmp = {HapUtils::HAP_PROPERTY_BLOCK_ID, *result};
379         optionalBlocks.insert(optionalBlocks.begin(), tmp);
380     }
381     return true;
382 }
383 
384 bool SignProvider::CreateSignerConfigs(STACK_OF(X509)* certificates, const std::optional<X509_CRL*>& crl,
385                                        Options* options, SignerConfig& inOut)
386 {
387     inOut.FillParameters(signParams);
388     inOut.SetCertificates(certificates);
389     inOut.SetOptions(options);
390     std::vector<SignatureAlgorithmHelper> signatureAlgorithms;
391     SignatureAlgorithmHelper alg;
392     // Since CheckParmaAndInitConfig has already validated all parameters, it is possible to directly use at
393     if (!Params::GetSignatureAlgorithm(signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG),
394                                        alg)) {
395         SIGNATURE_TOOLS_LOGE("[SignHap] get Signature Algorithm failed");
396         return false;
397     }
398     signatureAlgorithms.push_back(alg);
399     inOut.SetSignatureAlgorithms(signatureAlgorithms);
400     if (crl.has_value()) {
401         SIGNATURE_TOOLS_LOGE("not support crl");
402         return false;
403     }
404     return true;
405 }
406 
LoadOptionalBlocks()407 int SignProvider::LoadOptionalBlocks()
408 {
409     int ret = RET_OK;
410     if (auto property = signParams.find(ParamConstants::PARAM_BASIC_PROPERTY);
411         property != signParams.end()) {
412         if ((ret = LoadOptionalBlock(property->second, HapUtils::HAP_PROPERTY_BLOCK_ID)) != RET_OK)
413             return ret;
414     }
415     if (auto profile = signParams.find(ParamConstants::PARAM_BASIC_PROFILE); profile != signParams.end()) {
416         if ((ret = LoadOptionalBlock(profile->second, HapUtils::HAP_PROFILE_BLOCK_ID)) != RET_OK)
417             return ret;
418     }
419     if (auto proofOfRotation = signParams.find(ParamConstants::PARAM_BASIC_PROOF);
420         proofOfRotation != signParams.end()) {
421         if ((LoadOptionalBlock(proofOfRotation->second, HapUtils::HAP_PROOF_OF_ROTATION_BLOCK_ID)) != RET_OK)
422             return ret;
423     }
424     return ret;
425 }
426 
LoadOptionalBlock(const std::string& file, int type)427 int SignProvider::LoadOptionalBlock(const std::string& file, int type)
428 {
429     if (file.empty())
430         return RET_OK;
431     if (!CheckFile(file)) {
432         SIGNATURE_TOOLS_LOGE("check file failed. Invalid file: %s, file type: %d",
433                              file.c_str(), type);
434         return FILE_NOT_FOUND;
435     }
436     ByteBuffer optionalBlockBuffer;
437     if (!HapUtils::ReadFileToByteBuffer(file, optionalBlockBuffer))
438         return IO_ERROR;
439     if (optionalBlockBuffer.GetCapacity() == 0) {
440         PrintErrorNumberMsg("IO_ERROR", IO_ERROR, file + " is empty!");
441         return IO_ERROR;
442     }
443     optionalBlocks.push_back({type, optionalBlockBuffer});
444     return RET_OK;
445 }
446 
GetCrl()447 std::optional<X509_CRL*> SignProvider::GetCrl()
448 {
449     return std::nullopt;
450 }
451 
CheckFile(const std::string& filePath)452 bool SignProvider::CheckFile(const std::string& filePath)
453 {
454     if (filePath.empty()) {
455         PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "file name is null.");
456         return false;
457     }
458     if (!std::filesystem::exists(filePath) || !std::filesystem::is_regular_file(filePath)) {
459         PrintErrorNumberMsg("IO_ERROR", IO_ERROR, filePath + " not exist or can not read!");
460         return false;
461     }
462     return true;
463 }
464 
GetX509Certificates(Options* options, STACK_OF(X509)** X509Vec)465 int SignProvider::GetX509Certificates(Options* options, STACK_OF(X509)** X509Vec)
466 {
467     int ret = RET_OK;
468     // 1.check the parameters
469     if (!CheckParams(options)) {
470         SIGNATURE_TOOLS_LOGE("Check Params failed please check");
471         return COMMAND_ERROR;
472     }
473     // 2.get x509 verify certificate
474     ret = GetPublicCerts(options, X509Vec);
475     if (ret != RET_OK) {
476         SIGNATURE_TOOLS_LOGE("Get Public Certs please check");
477         return ret;
478     }
479     // 3. load optionalBlocks
480     ret = LoadOptionalBlocks();
481     if (ret != RET_OK) {
482         SIGNATURE_TOOLS_LOGE("Load Optional Blocks please check");
483         return ret;
484     }
485     std::string inForm = options->GetString(Options::INFORM);
486     std::string profileFile = options->GetString(Options::PROFILE_FILE);
487     if (StringUtils::CaseCompare(inForm, ELF) && FileUtils::IsEmpty(profileFile)) {
488         return ret;
489     }
490     // 4. check Profile Valid
491     if ((ret = CheckProfileValid(*X509Vec)) < 0) {
492         SIGNATURE_TOOLS_LOGE("profile check error");
493         sk_X509_pop_free(*X509Vec, X509_free);
494         *X509Vec = nullptr;
495         return ret;
496     }
497     return ret;
498 }
499 
GetPublicCerts(Options* options, STACK_OF(X509)** ret)500 int SignProvider::GetPublicCerts(Options* options, STACK_OF(X509)** ret)
501 {
502     std::string appCertFileName = options->GetString(Options::APP_CERT_FILE);
503     if (appCertFileName.empty()) {
504         SIGNATURE_TOOLS_LOGI("appCertFile param can not find,may be is RemoteSigner");
505         return RET_OK;
506     }
507     return GetCertificateChainFromFile(appCertFileName, ret);
508 }
509 
GetCertificateChainFromFile(const std::string& certChianFile, STACK_OF(X509)** ret)510 int SignProvider::GetCertificateChainFromFile(const std::string& certChianFile, STACK_OF(X509)** ret)
511 {
512     return GetCertListFromFile(certChianFile, ret);
513 }
514 
GetCertListFromFile(const std::string& certsFile, STACK_OF(X509)** ret)515 int SignProvider::GetCertListFromFile(const std::string& certsFile, STACK_OF(X509)** ret)
516 {
517     X509* cert = nullptr;
518     *ret = sk_X509_new(nullptr);
519     if (*ret == nullptr) {
520         PrintErrorNumberMsg("RET_FAILED", RET_FAILED, "get CertList FromFile [sk_X509_new] failed");
521         return RET_FAILED;
522     }
523     BIO* certBio = BIO_new_file(certsFile.c_str(), "rb");
524     if (!certBio) {
525         PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
526                             std::string("get CertList from file ") + certsFile + " failed");
527         sk_X509_free(*ret);
528         return IO_ERROR;
529     }
530     while (1) {
531         cert = PEM_read_bio_X509(certBio, NULL, NULL, NULL);
532         if (cert == nullptr)
533             break;
534         sk_X509_push(*ret, cert);
535     }
536     BIO_free(certBio);
537     return RET_OK;
538 }
539 
DoAfterSign(bool isPathOverlap, const std::string& tmpOutputFile, const std::string& inputFilePath)540 bool SignProvider::DoAfterSign(bool isPathOverlap, const std::string& tmpOutputFile, const std::string& inputFilePath)
541 {
542     if (isPathOverlap) {
543         remove(inputFilePath.c_str());
544         if (rename(tmpOutputFile.c_str(), inputFilePath.c_str()) != 0) {
545             PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
546                                 "File name " + tmpOutputFile + " rename to " + inputFilePath + " failed!");
547             return false;
548         }
549     }
550     return true;
551 }
552 
CopyFileAndAlignment(std::ifstream& input, std::ofstream& tmpOutput, int alignment, ZipSigner& zip)553 bool SignProvider::CopyFileAndAlignment(std::ifstream& input, std::ofstream& tmpOutput, int alignment, ZipSigner& zip)
554 {
555     if (!zip.Init(input)) {
556         PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "zip init failed");
557         return false;
558     }
559     zip.Alignment(alignment);
560     zip.RemoveSignBlock();
561     if (!zip.ToFile(input, tmpOutput)) {
562         PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "zip write to file failed");
563         return false;
564     }
565     return true;
566 }
567 
SetSignParams(Options* options, std::unordered_set<std::string>& paramSet)568 bool SignProvider::SetSignParams(Options* options, std::unordered_set<std::string>& paramSet)
569 {
570     for (auto it = options->begin(); it != options->end(); it++) {
571         if (paramSet.find(it->first) != paramSet.end()) {
572             size_t size = it->first.size();
573             std::string str = it->first.substr(size - 3);
574             if (str != "Pwd") {
575                 this->signParams.insert(std::make_pair(it->first, options->GetString(it->first)));
576             }
577         }
578     }
579     return true;
580 }
581 
CheckParams(Options* options)582 bool SignProvider::CheckParams(Options* options)
583 {
584     std::vector<std::string> paramFileds;
585     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_ALIGNMENT);
586     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_SIGANTURE_ALG);
587     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_INPUT_FILE);
588     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_OUTPUT_FILE);
589     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PRIVATE_KEY);
590     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROFILE);
591     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROOF);
592     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROPERTY);
593     paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_SERVER);
594     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
595     paramFileds.emplace_back(ParamConstants::PARAM_LOCAL_PUBLIC_CERT);
596     paramFileds.emplace_back(ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION);
597     paramFileds.emplace_back(ParamConstants::PARAM_SIGN_CODE);
598     paramFileds.emplace_back(ParamConstants::PARAM_IN_FORM);
599 
600     std::unordered_set<std::string> paramSet = Params::InitParamField(paramFileds);
601     for (auto it = options->begin(); it != options->end(); it++) {
602         if (paramSet.find(it->first) != paramSet.end()) {
603             signParams.insert(std::make_pair(it->first, options->GetString(it->first)));
604         }
605     }
606 
607     if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE_SIGNED) == signParams.end()
608         || signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED).empty()) {
609         signParams[ParamConstants::PARAM_BASIC_PROFILE_SIGNED] = "1";
610     }
611     if (!CheckSignCode()) {
612         SIGNATURE_TOOLS_LOGE("signCode Parameter check error, signCode must is 0 or 1");
613         return false;
614     }
615     if (!CheckSignatureAlg()) {
616         SIGNATURE_TOOLS_LOGE("signAlg Parameter is not support");
617         return false;
618     }
619     CheckSignAlignment();
620     return true;
621 }
622 
CheckSignCode()623 bool SignProvider::CheckSignCode()
624 {
625     if (signParams.find(ParamConstants::PARAM_SIGN_CODE) == signParams.end()) {
626         signParams.insert(std::make_pair(ParamConstants::PARAM_SIGN_CODE, ParamConstants::ENABLE_SIGN_CODE));
627         return true;
628     }
629     std::string codeSign = signParams[ParamConstants::PARAM_SIGN_CODE];
630     if ((codeSign != ParamConstants::ENABLE_SIGN_CODE) && (codeSign != ParamConstants::DISABLE_SIGN_CODE)) {
631         PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
632                             "signCode Parameter must 0 or 1, you put is " + codeSign);
633         return false;
634     }
635     return true;
636 }
637 
CheckSignatureAlg()638 bool SignProvider::CheckSignatureAlg()
639 {
640     std::string signAlg = signParams[ParamConstants::PARAM_BASIC_SIGANTURE_ALG];
641     // Remove leading spaces
642     size_t start = signAlg.find_first_not_of(" ");
643     if (start != std::string::npos) {
644         signAlg = signAlg.substr(start);
645     }
646     // Remove trailing spaces
647     size_t end = signAlg.find_last_not_of(" ");
648     if (end != std::string::npos) {
649         signAlg = signAlg.substr(0, end + 1);
650     }
651     for (auto it = VALID_SIGN_ALG_NAME.begin(); it != VALID_SIGN_ALG_NAME.end(); it++) {
652         if (StringUtils::CaseCompare(*it, signAlg)) {
653             return true;
654         }
655     }
656     PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
657                         "signAlg Parameter is only support [SHA256withECDSA / SHA384withECDSA]");
658     return false;
659 }
660 
CheckSignAlignment()661 void SignProvider::CheckSignAlignment()
662 {
663     if (signParams.find(ParamConstants::PARAM_BASIC_ALIGNMENT) == signParams.end()) {
664         signParams.insert(std::make_pair(ParamConstants::PARAM_BASIC_ALIGNMENT, ParamConstants::ALIGNMENT));
665     }
666 }
667 
CheckCompatibleVersion()668 bool SignProvider::CheckCompatibleVersion()
669 {
670     auto it = signParams.find(ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION);
671     if (it == signParams.end()) {
672         signParams[ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION] = "9";
673         return true;
674     }
675     const std::string& compatibleApiVersionVal = it->second;
676     int compatibleApiVersion;
677     if (!StringUtils::CheckStringToint(compatibleApiVersionVal, compatibleApiVersion)) {
678         PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
679                             "compatibleVersion Parameter is must integer");
680         return false;
681     }
682     return true;
683 }
684 
OutputSignedFile(RandomAccessFile* outputHap, long centralDirectoryOffset, ByteBuffer& signingBlock, ByteBufferDataSource* centralDirectory, ByteBuffer& eocdBuffer)685 bool SignProvider::OutputSignedFile(RandomAccessFile* outputHap,
686                                     long centralDirectoryOffset,
687                                     ByteBuffer& signingBlock,
688                                     ByteBufferDataSource* centralDirectory,
689                                     ByteBuffer& eocdBuffer)
690 {
691     std::shared_ptr<RandomAccessFileOutput> outputHapOut =
692         std::make_shared<RandomAccessFileOutput>(outputHap, centralDirectoryOffset);
693     if (!outputHapOut->Write(signingBlock)) {
694         SIGNATURE_TOOLS_LOGE("output hap file write signingBlock failed");
695         return false;
696     }
697     if (!outputHapOut->Write(centralDirectory->GetByteBuffer())) {
698         SIGNATURE_TOOLS_LOGE("output hap file write central directory failed");
699         return false;
700     }
701     if (!outputHapOut->Write(eocdBuffer) != 0) {
702         SIGNATURE_TOOLS_LOGE("output hap file write eocd failed");
703         return false;
704     }
705     return true;
706 }
707 
GetCertificate(const std::string& certificate) const708 X509* SignProvider::GetCertificate(const std::string& certificate)const
709 {
710     BIO* in = BIO_new_mem_buf(certificate.data(), certificate.size());
711     if (!in) {
712         PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR,
713                             "bio new error ,get ceritificate from base64 certificate failed");
714         return NULL;
715     }
716     X509* cert = NULL;
717     cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
718     if (!cert) {
719         BIO_free(in);
720         PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR,
721                             "read no cert from base64 certificate failed");
722         return NULL;
723     }
724     BIO_free(in);
725     return cert;
726 }
727 
GetCertificateCN(X509* cert) const728 std::string SignProvider::GetCertificateCN(X509* cert)const
729 {
730     X509_NAME* name = NULL;
731     int len = 0;
732     std::string ret;
733     if (cert == NULL) {
734         return "";
735     }
736     name = X509_get_subject_name(cert);
737     if (!name) {
738         SIGNATURE_TOOLS_LOGE("name is NULL,get X509_NAME from cert failed");
739     }
740     len = X509_NAME_get_text_by_NID(name, NID_countryName, NULL, 0);
741     if (len <= 0) {
742         return "";
743     }
744     ret.resize(len + 1);
745     if (X509_NAME_get_text_by_NID(name, NID_countryName, &ret[0], len + 1) != len) {
746         return "";
747     }
748     return ret;
749 }
750 
FindProfileFromOptionalBlocks() const751 std::string SignProvider::FindProfileFromOptionalBlocks()const
752 {
753     std::string profile;
754     for (const OptionalBlock& optionalBlock : optionalBlocks) {
755         if (optionalBlock.optionalType == HapUtils::HAP_PROFILE_BLOCK_ID) {
756             profile = std::string(optionalBlock.optionalBlockValue.GetBufferPtr(),
757                                   optionalBlock.optionalBlockValue.GetCapacity());
758         }
759     }
760     return profile;
761 }
762 
763 int SignProvider::CheckProfileValid(STACK_OF(X509)* inputCerts)
764 {
765     std::string profile = FindProfileFromOptionalBlocks();
766     std::map<std::string, std::string>::const_iterator ite =
767         signParams.find(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
768     if (ite == signParams.end()) {
769         PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
770                             "find PARAM_BASIC_PROFILE_SIGNED failed");
771         return INVALIDPARAM_ERROR;
772     }
773     bool isProfileWithoutSign = (ParamConstants::DISABLE_SIGN_CODE == ite->second);
774     if (!isProfileWithoutSign) {
775         PKCS7Data p7Data;
776         if (p7Data.Parse(profile) < 0) {
777             SIGNATURE_TOOLS_LOGE("Parse profile error.");
778             return PARSE_ERROR;
779         }
780         if (p7Data.Verify() < 0) {
781             SIGNATURE_TOOLS_LOGE("Verify profile pkcs7 failed! Profile is invalid.");
782             return VERIFY_ERROR;
783         }
784         profileContent.clear();
785         if (p7Data.GetContent(profileContent) < 0) {
786             SIGNATURE_TOOLS_LOGE("get content data failed");
787             return  INVALIDPARAM_ERROR;
788         }
789     } else {
790         profileContent = profile;
791     }
792 
793     ProfileInfo info;
794     if (ParseProvision(profileContent, info) != PROVISION_OK) {
795         SIGNATURE_TOOLS_LOGE("parse provision error");
796         return PARSE_ERROR;
797     }
798     if (CheckProfileInfo(info, inputCerts) < 0) {
799         SIGNATURE_TOOLS_LOGE("Check Profile Info error");
800         return RET_FAILED;
801     }
802     return 0;
803 }
804 
CheckProfileInfo(const ProfileInfo& info, STACK_OF(X509)* inputCerts) const805 int SignProvider::CheckProfileInfo(const ProfileInfo& info, STACK_OF(X509)* inputCerts)const
806 {
807     X509* certInProfile = NULL;
808     if (info.type == ProvisionType::RELEASE) {
809         certInProfile = GetCertificate(info.bundleInfo.distributionCertificate);
810     } else if (info.type == ProvisionType::DEBUG) {
811         certInProfile = GetCertificate(info.bundleInfo.developmentCertificate);
812     } else {
813         PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "Unsupported profile type!");
814         return NOT_SUPPORT_ERROR;
815     }
816     if (sk_X509_num(inputCerts) > 0 && !CheckInputCertMatchWithProfile(sk_X509_value(inputCerts, 0),
817                                                                        certInProfile)) {
818         X509_free(certInProfile);
819         SIGNATURE_TOOLS_LOGE("input certificates do not match with profile!");
820         return RET_FAILED;
821     }
822     std::string cn = GetCertificateCN(certInProfile);
823     X509_free(certInProfile);
824     SIGNATURE_TOOLS_LOGI("certificate in profile: %s", cn.c_str());
825     if (cn.empty()) {
826         PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "Common name of certificate is empty!");
827         return CERTIFICATE_ERROR;
828     }
829     return 0;
830 }
831 
CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile) const832 bool SignProvider::CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile)const
833 {
834     return true;
835 }
836 } // namespace SignatureTools
837 } // namespace OHOS