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