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