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