• 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 package com.ohos.hapsigntool.profile;
17 
18 import com.ohos.hapsigntool.error.CustomException;
19 import com.ohos.hapsigntool.error.ERROR;
20 import com.ohos.hapsigntool.hap.verify.VerifyUtils;
21 import com.ohos.hapsigntool.profile.model.Provision;
22 import com.ohos.hapsigntool.profile.model.VerificationResult;
23 import com.ohos.hapsigntool.utils.CertChainUtils;
24 import com.ohos.hapsigntool.utils.CertUtils;
25 import com.ohos.hapsigntool.utils.FileUtils;
26 import com.ohos.hapsigntool.utils.ValidateUtils;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.bouncycastle.cert.X509CertificateHolder;
30 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
31 import org.bouncycastle.cms.CMSException;
32 import org.bouncycastle.cms.CMSSignedData;
33 import org.bouncycastle.cms.SignerId;
34 import org.bouncycastle.cms.SignerInformation;
35 import org.bouncycastle.cms.SignerInformationStore;
36 import org.bouncycastle.util.Store;
37 
38 import javax.security.auth.x500.X500Principal;
39 import java.io.IOException;
40 import java.nio.charset.StandardCharsets;
41 import java.security.InvalidKeyException;
42 import java.security.NoSuchAlgorithmException;
43 import java.security.Signature;
44 import java.security.SignatureException;
45 import java.security.cert.CertificateException;
46 import java.security.cert.X509Certificate;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Iterator;
50 import java.util.List;
51 
52 /**
53  * Signed provision profile verifier.
54  *
55  * @since 2021/12/28
56  */
57 public class VerifyHelper implements IProvisionVerifier {
58     /**
59      * LOGGER.
60      */
61     private static final Logger LOGGER = LogManager.getLogger(VerifyHelper.class);
62 
63     /**
64      * Signed provision profile verifier.
65      */
VerifyHelper()66     public VerifyHelper() {
67         // Empty constructor
68     }
69 
70     /**
71      * Checked signed data with public key.
72      *
73      * @param cert         public key
74      * @param signedData   signed data with private key
75      * @param unsignedData unsigned data
76      * @param algorithm    algorithm
77      */
verifySignature(X509Certificate cert, byte[] signedData, byte[] unsignedData, String algorithm)78     public static void verifySignature(X509Certificate cert, byte[] signedData, byte[] unsignedData, String algorithm) {
79         try {
80             Signature signature = Signature.getInstance(algorithm);
81             signature.initVerify(cert);
82             signature.update(unsignedData);
83             ValidateUtils.throwIfNotMatches(signature.verify(signedData), ERROR.SIGN_ERROR, "Signature not matched!");
84         } catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException exception) {
85             LOGGER.debug(exception.getMessage(), exception);
86             CustomException.throwException(ERROR.SIGN_ERROR, "Failed to verify signature: " + exception.getMessage());
87         }
88     }
89 
90     /**
91      * Convert store collection to list.
92      *
93      * @param certificates certificates from cmsSignedData
94      * @return List<X509Certificate>
95      */
certStoreToCertList(Store<X509CertificateHolder> certificates)96     public static List<X509Certificate> certStoreToCertList(Store<X509CertificateHolder> certificates) {
97         String errorMsg = "Verify failed, not found cert chain";
98         JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
99         ValidateUtils.throwIfMatches(certificates == null, ERROR.VERIFY_ERROR, errorMsg);
100         Collection<X509CertificateHolder> matches = certificates.getMatches(null);
101         ValidateUtils.throwIfMatches(matches == null || !matches.iterator().hasNext(),
102                 ERROR.VERIFY_ERROR, errorMsg);
103 
104         Iterator<X509CertificateHolder> iterator = matches.iterator();
105         List<X509Certificate> certificateList = new ArrayList<>();
106         try {
107             while (iterator.hasNext()) {
108                 X509CertificateHolder next = iterator.next();
109                 certificateList.add(converter.getCertificate(next));
110             }
111         } catch (CertificateException exception) {
112             LOGGER.debug(exception.getMessage(), exception);
113             CustomException.throwException(ERROR.VERIFY_ERROR, errorMsg);
114         }
115         ValidateUtils.throwIfMatches(certificateList.size() == 0, ERROR.VERIFY_ERROR, errorMsg);
116         return certificateList;
117     }
118 
119     /**
120      * verify p7b content.
121      *
122      * @param p7b signed p7b content
123      * @return result
124      */
125     @Override
verify(byte[] p7b)126     public VerificationResult verify(byte[] p7b) {
127         VerificationResult result = new VerificationResult();
128 
129         try {
130             CMSSignedData cmsSignedData = this.verifyPkcs(p7b);
131             List<X509Certificate> certificates = certStoreToCertList(cmsSignedData.getCertificates());
132             CertUtils.sortCertificateChain(certificates);
133 
134             SignerInformationStore signerInfos = cmsSignedData.getSignerInfos();
135             Collection<SignerInformation> signers = signerInfos.getSigners();
136 
137             for (SignerInformation signer : signers) {
138                 SignerId sid = signer.getSID();
139                 X500Principal principal = new X500Principal(sid.getIssuer().getEncoded());
140                 CertChainUtils.verifyCertChain(certificates, principal, sid.getSerialNumber(),
141                         certificates.get(certificates.size() - 1));
142             }
143 
144             result.setContent(FileUtils.GSON.fromJson(new String((byte[]) (cmsSignedData
145                     .getSignedContent().getContent()), StandardCharsets.UTF_8), Provision.class));
146             result.setMessage("OK");
147             result.setVerifiedPassed(true);
148             return result;
149         } catch (CustomException | IOException exception) {
150             LOGGER.debug(exception.getMessage(), exception);
151             result.setMessage(exception.getMessage());
152             result.setVerifiedPassed(false);
153             return result;
154         }
155     }
156 
verifyPkcs(byte[] p7b)157     CMSSignedData verifyPkcs(byte[] p7b) {
158         CMSSignedData cmsSignedData = null;
159         try {
160             cmsSignedData = new CMSSignedData(p7b);
161             boolean verifyResult = VerifyUtils.verifyCmsSignedData(cmsSignedData);
162             ValidateUtils.throwIfNotMatches(verifyResult, ERROR.VERIFY_ERROR,
163                     "Failed to verify BC signatures");
164             return cmsSignedData;
165         } catch (CMSException exception) {
166             LOGGER.debug(exception.getMessage(), exception);
167             CustomException.throwException(ERROR.VERIFY_ERROR, "Failed to verify BC signatures: "
168                     + exception.getMessage());
169         }
170         return cmsSignedData;
171     }
172 }
173