• 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.cert;
17 
18 import com.ohos.hapsigntool.api.LocalizationAdapter;
19 import com.ohos.hapsigntool.api.ServiceApi;
20 import com.ohos.hapsigntool.api.model.Options;
21 import com.ohos.hapsigntool.error.CustomException;
22 import com.ohos.hapsigntool.error.ERROR;
23 import com.ohos.hapsigntool.utils.ValidateUtils;
24 import org.apache.logging.log4j.LogManager;
25 import org.apache.logging.log4j.Logger;
26 import org.bouncycastle.asn1.x500.X500Name;
27 import org.bouncycastle.asn1.x509.KeyPurposeId;
28 import org.bouncycastle.asn1.x509.KeyUsage;
29 import org.bouncycastle.jce.provider.BouncyCastleProvider;
30 import org.bouncycastle.operator.ContentSigner;
31 import org.bouncycastle.operator.OperatorCreationException;
32 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
33 import org.bouncycastle.pkcs.PKCS10CertificationRequest;
34 import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
35 
36 import java.io.IOException;
37 import java.security.KeyPair;
38 import java.security.PrivateKey;
39 import java.security.cert.X509Certificate;
40 import java.security.interfaces.ECPrivateKey;
41 import java.security.interfaces.RSAPrivateKey;
42 import java.util.regex.Matcher;
43 import java.util.regex.Pattern;
44 
45 /**
46  * CertTools.
47  *
48  * @since 2021/12/28
49  */
50 public final class CertTools {
51     /**
52      * Ten years, in days.
53      */
54     private static final int TEN_YEAR_DAY = 3650;
55 
56     /**
57      * Three years, in dats.
58      */
59     private static final int THREE_YEAR_DAY = 1095;
60 
61     /**
62      * Empty csr array.
63      */
64     private static final byte[] NO_CSR = {};
65 
66     /**
67      * ECC.
68      */
69     private static final String ECC = "ECDSA";
70 
71     /**
72      * Compile String.
73      */
74     private static final Pattern SIGN_ALGORITHM_PATTERN = Pattern.compile("^SHA([0-9]{3})with([A-Z]{1,5})$");
75 
76     /**
77      * Logger.
78      */
79     private static final Logger LOGGER = LogManager.getLogger(ServiceApi.class);
80 
CertTools()81     private CertTools() {
82     }
83 
84     /**
85      * Generate root ca certificate.
86      *
87      * @param keyPair keyPair
88      * @param csr     csr
89      * @param adapter adapter
90      * @return X509Certificate
91      */
generateRootCaCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter)92     public static X509Certificate generateRootCaCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter) {
93         try {
94             return new CertBuilder(keyPair, adapter.getIssuer(), csr,
95                     adapter.getOptions().getInt(Options.VALIDITY, TEN_YEAR_DAY))
96                     .withAuthorityKeyIdentifier(CertLevel.ROOT_CA)
97                     .withBasicConstraints(CertLevel.ROOT_CA, true, true,
98                             adapter.getBasicConstraintsPathLen())
99                     .withKeyUsages(new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign), true)
100                     .withExtKeyUsages(null, false)
101                     .build(adapter.getSignAlg());
102         } catch (IOException exception) {
103             LOGGER.debug(exception.getMessage(), exception);
104             CustomException.throwException(ERROR.IO_CERT_ERROR, exception.getMessage());
105         }
106         return null;
107     }
108 
109     /**
110      * Generate sub ca certificate.
111      *
112      * @param keyPair keyPair
113      * @param csr     csr
114      * @param adapter parameter
115      * @return X509Certificate
116      */
generateSubCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter)117     public static X509Certificate generateSubCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter) {
118         try {
119             return new CertBuilder(keyPair, adapter.getIssuer(), csr,
120                     adapter.getOptions().getInt(Options.VALIDITY, TEN_YEAR_DAY))
121                     .withAuthorityKeyIdentifier(CertLevel.SUB_CA)
122                     .withBasicConstraints(CertLevel.SUB_CA, true, true,
123                             adapter.getBasicConstraintsPathLen())
124                     .withKeyUsages(new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign), true)
125                     .build(adapter.getSignAlg());
126         } catch (IOException exception) {
127             LOGGER.debug(exception.getMessage(), exception);
128             CustomException.throwException(ERROR.IO_CERT_ERROR, exception.getMessage());
129         }
130         return null;
131     }
132 
133     /**
134      * Generate certificate.
135      *
136      * @param keyPair keyPair
137      * @param csr     csr
138      * @param adapter parameter
139      * @return X509Certificate
140      */
generateCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter)141     public static X509Certificate generateCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter) {
142         try {
143             return new CertBuilder(keyPair, adapter.getIssuer(), csr,
144                     adapter.getOptions().getInt(Options.VALIDITY, THREE_YEAR_DAY))
145                     // Need CertLevel
146                     .withAuthorityKeyIdentifier(CertLevel.ROOT_CA)
147                     .withBasicConstraints(CertLevel.ROOT_CA,
148                             adapter.isBasicConstraintsCritical(),
149                             adapter.isBasicConstraintsCa(),
150                             adapter.getBasicConstraintsPathLen())
151                     .withKeyUsages(adapter.getKeyUsage(), adapter.isKeyUsageCritical())
152                     .withExtKeyUsages(adapter.getExtKeyUsage(), adapter.isExtKeyUsageCritical())
153                     .build(adapter.getSignAlg());
154         } catch (IOException exception) {
155             LOGGER.debug(exception.getMessage(), exception);
156             CustomException.throwException(ERROR.IO_CERT_ERROR, exception.getMessage());
157         }
158         return null;
159     }
160 
161     /**
162      * Generate app certificate.
163      *
164      * @param keyPair keyPair
165      * @param csr     csr
166      * @param adapter adapter
167      * @return X509Certificate
168      */
generateEndCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter, byte[] signingCapabiltyBytes)169     public static X509Certificate generateEndCert(KeyPair keyPair, byte[] csr, LocalizationAdapter adapter,
170                                                   byte[] signingCapabiltyBytes) {
171         try {
172             return new CertBuilder(keyPair, adapter.getIssuer(), csr,
173                     adapter.getOptions().getInt(Options.VALIDITY, THREE_YEAR_DAY))
174                     .withBasicConstraints(CertLevel.END_ENTITY, false, false,
175                             null)
176                     .withKeyUsages(new KeyUsage(KeyUsage.digitalSignature), true)
177                     .withExtKeyUsages(new KeyPurposeId[]{KeyPurposeId.id_kp_codeSigning}, false)
178                     .withSigningCapabilty(signingCapabiltyBytes)
179                     .build(adapter.getSignAlg());
180         } catch (IOException exception) {
181             LOGGER.debug(exception.getMessage(), exception);
182             CustomException.throwException(ERROR.IO_CERT_ERROR, exception.getMessage());
183         }
184         return null;
185     }
186 
187     /**
188      * generateCsr.
189      *
190      * @param keyPair       Applier keypair
191      * @param signAlgorithm sign algorithm
192      * @param subject       Applier subject
193      * @return csr bytes
194      */
generateCsr(KeyPair keyPair, String signAlgorithm, X500Name subject)195     public static byte[] generateCsr(KeyPair keyPair, String signAlgorithm, X500Name subject) {
196         JcaPKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject,
197                 keyPair.getPublic());
198         PKCS10CertificationRequest csr = csrBuilder.build(createFixedContentSigner(keyPair.getPrivate(),
199                 signAlgorithm));
200         try {
201             return csr.getEncoded();
202         } catch (IOException exception) {
203             LOGGER.debug(exception.getMessage(), exception);
204             CustomException.throwException(ERROR.IO_CSR_ERROR, "Not support " + subject);
205             return NO_CSR;
206         }
207     }
208 
209     /**
210      * Auto fix algorithm according key type and create content signer.
211      *
212      * @param privateKey    Sign key
213      * @param signAlgorithm Sign algorithm
214      * @return ContentSigner
215      */
createFixedContentSigner(PrivateKey privateKey, String signAlgorithm)216     public static ContentSigner createFixedContentSigner(PrivateKey privateKey, String signAlgorithm) {
217         Matcher matcher = SIGN_ALGORITHM_PATTERN.matcher(signAlgorithm);
218         ValidateUtils.throwIfNotMatches(matcher.matches(), ERROR.NOT_SUPPORT_ERROR, "Not Support " + signAlgorithm);
219         // Auto fix signAlgorithm error
220         if (privateKey instanceof ECPrivateKey && signAlgorithm.contains("RSA")) {
221             signAlgorithm = signAlgorithm.replace("RSA", ECC);
222         } else {
223             if (privateKey instanceof RSAPrivateKey && signAlgorithm.contains(ECC)) {
224                 signAlgorithm = signAlgorithm.replace(ECC, "RSA");
225             }
226         }
227 
228         JcaContentSignerBuilder jcaContentSignerBuilder = new JcaContentSignerBuilder(signAlgorithm);
229         jcaContentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
230         try {
231             return jcaContentSignerBuilder.build(privateKey);
232         } catch (OperatorCreationException exception) {
233             LOGGER.debug(exception.getMessage(), exception);
234             CustomException.throwException(ERROR.OPERATOR_CREATION_ERROR, exception.getMessage());
235         }
236         return null;
237     }
238 
239 }
240