• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 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.codesigning.sign;
17 
18 import com.ohos.hapsigntool.codesigning.exception.CodeSignErrMsg;
19 import com.ohos.hapsigntool.codesigning.exception.CodeSignException;
20 import com.ohos.hapsigntool.codesigning.utils.CmsUtils;
21 import com.ohos.hapsigntool.codesigning.utils.DigestUtils;
22 import com.ohos.hapsigntool.entity.Pair;
23 import com.ohos.hapsigntool.entity.ContentDigestAlgorithm;
24 import com.ohos.hapsigntool.entity.SignatureAlgorithm;
25 import com.ohos.hapsigntool.hap.config.SignerConfig;
26 import com.ohos.hapsigntool.utils.LogUtils;
27 import org.bouncycastle.asn1.ASN1EncodableVector;
28 import org.bouncycastle.asn1.ASN1Encoding;
29 import org.bouncycastle.asn1.ASN1Integer;
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.ASN1ObjectIdentifier;
35 import org.bouncycastle.asn1.DERUTF8String;
36 import org.bouncycastle.asn1.cms.Time;
37 import org.bouncycastle.asn1.pkcs.Attribute;
38 import org.bouncycastle.asn1.pkcs.ContentInfo;
39 import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber;
40 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
41 import org.bouncycastle.asn1.pkcs.SignedData;
42 import org.bouncycastle.asn1.pkcs.SignerInfo;
43 import org.bouncycastle.cert.jcajce.JcaX509CRLHolder;
44 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
45 import org.bouncycastle.cms.CMSException;
46 import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
47 import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
48 import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
49 import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder;
50 
51 import java.io.IOException;
52 import java.security.InvalidAlgorithmParameterException;
53 import java.security.InvalidKeyException;
54 import java.security.NoSuchAlgorithmException;
55 import java.security.PublicKey;
56 import java.security.Signature;
57 import java.security.SignatureException;
58 import java.security.cert.CRLException;
59 import java.security.cert.CertificateEncodingException;
60 import java.security.cert.X509CRL;
61 import java.security.cert.X509Certificate;
62 import java.security.spec.AlgorithmParameterSpec;
63 import java.util.Date;
64 import java.util.List;
65 
66 /**
67  * BC implementation
68  *
69  * @since 2023/06/05
70  */
71 public class BcSignedDataGenerator implements SignedDataGenerator {
72     /**
73      * OID of the signer identity
74      */
75     public static final String SIGNER_OID = "1.3.6.1.4.1.2011.2.376.1.4.1";
76 
77     private static final LogUtils LOGGER = new LogUtils(BcSignedDataGenerator.class);
78 
79     private static final SignatureAlgorithmIdentifierFinder SIGN_ALG_ID_FINDER
80         = new DefaultSignatureAlgorithmIdentifierFinder();
81 
82     private static final DigestAlgorithmIdentifierFinder DIGEST_ALG_ID_FINDER
83         = new DefaultDigestAlgorithmIdentifierFinder();
84 
85     private String ownerID;
86 
setOwnerID(String ownerID)87     public void setOwnerID(String ownerID) {
88         this.ownerID = ownerID;
89     }
90 
91     @Override
generateSignedData(byte[] content, SignerConfig signConfig)92     public byte[] generateSignedData(byte[] content, SignerConfig signConfig) throws CodeSignException {
93         if (content == null) {
94             throw new CodeSignException(
95                 CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("The content to be signed is empty"));
96         }
97         Pair<DERSet, DERSet> pairDigestAndSignInfo = getSignInfo(content, signConfig);
98         // Unsupported certificate revocation, SignedData's _crls is null
99         SignedData signedData = new SignedData(new ASN1Integer(1), pairDigestAndSignInfo.getFirst(),
100             new ContentInfo(PKCSObjectIdentifiers.data, null), createBerSetFromLst(signConfig.getCertificates()),
101             createBerSetFromLst(null), pairDigestAndSignInfo.getSecond());
102         return encodingUnsignedData(content, signedData);
103     }
104 
getSignInfo(byte[] content, SignerConfig signConfig)105     private Pair<DERSet, DERSet> getSignInfo(byte[] content, SignerConfig signConfig) throws CodeSignException {
106         ASN1EncodableVector signInfoVector = new ASN1EncodableVector();
107         ASN1EncodableVector digestVector = new ASN1EncodableVector();
108         for (SignatureAlgorithm signAlgorithm : signConfig.getSignatureAlgorithms()) {
109             SignerInfo signInfo = createSignInfo(signAlgorithm, content, signConfig);
110             signInfoVector.add(signInfo);
111             digestVector.add(signInfo.getDigestAlgorithm());
112             LOGGER.info("Create a sign info successfully.");
113         }
114         return Pair.create(new DERSet(digestVector), new DERSet(signInfoVector));
115     }
116 
createSignInfo(SignatureAlgorithm signAlgorithm, byte[] unsignedDataDigest, SignerConfig signConfig)117     private SignerInfo createSignInfo(SignatureAlgorithm signAlgorithm, byte[] unsignedDataDigest,
118         SignerConfig signConfig) throws CodeSignException {
119         ContentDigestAlgorithm hashAlgorithm = signAlgorithm.getContentDigestAlgorithm();
120         byte[] digest = computeDigest(unsignedDataDigest, hashAlgorithm.name());
121         ASN1Set authed = getPKCS9Attributes(digest);
122         byte[] codeAuthed = getEncoded(authed);
123         Pair<String, ? extends AlgorithmParameterSpec> signPair = signAlgorithm.getSignatureAlgAndParams();
124         byte[] signBytes = signConfig.getSigner().getSignature(codeAuthed, signPair.getFirst(), signPair.getSecond());
125         if (signBytes == null) {
126             throw new CodeSignException(CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Get signature failed"));
127         }
128         if (signConfig.getCertificates().isEmpty()) {
129             throw new CodeSignException(
130                 CodeSignErrMsg.CERTIFICATES_CONFIGURE_ERROR.toString("No certificate is configured for sign"));
131         }
132         X509Certificate cert = signConfig.getCertificates().get(0);
133         if (!verifySignFromServer(cert.getPublicKey(), signBytes, signPair, codeAuthed)) {
134             throw new CodeSignException(
135                 CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Verify signed result failed"));
136         }
137         JcaX509CertificateHolder certificateHolder = getJcaX509CertificateHolder(cert);
138         return new SignerInfo(new ASN1Integer(1),
139             new IssuerAndSerialNumber(certificateHolder.getIssuer(), certificateHolder.getSerialNumber()),
140             DIGEST_ALG_ID_FINDER.find(hashAlgorithm.getDigestAlgorithm()), authed,
141             SIGN_ALG_ID_FINDER.find(signPair.getFirst()), new DEROctetString(signBytes), null);
142     }
143 
computeDigest(byte[] unsignedDataDigest, String algorithm)144     private byte[] computeDigest(byte[] unsignedDataDigest, String algorithm) throws CodeSignException {
145         byte[] digest;
146         try {
147             digest = DigestUtils.computeDigest(unsignedDataDigest, algorithm);
148         } catch (NoSuchAlgorithmException e) {
149             throw new CodeSignException(CodeSignErrMsg.ALGORITHM_NOT_SUPPORT_ERROR.toString(algorithm), e);
150         }
151         return digest;
152     }
153 
getEncoded(ASN1Set authed)154     private byte[] getEncoded(ASN1Set authed) throws CodeSignException {
155         byte[] codeAuthed;
156         try {
157             codeAuthed = authed.getEncoded();
158         } catch (IOException e) {
159             throw new CodeSignException(CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Encode data error"), e);
160         }
161         return codeAuthed;
162     }
163 
getJcaX509CRLHolder(X509CRL crl)164     private JcaX509CRLHolder getJcaX509CRLHolder(X509CRL crl) throws CodeSignException {
165         JcaX509CRLHolder crlHolder;
166         try {
167             crlHolder = new JcaX509CRLHolder(crl);
168         } catch (CRLException e) {
169             throw new CodeSignException(CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Create crl failed"), e);
170         }
171         return crlHolder;
172     }
173 
getJcaX509CertificateHolder(X509Certificate cert)174     private JcaX509CertificateHolder getJcaX509CertificateHolder(X509Certificate cert) throws CodeSignException {
175         JcaX509CertificateHolder certificateHolder;
176         try {
177             certificateHolder = new JcaX509CertificateHolder(cert);
178         } catch (CertificateEncodingException e) {
179             throw new CodeSignException(CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Create sign info failed"), e);
180         }
181         return certificateHolder;
182     }
183 
getPKCS9Attributes(byte[] digest)184     private ASN1Set getPKCS9Attributes(byte[] digest) {
185         ASN1EncodableVector table = new ASN1EncodableVector();
186         Attribute signingTimeAttr = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_signingTime,
187             new DERSet(new Time(new Date())));
188         Attribute contentTypeAttr = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_contentType,
189             new DERSet(PKCSObjectIdentifiers.data));
190         Attribute messageDigestAttr = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_messageDigest,
191             new DERSet(new DEROctetString(digest)));
192         table.add(signingTimeAttr);
193         table.add(contentTypeAttr);
194         table.add(messageDigestAttr);
195         if (ownerID != null) {
196             Attribute ownerIDAttr = new Attribute(new ASN1ObjectIdentifier(SIGNER_OID),
197                 new DERSet(new DERUTF8String(ownerID)));
198             table.add(ownerIDAttr);
199         }
200         return new DERSet(table);
201     }
202 
verifySignFromServer(PublicKey publicKey, byte[] signBytes, Pair<String, ? extends AlgorithmParameterSpec> signPair, byte[] authed)203     private boolean verifySignFromServer(PublicKey publicKey, byte[] signBytes,
204         Pair<String, ? extends AlgorithmParameterSpec> signPair, byte[] authed) throws CodeSignException {
205         try {
206             Signature signature = Signature.getInstance(signPair.getFirst());
207             signature.initVerify(publicKey);
208             if (signPair.getSecond() != null) {
209                 signature.setParameter(signPair.getSecond());
210             }
211             signature.update(authed);
212             if (!signature.verify(signBytes)) {
213                 throw new CodeSignException(CodeSignErrMsg.SIGNATURE_VERIFY_FAILED_ERROR.toString());
214             }
215             return true;
216         } catch (InvalidKeyException | SignatureException e) {
217             LOGGER.error("The generated signature could not be verified " + " using the public key in the certificate",
218                 e);
219         } catch (NoSuchAlgorithmException e) {
220             LOGGER.error("The generated signature " + signPair.getFirst()
221                 + " could not be verified using the public key in the certificate", e);
222         } catch (InvalidAlgorithmParameterException e) {
223             LOGGER.error("The generated signature " + signPair.getSecond()
224                 + " could not be verified using the public key in the certificate", e);
225         }
226         return false;
227     }
228 
createBerSetFromLst(List<?> lists)229     private ASN1Set createBerSetFromLst(List<?> lists) throws CodeSignException {
230         if (lists == null || lists.size() == 0) {
231             return null;
232         }
233         ASN1EncodableVector vector = new ASN1EncodableVector();
234         for (Object obj : lists) {
235             if (obj instanceof X509CRL) {
236                 vector.add(getJcaX509CRLHolder((X509CRL) obj).toASN1Structure());
237             } else if (obj instanceof X509Certificate) {
238                 vector.add(getJcaX509CertificateHolder((X509Certificate) obj).toASN1Structure());
239             }
240         }
241         return new BERSet(vector);
242     }
243 
encodingUnsignedData(byte[] unsignedDataDigest, SignedData signedData)244     private byte[] encodingUnsignedData(byte[] unsignedDataDigest, SignedData signedData) throws CodeSignException {
245         byte[] signResult;
246         try {
247             ContentInfo contentInfo = new ContentInfo(PKCSObjectIdentifiers.signedData, signedData);
248             signResult = contentInfo.getEncoded(ASN1Encoding.DER);
249         } catch (IOException e) {
250             throw new CodeSignException(CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Encode data error"), e);
251         }
252         verifySignResult(unsignedDataDigest, signResult);
253         return signResult;
254     }
255 
verifySignResult(byte[] unsignedDataDigest, byte[] signResult)256     private void verifySignResult(byte[] unsignedDataDigest, byte[] signResult) throws CodeSignException {
257         boolean result = false;
258         try {
259             result = CmsUtils.verifySignDataWithUnsignedDataDigest(unsignedDataDigest, signResult);
260         } catch (CMSException e) {
261             throw new CodeSignException(
262                 CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("PKCS cms data verify failed"), e);
263         }
264         if (!result) {
265             throw new CodeSignException(
266                 CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("PKCS cms data did not verify"));
267         }
268     }
269 }
270