/** * Copyright 2012 Emmanuel Bourg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jsign; import java.io.File; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import static net.jsign.PESignerHelper.*; /** * Command line interface for signing PE files. * * @author Emmanuel Bourg * @since 1.1 */ public class PESignerCLI { public static void main(String... args) { try { new PESignerCLI().execute(args); } catch (SignerException | ParseException e) { System.err.println("pesign: " + e.getMessage()); if (e.getCause() != null) { e.getCause().printStackTrace(System.err); } System.err.println("Try `pesign --help' for more information."); System.exit(1); } } private Options options; PESignerCLI() { options = new Options(); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_KEYSTORE).withArgName("FILE").withDescription("The keystore file, or the SunPKCS11 configuration file").withType(File.class).create('s')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_STOREPASS).withArgName("PASSWORD").withDescription("The password to open the keystore").create()); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_STORETYPE).withArgName("TYPE").withDescription("The type of the keystore:\n- JKS: Java keystore (.jks files)\n- PKCS12: Standard PKCS#12 keystore (.p12 or .pfx files)\n- PKCS11: PKCS#11 hardware token\n").create()); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_ALIAS).withArgName("NAME").withDescription("The alias of the certificate used for signing in the keystore.").create('a')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_KEYPASS).withArgName("PASSWORD").withDescription("The password of the private key. When using a keystore, this parameter can be omitted if the keystore shares the same password.").create()); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_KEYFILE).withArgName("FILE").withDescription("The file containing the private key. PEM and PVK files are supported. ").withType(File.class).create()); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_CERTFILE).withArgName("FILE").withDescription("The file containing the PKCS#7 certificate chain\n(.p7b or .spc files).").withType(File.class).create('c')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_ALG).withArgName("ALGORITHM").withDescription("The digest algorithm (SHA-1, SHA-256, SHA-384 or SHA-512)").create('d')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_TSAURL).withArgName("URL").withDescription("The URL of the timestamping authority.").create('t')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_TSMODE).withArgName("MODE").withDescription("The timestamping mode (RFC3161 or Authenticode)").create('m')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_TSRETRIES).withArgName("NUMBER").withDescription("The number of retries for timestamping").create('r')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_TSRETRY_WAIT).withArgName("SECONDS").withDescription("The number of seconds to wait between timestamping retries").create('w')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_NAME).withArgName("NAME").withDescription("The name of the application").create('n')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_URL).withArgName("URL").withDescription("The URL of the application").create('u')); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_PROXY_URL).withArgName("URL").withDescription("The URL of the HTTP proxy").create()); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_PROXY_USER).withArgName("NAME").withDescription("The user for the HTTP proxy. If an user is needed.").create()); options.addOption(OptionBuilder.hasArg().withLongOpt(PARAM_PROXY_PASS).withArgName("PASSWORD").withDescription("The password for the HTTP proxy user. If an user is needed.").create()); options.addOption(OptionBuilder.withLongOpt(PARAM_REPLACE).withDescription("Tells if previous signatures should be replaced.").create()); options.addOption(OptionBuilder.withLongOpt("help").withDescription("Print the help").create('h')); } void execute(String... args) throws SignerException, ParseException { DefaultParser parser = new DefaultParser(); CommandLine cmd = parser.parse(options, args); if (cmd.hasOption("help") || args.length == 0) { printHelp(); return; } PESignerHelper helper = new PESignerHelper(new StdOutConsole(), "option"); setOption(PARAM_KEYSTORE, helper, cmd); setOption(PARAM_STOREPASS, helper, cmd); setOption(PARAM_STORETYPE, helper, cmd); setOption(PARAM_ALIAS, helper, cmd); setOption(PARAM_KEYPASS, helper, cmd); setOption(PARAM_KEYFILE, helper, cmd); setOption(PARAM_CERTFILE, helper, cmd); setOption(PARAM_ALG, helper, cmd); setOption(PARAM_TSAURL, helper, cmd); setOption(PARAM_TSMODE, helper, cmd); setOption(PARAM_TSRETRIES, helper, cmd); setOption(PARAM_TSRETRY_WAIT, helper, cmd); setOption(PARAM_NAME, helper, cmd); setOption(PARAM_URL, helper, cmd); setOption(PARAM_PROXY_URL, helper, cmd); setOption(PARAM_PROXY_USER, helper, cmd); setOption(PARAM_PROXY_PASS, helper, cmd); helper.replace(cmd.hasOption("replace")); File file = cmd.getArgList().isEmpty() ? null : new File(cmd.getArgList().get(0)); helper.sign(file); } private void setOption(String key, PESignerHelper helper, CommandLine cmd) throws SignerException { String value = cmd.getOptionValue(key); helper.param(key, value); } private void printHelp() { String header = "Sign and timestamp a Windows executable file.\n\n"; String footer = "\nPlease report suggestions and issues on the GitHub project at https://github.com/ebourg/jsign/issues"; HelpFormatter formatter = new HelpFormatter(); formatter.setOptionComparator(null); formatter.setWidth(85); formatter.setDescPadding(1); formatter.printHelp("java -jar jsign.jar [OPTIONS] FILE", header, options, footer); } }