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