• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <regex>
21 
22 #include "securec.h"
23 
24 #include "common/hap_verify_log.h"
25 #include "init/hap_crl_manager.h"
26 #include "init/trusted_source_manager.h"
27 #include "ticket/ticket_verify.h"
28 #include "util/hap_profile_verify_utils.h"
29 #include "util/hap_signing_block_utils.h"
30 #include "util/signature_info.h"
31 
32 namespace OHOS {
33 namespace Security {
34 namespace Verify {
35 const int HapVerifyV2::HEX_PRINT_LENGTH = 3;
36 const int HapVerifyV2::DIGEST_BLOCK_LEN_OFFSET = 8;
37 const int HapVerifyV2::DIGEST_ALGORITHM_OFFSET = 12;
38 const int HapVerifyV2::DIGEST_LEN_OFFSET = 16;
39 const int HapVerifyV2::DIGEST_OFFSET_IN_CONTENT = 20;
40 const std::string HapVerifyV2::HAP_APP_PATTERN = "[^]*.hap$";
41 const std::string HapVerifyV2::HQF_APP_PATTERN = "[^]*.hqf$";
42 const std::string HapVerifyV2::HSP_APP_PATTERN = "[^]*.hsp$";
43 
Verify(const std::string & filePath,HapVerifyResult & hapVerifyV1Result)44 int HapVerifyV2::Verify(const std::string& filePath, HapVerifyResult& hapVerifyV1Result)
45 {
46     HAPVERIFY_LOG_DEBUG(LABEL, "Start Verify");
47     std::string standardFilePath;
48     if (!CheckFilePath(filePath, standardFilePath)) {
49         return FILE_PATH_INVALID;
50     }
51 
52     RandomAccessFile hapFile;
53     if (!hapFile.Init(standardFilePath)) {
54         HAPVERIFY_LOG_ERROR(LABEL, "open standard file failed");
55         return OPEN_FILE_ERROR;
56     }
57 
58     int resultCode = Verify(hapFile, hapVerifyV1Result);
59     return resultCode;
60 }
61 
CheckFilePath(const std::string & filePath,std::string & standardFilePath)62 bool HapVerifyV2::CheckFilePath(const std::string& filePath, std::string& standardFilePath)
63 {
64     char path[PATH_MAX + 1] = { 0x00 };
65     if (filePath.size() > PATH_MAX || realpath(filePath.c_str(), path) == nullptr) {
66         HAPVERIFY_LOG_ERROR(LABEL, "filePath is not a standard path");
67         return false;
68     }
69     standardFilePath = std::string(path);
70     if (!std::regex_match(standardFilePath, std::regex(HAP_APP_PATTERN)) &&
71         !std::regex_match(standardFilePath, std::regex(HSP_APP_PATTERN)) &&
72         !std::regex_match(standardFilePath, std::regex(HQF_APP_PATTERN))) {
73         HAPVERIFY_LOG_ERROR(LABEL, "file is not hap, hsp or hqf package");
74         return false;
75     }
76     return true;
77 }
78 
Verify(RandomAccessFile & hapFile,HapVerifyResult & hapVerifyV1Result)79 int HapVerifyV2::Verify(RandomAccessFile& hapFile, HapVerifyResult& hapVerifyV1Result)
80 {
81     SignatureInfo hapSignInfo;
82     if (!HapSigningBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {
83         return SIGNATURE_NOT_FOUND;
84     }
85     hapVerifyV1Result.SetVersion(hapSignInfo.version);
86     hapVerifyV1Result.SetPkcs7SignBlock(hapSignInfo.hapSignatureBlock);
87     hapVerifyV1Result.SetPkcs7ProfileBlock(hapSignInfo.hapSignatureBlock);
88     hapVerifyV1Result.SetOptionalBlocks(hapSignInfo.optionBlocks);
89     Pkcs7Context pkcs7Context;
90     if (!VerifyAppPkcs7(pkcs7Context, hapSignInfo.hapSignatureBlock)) {
91         return VERIFY_APP_PKCS7_FAIL;
92     }
93     int profileIndex = 0;
94     if (!HapSigningBlockUtils::GetOptionalBlockIndex(hapSignInfo.optionBlocks, PROFILE_BLOB, profileIndex)) {
95         return NO_PROFILE_BLOCK_FAIL;
96     }
97     bool profileNeedWriteCrl = false;
98     if (!VerifyAppSourceAndParseProfile(pkcs7Context, hapSignInfo.optionBlocks[profileIndex].optionalBlockValue,
99         hapVerifyV1Result, profileNeedWriteCrl)) {
100         HAPVERIFY_LOG_ERROR(LABEL, "APP source is not trusted");
101         return APP_SOURCE_NOT_TRUSTED;
102     }
103     if (!GetDigestAndAlgorithm(pkcs7Context)) {
104         HAPVERIFY_LOG_ERROR(LABEL, "Get digest failed");
105         return GET_DIGEST_FAIL;
106     }
107     std::vector<std::string> publicKeys;
108     if (!HapVerifyOpensslUtils::GetPublickeys(pkcs7Context.certChains[0], publicKeys)) {
109         HAPVERIFY_LOG_ERROR(LABEL, "Get publicKeys failed");
110         return GET_PUBLICKEY_FAIL;
111     }
112     hapVerifyV1Result.SetPublicKey(publicKeys);
113     std::vector<std::string> certSignatures;
114     if (!HapVerifyOpensslUtils::GetSignatures(pkcs7Context.certChains[0], certSignatures)) {
115         HAPVERIFY_LOG_ERROR(LABEL, "Get sianatures failed");
116         return GET_SIGNATURE_FAIL;
117     }
118     hapVerifyV1Result.SetSignature(certSignatures);
119     if (!HapSigningBlockUtils::VerifyHapIntegrity(pkcs7Context, hapFile, hapSignInfo)) {
120         HAPVERIFY_LOG_ERROR(LABEL, "Verify Integrity failed");
121         return VERIFY_INTEGRITY_FAIL;
122     }
123     WriteCrlIfNeed(pkcs7Context, profileNeedWriteCrl);
124     return VERIFY_SUCCESS;
125 }
126 
VerifyAppPkcs7(Pkcs7Context & pkcs7Context,const HapByteBuffer & hapSignatureBlock)127 bool HapVerifyV2::VerifyAppPkcs7(Pkcs7Context& pkcs7Context, const HapByteBuffer& hapSignatureBlock)
128 {
129     const unsigned char* pkcs7Block = reinterpret_cast<const unsigned char*>(hapSignatureBlock.GetBufferPtr());
130     unsigned int pkcs7Len = static_cast<unsigned int>(hapSignatureBlock.GetCapacity());
131     if (!HapVerifyOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, pkcs7Context)) {
132         HAPVERIFY_LOG_ERROR(LABEL, "parse pkcs7 failed");
133         return false;
134     }
135     if (!HapVerifyOpensslUtils::GetCertChains(pkcs7Context.p7, pkcs7Context)) {
136         HAPVERIFY_LOG_ERROR(LABEL, "GetCertChains from pkcs7 failed");
137         return false;
138     }
139     if (!HapVerifyOpensslUtils::VerifyPkcs7(pkcs7Context)) {
140         HAPVERIFY_LOG_ERROR(LABEL, "verify signature failed");
141         return false;
142     }
143     return true;
144 }
145 
VerifyAppSourceAndParseProfile(Pkcs7Context & pkcs7Context,const HapByteBuffer & hapProfileBlock,HapVerifyResult & hapVerifyV1Result,bool & profileNeadWriteCrl)146 bool HapVerifyV2::VerifyAppSourceAndParseProfile(Pkcs7Context& pkcs7Context,
147     const HapByteBuffer& hapProfileBlock, HapVerifyResult& hapVerifyV1Result, bool& profileNeadWriteCrl)
148 {
149     std::string certSubject;
150     if (!HapCertVerifyOpensslUtils::GetSubjectFromX509(pkcs7Context.certChains[0][0], certSubject)) {
151         HAPVERIFY_LOG_ERROR(LABEL, "Get info of sign cert failed");
152         return false;
153     }
154     HAPVERIFY_LOG_INFO(LABEL, "App signature subject: %{public}s, issuer: %{public}s",
155         certSubject.c_str(), pkcs7Context.certIssuer.c_str());
156 
157     TrustedSourceManager& trustedSourceManager = TrustedSourceManager::GetInstance();
158     pkcs7Context.matchResult = trustedSourceManager.IsTrustedSource(certSubject, pkcs7Context.certIssuer,
159         HAP_SIGN_BLOB, pkcs7Context.certChains[0].size());
160 
161     Pkcs7Context profileContext;
162     std::string profile;
163     if (!HapProfileVerifyUtils::ParseProfile(profileContext, pkcs7Context, hapProfileBlock, profile)) {
164         HAPVERIFY_LOG_ERROR(LABEL, "Parse profile pkcs7 failed");
165         return false;
166     }
167 
168     if (!VerifyProfileSignature(pkcs7Context, profileContext)) {
169         HAPVERIFY_LOG_ERROR(LABEL, "VerifyProfileSignature failed");
170         return false;
171     }
172     /*
173      * If app source is not trusted, verify profile.
174      * If profile is debug, check whether app signed cert is same as the debug cert in profile.
175      * If profile is release, do not allow installation of this app.
176      */
177     bool isCallParseAndVerify = false;
178     ProvisionInfo provisionInfo;
179     if (pkcs7Context.matchResult.matchState == DO_NOT_MATCH) {
180         if (!HapProfileVerifyUtils::VerifyProfile(profileContext)) {
181             HAPVERIFY_LOG_ERROR(LABEL, "profile verify failed");
182             return false;
183         }
184         AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo);
185         if (profileRet != PROVISION_OK) {
186             HAPVERIFY_LOG_ERROR(LABEL, "profile parsing failed, error: %{public}d", static_cast<int>(profileRet));
187             return false;
188         }
189         if (!VerifyProfileInfo(pkcs7Context, profileContext, provisionInfo)) {
190             HAPVERIFY_LOG_ERROR(LABEL, "VerifyProfileInfo failed");
191             return false;
192         }
193         isCallParseAndVerify = true;
194     }
195 
196     if (!ParseAndVerifyProfileIfNeed(profile, provisionInfo, isCallParseAndVerify)) {
197         return false;
198     }
199 
200     if (!GenerateAppId(provisionInfo) || !GenerateFingerprint(provisionInfo)) {
201         HAPVERIFY_LOG_ERROR(LABEL, "Generate appId or generate fingerprint failed");
202         return false;
203     }
204 
205     hapVerifyV1Result.SetProvisionInfo(provisionInfo);
206     profileNeadWriteCrl = profileContext.needWriteCrl;
207     return true;
208 }
209 
VerifyProfileSignature(const Pkcs7Context & pkcs7Context,Pkcs7Context & profileContext)210 bool HapVerifyV2::VerifyProfileSignature(const Pkcs7Context& pkcs7Context, Pkcs7Context& profileContext)
211 {
212     if (pkcs7Context.matchResult.matchState == MATCH_WITH_SIGN &&
213         pkcs7Context.matchResult.source == APP_THIRD_PARTY_PRELOAD) {
214         if (!HapProfileVerifyUtils::VerifyProfile(profileContext)) {
215             HAPVERIFY_LOG_ERROR(LABEL, "profile verify failed");
216             return false;
217         }
218     }
219     return true;
220 }
221 
GenerateAppId(ProvisionInfo & provisionInfo)222 bool HapVerifyV2::GenerateAppId(ProvisionInfo& provisionInfo)
223 {
224     std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate;
225     if (provisionInfo.bundleInfo.distributionCertificate.empty()) {
226         certInProfile = provisionInfo.bundleInfo.developmentCertificate;
227         HAPVERIFY_LOG_DEBUG(LABEL, "use development Certificate");
228     }
229     std::string publicKey;
230     if (!HapCertVerifyOpensslUtils::GetPublickeyBase64FromPemCert(certInProfile, publicKey)) {
231         return false;
232     }
233     provisionInfo.appId = publicKey;
234     HAPVERIFY_LOG_DEBUG(LABEL, "provisionInfo.appId: %{public}s", provisionInfo.appId.c_str());
235     return true;
236 }
237 
GenerateFingerprint(ProvisionInfo & provisionInfo)238 bool HapVerifyV2::GenerateFingerprint(ProvisionInfo& provisionInfo)
239 {
240     std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate;
241     if (provisionInfo.bundleInfo.distributionCertificate.empty()) {
242         certInProfile = provisionInfo.bundleInfo.developmentCertificate;
243         HAPVERIFY_LOG_DEBUG(LABEL, "use development Certificate");
244     }
245     std::string fingerprint;
246     if (!HapCertVerifyOpensslUtils::GetFingerprintBase64FromPemCert(certInProfile, fingerprint)) {
247         HAPVERIFY_LOG_ERROR(LABEL, "Generate fingerprint from pem certificate failed");
248         return false;
249     }
250     provisionInfo.fingerprint = fingerprint;
251     HAPVERIFY_LOG_DEBUG(LABEL, "fingerprint is : %{public}s", fingerprint.c_str());
252     return true;
253 }
254 
VerifyProfileInfo(const Pkcs7Context & pkcs7Context,const Pkcs7Context & profileContext,ProvisionInfo & provisionInfo)255 bool HapVerifyV2::VerifyProfileInfo(const Pkcs7Context& pkcs7Context, const Pkcs7Context& profileContext,
256     ProvisionInfo& provisionInfo)
257 {
258     if (!CheckProfileSignatureIsRight(profileContext.matchResult.matchState, provisionInfo.type)) {
259         return false;
260     }
261     std::string& certInProfile = provisionInfo.bundleInfo.developmentCertificate;
262     if (provisionInfo.type == ProvisionType::RELEASE) {
263         if (!IsAppDistributedTypeAllowInstall(provisionInfo.distributionType, provisionInfo)) {
264             HAPVERIFY_LOG_ERROR(LABEL, "untrusted source app with release profile distributionType: %{public}d",
265                 static_cast<int>(provisionInfo.distributionType));
266             return false;
267         }
268         certInProfile = provisionInfo.bundleInfo.distributionCertificate;
269         HAPVERIFY_LOG_DEBUG(LABEL, "allow install app with release profile distributionType: %{public}d",
270             static_cast<int>(provisionInfo.distributionType));
271     }
272     HAPVERIFY_LOG_DEBUG(LABEL, "provisionInfo.type: %{public}d", static_cast<int>(provisionInfo.type));
273     if (!HapCertVerifyOpensslUtils::CompareX509Cert(pkcs7Context.certChains[0][0], certInProfile)) {
274         HAPVERIFY_LOG_ERROR(LABEL, "developed cert is not same as signed cert");
275         return false;
276     }
277     return true;
278 }
279 
IsAppDistributedTypeAllowInstall(const AppDistType & type,const ProvisionInfo & provisionInfo) const280 bool HapVerifyV2::IsAppDistributedTypeAllowInstall(const AppDistType& type, const ProvisionInfo& provisionInfo) const
281 {
282     switch (type) {
283         case AppDistType::NONE_TYPE:
284             return false;
285         case AppDistType::APP_GALLERY:
286             if (CheckTicketSource(provisionInfo)) {
287                 HAPVERIFY_LOG_INFO(LABEL, "current device is allowed to install opentest application");
288                 return true;
289             }
290             return false;
291         case AppDistType::ENTERPRISE:
292         case AppDistType::OS_INTEGRATION:
293         case AppDistType::CROWDTESTING:
294             return true;
295         default:
296             return false;
297     }
298 }
299 
CheckProfileSignatureIsRight(const MatchingStates & matchState,const ProvisionType & type)300 bool HapVerifyV2::CheckProfileSignatureIsRight(const MatchingStates& matchState, const ProvisionType& type)
301 {
302     if (matchState == MATCH_WITH_PROFILE && type == ProvisionType::RELEASE) {
303         return true;
304     } else if (matchState == MATCH_WITH_PROFILE_DEBUG && type == ProvisionType::DEBUG) {
305         return true;
306     }
307     HAPVERIFY_LOG_ERROR(LABEL, "isTrustedSource: %{public}d is not match with profile type: %{public}d",
308         static_cast<int>(matchState), static_cast<int>(type));
309     return false;
310 }
311 
WriteCrlIfNeed(const Pkcs7Context & pkcs7Context,const bool & profileNeedWriteCrl)312 void HapVerifyV2::WriteCrlIfNeed(const Pkcs7Context& pkcs7Context, const bool& profileNeedWriteCrl)
313 {
314     if (!pkcs7Context.needWriteCrl && !profileNeedWriteCrl) {
315         return;
316     }
317     HapCrlManager& hapCrlManager = HapCrlManager::GetInstance();
318     hapCrlManager.WriteCrlsToFile();
319 }
320 
ParseAndVerifyProfileIfNeed(const std::string & profile,ProvisionInfo & provisionInfo,bool isCallParseAndVerify)321 bool HapVerifyV2::ParseAndVerifyProfileIfNeed(const std::string& profile,
322     ProvisionInfo& provisionInfo, bool isCallParseAndVerify)
323 {
324     if (isCallParseAndVerify) {
325         return isCallParseAndVerify;
326     }
327     AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo);
328     if (profileRet != PROVISION_OK) {
329         HAPVERIFY_LOG_ERROR(LABEL, "profile parse failed, error: %{public}d", static_cast<int>(profileRet));
330         return false;
331     }
332     return true;
333 }
334 
GetDigestAndAlgorithm(Pkcs7Context & digest)335 bool HapVerifyV2::GetDigestAndAlgorithm(Pkcs7Context& digest)
336 {
337     /*
338      * contentinfo format:
339      * int: version
340      * int: block number
341      * digest blocks:
342      * each digest block format:
343      * int: length of sizeof(digestblock) - 4
344      * int: Algorithm ID
345      * int: length of digest
346      * byte[]: digest
347      */
348     /* length of sizeof(digestblock - 4) */
349     int digestBlockLen;
350     if (!digest.content.GetInt32(DIGEST_BLOCK_LEN_OFFSET, digestBlockLen)) {
351         HAPVERIFY_LOG_ERROR(LABEL, "get digestBlockLen failed");
352         return false;
353     }
354     /* Algorithm ID */
355     if (!digest.content.GetInt32(DIGEST_ALGORITHM_OFFSET, digest.digestAlgorithm)) {
356         HAPVERIFY_LOG_ERROR(LABEL, "get digestAlgorithm failed");
357         return false;
358     }
359     /* length of digest */
360     int digestlen;
361     if (!digest.content.GetInt32(DIGEST_LEN_OFFSET, digestlen)) {
362         HAPVERIFY_LOG_ERROR(LABEL, "get digestlen failed");
363         return false;
364     }
365 
366     int sum = sizeof(digestlen) + sizeof(digest.digestAlgorithm) + digestlen;
367     if (sum != digestBlockLen) {
368         HAPVERIFY_LOG_ERROR(LABEL, "digestBlockLen: %{public}d is not equal to sum: %{public}d",
369             digestBlockLen, sum);
370         return false;
371     }
372     /* set position to the digest start point */
373     digest.content.SetPosition(DIGEST_OFFSET_IN_CONTENT);
374     /* set limit to the digest end point */
375     digest.content.SetLimit(DIGEST_OFFSET_IN_CONTENT + digestlen);
376     digest.content.Slice();
377     return true;
378 }
379 
ParseHapProfile(const std::string & filePath,HapVerifyResult & hapVerifyV1Result)380 int HapVerifyV2::ParseHapProfile(const std::string& filePath, HapVerifyResult& hapVerifyV1Result)
381 {
382     HAPVERIFY_LOG_INFO(LABEL, "start to ParseHapProfile");
383     std::string standardFilePath;
384     if (!CheckFilePath(filePath, standardFilePath)) {
385         return FILE_PATH_INVALID;
386     }
387 
388     RandomAccessFile hapFile;
389     if (!hapFile.Init(standardFilePath)) {
390         HAPVERIFY_LOG_ERROR(LABEL, "open standard file failed");
391         return OPEN_FILE_ERROR;
392     }
393 
394     SignatureInfo hapSignInfo;
395     if (!HapSigningBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {
396         return SIGNATURE_NOT_FOUND;
397     }
398 
399     int profileIndex = 0;
400     if (!HapSigningBlockUtils::GetOptionalBlockIndex(hapSignInfo.optionBlocks, PROFILE_BLOB, profileIndex)) {
401         return NO_PROFILE_BLOCK_FAIL;
402     }
403     auto pkcs7ProfileBlock = hapSignInfo.optionBlocks[profileIndex].optionalBlockValue;
404     const unsigned char* pkcs7Block = reinterpret_cast<const unsigned char*>(pkcs7ProfileBlock.GetBufferPtr());
405     unsigned int pkcs7Len = static_cast<unsigned int>(pkcs7ProfileBlock.GetCapacity());
406     Pkcs7Context profileContext;
407     if (!HapVerifyOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, profileContext)) {
408         HAPVERIFY_LOG_ERROR(LABEL, "parse pkcs7 failed");
409         return false;
410     }
411     std::string profile = std::string(profileContext.content.GetBufferPtr(), profileContext.content.GetCapacity());
412     HAPVERIFY_LOG_DEBUG(LABEL, "profile is %{public}s", profile.c_str());
413     ProvisionInfo info;
414     auto ret = ParseProfile(profile, info);
415     if (ret != PROVISION_OK) {
416         return PROFILE_PARSE_FAIL;
417     }
418 
419     if (!GenerateFingerprint(info)) {
420         HAPVERIFY_LOG_ERROR(LABEL, "Generate appId or generate fingerprint failed");
421         return PROFILE_PARSE_FAIL;
422     }
423     hapVerifyV1Result.SetProvisionInfo(info);
424     return VERIFY_SUCCESS;
425 }
426 } // namespace Verify
427 } // namespace Security
428 } // namespace OHOS
429