• 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.adapter.LocalizationAdapter;
19 import com.ohos.hapsigntool.error.CustomException;
20 import com.ohos.hapsigntool.error.ERROR;
21 import com.ohos.hapsigntool.error.VerifyException;
22 import com.ohos.hapsigntool.profile.model.VerificationResult;
23 import com.ohos.hapsigntool.signer.ISigner;
24 import com.ohos.hapsigntool.signer.SignerFactory;
25 import com.ohos.hapsigntool.utils.ValidateUtils;
26 import org.apache.logging.log4j.LogManager;
27 import org.apache.logging.log4j.Logger;
28 import org.bouncycastle.asn1.ASN1EncodableVector;
29 import org.bouncycastle.asn1.ASN1Set;
30 import org.bouncycastle.asn1.BERSet;
31 import org.bouncycastle.asn1.DEROctetString;
32 import org.bouncycastle.asn1.DERSet;
33 import org.bouncycastle.asn1.cms.Attribute;
34 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
35 import org.bouncycastle.asn1.cms.ContentInfo;
36 import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
37 import org.bouncycastle.asn1.cms.SignedData;
38 import org.bouncycastle.asn1.cms.SignerIdentifier;
39 import org.bouncycastle.asn1.cms.SignerInfo;
40 import org.bouncycastle.asn1.cms.Time;
41 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
42 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
43 import org.bouncycastle.cert.jcajce.JcaX509CRLHolder;
44 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
45 import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
46 import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
47 import org.bouncycastle.operator.DigestCalculator;
48 import org.bouncycastle.operator.DigestCalculatorProvider;
49 import org.bouncycastle.operator.OperatorCreationException;
50 import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
51 
52 import java.io.IOException;
53 import java.security.cert.CRLException;
54 import java.security.cert.CertificateEncodingException;
55 import java.security.cert.X509CRL;
56 import java.security.cert.X509Certificate;
57 import java.time.LocalDateTime;
58 import java.time.ZoneId;
59 import java.util.Date;
60 import java.util.List;
61 
62 /**
63  * To sign and verify profile.
64  *
65  * @since 2021/12/28
66  */
67 public final class ProfileSignTool {
68     /**
69      * Empty byte array.
70      */
71     private static final byte[] NO_BYTE = {};
72 
73     /**
74      * logger
75      */
76     private static final Logger LOGGER = LogManager.getLogger(ProfileSignTool.class);
77 
ProfileSignTool()78     private ProfileSignTool() {
79     }
80 
81     /**
82      * generateP7b.
83      *
84      * @param adapter local adapter with params
85      * @param content content to sign
86      * @return signed content
87      */
generateP7b(LocalizationAdapter adapter, byte[] content)88     public static byte[] generateP7b(LocalizationAdapter adapter, byte[] content) {
89         ISigner signer = new SignerFactory().getSigner(adapter);
90         byte[] p7b = signProfile(content, signer, adapter.getSignAlg());
91         VerifyHelper verifyHelper = new VerifyHelper();
92         VerificationResult verificationResult = null;
93         try {
94             verificationResult = verifyHelper.verify(p7b);
95         } catch (VerifyException e) {
96             CustomException.throwException(ERROR.VERIFY_ERROR, "Generate Profile Failed! " + e.getMessage());
97         }
98         ValidateUtils.throwIfNotMatches(verificationResult.isVerifiedPassed(), ERROR.SIGN_ERROR,
99                 verificationResult.getMessage());
100         return p7b;
101     }
102 
103     /**
104      * signProfile.
105      *
106      * @param content content to sign
107      * @param signer signer
108      * @param sigAlg sign algorithm
109      * @return signed data
110      */
signProfile(byte[] content, ISigner signer, String sigAlg)111     public static byte[] signProfile(byte[] content, ISigner signer, String sigAlg) {
112         try {
113             AlgorithmIdentifier sigAlgId = (new DefaultSignatureAlgorithmIdentifierFinder()).find(sigAlg);
114             ASN1EncodableVector digestAlgIds = new ASN1EncodableVector();
115             AlgorithmIdentifier digestAlgId = (new DefaultDigestAlgorithmIdentifierFinder()).find(sigAlgId);
116             digestAlgIds.add(digestAlgId);
117             byte[] digest = getContentDigest(content, digestAlgId);
118             ASN1Set signedAttr = generatePKCS9Attributes(digest);
119             byte[] signature = signer.getSignature(signedAttr.getEncoded("DER"), sigAlg, null);
120             // To validate cert(public key) and private key
121             VerifyHelper.verifySignature(signer.getCertificates().get(0), signature,
122                     signedAttr.getEncoded("DER"), sigAlg);
123             SignerIdentifier signerIdentifier = generateSignerIdentifier(signer.getCertificates().get(0));
124             SignerInfo signerInfo = new SignerInfo(signerIdentifier, digestAlgId, signedAttr, sigAlgId,
125                     new DEROctetString(signature), null);
126             ASN1EncodableVector signerInfos = new ASN1EncodableVector();
127             signerInfos.add(signerInfo);
128             ASN1Set certList = createBerSetFromCerts(signer.getCertificates());
129             List<X509CRL> crls = signer.getCrls();
130             ASN1Set crlList = createBerSetFromCrls(crls);
131             ContentInfo encryptInfo = new ContentInfo(CMSObjectIdentifiers.data, new DEROctetString(content));
132             SignedData sd = new SignedData(new DERSet(digestAlgIds), encryptInfo, certList, crlList,
133                     new DERSet(signerInfos));
134             ContentInfo contentInfo = new ContentInfo(CMSObjectIdentifiers.signedData, sd);
135             return contentInfo.getEncoded("DER");
136         } catch (OperatorCreationException | IOException | CertificateEncodingException | CRLException e) {
137             LOGGER.debug(e.getMessage(), e);
138             CustomException.throwException(ERROR.SIGN_ERROR, e.getMessage());
139         }
140         return NO_BYTE;
141     }
142 
generateSignerIdentifier(X509Certificate certificate)143     private static SignerIdentifier generateSignerIdentifier(X509Certificate certificate)
144             throws CertificateEncodingException {
145         return new SignerIdentifier(new IssuerAndSerialNumber(
146                 (new JcaX509CertificateHolder(certificate)).toASN1Structure()));
147     }
148 
generatePKCS9Attributes(byte[] digest)149     private static ASN1Set generatePKCS9Attributes(byte[] digest) {
150         ASN1EncodableVector vector = new ASN1EncodableVector();
151         Attribute signTime = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_signingTime,
152                 new DERSet(new Time(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()))));
153         Attribute contentType = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_contentType,
154                 new DERSet(PKCSObjectIdentifiers.data));
155         Attribute digestAtt = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_messageDigest,
156                 new DERSet(new DEROctetString(digest)));
157         vector.add(signTime);
158         vector.add(contentType);
159         vector.add(digestAtt);
160         return new DERSet(vector);
161     }
162 
getContentDigest(byte[] content, AlgorithmIdentifier digestAlgorithmIdentifier)163     private static byte[] getContentDigest(byte[] content, AlgorithmIdentifier digestAlgorithmIdentifier)
164             throws OperatorCreationException, IOException {
165         DigestCalculatorProvider digestCalculatorProvider = (new JcaDigestCalculatorProviderBuilder()).build();
166         DigestCalculator digestCalculator = digestCalculatorProvider.get(digestAlgorithmIdentifier);
167         digestCalculator.getOutputStream().write(content);
168         return digestCalculator.getDigest();
169     }
170 
createBerSetFromCrls(List<X509CRL> crls)171     private static ASN1Set createBerSetFromCrls(List<X509CRL> crls) throws CRLException {
172         if (crls != null && crls.size() != 0) {
173             ASN1EncodableVector vector = new ASN1EncodableVector(crls.size());
174             for (X509CRL crl : crls) {
175                 vector.add((new JcaX509CRLHolder(crl)).toASN1Structure());
176             }
177             return new BERSet(vector);
178         } else {
179             return null;
180         }
181     }
182 
createBerSetFromCerts(List<X509Certificate> certs)183     private static ASN1Set createBerSetFromCerts(List<X509Certificate> certs) throws CertificateEncodingException {
184         if (certs != null && certs.size() != 0) {
185             ASN1EncodableVector vector = new ASN1EncodableVector(certs.size());
186             for (X509Certificate cert : certs) {
187                 vector.add((new JcaX509CertificateHolder(cert)).toASN1Structure());
188             }
189             return new BERSet(vector);
190         } else {
191             return null;
192         }
193     }
194 }
195