mitm.common.tools.PfxTool.java Source code

Java tutorial

Introduction

Here is the source code for mitm.common.tools.PfxTool.java

Source

/*
 * Copyright (c) 2010-2011, Martijn Brinkers, Djigzo.
 *
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3, 19 November 2007 as published by the Free Software
 * Foundation.
 *
 * Djigzo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 *
 * If you modify this Program, or any covered work, by linking or
 * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar,
 * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar,
 * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar,
 * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar,
 * wsdl4j-1.6.1.jar (or modified versions of these libraries),
 * containing parts covered by the terms of Eclipse Public License,
 * tyrex license, freemarker license, dom4j license, mx4j license,
 * Spice Software License, Common Development and Distribution License
 * (CDDL), Common Public License (CPL) the licensors of this Program grant
 * you additional permission to convey the resulting work.
 */
package mitm.common.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.util.Enumeration;
import java.util.UUID;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingArgumentException;
import org.apache.commons.cli.MissingOptionException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrBuilder;

/**
 * Tool which can be used to manage PFX files
 *
 * @author Martijn Brinkers
 *
 */
public class PfxTool {
    private static final String COMMAND_NAME = PfxTool.class.getName();

    private String inPassword;
    private String destPassword;
    private String inFile;
    private String destFile;
    private boolean retainAliases;

    private Option inPasswordOption;

    private Option destPasswordOption;

    private Option inOption;

    private Option destOption;

    private Option mergeOption;

    private Option listOption;

    private Option retainAliasesOption;

    private Option helpOption;

    @SuppressWarnings("static-access")
    private Options createCommandLineOptions() {
        Options options = new Options();

        inPasswordOption = OptionBuilder.withArgName("inpass").hasArg()
                .withDescription("Password for the input pfx.").create("inpass");
        inPasswordOption.setRequired(true);
        options.addOption(inPasswordOption);

        destPasswordOption = OptionBuilder.withArgName("destpass").hasArg()
                .withDescription("Password for the destination pfx.").create("destpass");
        destPasswordOption.setRequired(false);
        options.addOption(destPasswordOption);

        inOption = OptionBuilder.withArgName("file").hasArg().withDescription("The filename of the input pfx.")
                .create("in");
        inOption.setRequired(true);
        options.addOption(inOption);

        destOption = OptionBuilder.withArgName("file").hasArg()
                .withDescription("The filename of the destination pfx.").create("dest");
        destOption.setRequired(false);
        options.addOption(destOption);

        mergeOption = OptionBuilder.withDescription("Adds the input pfx to the output pfx.").create("merge");
        mergeOption.setRequired(false);
        options.addOption(mergeOption);

        listOption = OptionBuilder.withDescription("Shows all items from the input pfx.").create("list");
        listOption.setRequired(false);
        options.addOption(listOption);

        helpOption = OptionBuilder.withDescription("Show help").create("help");
        helpOption.setRequired(false);
        options.addOption(helpOption);

        retainAliasesOption = OptionBuilder.withDescription("If enabled, the aliases from the input will be kept.")
                .create("retainaliases");
        retainAliasesOption.setRequired(false);
        options.addOption(retainAliasesOption);

        return options;
    }

    private static KeyStore loadKeyStore(String keyFile, boolean shouldExist, String password) throws Exception {
        File file = new File(keyFile);

        file = file.getAbsoluteFile();

        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        if (shouldExist && !file.exists()) {
            throw new FileNotFoundException(keyFile + " pfx file not found.");
        }

        /* initialize key store */
        char[] pw = password != null ? password.toCharArray() : null;

        if (file.exists()) {
            InputStream input = new FileInputStream(file);
            keyStore.load(input, pw);
            input.close();
        } else {
            // creates an empty keystore
            keyStore.load(null, pw);
        }

        return keyStore;
    }

    private void mergePfx() throws Exception {
        if (StringUtils.isEmpty(destFile)) {
            throw new MissingOptionException(destOption.getOpt() + " is missing.");
        }

        if (StringUtils.isEmpty(destPassword)) {
            throw new MissingOptionException(destPasswordOption.getOpt() + " is missing.");
        }

        KeyStore inStore = loadKeyStore(inFile, true, inPassword);
        KeyStore destStore = loadKeyStore(destFile, false, destPassword);

        Enumeration<String> aliases = inStore.aliases();

        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();

            String destAlias = retainAliases ? alias : UUID.randomUUID().toString() + "_" + alias;

            if (inStore.isKeyEntry(alias)) {
                KeyStore.Entry entry = inStore.getEntry(alias,
                        new KeyStore.PasswordProtection(inPassword.toCharArray()));

                destStore.setEntry(destAlias, entry, new KeyStore.PasswordProtection(destPassword.toCharArray()));
            } else {
                Certificate certificate = inStore.getCertificate(alias);

                destStore.setCertificateEntry(destAlias, certificate);
            }
        }

        destStore.store(new FileOutputStream(destFile), destPassword.toCharArray());
    }

    private static void printKeystoreDetails(KeyStore keyStore) throws KeyStoreException {
        Enumeration<String> aliases = keyStore.aliases();

        int count = 0;

        System.out.println("**** BEGIN ENTRIES ***");

        while (aliases.hasMoreElements()) {
            count++;

            String alias = aliases.nextElement();

            StrBuilder sb = new StrBuilder();

            sb.append("Alias: ").append(alias).append(", key entry: ").append(keyStore.isKeyEntry(alias));

            System.out.println(sb.toString());
        }

        System.out.println("**** END ENTRIES ***");
        System.out.println("Nr of entries: " + count);
    }

    private void listPfx() throws Exception {
        KeyStore keyStore = loadKeyStore(inFile, true, inPassword);

        printKeystoreDetails(keyStore);
    }

    private void handleCommandline(String[] args) throws Exception {
        CommandLineParser parser = new BasicParser();

        Options options = createCommandLineOptions();

        HelpFormatter formatter = new HelpFormatter();

        CommandLine commandLine;

        try {
            commandLine = parser.parse(options, args);
        } catch (ParseException e) {
            formatter.printHelp(COMMAND_NAME, options, true);

            throw e;
        }

        if (commandLine.getOptions().length == 0) {
            formatter.printHelp(COMMAND_NAME, options, true);

            System.exit(1);

            return;
        }

        if (commandLine.getOptions().length == 0 || commandLine.hasOption(helpOption.getOpt())) {
            formatter.printHelp(COMMAND_NAME, options, true);

            return;
        }

        inPassword = inPasswordOption.getValue();
        destPassword = destPasswordOption.getValue();
        inFile = inOption.getValue();
        destFile = destOption.getValue();
        retainAliases = commandLine.hasOption(retainAliasesOption.getOpt());

        if (commandLine.hasOption(mergeOption.getOpt())) {
            mergePfx();
        }

        if (commandLine.hasOption(listOption.getOpt())) {
            listPfx();
        }
    }

    public static void main(String[] args) throws Exception {
        PfxTool tool = new PfxTool();

        try {
            tool.handleCommandline(args);
        } catch (MissingArgumentException e) {
            System.err.println("Not all required parameters are specified. " + e.getMessage());

            System.exit(3);
        } catch (MissingOptionException e) {
            System.err.println("Not all required options are specified. " + e.getMessage());

            System.exit(4);
        } catch (UnrecognizedOptionException e) {
            System.err.println("Unknown option specified. " + e.getMessage());

            System.exit(4);
        }
    }
}