• 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.hap.provider;
17 
18 import com.google.gson.JsonElement;
19 import com.google.gson.JsonObject;
20 import com.google.gson.JsonParseException;
21 import com.google.gson.JsonParser;
22 import com.ohos.hapsigntool.api.model.Options;
23 import com.ohos.hapsigntool.error.CustomException;
24 import com.ohos.hapsigntool.hap.config.SignerConfig;
25 import com.ohos.hapsigntool.hap.entity.SigningBlock;
26 import com.ohos.hapsigntool.hap.exception.InvalidParamsException;
27 import com.ohos.hapsigntool.hap.exception.MissingParamsException;
28 import com.ohos.hapsigntool.hap.exception.ProfileException;
29 import com.ohos.hapsigntool.hap.exception.SignatureException;
30 import com.ohos.hapsigntool.hap.exception.VerifyCertificateChainException;
31 import com.ohos.hapsigntool.hap.exception.HapFormatException;
32 import com.ohos.hapsigntool.hap.sign.SignBin;
33 import com.ohos.hapsigntool.hap.sign.SignHap;
34 import com.ohos.hapsigntool.hap.sign.SignatureAlgorithm;
35 import com.ohos.hapsigntool.hap.verify.VerifyUtils;
36 import com.ohos.hapsigntool.utils.CertificateUtils;
37 import com.ohos.hapsigntool.utils.DigestUtils;
38 import com.ohos.hapsigntool.utils.EscapeCharacter;
39 import com.ohos.hapsigntool.utils.HapUtils;
40 import com.ohos.hapsigntool.utils.ParamConstants;
41 import com.ohos.hapsigntool.utils.ParamProcessUtil;
42 import com.ohos.hapsigntool.utils.StringUtils;
43 import com.ohos.hapsigntool.zip.ByteBufferZipDataInput;
44 import com.ohos.hapsigntool.zip.RandomAccessFileZipDataInput;
45 import com.ohos.hapsigntool.zip.RandomAccessFileZipDataOutput;
46 import com.ohos.hapsigntool.zip.ZipDataInput;
47 import com.ohos.hapsigntool.zip.ZipDataOutput;
48 import com.ohos.hapsigntool.zip.ZipFileInfo;
49 import com.ohos.hapsigntool.zip.ZipUtils;
50 
51 import org.apache.logging.log4j.LogManager;
52 import org.apache.logging.log4j.Logger;
53 import org.bouncycastle.cms.CMSException;
54 import org.bouncycastle.cms.CMSSignedData;
55 import org.bouncycastle.jce.provider.BouncyCastleProvider;
56 
57 import java.io.File;
58 import java.io.FileOutputStream;
59 import java.io.IOException;
60 import java.io.RandomAccessFile;
61 import java.nio.ByteBuffer;
62 import java.nio.charset.StandardCharsets;
63 import java.nio.file.Files;
64 import java.nio.file.StandardCopyOption;
65 import java.security.InvalidKeyException;
66 import java.security.Security;
67 import java.security.cert.CertificateException;
68 import java.security.cert.X509CRL;
69 import java.security.cert.X509Certificate;
70 import java.util.ArrayList;
71 import java.util.Collections;
72 import java.util.HashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Set;
76 import java.util.TimeZone;
77 import java.util.jar.JarFile;
78 import java.util.jar.JarOutputStream;
79 
80 /**
81  * Sign provider super class
82  *
83  * @since 2021-12-14
84  */
85 public abstract class SignProvider {
86     private static final Logger LOGGER = LogManager.getLogger(SignProvider.class);
87     private static final List<String> VALID_SIGN_ALG_NAME = new ArrayList<String>();
88     private static final List<String> PARAMETERS_NEED_ESCAPE = new ArrayList<String>();
89     private static final long TIMESTAMP = 1230768000000L;
90     private static final int COMPRESSION_MODE = 9;
91     /**
92      * list of hap signature optional blocks
93      */
94     protected List<SigningBlock> optionalBlocks = new ArrayList<SigningBlock>();
95 
96     /**
97      * parameters only used in signing
98      */
99     protected Map<String, String> signParams = new HashMap<String, String>();
100 
101     /**
102      * Read data of optional blocks from file user inputted.
103      *
104      * @throws InvalidParamsException Exception occurs when the input is invalid.
105      */
loadOptionalBlocks()106     protected void loadOptionalBlocks() throws InvalidParamsException {
107         String property = signParams.get(ParamConstants.PARAM_BASIC_PROPERTY);
108         loadOptionalBlock(property, HapUtils.HAP_PROPERTY_BLOCK_ID);
109 
110         String profile = signParams.get(ParamConstants.PARAM_BASIC_PROFILE);
111         loadOptionalBlock(profile, HapUtils.HAP_PROFILE_BLOCK_ID);
112 
113         String proofOfRotation = signParams.get(ParamConstants.PARAM_BASIC_PROOF);
114         loadOptionalBlock(proofOfRotation, HapUtils.HAP_PROOF_OF_ROTATION_BLOCK_ID);
115     }
116 
loadOptionalBlock(String file, int type)117     private void loadOptionalBlock(String file, int type) throws InvalidParamsException {
118         if (!checkStringIsNotNullAndEmity(file)) {
119             return;
120         }
121         if (!checkFile(file)) {
122             LOGGER.error("check file failed");
123             throw new InvalidParamsException("Invalid file: " + file + ", filetype: " + type);
124         }
125         try {
126             byte[] optionalBlockBytes = HapUtils.readFileToByte(file);
127             if (optionalBlockBytes == null || optionalBlockBytes.length <= 0) {
128                 LOGGER.warn("Optional block is null!");
129                 return;
130             }
131             optionalBlocks.add(new SigningBlock(type, optionalBlockBytes));
132         } catch (IOException e) {
133             LOGGER.error("read file error", e);
134             throw new InvalidParamsException("Invalid file: " + file + " is not readable. filetype: " + type);
135         }
136     }
137 
138     /**
139      * check if the input path is a file
140      * @param filePath input file path
141      * @return true, if path is a file and can be read
142      */
checkFile(String filePath)143     private boolean checkFile(String filePath) {
144         if (!(checkStringIsNotNullAndEmity(filePath))) {
145             LOGGER.error("fileName is null");
146             return false;
147         }
148         File file = new File(filePath);
149         if (!file.canRead() || !file.isFile()) {
150             LOGGER.error(filePath + " not exist or can not read!");
151             return false;
152         }
153         return true;
154     }
155 
checkStringIsNotNullAndEmity(String str)156     private boolean checkStringIsNotNullAndEmity(String str) {
157         return !(str == null || "".equals(str));
158     }
159 
160     /**
161      * Get certificate chain used to sign.
162      *
163      * @return list of x509 certificates.
164      */
getPublicCerts()165     private List<X509Certificate> getPublicCerts() {
166         String publicCertsFile = signParams.get(ParamConstants.PARAM_LOCAL_PUBLIC_CERT);
167         if (StringUtils.isEmpty(publicCertsFile)) {
168             return Collections.emptyList();
169         }
170         return getCertificateChainFromFile(publicCertsFile);
171     }
172 
173     /**
174      * get certificate revocation list used to sign
175      *
176      * @return certificate revocation list
177      */
getCrl()178     public X509CRL getCrl() {
179         return null;
180     }
181 
182     /**
183      * Create SignerConfig by certificate chain and certificate revocation list.
184      *
185      * @param certificates certificate chain
186      * @param crl certificate revocation list
187      * @return Object of SignerConfig
188      * @throws InvalidKeyException on error when the key is invalid.
189      */
createSignerConfigs(List<X509Certificate> certificates, X509CRL crl, Options options)190     public SignerConfig createSignerConfigs(List<X509Certificate> certificates, X509CRL crl, Options options)
191             throws InvalidKeyException {
192         SignerConfig signerConfig = new SignerConfig();
193         signerConfig.fillParameters(this.signParams);
194         signerConfig.setCertificates(certificates);
195         signerConfig.setOptions(options);
196 
197         List<SignatureAlgorithm> signatureAlgorithms = new ArrayList<SignatureAlgorithm>();
198         signatureAlgorithms.add(
199             ParamProcessUtil.getSignatureAlgorithm(this.signParams.get(ParamConstants.PARAM_BASIC_SIGANTURE_ALG)));
200         signerConfig.setSignatureAlgorithms(signatureAlgorithms);
201 
202         if (crl != null) {
203             signerConfig.setX509CRLs(Collections.singletonList(crl));
204         }
205         return signerConfig;
206     }
207 
208     /**
209      * sign bin file
210      *
211      * @param options parameters used to sign bin file
212      * @return true, if sign successfully.
213      */
signBin(Options options)214     public boolean signBin(Options options) {
215         Security.addProvider(new BouncyCastleProvider());
216         List<X509Certificate> publicCert = null;
217         SignerConfig signerConfig;
218         try {
219             // 1. check the parameters
220             checkParams(options);
221 
222             // 2. load optionalBlocks
223             loadOptionalBlocks();
224 
225             // 3. get x509 verify certificate
226             publicCert = getPublicCerts();
227 
228             checkProfileValid(publicCert);
229 
230             // 4. Get x509 CRL
231             X509CRL crl = getCrl();
232 
233             // 5. Create signer configs, which contains public cert and crl info.
234             signerConfig = createSignerConfigs(publicCert, crl, options);
235         } catch (InvalidKeyException | InvalidParamsException | MissingParamsException | ProfileException e) {
236             LOGGER.error("create signer configs failed.", e);
237             printErrorLogWithoutStack(e);
238             return false;
239         }
240 
241         /* 6. make signed file into output file. */
242         if (!SignBin.sign(signerConfig, signParams)) {
243             LOGGER.error("hap-sign-tool: error: Sign bin internal failed.");
244             return false;
245         }
246         LOGGER.info("Sign success");
247         return true;
248     }
249 
250     /**
251      * sign hap file
252      *
253      * @param options parameters used to sign hap file
254      * @return true, if sign successfully
255      */
sign(Options options)256     public boolean sign(Options options) {
257         Security.addProvider(new BouncyCastleProvider());
258         List<X509Certificate> publicCerts = null;
259         File output = null;
260         File tmpOutput = null;
261         boolean ret = false;
262         boolean pathOverlap = false;
263         try {
264             // 1. check the parameters
265             checkParams(options);
266 
267             // 2. get x509 verify certificate
268             publicCerts = getPublicCerts();
269 
270             // 3. load optionalBlocks
271             loadOptionalBlocks();
272 
273             checkProfileValid(publicCerts);
274 
275             X509CRL crl = getCrl();
276             File input = new File(signParams.get(ParamConstants.PARAM_BASIC_INPUT_FILE));
277             output = new File(signParams.get(ParamConstants.PARAM_BASIC_OUTPUT_FILE));
278             if (input.getCanonicalPath().equals(output.getCanonicalPath())) {
279                 tmpOutput = File.createTempFile("signedHap", ".hap");
280                 tmpOutput.deleteOnExit();
281                 pathOverlap = true;
282             } else {
283                 tmpOutput = output;
284             }
285             // copy file and Alignment
286             int alignment = Integer.parseInt(signParams.get(ParamConstants.PARAM_BASIC_ALIGNMENT));
287             copyFileAndAlignment(input, tmpOutput, alignment);
288             // generate sign block and output signedHap
289             try (RandomAccessFile outputHap = new RandomAccessFile(tmpOutput, "rw")) {
290                 ZipDataInput outputHapIn = new RandomAccessFileZipDataInput(outputHap);
291                 ZipFileInfo zipInfo = ZipUtils.findZipInfo(outputHapIn);
292                 long centralDirectoryOffset = zipInfo.getCentralDirectoryOffset();
293                 ZipDataInput beforeCentralDir = outputHapIn.slice(0, centralDirectoryOffset);
294                 ByteBuffer centralDirBuffer =
295                     outputHapIn.createByteBuffer(centralDirectoryOffset, zipInfo.getCentralDirectorySize());
296                 ZipDataInput centralDirectory = new ByteBufferZipDataInput(centralDirBuffer);
297 
298                 ByteBuffer eocdBuffer = zipInfo.getEocd();
299                 ZipDataInput eocd = new ByteBufferZipDataInput(eocdBuffer);
300 
301                 SignerConfig signerConfig = createSignerConfigs(publicCerts, crl, options);
302                 ZipDataInput[] contents = {beforeCentralDir, centralDirectory, eocd};
303                 byte[] signingBlock = SignHap.sign(contents, signerConfig, optionalBlocks);
304                 long newCentralDirectoryOffset = centralDirectoryOffset + signingBlock.length;
305                 ZipUtils.setCentralDirectoryOffset(eocdBuffer, newCentralDirectoryOffset);
306                 LOGGER.info("Generate signing block success, begin write it to output file");
307 
308                 outputSignedFile(outputHap, centralDirectoryOffset, signingBlock, centralDirectory, eocdBuffer);
309                 ret = true;
310             }
311         } catch (IOException | InvalidKeyException | HapFormatException | MissingParamsException
312             | InvalidParamsException | ProfileException | CustomException e) {
313             printErrorLogWithoutStack(e);
314             ret = false;
315         } catch (SignatureException e) {
316             printErrorLog(e);
317             ret = false;
318         }
319 
320         return doAfterSign(ret, pathOverlap, tmpOutput, output);
321     }
322 
outputSignedFile(RandomAccessFile outputHap, long centralDirectoryOffset, byte[] signingBlock, ZipDataInput centralDirectory, ByteBuffer eocdBuffer)323     private void outputSignedFile(RandomAccessFile outputHap, long centralDirectoryOffset,
324         byte[] signingBlock, ZipDataInput centralDirectory, ByteBuffer eocdBuffer) throws IOException {
325         ZipDataOutput outputHapOut = new RandomAccessFileZipDataOutput(outputHap, centralDirectoryOffset);
326         outputHapOut.write(signingBlock, 0, signingBlock.length);
327         centralDirectory.copyTo(0, centralDirectory.size(), outputHapOut);
328         outputHapOut.write(eocdBuffer);
329     }
330 
doAfterSign(boolean isSuccess, boolean pathOverlap, File tmpOutput, File output)331     private boolean doAfterSign(boolean isSuccess, boolean pathOverlap, File tmpOutput, File output) {
332         boolean ret = isSuccess;
333         if (ret && pathOverlap) {
334             try {
335                 Files.move(tmpOutput.toPath(), output.toPath(), StandardCopyOption.REPLACE_EXISTING);
336             } catch (IOException e) {
337                 printErrorLog(e);
338                 ret = false;
339             }
340         }
341         if ((!ret) && (!pathOverlap) && (output != null)) {
342             output.deleteOnExit();
343         }
344 
345         if (ret) {
346             LOGGER.info("Sign Hap success!");
347         }
348         return ret;
349     }
350 
printErrorLog(Exception e)351     private void printErrorLog(Exception e) {
352         if (e != null) {
353             LOGGER.error("hap-sign-tool: error: {}", e.getMessage(), e);
354         }
355     }
356 
printErrorLogWithoutStack(Exception e)357     private void printErrorLogWithoutStack(Exception e) {
358         if (e != null) {
359             LOGGER.error("hap-sign-tool: error: {}", e.getMessage());
360         }
361     }
362 
copyFileAndAlignment(File input, File tmpOutput, int alignment)363     private void copyFileAndAlignment(File input, File tmpOutput, int alignment) throws IOException {
364         try (JarFile inputJar = new JarFile(input, false);
365             FileOutputStream outputFile = new FileOutputStream(tmpOutput);
366             JarOutputStream outputJar = new JarOutputStream(outputFile)) {
367             long timestamp = TIMESTAMP;
368             timestamp -= TimeZone.getDefault().getOffset(timestamp);
369             outputJar.setLevel(COMPRESSION_MODE);
370             List<String> entryNames = SignHap.getEntryNamesFromHap(inputJar);
371             SignHap.copyFiles(entryNames, inputJar, outputJar, timestamp, alignment);
372         }
373     }
374 
375     static {
376         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA256_ECDSA);
377         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA384_ECDSA);
378         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA512_ECDSA);
379         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA256_RSA_PSS);
380         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA384_RSA_PSS);
381         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA512_RSA_PSS);
382         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA256_RSA_MGF1);
383         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA384_RSA_MGF1);
384         VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA512_RSA_MGF1);
385     }
386 
387     /**
388      * check signature algorithm
389      *
390      * @throws InvalidParamsException Exception occurs when the inputted sign algorithm is invalid.
391      */
checkSignatureAlg()392     private void checkSignatureAlg() throws InvalidParamsException {
393         String signAlg = signParams.get( ParamConstants.PARAM_BASIC_SIGANTURE_ALG).trim();
394         for (String validAlg : VALID_SIGN_ALG_NAME) {
395             if (validAlg.equalsIgnoreCase(signAlg)) {
396                 return;
397             }
398         }
399         LOGGER.error("Unsupported signature algorithm :" + signAlg);
400         throw new InvalidParamsException("Invalid parameter: Sign Alg");
401     }
402 
403     /**
404      * check alignment
405      */
checkSignAlignment()406     protected void checkSignAlignment() {
407         if (!signParams.containsKey(ParamConstants.PARAM_BASIC_ALIGNMENT)) {
408             signParams.put(ParamConstants.PARAM_BASIC_ALIGNMENT, ParamConstants.ALIGNMENT);
409         }
410     }
411 
412     /**
413      * Get CN value of developer certificate from profile.
414      *
415      * @param buildInfoObject json obect of buildInfo in profile.
416      * @return Object of development-certificate.
417      */
getDevelopmentCertificate(JsonObject buildInfoObject)418     private X509Certificate getDevelopmentCertificate(JsonObject buildInfoObject) {
419         final String developmentCertElememt = "development-certificate";
420         String developmentCertificate = buildInfoObject.get(developmentCertElememt).getAsString();
421         return DigestUtils.decodeBase64ToX509Certifate(developmentCertificate);
422     }
423 
424     /**
425      * Get CN value of release certificate from profile.
426      *
427      * @param buildInfoObject json obect of buildInfo in profile.
428      * @return Object of distribution-certificate.
429      */
getReleaseCertificate(JsonObject buildInfoObject)430     private X509Certificate getReleaseCertificate(JsonObject buildInfoObject) {
431         final String distributeCertElememt = "distribution-certificate";
432         String distributeCertificate = buildInfoObject.get(distributeCertElememt).getAsString();
433         return DigestUtils.decodeBase64ToX509Certifate(distributeCertificate);
434     }
435 
getCertificateCN(X509Certificate cert)436     private String getCertificateCN(X509Certificate cert) {
437         if (cert == null) {
438             return "";
439         }
440         String valueOfDN = cert.getSubjectDN().toString();
441         valueOfDN = valueOfDN.replace("\"", "");
442         String[] arrayDN = valueOfDN.split(",");
443         for (String element : arrayDN) {
444             if (element.trim().startsWith("CN=")) {
445                 return element.split("=")[1];
446             }
447         }
448         return "";
449     }
450 
findProfileFromOptionalBlocks()451     private byte[] findProfileFromOptionalBlocks() {
452         byte[] profile = new byte[0];
453         for (SigningBlock optionalBlock : optionalBlocks) {
454             if (optionalBlock.getType() == HapUtils.HAP_PROFILE_BLOCK_ID) {
455                 profile = optionalBlock.getValue();
456             }
457         }
458         return profile;
459     }
460 
461     /**
462      * Check profile is valid. A valid profile must include type and
463      * certificate which has a non-empty value of DN.
464      *
465      * @param inputCerts certificates inputted by user.
466      * @throws ProfileException Exception occurs when profile is invalid.
467      */
checkProfileValid(List<X509Certificate> inputCerts)468     private void checkProfileValid(List<X509Certificate> inputCerts) throws ProfileException {
469         try {
470             byte[] profile = findProfileFromOptionalBlocks();
471             boolean isProfileWithoutSign = ParamConstants.ProfileSignFlag.UNSIGNED_PROFILE.getSignFlag().equals(
472                     signParams.get(ParamConstants.PARAM_BASIC_PROFILE_SIGNED));
473             String content;
474             if (!isProfileWithoutSign) {
475                 CMSSignedData cmsSignedData = new CMSSignedData(profile);
476                 boolean verifyResult = VerifyUtils.verifyCmsSignedData(cmsSignedData);
477                 if (!verifyResult) {
478                     throw new ProfileException("Verify profile pkcs7 failed! Profile is invalid.");
479                 }
480                 Object contentObj = cmsSignedData.getSignedContent().getContent();
481                 if (!(contentObj instanceof byte[])) {
482                     throw new ProfileException("Check profile failed, signed profile content is not byte array!");
483                 }
484                 content = new String((byte[]) contentObj, StandardCharsets.UTF_8);
485             } else {
486                 content = new String(profile, StandardCharsets.UTF_8);
487             }
488             JsonElement parser = JsonParser.parseString(content);
489             JsonObject profileJson = parser.getAsJsonObject();
490             checkProfileInfo(profileJson, inputCerts);
491         } catch (CMSException e) {
492             throw new ProfileException("Verify profile pkcs7 failed! Profile is invalid.", e);
493         } catch (JsonParseException e) {
494             throw new ProfileException("Invalid parameter: profile content is not a JSON.", e);
495         }
496     }
497 
checkProfileInfo(JsonObject profileJson, List<X509Certificate> inputCerts)498     private void checkProfileInfo(JsonObject profileJson, List<X509Certificate> inputCerts) throws ProfileException {
499         String profileTypeKey = "type";
500         String profileType = profileJson.get(profileTypeKey).getAsString();
501         if (profileType == null || profileType.length() == 0) {
502             throw new ProfileException("Get profile type error!");
503         }
504         String buildInfoMember = "bundle-info";
505         JsonObject buildInfoObject = profileJson.getAsJsonObject(buildInfoMember);
506         X509Certificate certInProfile;
507         if (profileType.equalsIgnoreCase("release")) {
508             certInProfile = getReleaseCertificate(buildInfoObject);
509         } else if (profileType.equalsIgnoreCase("debug")) {
510             certInProfile = getDevelopmentCertificate(buildInfoObject);
511         } else {
512             throw new ProfileException("Unsupported profile type!");
513         }
514         if (!inputCerts.isEmpty() && !checkInputCertMatchWithProfile(inputCerts.get(0), certInProfile)) {
515                 throw new ProfileException("input certificates do not match with profile!");
516         }
517         String cn = getCertificateCN(certInProfile);
518         LOGGER.info("certificate in profile: {}", cn);
519         if (cn.isEmpty()) {
520             throw new ProfileException("Common name of certificate is empty!");
521         }
522     }
523 
524     /**
525      * check whether certificate inputted by user is matched with the certificate in profile.
526      *
527      * @param inputCert certificates inputted by user.
528      * @param certInProfile the certificate in profile.
529      * @return true, if it is match.
530      */
checkInputCertMatchWithProfile(X509Certificate inputCert, X509Certificate certInProfile)531     protected boolean checkInputCertMatchWithProfile(X509Certificate inputCert, X509Certificate certInProfile) {
532         return true;
533     }
534 
535     /**
536      * Check input parameters is valid. And put valid parameters into signParams.
537      *
538      * @param options parameters inputted by user.
539      * @throws MissingParamsException Exception occurs when the required parameters are not entered.
540      * @throws InvalidParamsException Exception occurs when the required parameters are invalid.
541      */
checkParams(Options options)542     public void checkParams(Options options) throws MissingParamsException, InvalidParamsException {
543         String[] paramFileds = {
544             ParamConstants.PARAM_BASIC_ALIGNMENT,
545             ParamConstants.PARAM_BASIC_SIGANTURE_ALG,
546             ParamConstants.PARAM_BASIC_INPUT_FILE,
547             ParamConstants.PARAM_BASIC_OUTPUT_FILE,
548             ParamConstants.PARAM_BASIC_PRIVATE_KEY,
549             ParamConstants.PARAM_BASIC_PROFILE,
550             ParamConstants.PARAM_BASIC_PROOF,
551             ParamConstants.PARAM_BASIC_PROPERTY,
552             ParamConstants.PARAM_REMOTE_SERVER,
553             ParamConstants.PARAM_BASIC_PROFILE_SIGNED
554         };
555         Set<String> paramSet = ParamProcessUtil.initParamField(paramFileds);
556 
557         for (String paramKey : options.keySet()) {
558             if (paramSet.contains(paramKey)) {
559                 signParams.put(paramKey, getParamValue(paramKey, options.getString(paramKey)));
560             }
561         }
562         if (!signParams.containsKey(ParamConstants.PARAM_BASIC_PROFILE_SIGNED)) {
563             signParams.put(ParamConstants.PARAM_BASIC_PROFILE_SIGNED, "1");
564         }
565         checkSignatureAlg();
566         checkSignAlignment();
567     }
568 
569     static {
570         PARAMETERS_NEED_ESCAPE.add(ParamConstants.PARAM_REMOTE_CODE);
571         PARAMETERS_NEED_ESCAPE.add(ParamConstants.PARAM_LOCAL_JKS_KEYSTORE_CODE);
572         PARAMETERS_NEED_ESCAPE.add(ParamConstants.PARAM_LOCAL_JKS_KEYALIAS_CODE);
573     }
574 
575     /**
576      * Get parameters from inputted strings. This function unescape some escaped parameters and return it.
577      *
578      * @param paramName the name of parameter
579      * @param paramValue the value of parameter
580      * @return parameter value in the correct form.
581      */
getParamValue(String paramName, String paramValue)582     protected String getParamValue(String paramName, String paramValue) {
583         for ( String name : PARAMETERS_NEED_ESCAPE) {
584             if (name.equals(paramName)) {
585                 return EscapeCharacter.unescape(paramValue);
586             }
587         }
588         return paramValue;
589     }
590 
getCertificateChainFromFile(String certChianFile)591     private List<X509Certificate> getCertificateChainFromFile(String certChianFile) {
592         try {
593             return CertificateUtils.getCertListFromFile(certChianFile);
594         } catch (CertificateException e) {
595             LOGGER.error("File content is not certificates! " + e.getMessage());
596         } catch (IOException e) {
597             LOGGER.error("Certificate file exception: " + e.getMessage());
598         } catch (VerifyCertificateChainException e) {
599             LOGGER.error(e.getMessage());
600         }
601         return Collections.emptyList();
602     }
603 }
604