1 /*
2 * Copyright (C) 2021-2022 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
16 #include "verify/hap_verify_v2.h"
17
18 #include <climits>
19 #include <cstdlib>
20 #include <fcntl.h>
21 #include <regex>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "securec.h"
26
27 #include "common/hap_verify_log.h"
28 #include "init/hap_crl_manager.h"
29 #include "init/trusted_source_manager.h"
30 #include "ticket/ticket_verify.h"
31 #include "util/hap_profile_verify_utils.h"
32 #include "util/hap_signing_block_utils.h"
33 #include "util/signature_info.h"
34
35 namespace OHOS {
36 namespace Security {
37 namespace Verify {
38 const int32_t HapVerifyV2::HEX_PRINT_LENGTH = 3;
39 const int32_t HapVerifyV2::DIGEST_BLOCK_LEN_OFFSET = 8;
40 const int32_t HapVerifyV2::DIGEST_ALGORITHM_OFFSET = 12;
41 const int32_t HapVerifyV2::DIGEST_LEN_OFFSET = 16;
42 const int32_t HapVerifyV2::DIGEST_OFFSET_IN_CONTENT = 20;
43 const std::string HapVerifyV2::HAP_APP_PATTERN = "[^]*.hap$";
44 const std::string HapVerifyV2::HQF_APP_PATTERN = "[^]*.hqf$";
45 const std::string HapVerifyV2::HSP_APP_PATTERN = "[^]*.hsp$";
46 const std::string HapVerifyV2::P7B_PATTERN = "[^]*\\.p7b$";
47 const std::string OPENHARMONY_CERT = "C=CN, O=OpenHarmony, OU=OpenHarmony Team, CN=OpenHarmony Application Root CA";
48
Verify(const std::string & filePath,HapVerifyResult & hapVerifyV1Result,bool readFile)49 int32_t HapVerifyV2::Verify(const std::string& filePath, HapVerifyResult& hapVerifyV1Result, bool readFile)
50 {
51 HAPVERIFY_LOG_DEBUG("Start Verify");
52 std::string standardFilePath;
53 if (!CheckFilePath(filePath, standardFilePath)) {
54 return FILE_PATH_INVALID;
55 }
56
57 RandomAccessFile hapFile;
58 if (!hapFile.Init(standardFilePath, readFile)) {
59 HAPVERIFY_LOG_ERROR("open standard file failed");
60 return OPEN_FILE_ERROR;
61 }
62
63 int32_t resultCode = Verify(hapFile, hapVerifyV1Result);
64 return resultCode;
65 }
66
Verify(const int32_t fileFd,HapVerifyResult & hapVerifyV1Result)67 int32_t HapVerifyV2::Verify(const int32_t fileFd, HapVerifyResult& hapVerifyV1Result)
68 {
69 HAPVERIFY_LOG_INFO("Start Verify with fd");
70 RandomAccessFile hapFile;
71 if (!hapFile.InitWithFd(fileFd)) {
72 HAPVERIFY_LOG_ERROR("init with fd failed");
73 return OPEN_FILE_ERROR;
74 }
75
76 return Verify(hapFile, hapVerifyV1Result);
77 }
78
CheckFilePath(const std::string & filePath,std::string & standardFilePath)79 bool HapVerifyV2::CheckFilePath(const std::string& filePath, std::string& standardFilePath)
80 {
81 char path[PATH_MAX + 1] = { 0x00 };
82 if (filePath.size() > PATH_MAX || realpath(filePath.c_str(), path) == nullptr) {
83 HAPVERIFY_LOG_ERROR("filePath is not a standard path");
84 return false;
85 }
86 standardFilePath = std::string(path);
87 try {
88 if (!std::regex_match(standardFilePath, std::regex(HAP_APP_PATTERN)) &&
89 !std::regex_match(standardFilePath, std::regex(HSP_APP_PATTERN)) &&
90 !std::regex_match(standardFilePath, std::regex(HQF_APP_PATTERN))) {
91 HAPVERIFY_LOG_ERROR("file is not hap, hsp or hqf package");
92 return false;
93 }
94 } catch(const std::regex_error& e) {
95 HAPVERIFY_LOG_ERROR("regex match error");
96 return false;
97 }
98 return true;
99 }
100
CheckP7bPath(const std::string & filePath,std::string & standardFilePath)101 bool HapVerifyV2::CheckP7bPath(const std::string& filePath, std::string& standardFilePath)
102 {
103 char path[PATH_MAX + 1] = { 0x00 };
104 if (filePath.size() > PATH_MAX || realpath(filePath.c_str(), path) == nullptr) {
105 HAPVERIFY_LOG_ERROR("filePath is not a standard path");
106 return false;
107 }
108 standardFilePath = std::string(path);
109 try {
110 if (!std::regex_match(standardFilePath, std::regex(P7B_PATTERN))) {
111 HAPVERIFY_LOG_ERROR("file is not p7b");
112 return false;
113 }
114 } catch(const std::regex_error& e) {
115 HAPVERIFY_LOG_ERROR("regex match error");
116 return false;
117 }
118 return true;
119 }
120
Verify(RandomAccessFile & hapFile,HapVerifyResult & hapVerifyV1Result)121 int32_t HapVerifyV2::Verify(RandomAccessFile& hapFile, HapVerifyResult& hapVerifyV1Result)
122 {
123 SignatureInfo hapSignInfo;
124 if (!HapSigningBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {
125 return SIGNATURE_NOT_FOUND;
126 }
127 hapVerifyV1Result.SetVersion(hapSignInfo.version);
128 hapVerifyV1Result.SetPkcs7SignBlock(hapSignInfo.hapSignatureBlock);
129 hapVerifyV1Result.SetPkcs7ProfileBlock(hapSignInfo.hapSignatureBlock);
130 hapVerifyV1Result.SetOptionalBlocks(hapSignInfo.optionBlocks);
131 Pkcs7Context pkcs7Context;
132 if (!VerifyAppPkcs7(pkcs7Context, hapSignInfo.hapSignatureBlock)) {
133 return VERIFY_APP_PKCS7_FAIL;
134 }
135 int32_t profileIndex = 0;
136 if (!HapSigningBlockUtils::GetOptionalBlockIndex(hapSignInfo.optionBlocks, PROFILE_BLOB, profileIndex)) {
137 return NO_PROFILE_BLOCK_FAIL;
138 }
139 bool profileNeedWriteCrl = false;
140 int32_t ret = VerifyAppSourceAndParseProfile(pkcs7Context,
141 hapSignInfo.optionBlocks[profileIndex].optionalBlockValue, hapVerifyV1Result, profileNeedWriteCrl);
142 if (ret != VERIFY_SUCCESS) {
143 HAPVERIFY_LOG_ERROR("APP source is not trusted");
144 return ret;
145 }
146 if (!GetDigestAndAlgorithm(pkcs7Context)) {
147 HAPVERIFY_LOG_ERROR("Get digest failed");
148 return GET_DIGEST_FAIL;
149 }
150 std::vector<std::string> publicKeys;
151 if (!HapVerifyOpensslUtils::GetPublickeys(pkcs7Context.certChains[0], publicKeys)) {
152 HAPVERIFY_LOG_ERROR("Get publicKeys failed");
153 return GET_PUBLICKEY_FAIL;
154 }
155 hapVerifyV1Result.SetPublicKey(publicKeys);
156 std::vector<std::string> certSignatures;
157 if (!HapVerifyOpensslUtils::GetSignatures(pkcs7Context.certChains[0], certSignatures)) {
158 HAPVERIFY_LOG_ERROR("Get sianatures failed");
159 return GET_SIGNATURE_FAIL;
160 }
161 hapVerifyV1Result.SetSignature(certSignatures);
162 if (!HapSigningBlockUtils::VerifyHapIntegrity(pkcs7Context, hapFile, hapSignInfo)) {
163 HAPVERIFY_LOG_ERROR("Verify Integrity failed");
164 return VERIFY_INTEGRITY_FAIL;
165 }
166 WriteCrlIfNeed(pkcs7Context, profileNeedWriteCrl);
167 return VERIFY_SUCCESS;
168 }
169
VerifyAppPkcs7(Pkcs7Context & pkcs7Context,const HapByteBuffer & hapSignatureBlock)170 bool HapVerifyV2::VerifyAppPkcs7(Pkcs7Context& pkcs7Context, const HapByteBuffer& hapSignatureBlock)
171 {
172 const unsigned char* pkcs7Block = reinterpret_cast<const unsigned char*>(hapSignatureBlock.GetBufferPtr());
173 uint32_t pkcs7Len = static_cast<unsigned int>(hapSignatureBlock.GetCapacity());
174 if (!HapVerifyOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, pkcs7Context)) {
175 HAPVERIFY_LOG_ERROR("parse pkcs7 failed");
176 return false;
177 }
178 if (!HapVerifyOpensslUtils::GetCertChains(pkcs7Context.p7, pkcs7Context)) {
179 HAPVERIFY_LOG_ERROR("GetCertChains from pkcs7 failed");
180 return false;
181 }
182 if (!HapVerifyOpensslUtils::VerifyPkcs7(pkcs7Context)) {
183 HAPVERIFY_LOG_ERROR("verify signature failed");
184 return false;
185 }
186 return true;
187 }
188
VerifyAppSourceAndParseProfile(Pkcs7Context & pkcs7Context,const HapByteBuffer & hapProfileBlock,HapVerifyResult & hapVerifyV1Result,bool & profileNeadWriteCrl)189 int32_t HapVerifyV2::VerifyAppSourceAndParseProfile(Pkcs7Context& pkcs7Context,
190 const HapByteBuffer& hapProfileBlock, HapVerifyResult& hapVerifyV1Result, bool& profileNeadWriteCrl)
191 {
192 std::string certSubject;
193 if (!HapCertVerifyOpensslUtils::GetSubjectFromX509(pkcs7Context.certChains[0][0], certSubject)) {
194 HAPVERIFY_LOG_ERROR("Get info of sign cert failed");
195 return APP_SOURCE_NOT_TRUSTED;
196 }
197 HAPVERIFY_LOG_DEBUG("App signature subject: %{private}s, issuer: %{public}s",
198 certSubject.c_str(), pkcs7Context.certIssuer.c_str());
199
200 TrustedSourceManager& trustedSourceManager = TrustedSourceManager::GetInstance();
201 pkcs7Context.matchResult = trustedSourceManager.IsTrustedSource(certSubject, pkcs7Context.certIssuer,
202 HAP_SIGN_BLOB, pkcs7Context.certChains[0].size());
203
204 if (pkcs7Context.matchResult.matchState == MATCH_WITH_SIGN &&
205 pkcs7Context.matchResult.rootCa != pkcs7Context.rootCa) {
206 HAPVERIFY_LOG_ERROR("MatchRootCa failed, target rootCa: %{public}s, rootCa in pkcs7: %{public}s",
207 pkcs7Context.matchResult.rootCa.c_str(), pkcs7Context.rootCa.c_str());
208 return APP_SOURCE_NOT_TRUSTED;
209 }
210
211 Pkcs7Context profileContext;
212 std::string profile;
213 if (!HapProfileVerifyUtils::ParseProfile(profileContext, pkcs7Context, hapProfileBlock, profile)) {
214 HAPVERIFY_LOG_ERROR("Parse profile pkcs7 failed");
215 return APP_SOURCE_NOT_TRUSTED;
216 }
217
218 if (!VerifyProfileSignature(pkcs7Context, profileContext)) {
219 HAPVERIFY_LOG_ERROR("VerifyProfileSignature failed");
220 return APP_SOURCE_NOT_TRUSTED;
221 }
222 /*
223 * If app source is not trusted, verify profile.
224 * If profile is debug, check whether app signed cert is same as the debug cert in profile.
225 * If profile is release, do not allow installation of this app.
226 */
227 bool isCallParseAndVerify = false;
228 ProvisionInfo provisionInfo;
229 if (pkcs7Context.matchResult.matchState == DO_NOT_MATCH) {
230 if (!HapProfileVerifyUtils::VerifyProfile(profileContext)) {
231 HAPVERIFY_LOG_ERROR("profile verify failed");
232 return APP_SOURCE_NOT_TRUSTED;
233 }
234 if (profileContext.matchResult.rootCa != pkcs7Context.rootCa) {
235 HAPVERIFY_LOG_ERROR("MatchProfileRootCa failed, target rootCa: %{public}s, rootCa in profile: %{public}s",
236 profileContext.matchResult.rootCa.c_str(), pkcs7Context.rootCa.c_str());
237 return APP_SOURCE_NOT_TRUSTED;
238 }
239 AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo);
240 if (profileRet != PROVISION_OK) {
241 HAPVERIFY_LOG_ERROR("profile parsing failed, error: %{public}d", static_cast<int>(profileRet));
242 if (profileRet == PROVISION_DEVICE_UNAUTHORIZED) {
243 return DEVICE_UNAUTHORIZED;
244 }
245 return APP_SOURCE_NOT_TRUSTED;
246 }
247 if (!VerifyProfileInfo(pkcs7Context, profileContext, provisionInfo)) {
248 HAPVERIFY_LOG_ERROR("VerifyProfileInfo failed");
249 return APP_SOURCE_NOT_TRUSTED;
250 }
251 isCallParseAndVerify = true;
252 }
253
254 AppProvisionVerifyResult profileRet = ParseAndVerifyProfileIfNeed(profile, provisionInfo, isCallParseAndVerify);
255 if (profileRet != PROVISION_OK) {
256 if (profileRet == PROVISION_DEVICE_UNAUTHORIZED) {
257 return DEVICE_UNAUTHORIZED;
258 }
259 return APP_SOURCE_NOT_TRUSTED;
260 }
261
262 if (!GenerateAppId(provisionInfo) || !GenerateFingerprint(provisionInfo)) {
263 HAPVERIFY_LOG_ERROR("Generate appId or generate fingerprint failed");
264 return APP_SOURCE_NOT_TRUSTED;
265 }
266 SetOrganization(provisionInfo);
267 SetProfileBlockData(pkcs7Context, hapProfileBlock, provisionInfo);
268 provisionInfo.isOpenHarmony = OPENHARMONY_CERT == pkcs7Context.rootCa;
269
270 hapVerifyV1Result.SetProvisionInfo(provisionInfo);
271 profileNeadWriteCrl = profileContext.needWriteCrl;
272 return VERIFY_SUCCESS;
273 }
274
VerifyProfileSignature(const Pkcs7Context & pkcs7Context,Pkcs7Context & profileContext)275 bool HapVerifyV2::VerifyProfileSignature(const Pkcs7Context& pkcs7Context, Pkcs7Context& profileContext)
276 {
277 if (pkcs7Context.matchResult.matchState == MATCH_WITH_SIGN &&
278 (pkcs7Context.matchResult.source == APP_THIRD_PARTY_PRELOAD ||
279 pkcs7Context.matchResult.source == APP_SYSTEM)) {
280 if (!HapProfileVerifyUtils::VerifyProfile(profileContext)) {
281 HAPVERIFY_LOG_ERROR("profile verify failed");
282 return false;
283 }
284 }
285 return true;
286 }
287
GenerateAppId(ProvisionInfo & provisionInfo)288 bool HapVerifyV2::GenerateAppId(ProvisionInfo& provisionInfo)
289 {
290 std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate;
291 if (provisionInfo.bundleInfo.distributionCertificate.empty()) {
292 certInProfile = provisionInfo.bundleInfo.developmentCertificate;
293 HAPVERIFY_LOG_DEBUG("use development Certificate");
294 }
295 std::string publicKey;
296 if (!HapCertVerifyOpensslUtils::GetPublickeyBase64FromPemCert(certInProfile, publicKey)) {
297 return false;
298 }
299 provisionInfo.appId = publicKey;
300 HAPVERIFY_LOG_DEBUG("provisionInfo.appId: %{public}s", provisionInfo.appId.c_str());
301 return true;
302 }
303
GenerateFingerprint(ProvisionInfo & provisionInfo)304 bool HapVerifyV2::GenerateFingerprint(ProvisionInfo& provisionInfo)
305 {
306 std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate;
307 if (provisionInfo.bundleInfo.distributionCertificate.empty()) {
308 certInProfile = provisionInfo.bundleInfo.developmentCertificate;
309 HAPVERIFY_LOG_DEBUG("use development Certificate");
310 }
311 std::string fingerprint;
312 if (!HapCertVerifyOpensslUtils::GetFingerprintBase64FromPemCert(certInProfile, fingerprint)) {
313 HAPVERIFY_LOG_ERROR("Generate fingerprint from pem certificate failed");
314 return false;
315 }
316 provisionInfo.fingerprint = fingerprint;
317 HAPVERIFY_LOG_DEBUG("fingerprint is : %{private}s", fingerprint.c_str());
318 return true;
319 }
320
SetProfileBlockData(const Pkcs7Context & pkcs7Context,const HapByteBuffer & hapProfileBlock,ProvisionInfo & provisionInfo)321 void HapVerifyV2::SetProfileBlockData(const Pkcs7Context& pkcs7Context, const HapByteBuffer& hapProfileBlock,
322 ProvisionInfo& provisionInfo)
323 {
324 if (pkcs7Context.matchResult.matchState == MATCH_WITH_SIGN &&
325 pkcs7Context.matchResult.source == APP_GALLARY) {
326 HAPVERIFY_LOG_DEBUG("profile is from app gallary and unnecessary to set profile block");
327 return;
328 }
329 provisionInfo.profileBlockLength = hapProfileBlock.GetCapacity();
330 HAPVERIFY_LOG_DEBUG("profile block data length is %{public}d", provisionInfo.profileBlockLength);
331 if (provisionInfo.profileBlockLength == 0) {
332 HAPVERIFY_LOG_ERROR("invalid profile block");
333 return;
334 }
335 provisionInfo.profileBlock = std::make_unique<unsigned char[]>(provisionInfo.profileBlockLength);
336 unsigned char *profileBlockData = provisionInfo.profileBlock.get();
337 const unsigned char *originalProfile = reinterpret_cast<const unsigned char*>(hapProfileBlock.GetBufferPtr());
338 if (profileBlockData == nullptr || originalProfile ==nullptr) {
339 HAPVERIFY_LOG_ERROR("invalid profileBlockData or originalProfile");
340 return;
341 }
342 if (memcpy_s(profileBlockData, provisionInfo.profileBlockLength, originalProfile,
343 provisionInfo.profileBlockLength) != 0) {
344 HAPVERIFY_LOG_ERROR("memcpy failed");
345 }
346 }
347
VerifyProfileInfo(const Pkcs7Context & pkcs7Context,const Pkcs7Context & profileContext,ProvisionInfo & provisionInfo)348 bool HapVerifyV2::VerifyProfileInfo(const Pkcs7Context& pkcs7Context, const Pkcs7Context& profileContext,
349 ProvisionInfo& provisionInfo)
350 {
351 if (!CheckProfileSignatureIsRight(profileContext.matchResult.matchState, provisionInfo.type)) {
352 return false;
353 }
354 std::string& certInProfile = provisionInfo.bundleInfo.developmentCertificate;
355 if (provisionInfo.type == ProvisionType::RELEASE) {
356 if (!IsAppDistributedTypeAllowInstall(provisionInfo.distributionType, provisionInfo)) {
357 HAPVERIFY_LOG_ERROR("untrusted source app with release profile distributionType: %{public}d",
358 static_cast<int>(provisionInfo.distributionType));
359 return false;
360 }
361 certInProfile = provisionInfo.bundleInfo.distributionCertificate;
362 HAPVERIFY_LOG_DEBUG("allow install app with release profile distributionType: %{public}d",
363 static_cast<int>(provisionInfo.distributionType));
364 }
365 HAPVERIFY_LOG_DEBUG("provisionInfo.type: %{public}d", static_cast<int>(provisionInfo.type));
366 if (!HapCertVerifyOpensslUtils::CompareX509Cert(pkcs7Context.certChains[0][0], certInProfile)) {
367 HAPVERIFY_LOG_ERROR("developed cert is not same as signed cert");
368 return false;
369 }
370 return true;
371 }
372
IsAppDistributedTypeAllowInstall(const AppDistType & type,const ProvisionInfo & provisionInfo) const373 bool HapVerifyV2::IsAppDistributedTypeAllowInstall(const AppDistType& type, const ProvisionInfo& provisionInfo) const
374 {
375 switch (type) {
376 case AppDistType::NONE_TYPE:
377 return false;
378 case AppDistType::APP_GALLERY:
379 if (CheckTicketSource(provisionInfo)) {
380 HAPVERIFY_LOG_INFO("current device is allowed to install opentest application");
381 return true;
382 }
383 return false;
384 case AppDistType::ENTERPRISE:
385 case AppDistType::ENTERPRISE_NORMAL:
386 case AppDistType::ENTERPRISE_MDM:
387 case AppDistType::OS_INTEGRATION:
388 case AppDistType::CROWDTESTING:
389 case AppDistType::INTERNALTESTING:
390 return true;
391 default:
392 return false;
393 }
394 }
395
CheckProfileSignatureIsRight(const MatchingStates & matchState,const ProvisionType & type)396 bool HapVerifyV2::CheckProfileSignatureIsRight(const MatchingStates& matchState, const ProvisionType& type)
397 {
398 if (matchState == MATCH_WITH_PROFILE && type == ProvisionType::RELEASE) {
399 return true;
400 } else if (matchState == MATCH_WITH_PROFILE_DEBUG && type == ProvisionType::DEBUG) {
401 return true;
402 }
403 HAPVERIFY_LOG_ERROR("isTrustedSource: %{public}d is not match with profile type: %{public}d",
404 static_cast<int>(matchState), static_cast<int>(type));
405 return false;
406 }
407
WriteCrlIfNeed(const Pkcs7Context & pkcs7Context,const bool & profileNeedWriteCrl)408 void HapVerifyV2::WriteCrlIfNeed(const Pkcs7Context& pkcs7Context, const bool& profileNeedWriteCrl)
409 {
410 if (!pkcs7Context.needWriteCrl && !profileNeedWriteCrl) {
411 return;
412 }
413 HapCrlManager& hapCrlManager = HapCrlManager::GetInstance();
414 hapCrlManager.WriteCrlsToFile();
415 }
416
ParseAndVerifyProfileIfNeed(const std::string & profile,ProvisionInfo & provisionInfo,bool isCallParseAndVerify)417 AppProvisionVerifyResult HapVerifyV2::ParseAndVerifyProfileIfNeed(const std::string& profile,
418 ProvisionInfo& provisionInfo, bool isCallParseAndVerify)
419 {
420 if (isCallParseAndVerify) {
421 return PROVISION_OK;
422 }
423 AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo);
424 if (profileRet != PROVISION_OK) {
425 HAPVERIFY_LOG_ERROR("profile parse failed, error: %{public}d", static_cast<int>(profileRet));
426 return profileRet;
427 }
428 return PROVISION_OK;
429 }
430
GetDigestAndAlgorithm(Pkcs7Context & digest)431 bool HapVerifyV2::GetDigestAndAlgorithm(Pkcs7Context& digest)
432 {
433 /*
434 * contentinfo format:
435 * int: version
436 * int: block number
437 * digest blocks:
438 * each digest block format:
439 * int: length of sizeof(digestblock) - 4
440 * int: Algorithm ID
441 * int: length of digest
442 * byte[]: digest
443 */
444 /* length of sizeof(digestblock - 4) */
445 int32_t digestBlockLen;
446 if (!digest.content.GetInt32(DIGEST_BLOCK_LEN_OFFSET, digestBlockLen)) {
447 HAPVERIFY_LOG_ERROR("get digestBlockLen failed");
448 return false;
449 }
450 /* Algorithm ID */
451 if (!digest.content.GetInt32(DIGEST_ALGORITHM_OFFSET, digest.digestAlgorithm)) {
452 HAPVERIFY_LOG_ERROR("get digestAlgorithm failed");
453 return false;
454 }
455 /* length of digest */
456 int32_t digestlen;
457 if (!digest.content.GetInt32(DIGEST_LEN_OFFSET, digestlen)) {
458 HAPVERIFY_LOG_ERROR("get digestlen failed");
459 return false;
460 }
461
462 int32_t sum = sizeof(digestlen) + sizeof(digest.digestAlgorithm) + digestlen;
463 if (sum != digestBlockLen) {
464 HAPVERIFY_LOG_ERROR("digestBlockLen: %{public}d is not equal to sum: %{public}d",
465 digestBlockLen, sum);
466 return false;
467 }
468 /* set position to the digest start point */
469 digest.content.SetPosition(DIGEST_OFFSET_IN_CONTENT);
470 /* set limit to the digest end point */
471 digest.content.SetLimit(DIGEST_OFFSET_IN_CONTENT + digestlen);
472 digest.content.Slice();
473 return true;
474 }
475
ParseHapProfile(const std::string & filePath,HapVerifyResult & hapVerifyV1Result,bool readFile)476 int32_t HapVerifyV2::ParseHapProfile(const std::string& filePath, HapVerifyResult& hapVerifyV1Result, bool readFile)
477 {
478 HAPVERIFY_LOG_INFO("start to ParseHapProfile");
479 std::string standardFilePath;
480 if (!CheckFilePath(filePath, standardFilePath)) {
481 return FILE_PATH_INVALID;
482 }
483
484 RandomAccessFile hapFile;
485 if (!hapFile.Init(standardFilePath, readFile)) {
486 HAPVERIFY_LOG_ERROR("open standard file failed");
487 return OPEN_FILE_ERROR;
488 }
489
490 SignatureInfo hapSignInfo;
491 if (!HapSigningBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {
492 return SIGNATURE_NOT_FOUND;
493 }
494
495 int32_t profileIndex = 0;
496 if (!HapSigningBlockUtils::GetOptionalBlockIndex(hapSignInfo.optionBlocks, PROFILE_BLOB, profileIndex)) {
497 return NO_PROFILE_BLOCK_FAIL;
498 }
499 auto pkcs7ProfileBlock = hapSignInfo.optionBlocks[profileIndex].optionalBlockValue;
500 const unsigned char* pkcs7Block = reinterpret_cast<const unsigned char*>(pkcs7ProfileBlock.GetBufferPtr());
501 uint32_t pkcs7Len = static_cast<unsigned int>(pkcs7ProfileBlock.GetCapacity());
502 Pkcs7Context profileContext;
503 if (!HapVerifyOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, profileContext)) {
504 HAPVERIFY_LOG_ERROR("parse pkcs7 failed");
505 return false;
506 }
507 std::string profile = std::string(profileContext.content.GetBufferPtr(), profileContext.content.GetCapacity());
508 HAPVERIFY_LOG_DEBUG("profile is %{public}s", profile.c_str());
509 ProvisionInfo info;
510 auto ret = ParseProfile(profile, info);
511 if (ret != PROVISION_OK) {
512 return PROFILE_PARSE_FAIL;
513 }
514
515 if (!GenerateFingerprint(info)) {
516 HAPVERIFY_LOG_ERROR("Generate appId or generate fingerprint failed");
517 return PROFILE_PARSE_FAIL;
518 }
519 SetOrganization(info);
520 hapVerifyV1Result.SetProvisionInfo(info);
521 return VERIFY_SUCCESS;
522 }
523
ParseHapSignatureInfo(const std::string & filePath,SignatureInfo & hapSignInfo)524 int32_t HapVerifyV2::ParseHapSignatureInfo(const std::string& filePath, SignatureInfo &hapSignInfo)
525 {
526 std::string standardFilePath;
527 if (!CheckFilePath(filePath, standardFilePath)) {
528 return FILE_PATH_INVALID;
529 }
530
531 RandomAccessFile hapFile;
532 if (!hapFile.Init(standardFilePath)) {
533 HAPVERIFY_LOG_ERROR("open standard file failed");
534 return OPEN_FILE_ERROR;
535 }
536
537 if (!HapSigningBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {
538 return SIGNATURE_NOT_FOUND;
539 }
540 return VERIFY_SUCCESS;
541 }
542
SetOrganization(ProvisionInfo & provisionInfo)543 void HapVerifyV2::SetOrganization(ProvisionInfo& provisionInfo)
544 {
545 std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate;
546 if (provisionInfo.bundleInfo.distributionCertificate.empty()) {
547 HAPVERIFY_LOG_ERROR("distributionCertificate is empty");
548 return;
549 }
550 std::string organization;
551 if (!HapCertVerifyOpensslUtils::GetOrganizationFromPemCert(certInProfile, organization)) {
552 HAPVERIFY_LOG_ERROR("Generate organization from pem certificate failed");
553 return;
554 }
555 provisionInfo.organization = organization;
556 }
557
VerifyProfile(const std::string & filePath,ProvisionInfo & provisionInfo)558 int32_t HapVerifyV2::VerifyProfile(const std::string& filePath, ProvisionInfo& provisionInfo)
559 {
560 HAPVERIFY_LOG_INFO("start to VerifyProfile");
561 std::string standardFilePath;
562 if (!CheckP7bPath(filePath, standardFilePath)) {
563 return FILE_PATH_INVALID;
564 }
565 Pkcs7Context pkcs7Context;
566 if (!ParseProfileFromP7b(filePath, pkcs7Context)) {
567 return PROFILE_PARSE_FAIL;
568 }
569 std::string profile = std::string(pkcs7Context.content.GetBufferPtr(), pkcs7Context.content.GetCapacity());
570 if (!HapProfileVerifyUtils::VerifyProfile(pkcs7Context)) {
571 HAPVERIFY_LOG_ERROR("profile verify failed");
572 return APP_SOURCE_NOT_TRUSTED;
573 }
574 AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo);
575 if (profileRet != PROVISION_OK) {
576 HAPVERIFY_LOG_ERROR("profile parsing failed, error: %{public}d", static_cast<int>(profileRet));
577 if (profileRet == PROVISION_DEVICE_UNAUTHORIZED) {
578 return DEVICE_UNAUTHORIZED;
579 }
580 return APP_SOURCE_NOT_TRUSTED;
581 }
582 return VERIFY_SUCCESS;
583 }
584
ParseProfileFromP7b(const std::string & p7bFilePath,Pkcs7Context & pkcs7Context)585 bool HapVerifyV2::ParseProfileFromP7b(const std::string& p7bFilePath, Pkcs7Context& pkcs7Context)
586 {
587 int32_t fd = open(p7bFilePath.c_str(), O_RDONLY);
588 if (fd < 0) {
589 HAPVERIFY_LOG_ERROR("open p7b file failed, path: %{public}s", p7bFilePath.c_str());
590 return false;
591 }
592 struct stat st;
593 if (fstat(fd, &st) < 0 || st.st_size <= 0) {
594 HAPVERIFY_LOG_ERROR("fstat p7b file failed, path: %{public}s", p7bFilePath.c_str());
595 close(fd);
596 return false;
597 }
598 std::vector<unsigned char> buffer(st.st_size);
599 ssize_t readSize = pread(fd, buffer.data(), st.st_size, 0);
600 if (readSize < 0 || static_cast<size_t>(readSize) != buffer.size()) {
601 HAPVERIFY_LOG_ERROR("pread p7b file failed, path: %{public}s, error: %{public}d", p7bFilePath.c_str(), errno);
602 close(fd);
603 return false;
604 }
605 close(fd);
606 const unsigned char* p7bData = buffer.data();
607 uint32_t p7bLen = static_cast<uint32_t>(buffer.size());
608 if (!HapVerifyOpensslUtils::ParsePkcs7Package(p7bData, p7bLen, pkcs7Context)) {
609 HAPVERIFY_LOG_ERROR("parse p7b failed, path: %{public}s", p7bFilePath.c_str());
610 return false;
611 }
612 return true;
613 }
614 } // namespace Verify
615 } // namespace Security
616 } // namespace OHOS
617