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