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