All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.util.ssl.cert.ManageCertificates Maven / Gradle / Ivy

/*
 * Copyright 2017-2024 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2017-2024 Ping Identity Corporation
 *
 * 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.
 */
/*
 * Copyright (C) 2017-2024 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.util.ssl.cert;



import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.net.InetAddress;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import com.unboundid.asn1.ASN1BitString;
import com.unboundid.asn1.ASN1Element;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.Version;
import com.unboundid.util.Base64;
import com.unboundid.util.BouncyCastleFIPSHelper;
import com.unboundid.util.ByteStringBuffer;
import com.unboundid.util.CommandLineTool;
import com.unboundid.util.CryptoHelper;
import com.unboundid.util.Debug;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.OID;
import com.unboundid.util.ObjectPair;
import com.unboundid.util.PasswordReader;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.BooleanValueArgument;
import com.unboundid.util.args.DNArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.IA5StringArgumentValueValidator;
import com.unboundid.util.args.IPAddressArgumentValueValidator;
import com.unboundid.util.args.IntegerArgument;
import com.unboundid.util.args.OIDArgumentValueValidator;
import com.unboundid.util.args.StringArgument;
import com.unboundid.util.args.TimestampArgument;
import com.unboundid.util.args.SubCommand;
import com.unboundid.util.ssl.JVMDefaultTrustManager;
import com.unboundid.util.ssl.PKCS11KeyManager;

import static com.unboundid.util.ssl.cert.CertMessages.*;



/**
 * This class provides a tool that can be used to manage X.509 certificates for
 * use in TLS communication.
 */
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public final class ManageCertificates
       extends CommandLineTool
{
  /**
   * The path to the keystore with the JVM's set of default trusted issuer
   * certificates.
   */
  @Nullable private static final File JVM_DEFAULT_CACERTS_FILE;
  static
  {
    File caCertsFile;
    try
    {
      caCertsFile = JVMDefaultTrustManager.getInstance().getCACertsFile();
    }
    catch (final Exception e)
    {
      Debug.debugException(e);
      caCertsFile = null;
    }

    JVM_DEFAULT_CACERTS_FILE = caCertsFile;
  }



  /**
   * The name of the keystore type that should be used for the Bouncy Castle
   * FIPS 140-2-compliant keystore.
   */
  @NotNull private static final String BCFKS_KEYSTORE_TYPE =
       BouncyCastleFIPSHelper.FIPS_KEY_STORE_TYPE;



  /**
   * The name of the BCFKS keystore type, formatted in all lowercase.
   */
  @NotNull private static final String BCFKS_KEYSTORE_TYPE_LC =
       BCFKS_KEYSTORE_TYPE.toLowerCase();



  /**
   * The name of a system property that can be used to specify the default
   * keystore type for new keystores.
   */
  @NotNull private static final String PROPERTY_DEFAULT_KEYSTORE_TYPE =
       ManageCertificates.class.getName() + ".defaultKeystoreType";



  /**
   * The default keystore type that will be used for new keystores when the
   * type is not specified.
   */
  @NotNull private static final String DEFAULT_KEYSTORE_TYPE;
  static
  {
    final String propertyValue =
         StaticUtils.getSystemProperty(PROPERTY_DEFAULT_KEYSTORE_TYPE);
    if (CryptoHelper.usingFIPSMode() ||
         ((propertyValue != null) && propertyValue.equalsIgnoreCase(
              BCFKS_KEYSTORE_TYPE)))
    {
      DEFAULT_KEYSTORE_TYPE = BCFKS_KEYSTORE_TYPE;
    }
    else if ((propertyValue != null) &&
         (propertyValue.equalsIgnoreCase("PKCS12") ||
              propertyValue.equalsIgnoreCase("PKCS#12") ||
              propertyValue.equalsIgnoreCase("PKCS #12") ||
              propertyValue.equalsIgnoreCase("PKCS 12")))
    {
      DEFAULT_KEYSTORE_TYPE = CryptoHelper.KEY_STORE_TYPE_PKCS_12;
    }
    else
    {
      DEFAULT_KEYSTORE_TYPE = CryptoHelper.KEY_STORE_TYPE_JKS;
    }
  }



  /**
   * The column at which to wrap long lines of output.
   */
  private static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1;



  /**
   * The set of values that will be allowed for the keystore type argument.
   */
  @NotNull private static final Set ALLOWED_KEYSTORE_TYPE_VALUES =
       StaticUtils.setOf("jks",
            "pkcs11", "pkcs 11", "pkcs#11", "pkcs #11",
            "pkcs12", "pkcs 12", "pkcs#12", "pkcs #12",
            BCFKS_KEYSTORE_TYPE_LC);



  // The global argument parser used by this tool.
  @Nullable private volatile ArgumentParser globalParser = null;

  // The argument parser for the selected subcommand.
  @Nullable private volatile ArgumentParser subCommandParser = null;

  // The input stream to use for standard input.
  @NotNull private final InputStream in;



  /**
   * Invokes this tool with the default standard output and standard error and
   * the provided set of arguments.
   *
   * @param  args  The command-line arguments provided to this program.
   */
  public static void main(@NotNull final String... args)
  {
    final ResultCode resultCode = main(System.in, System.out, System.err, args);
    if (resultCode != ResultCode.SUCCESS)
    {
      System.exit(Math.max(1, Math.min(resultCode.intValue(), 255)));
    }
  }



  /**
   * Invokes this tool with the provided output and error streams and set of
   * arguments.
   *
   * @param  in    The input stream to use for standard input.  It may be
   *               {@code null} if no input stream should be available.
   * @param  out   The output stream to use for standard output.  It may be
   *               {@code null} if standard output should be suppressed.
   * @param  err   The output stream to use for standard error.  It may be
   *               {@code null} if standard error should be suppressed.
   * @param  args  The command-line arguments provided to this program.
   *
   * @return  The result code obtained from tool processing.
   */
  @NotNull()
  public static ResultCode main(@Nullable final InputStream in,
                                @Nullable final OutputStream out,
                                @Nullable final OutputStream err,
                                @NotNull final String... args)
  {
    final ManageCertificates manageCertificates =
         new ManageCertificates(in, out, err);
    return manageCertificates.runTool(args);
  }



  /**
   * Creates a new instance of this tool with the provided output and error
   * streams.  Standard input will bot be available.
   *
   * @param  out  The output stream to use for standard output.  It may be
   *              {@code null} if standard output should be suppressed.
   * @param  err  The output stream to use for standard error.  It may be
   *              {@code null} if standard error should be suppressed.
   */
  public ManageCertificates(@Nullable final OutputStream out,
                            @Nullable final OutputStream err)
  {
    this(null, out, err);
  }



  /**
   * Creates a new instance of this tool with the provided output and error
   * streams.
   *
   * @param  in   The input stream to use for standard input.  It may be
   *              {@code null} if no input stream should be available.
   * @param  out  The output stream to use for standard output.  It may be
   *              {@code null} if standard output should be suppressed.
   * @param  err  The output stream to use for standard error.  It may be
   *              {@code null} if standard error should be suppressed.
   */
  public ManageCertificates(@Nullable final InputStream in,
                            @Nullable final OutputStream out,
                            @Nullable final OutputStream err)
  {
    super(out, err);

    if (in == null)
    {
      this.in = new ByteArrayInputStream(StaticUtils.NO_BYTES);
    }
    else
    {
      this.in = in;
    }
  }



  /**
   * Retrieves the name of this tool.  It should be the name of the command used
   * to invoke this tool.
   *
   * @return  The name for this tool.
   */
  @Override()
  @NotNull()
  public String getToolName()
  {
    return "manage-certificates";
  }



  /**
   * Retrieves a human-readable description for this tool.
   *
   * @return  A human-readable description for this tool.
   */
  @Override()
  @NotNull()
  public String getToolDescription()
  {
    return INFO_MANAGE_CERTS_TOOL_DESC.get();
  }



  /**
   * Retrieves a version string for this tool, if available.
   *
   * @return  A version string for this tool, or {@code null} if none is
   *          available.
   */
  @Override()
  @NotNull()
  public String getToolVersion()
  {
    return Version.NUMERIC_VERSION_STRING;
  }



  /**
   * Indicates whether this tool should provide support for an interactive mode,
   * in which the tool offers a mode in which the arguments can be provided in
   * a text-driven menu rather than requiring them to be given on the command
   * line.  If interactive mode is supported, it may be invoked using the
   * "--interactive" argument.  Alternately, if interactive mode is supported
   * and {@link #defaultsToInteractiveMode()} returns {@code true}, then
   * interactive mode may be invoked by simply launching the tool without any
   * arguments.
   *
   * @return  {@code true} if this tool supports interactive mode, or
   *          {@code false} if not.
   */
  @Override()
  public boolean supportsInteractiveMode()
  {
    return true;
  }



  /**
   * Indicates whether this tool defaults to launching in interactive mode if
   * the tool is invoked without any command-line arguments.  This will only be
   * used if {@link #supportsInteractiveMode()} returns {@code true}.
   *
   * @return  {@code true} if this tool defaults to using interactive mode if
   *          launched without any command-line arguments, or {@code false} if
   *          not.
   */
  @Override()
  public boolean defaultsToInteractiveMode()
  {
    return true;
  }



  /**
   * Indicates whether this tool supports the use of a properties file for
   * specifying default values for arguments that aren't specified on the
   * command line.
   *
   * @return  {@code true} if this tool supports the use of a properties file
   *          for specifying default values for arguments that aren't specified
   *          on the command line, or {@code false} if not.
   */
  @Override()
  public boolean supportsPropertiesFile()
  {
    return true;
  }



  /**
   * Indicates whether this tool should provide arguments for redirecting output
   * to a file.  If this method returns {@code true}, then the tool will offer
   * an "--outputFile" argument that will specify the path to a file to which
   * all standard output and standard error content will be written, and it will
   * also offer a "--teeToStandardOut" argument that can only be used if the
   * "--outputFile" argument is present and will cause all output to be written
   * to both the specified output file and to standard output.
   *
   * @return  {@code true} if this tool should provide arguments for redirecting
   *          output to a file, or {@code false} if not.
   */
  @Override()
  protected boolean supportsOutputFile()
  {
    return false;
  }



  /**
   * {@inheritDoc}
   */
  @Override()
  protected boolean supportsDebugLogging()
  {
    return true;
  }



  /**
   * Indicates whether to log messages about the launch and completion of this
   * tool into the invocation log of Ping Identity server products that may
   * include it.  This method is not needed for tools that are not expected to
   * be part of the Ping Identity server products suite.  Further, this value
   * may be overridden by settings in the server's
   * tool-invocation-logging.properties file.
   * 

* This method should generally return {@code true} for tools that may alter * the server configuration, data, or other state information, and * {@code false} for tools that do not make any changes. * * @return {@code true} if Ping Identity server products should include * messages about the launch and completion of this tool in tool * invocation log files by default, or {@code false} if not. */ @Override() protected boolean logToolInvocationByDefault() { return true; } /** * Adds the command-line arguments supported for use with this tool to the * provided argument parser. The tool may need to retain references to the * arguments (and/or the argument parser, if trailing arguments are allowed) * to it in order to obtain their values for use in later processing. * * @param parser The argument parser to which the arguments are to be added. * * @throws ArgumentException If a problem occurs while adding any of the * tool-specific arguments to the provided * argument parser. */ @Override() public void addToolArguments(@NotNull final ArgumentParser parser) throws ArgumentException { globalParser = parser; // Define the "list-certificates" subcommand and all of its arguments. final ArgumentParser listCertsParser = new ArgumentParser( "list-certificates", INFO_MANAGE_CERTS_SC_LIST_CERTS_DESC.get()); final FileArgument listCertsKeystore = new FileArgument(null, "keystore", (JVM_DEFAULT_CACERTS_FILE == null), 1, null, INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_KS_DESC.get(), true, true, true, false); listCertsKeystore.addLongIdentifier("keystore-path", true); listCertsKeystore.addLongIdentifier("keystorePath", true); listCertsKeystore.addLongIdentifier("keystore-file", true); listCertsKeystore.addLongIdentifier("keystoreFile", true); listCertsParser.addArgument(listCertsKeystore); if (JVM_DEFAULT_CACERTS_FILE != null) { final BooleanArgument listCertsUseJVMDefault = new BooleanArgument(null, "use-jvm-default-trust-store", 1, INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_JVM_DEFAULT_DESC.get( JVM_DEFAULT_CACERTS_FILE.getAbsolutePath())); listCertsUseJVMDefault.addLongIdentifier("useJVMDefaultTrustStore", true); listCertsUseJVMDefault.addLongIdentifier("jvm-default", true); listCertsUseJVMDefault.addLongIdentifier("jvmDefault", true); listCertsParser.addArgument(listCertsUseJVMDefault); listCertsParser.addRequiredArgumentSet(listCertsUseJVMDefault, listCertsKeystore); listCertsParser.addExclusiveArgumentSet(listCertsUseJVMDefault, listCertsKeystore); } final StringArgument listCertsKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_KS_PW_DESC.get()); listCertsKeystorePassword.addLongIdentifier("keystorePassword", true); listCertsKeystorePassword.addLongIdentifier("keystore-passphrase", true); listCertsKeystorePassword.addLongIdentifier("keystorePassphrase", true); listCertsKeystorePassword.addLongIdentifier("keystore-pin", true); listCertsKeystorePassword.addLongIdentifier("keystorePIN", true); listCertsKeystorePassword.addLongIdentifier("storepass", true); listCertsKeystorePassword.setSensitive(true); listCertsParser.addArgument(listCertsKeystorePassword); final FileArgument listCertsKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); listCertsKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); listCertsKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); listCertsKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); listCertsKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); listCertsKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); listCertsParser.addArgument(listCertsKeystorePasswordFile); final BooleanArgument listCertsPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_PROMPT_FOR_KS_PW_DESC.get()); listCertsPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); listCertsPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); listCertsPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); listCertsPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); listCertsPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); listCertsParser.addArgument(listCertsPromptForKeystorePassword); final StringArgument listCertsKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); listCertsKeystoreType.addLongIdentifier("key-store-type", true); listCertsKeystoreType.addLongIdentifier("keystoreType", true); listCertsKeystoreType.addLongIdentifier("keystore-format", true); listCertsKeystoreType.addLongIdentifier("key-store-format", true); listCertsKeystoreType.addLongIdentifier("keystoreFormat", true); listCertsKeystoreType.addLongIdentifier("storetype", true); listCertsParser.addArgument(listCertsKeystoreType); final StringArgument listCertsAlias = new StringArgument(null, "alias", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_ALIAS_DESC.get()); listCertsAlias.addLongIdentifier("nickname", true); listCertsParser.addArgument(listCertsAlias); final BooleanArgument listCertsDisplayPEM = new BooleanArgument(null, "display-pem-certificate", 1, INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_DISPLAY_PEM_DESC.get()); listCertsDisplayPEM.addLongIdentifier("displayPEMCertificate", true); listCertsDisplayPEM.addLongIdentifier("display-pem", true); listCertsDisplayPEM.addLongIdentifier("displayPEM", true); listCertsDisplayPEM.addLongIdentifier("show-pem-certificate", true); listCertsDisplayPEM.addLongIdentifier("showPEMCertificate", true); listCertsDisplayPEM.addLongIdentifier("show-pem", true); listCertsDisplayPEM.addLongIdentifier("showPEM", true); listCertsDisplayPEM.addLongIdentifier("pem", true); listCertsDisplayPEM.addLongIdentifier("rfc", true); listCertsParser.addArgument(listCertsDisplayPEM); final BooleanArgument listCertsVerbose = new BooleanArgument(null, "verbose", 1, INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_VERBOSE_DESC.get()); listCertsParser.addArgument(listCertsVerbose); final BooleanArgument listCertsDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_LIST_CERTS_ARG_DISPLAY_COMMAND_DESC.get()); listCertsDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); listCertsDisplayCommand.addLongIdentifier("show-keytool-command", true); listCertsDisplayCommand.addLongIdentifier("showKeytoolCommand", true); listCertsParser.addArgument(listCertsDisplayCommand); listCertsParser.addExclusiveArgumentSet(listCertsKeystorePassword, listCertsKeystorePasswordFile, listCertsPromptForKeystorePassword); final LinkedHashMap listCertsExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(3)); listCertsExamples.put( new String[] { "list-certificates", "--keystore", getPlatformSpecificPath("config", "keystore") }, INFO_MANAGE_CERTS_SC_LIST_CERTS_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"))); listCertsExamples.put( new String[] { "list-certificates", "--keystore", getPlatformSpecificPath("config", "keystore.p12"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--verbose", "--display-pem-certificate", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_LIST_CERTS_EXAMPLE_2.get( getPlatformSpecificPath("config", "keystore.p12"), getPlatformSpecificPath("config", "keystore.pin"))); if (JVM_DEFAULT_CACERTS_FILE != null) { listCertsExamples.put( new String[] { "list-certificates", "--use-jvm-default-trust-store" }, INFO_MANAGE_CERTS_SC_LIST_CERTS_EXAMPLE_3.get()); } final SubCommand listCertsSubCommand = new SubCommand("list-certificates", INFO_MANAGE_CERTS_SC_LIST_CERTS_DESC.get(), listCertsParser, listCertsExamples); listCertsSubCommand.addName("listCertificates", true); listCertsSubCommand.addName("list-certs", true); listCertsSubCommand.addName("listCerts", true); listCertsSubCommand.addName("list", true); parser.addSubCommand(listCertsSubCommand); // Define the "export-certificate" subcommand and all of its arguments. final ArgumentParser exportCertParser = new ArgumentParser( "export-certificate", INFO_MANAGE_CERTS_SC_EXPORT_CERT_DESC.get()); final FileArgument exportCertKeystore = new FileArgument(null, "keystore", (JVM_DEFAULT_CACERTS_FILE == null), 1, null, INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_KS_DESC.get(), true, true, true, false); exportCertKeystore.addLongIdentifier("keystore-path", true); exportCertKeystore.addLongIdentifier("keystorePath", true); exportCertKeystore.addLongIdentifier("keystore-file", true); exportCertKeystore.addLongIdentifier("keystoreFile", true); exportCertParser.addArgument(exportCertKeystore); if (JVM_DEFAULT_CACERTS_FILE != null) { final BooleanArgument exportCertUseJVMDefault = new BooleanArgument(null, "use-jvm-default-trust-store", 1, INFO_MANAGE_CERTS_SC_EXPORT_CERTS_ARG_JVM_DEFAULT_DESC.get( JVM_DEFAULT_CACERTS_FILE.getAbsolutePath())); exportCertUseJVMDefault.addLongIdentifier("useJVMDefaultTrustStore", true); exportCertUseJVMDefault.addLongIdentifier("jvm-default", true); exportCertUseJVMDefault.addLongIdentifier("jvmDefault", true); exportCertParser.addArgument(exportCertUseJVMDefault); exportCertParser.addRequiredArgumentSet(exportCertUseJVMDefault, exportCertKeystore); exportCertParser.addExclusiveArgumentSet(exportCertUseJVMDefault, exportCertKeystore); } final StringArgument exportCertKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_KS_PW_DESC.get()); exportCertKeystorePassword.addLongIdentifier("keystorePassword", true); exportCertKeystorePassword.addLongIdentifier("keystore-passphrase", true); exportCertKeystorePassword.addLongIdentifier("keystorePassphrase", true); exportCertKeystorePassword.addLongIdentifier("keystore-pin", true); exportCertKeystorePassword.addLongIdentifier("keystorePIN", true); exportCertKeystorePassword.addLongIdentifier("storepass", true); exportCertKeystorePassword.setSensitive(true); exportCertParser.addArgument(exportCertKeystorePassword); final FileArgument exportCertKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); exportCertKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); exportCertKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); exportCertKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); exportCertKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); exportCertKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); exportCertParser.addArgument(exportCertKeystorePasswordFile); final BooleanArgument exportCertPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_PROMPT_FOR_KS_PW_DESC.get()); exportCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); exportCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); exportCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); exportCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); exportCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); exportCertParser.addArgument(exportCertPromptForKeystorePassword); final StringArgument exportCertKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); exportCertKeystoreType.addLongIdentifier("key-store-type", true); exportCertKeystoreType.addLongIdentifier("keystoreType", true); exportCertKeystoreType.addLongIdentifier("keystore-format", true); exportCertKeystoreType.addLongIdentifier("key-store-format", true); exportCertKeystoreType.addLongIdentifier("keystoreFormat", true); exportCertKeystoreType.addLongIdentifier("storetype", true); exportCertParser.addArgument(exportCertKeystoreType); final StringArgument exportCertAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_ALIAS_DESC.get()); exportCertAlias.addLongIdentifier("nickname", true); exportCertParser.addArgument(exportCertAlias); final BooleanArgument exportCertChain = new BooleanArgument(null, "export-certificate-chain", 1, INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_CHAIN_DESC.get()); exportCertChain.addLongIdentifier("exportCertificateChain", true); exportCertChain.addLongIdentifier("export-chain", true); exportCertChain.addLongIdentifier("exportChain", true); exportCertChain.addLongIdentifier("certificate-chain", true); exportCertChain.addLongIdentifier("certificateChain", true); exportCertChain.addLongIdentifier("chain", true); exportCertParser.addArgument(exportCertChain); final Set exportCertOutputFormatAllowedValues = StaticUtils.setOf( "PEM", "text", "txt", "RFC", "DER", "binary", "bin"); final StringArgument exportCertOutputFormat = new StringArgument(null, "output-format", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_FORMAT.get(), INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_FORMAT_DESC.get(), exportCertOutputFormatAllowedValues, "PEM"); exportCertOutputFormat.addLongIdentifier("outputFormat", true); exportCertParser.addArgument(exportCertOutputFormat); final FileArgument exportCertOutputFile = new FileArgument(null, "output-file", false, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_FILE_DESC.get(), false, true, true, false); exportCertOutputFile.addLongIdentifier("outputFile", true); exportCertOutputFile.addLongIdentifier("export-file", true); exportCertOutputFile.addLongIdentifier("exportFile", true); exportCertOutputFile.addLongIdentifier("certificate-file", true); exportCertOutputFile.addLongIdentifier("certificateFile", true); exportCertOutputFile.addLongIdentifier("file", true); exportCertOutputFile.addLongIdentifier("filename", true); exportCertParser.addArgument(exportCertOutputFile); final BooleanArgument exportCertSeparateFile = new BooleanArgument(null, "separate-file-per-certificate", 1, INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_SEPARATE_FILE_DESC.get()); exportCertSeparateFile.addLongIdentifier("separateFilePerCertificate", true); exportCertSeparateFile.addLongIdentifier("separate-files", true); exportCertSeparateFile.addLongIdentifier("separateFiles", true); exportCertParser.addArgument(exportCertSeparateFile); final BooleanArgument exportCertDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_DISPLAY_COMMAND_DESC.get()); exportCertDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); exportCertDisplayCommand.addLongIdentifier("show-keytool-command", true); exportCertDisplayCommand.addLongIdentifier("showKeytoolCommand", true); exportCertParser.addArgument(exportCertDisplayCommand); exportCertParser.addExclusiveArgumentSet(exportCertKeystorePassword, exportCertKeystorePasswordFile, exportCertPromptForKeystorePassword); exportCertParser.addDependentArgumentSet(exportCertSeparateFile, exportCertChain); exportCertParser.addDependentArgumentSet(exportCertSeparateFile, exportCertOutputFile); final LinkedHashMap exportCertExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); exportCertExamples.put( new String[] { "export-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--alias", "server-cert" }, INFO_MANAGE_CERTS_SC_EXPORT_CERT_EXAMPLE_1.get()); exportCertExamples.put( new String[] { "export-certificate", "--keystore", getPlatformSpecificPath("config", "keystore.p12"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--export-certificate-chain", "--output-format", "DER", "--output-file", "certificate-chain.der", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_EXPORT_CERT_EXAMPLE_2.get()); final SubCommand exportCertSubCommand = new SubCommand("export-certificate", INFO_MANAGE_CERTS_SC_EXPORT_CERT_DESC.get(), exportCertParser, exportCertExamples); exportCertSubCommand.addName("exportCertificate", true); exportCertSubCommand.addName("export-cert", true); exportCertSubCommand.addName("exportCert", true); exportCertSubCommand.addName("export", true); parser.addSubCommand(exportCertSubCommand); // Define the "export-private-key" subcommand and all of its arguments. final ArgumentParser exportKeyParser = new ArgumentParser( "export-private-key", INFO_MANAGE_CERTS_SC_EXPORT_KEY_DESC.get()); final FileArgument exportKeyKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_KS_DESC.get(), true, true, true, false); exportKeyKeystore.addLongIdentifier("keystore-path", true); exportKeyKeystore.addLongIdentifier("keystorePath", true); exportKeyKeystore.addLongIdentifier("keystore-file", true); exportKeyKeystore.addLongIdentifier("keystoreFile", true); exportKeyParser.addArgument(exportKeyKeystore); final StringArgument exportKeyKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_KS_PW_DESC.get()); exportKeyKeystorePassword.addLongIdentifier("keystorePassword", true); exportKeyKeystorePassword.addLongIdentifier("keystore-passphrase", true); exportKeyKeystorePassword.addLongIdentifier("keystorePassphrase", true); exportKeyKeystorePassword.addLongIdentifier("keystore-pin", true); exportKeyKeystorePassword.addLongIdentifier("keystorePIN", true); exportKeyKeystorePassword.addLongIdentifier("storepass", true); exportKeyKeystorePassword.setSensitive(true); exportKeyParser.addArgument(exportKeyKeystorePassword); final FileArgument exportKeyKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); exportKeyKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); exportKeyKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); exportKeyKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); exportKeyKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); exportKeyKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); exportKeyParser.addArgument(exportKeyKeystorePasswordFile); final BooleanArgument exportKeyPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_PROMPT_FOR_KS_PW_DESC.get()); exportKeyPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); exportKeyPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); exportKeyPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); exportKeyPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); exportKeyPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); exportKeyParser.addArgument(exportKeyPromptForKeystorePassword); final StringArgument exportKeyPKPassword = new StringArgument(null, "private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_PK_PW_DESC.get()); exportKeyPKPassword.addLongIdentifier("privateKeyPassword", true); exportKeyPKPassword.addLongIdentifier("private-key-passphrase", true); exportKeyPKPassword.addLongIdentifier("privateKeyPassphrase", true); exportKeyPKPassword.addLongIdentifier("private-key-pin", true); exportKeyPKPassword.addLongIdentifier("privateKeyPIN", true); exportKeyPKPassword.addLongIdentifier("key-password", true); exportKeyPKPassword.addLongIdentifier("keyPassword", true); exportKeyPKPassword.addLongIdentifier("key-passphrase", true); exportKeyPKPassword.addLongIdentifier("keyPassphrase", true); exportKeyPKPassword.addLongIdentifier("key-pin", true); exportKeyPKPassword.addLongIdentifier("keyPIN", true); exportKeyPKPassword.addLongIdentifier("keypass", true); exportKeyPKPassword.setSensitive(true); exportKeyParser.addArgument(exportKeyPKPassword); final FileArgument exportKeyPKPasswordFile = new FileArgument(null, "private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_PK_PW_FILE_DESC.get(), true, true, true, false); exportKeyPKPasswordFile.addLongIdentifier("privateKeyPasswordFile", true); exportKeyPKPasswordFile.addLongIdentifier("private-key-passphrase-file", true); exportKeyPKPasswordFile.addLongIdentifier("privateKeyPassphraseFile", true); exportKeyPKPasswordFile.addLongIdentifier("private-key-pin-file", true); exportKeyPKPasswordFile.addLongIdentifier("privateKeyPINFile", true); exportKeyPKPasswordFile.addLongIdentifier("key-password-file", true); exportKeyPKPasswordFile.addLongIdentifier("keyPasswordFile", true); exportKeyPKPasswordFile.addLongIdentifier("key-passphrase-file", true); exportKeyPKPasswordFile.addLongIdentifier("keyPassphraseFile", true); exportKeyPKPasswordFile.addLongIdentifier("key-pin-file", true); exportKeyPKPasswordFile.addLongIdentifier("keyPINFile", true); exportKeyParser.addArgument(exportKeyPKPasswordFile); final BooleanArgument exportKeyPromptForPKPassword = new BooleanArgument(null, "prompt-for-private-key-password", INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_PROMPT_FOR_PK_PW_DESC.get()); exportKeyPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassword", true); exportKeyPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-passphrase", true); exportKeyPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassphrase", true); exportKeyPromptForPKPassword.addLongIdentifier("prompt-for-private-key-pin", true); exportKeyPromptForPKPassword.addLongIdentifier("promptForPrivateKeyPIN", true); exportKeyPromptForPKPassword.addLongIdentifier("prompt-for-key-password", true); exportKeyPromptForPKPassword.addLongIdentifier("promptForKeyPassword", true); exportKeyPromptForPKPassword.addLongIdentifier( "prompt-for-key-passphrase", true); exportKeyPromptForPKPassword.addLongIdentifier( "promptForKeyPassphrase", true); exportKeyPromptForPKPassword.addLongIdentifier("prompt-for-key-pin", true); exportKeyPromptForPKPassword.addLongIdentifier("promptForKeyPIN", true); exportKeyParser.addArgument(exportKeyPromptForPKPassword); final StringArgument exportKeyKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); exportKeyKeystoreType.addLongIdentifier("key-store-type", true); exportKeyKeystoreType.addLongIdentifier("keystoreType", true); exportKeyKeystoreType.addLongIdentifier("keystore-format", true); exportKeyKeystoreType.addLongIdentifier("key-store-format", true); exportKeyKeystoreType.addLongIdentifier("keystoreFormat", true); exportKeyKeystoreType.addLongIdentifier("storetype", true); exportKeyParser.addArgument(exportKeyKeystoreType); final StringArgument exportKeyAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_ALIAS_DESC.get()); exportKeyAlias.addLongIdentifier("nickname", true); exportKeyParser.addArgument(exportKeyAlias); final Set exportKeyOutputFormatAllowedValues = StaticUtils.setOf( "PEM", "text", "txt", "RFC", "DER", "binary", "bin"); final StringArgument exportKeyOutputFormat = new StringArgument(null, "output-format", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_FORMAT.get(), INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_FORMAT_DESC.get(), exportKeyOutputFormatAllowedValues, "PEM"); exportKeyOutputFormat.addLongIdentifier("outputFormat", true); exportKeyParser.addArgument(exportKeyOutputFormat); final FileArgument exportKeyOutputFile = new FileArgument(null, "output-file", false, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_FILE_DESC.get(), false, true, true, false); exportKeyOutputFile.addLongIdentifier("outputFile", true); exportKeyOutputFile.addLongIdentifier("export-file", true); exportKeyOutputFile.addLongIdentifier("exportFile", true); exportKeyOutputFile.addLongIdentifier("private-key-file", true); exportKeyOutputFile.addLongIdentifier("privateKeyFile", true); exportKeyOutputFile.addLongIdentifier("key-file", true); exportKeyOutputFile.addLongIdentifier("keyFile", true); exportKeyOutputFile.addLongIdentifier("file", true); exportKeyOutputFile.addLongIdentifier("filename", true); exportKeyParser.addArgument(exportKeyOutputFile); final StringArgument exportKeyEncryptionPassword = new StringArgument(null, "encryption-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_EXPIRT_KEY_ARG_ENC_PW_DESC.get()); exportKeyEncryptionPassword.addLongIdentifier("encryptionPassword", true); exportKeyParser.addArgument(exportKeyEncryptionPassword); final FileArgument exportKeyEncryptionPasswordFile = new FileArgument(null, "encryption-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_ENC_PW_FILE_DESC.get(), true, true, true, false); exportKeyEncryptionPasswordFile.addLongIdentifier("encryptionPasswordFile", true); exportKeyParser.addArgument(exportKeyEncryptionPasswordFile); final BooleanArgument exportKeyPromptForEncryptionPassword = new BooleanArgument(null, "prompt-for-encryption-password", 1, INFO_MANAGE_CERTS_SC_EXPORT_KEY_ARG_PROMPT_FOR_ENC_PW.get()); exportKeyPromptForEncryptionPassword.addLongIdentifier( "promptForEncryptionPassword", true); exportKeyParser.addArgument(exportKeyPromptForEncryptionPassword); exportKeyParser.addRequiredArgumentSet(exportKeyKeystorePassword, exportKeyKeystorePasswordFile, exportKeyPromptForKeystorePassword); exportKeyParser.addExclusiveArgumentSet(exportKeyKeystorePassword, exportKeyKeystorePasswordFile, exportKeyPromptForKeystorePassword); exportKeyParser.addExclusiveArgumentSet(exportKeyPKPassword, exportKeyPKPasswordFile, exportKeyPromptForPKPassword); exportKeyParser.addExclusiveArgumentSet(exportKeyEncryptionPassword, exportKeyEncryptionPasswordFile, exportKeyPromptForEncryptionPassword); final LinkedHashMap exportKeyExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); exportKeyExamples.put( new String[] { "export-private-key", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert" }, INFO_MANAGE_CERTS_SC_EXPORT_KEY_EXAMPLE_1.get()); exportKeyExamples.put( new String[] { "export-private-key", "--keystore", getPlatformSpecificPath("config", "keystore.p12"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--private-key-password-file", getPlatformSpecificPath("config", "server-cert-key.pin"), "--alias", "server-cert", "--output-format", "DER", "--output-file", "server-cert-key.der" }, INFO_MANAGE_CERTS_SC_EXPORT_KEY_EXAMPLE_2.get()); final SubCommand exportKeySubCommand = new SubCommand("export-private-key", INFO_MANAGE_CERTS_SC_EXPORT_CERT_DESC.get(), exportKeyParser, exportKeyExamples); exportKeySubCommand.addName("exportPrivateKey", true); exportKeySubCommand.addName("export-key", true); exportKeySubCommand.addName("exportKey", true); parser.addSubCommand(exportKeySubCommand); // Define the "import-certificate" subcommand and all of its arguments. final ArgumentParser importCertParser = new ArgumentParser( "import-certificate", INFO_MANAGE_CERTS_SC_IMPORT_CERT_DESC.get()); final FileArgument importCertKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_KS_DESC.get(), false, true, true, false); importCertKeystore.addLongIdentifier("keystore-path", true); importCertKeystore.addLongIdentifier("keystorePath", true); importCertKeystore.addLongIdentifier("keystore-file", true); importCertKeystore.addLongIdentifier("keystoreFile", true); importCertParser.addArgument(importCertKeystore); final StringArgument importCertKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_KS_PW_DESC.get()); importCertKeystorePassword.addLongIdentifier("keystorePassword", true); importCertKeystorePassword.addLongIdentifier("keystore-passphrase", true); importCertKeystorePassword.addLongIdentifier("keystorePassphrase", true); importCertKeystorePassword.addLongIdentifier("keystore-pin", true); importCertKeystorePassword.addLongIdentifier("keystorePIN", true); importCertKeystorePassword.addLongIdentifier("storepass", true); importCertKeystorePassword.setSensitive(true); importCertParser.addArgument(importCertKeystorePassword); final FileArgument importCertKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); importCertKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); importCertKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); importCertKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); importCertKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); importCertKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); importCertParser.addArgument(importCertKeystorePasswordFile); final BooleanArgument importCertPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_PROMPT_FOR_KS_PW_DESC.get()); importCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); importCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); importCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); importCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); importCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); importCertParser.addArgument(importCertPromptForKeystorePassword); final StringArgument importCertKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); importCertKeystoreType.addLongIdentifier("key-store-type", true); importCertKeystoreType.addLongIdentifier("keystoreType", true); importCertKeystoreType.addLongIdentifier("keystore-format", true); importCertKeystoreType.addLongIdentifier("key-store-format", true); importCertKeystoreType.addLongIdentifier("keystoreFormat", true); importCertKeystoreType.addLongIdentifier("storetype", true); importCertParser.addArgument(importCertKeystoreType); final StringArgument importCertAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_ALIAS_DESC.get()); importCertAlias.addLongIdentifier("nickname", true); importCertParser.addArgument(importCertAlias); final FileArgument importCertCertificateFile = new FileArgument(null, "certificate-file", true, 0, null, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_CERT_FILE_DESC.get(), true, true, true, false); importCertCertificateFile.addLongIdentifier("certificateFile", true); importCertCertificateFile.addLongIdentifier("certificate-chain-file", true); importCertCertificateFile.addLongIdentifier("certificateChainFile", true); importCertCertificateFile.addLongIdentifier("input-file", true); importCertCertificateFile.addLongIdentifier("inputFile", true); importCertCertificateFile.addLongIdentifier("import-file", true); importCertCertificateFile.addLongIdentifier("importFile", true); importCertCertificateFile.addLongIdentifier("file", true); importCertCertificateFile.addLongIdentifier("filename", true); importCertParser.addArgument(importCertCertificateFile); final FileArgument importCertPKFile = new FileArgument(null, "private-key-file", false, 1, null, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_KEY_FILE_DESC.get(), true, true, true, false); importCertPKFile.addLongIdentifier("privateKeyFile", true); importCertPKFile.addLongIdentifier("key-file", true); importCertPKFile.addLongIdentifier("keyFile", true); importCertParser.addArgument(importCertPKFile); final StringArgument importCertPKPassword = new StringArgument(null, "private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_PK_PW_DESC.get()); importCertPKPassword.addLongIdentifier("privateKeyPassword", true); importCertPKPassword.addLongIdentifier("private-key-passphrase", true); importCertPKPassword.addLongIdentifier("privateKeyPassphrase", true); importCertPKPassword.addLongIdentifier("private-key-pin", true); importCertPKPassword.addLongIdentifier("privateKeyPIN", true); importCertPKPassword.addLongIdentifier("key-password", true); importCertPKPassword.addLongIdentifier("keyPassword", true); importCertPKPassword.addLongIdentifier("key-passphrase", true); importCertPKPassword.addLongIdentifier("keyPassphrase", true); importCertPKPassword.addLongIdentifier("key-pin", true); importCertPKPassword.addLongIdentifier("keyPIN", true); importCertPKPassword.addLongIdentifier("keypass", true); importCertPKPassword.setSensitive(true); importCertParser.addArgument(importCertPKPassword); final FileArgument importCertPKPasswordFile = new FileArgument(null, "private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_PK_PW_FILE_DESC.get(), true, true, true, false); importCertPKPasswordFile.addLongIdentifier("privateKeyPasswordFile", true); importCertPKPasswordFile.addLongIdentifier("private-key-passphrase-file", true); importCertPKPasswordFile.addLongIdentifier("privateKeyPassphraseFile", true); importCertPKPasswordFile.addLongIdentifier("private-key-pin-file", true); importCertPKPasswordFile.addLongIdentifier("privateKeyPINFile", true); importCertPKPasswordFile.addLongIdentifier("key-password-file", true); importCertPKPasswordFile.addLongIdentifier("keyPasswordFile", true); importCertPKPasswordFile.addLongIdentifier("key-passphrase-file", true); importCertPKPasswordFile.addLongIdentifier("keyPassphraseFile", true); importCertPKPasswordFile.addLongIdentifier("key-pin-file", true); importCertPKPasswordFile.addLongIdentifier("keyPINFile", true); importCertParser.addArgument(importCertPKPasswordFile); final BooleanArgument importCertPromptForPKPassword = new BooleanArgument(null, "prompt-for-private-key-password", INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_PROMPT_FOR_PK_PW_DESC.get()); importCertPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassword", true); importCertPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-passphrase", true); importCertPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassphrase", true); importCertPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-pin", true); importCertPromptForPKPassword.addLongIdentifier("promptForPrivateKeyPIN", true); importCertPromptForPKPassword.addLongIdentifier("prompt-for-key-password", true); importCertPromptForPKPassword.addLongIdentifier("promptForKeyPassword", true); importCertPromptForPKPassword.addLongIdentifier( "prompt-for-key-passphrase", true); importCertPromptForPKPassword.addLongIdentifier( "promptForKeyPassphrase", true); importCertPromptForPKPassword.addLongIdentifier("prompt-for-key-pin", true); importCertPromptForPKPassword.addLongIdentifier("promptForKeyPIN", true); importCertParser.addArgument(importCertPromptForPKPassword); final StringArgument importCertEncryptionPassword = new StringArgument(null, "encryption-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_ENC_PW_DESC.get()); importCertEncryptionPassword.addLongIdentifier("encryptionPassword", true); importCertEncryptionPassword.setSensitive(true); importCertParser.addArgument(importCertEncryptionPassword); final FileArgument importCertEncryptionPasswordFile = new FileArgument(null, "encryption-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_ENC_PW_FILE_DESC.get(), true, true, true, false); importCertEncryptionPasswordFile.addLongIdentifier("encryptionPasswordFile", true); importCertParser.addArgument(importCertEncryptionPasswordFile); final BooleanArgument importCertPromptForEncryptionPassword = new BooleanArgument(null, "prompt-for-encryption-password", INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_PROMPT_FOR_ENC_PW_DESC.get()); importCertPromptForEncryptionPassword.addLongIdentifier( "promptForEncryptionPassword", true); importCertParser.addArgument(importCertPromptForEncryptionPassword); final BooleanArgument importCertNoPrompt = new BooleanArgument(null, "no-prompt", 1, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_NO_PROMPT_DESC.get()); importCertNoPrompt.addLongIdentifier("noPrompt", true); importCertParser.addArgument(importCertNoPrompt); final BooleanArgument importCertDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_IMPORT_CERT_ARG_DISPLAY_COMMAND_DESC.get()); importCertDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); importCertDisplayCommand.addLongIdentifier("show-keytool-command", true); importCertDisplayCommand.addLongIdentifier("showKeytoolCommand", true); importCertParser.addArgument(importCertDisplayCommand); importCertParser.addRequiredArgumentSet(importCertKeystorePassword, importCertKeystorePasswordFile, importCertPromptForKeystorePassword); importCertParser.addExclusiveArgumentSet(importCertKeystorePassword, importCertKeystorePasswordFile, importCertPromptForKeystorePassword); importCertParser.addExclusiveArgumentSet(importCertPKPassword, importCertPKPasswordFile, importCertPromptForPKPassword); importCertParser.addExclusiveArgumentSet(importCertEncryptionPassword, importCertEncryptionPasswordFile, importCertPromptForEncryptionPassword); final LinkedHashMap importCertExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); importCertExamples.put( new String[] { "import-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--certificate-file", "server-cert.crt" }, INFO_MANAGE_CERTS_SC_IMPORT_CERT_EXAMPLE_1.get("server-cert.crt")); importCertExamples.put( new String[] { "import-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--certificate-file", "server-cert.crt", "--certificate-file", "server-cert-issuer.crt", "--private-key-file", "server-cert.key", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_IMPORT_CERT_EXAMPLE_2.get()); final SubCommand importCertSubCommand = new SubCommand("import-certificate", INFO_MANAGE_CERTS_SC_IMPORT_CERT_DESC.get(), importCertParser, importCertExamples); importCertSubCommand.addName("importCertificate", true); importCertSubCommand.addName("import-certificates", true); importCertSubCommand.addName("importCertificates", true); importCertSubCommand.addName("import-cert", true); importCertSubCommand.addName("importCert", true); importCertSubCommand.addName("import-certs", true); importCertSubCommand.addName("importCerts", true); importCertSubCommand.addName("import-certificate-chain", true); importCertSubCommand.addName("importCertificateChain", true); importCertSubCommand.addName("import-chain", true); importCertSubCommand.addName("importChain", true); importCertSubCommand.addName("import", true); parser.addSubCommand(importCertSubCommand); // Define the "delete-certificate" subcommand and all of its arguments. final ArgumentParser deleteCertParser = new ArgumentParser( "delete-certificate", INFO_MANAGE_CERTS_SC_DELETE_CERT_DESC.get()); final FileArgument deleteCertKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_KS_DESC.get(), true, true, true, false); deleteCertKeystore.addLongIdentifier("keystore-path", true); deleteCertKeystore.addLongIdentifier("keystorePath", true); deleteCertKeystore.addLongIdentifier("keystore-file", true); deleteCertKeystore.addLongIdentifier("keystoreFile", true); deleteCertParser.addArgument(deleteCertKeystore); final StringArgument deleteCertKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_KS_PW_DESC.get()); deleteCertKeystorePassword.addLongIdentifier("keystorePassword", true); deleteCertKeystorePassword.addLongIdentifier("keystore-passphrase", true); deleteCertKeystorePassword.addLongIdentifier("keystorePassphrase", true); deleteCertKeystorePassword.addLongIdentifier("keystore-pin", true); deleteCertKeystorePassword.addLongIdentifier("keystorePIN", true); deleteCertKeystorePassword.addLongIdentifier("storepass", true); deleteCertKeystorePassword.setSensitive(true); deleteCertParser.addArgument(deleteCertKeystorePassword); final FileArgument deleteCertKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); deleteCertKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); deleteCertKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); deleteCertKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); deleteCertKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); deleteCertKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); deleteCertParser.addArgument(deleteCertKeystorePasswordFile); final BooleanArgument deleteCertPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_PROMPT_FOR_KS_PW_DESC.get()); deleteCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); deleteCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); deleteCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); deleteCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); deleteCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); deleteCertParser.addArgument(deleteCertPromptForKeystorePassword); final StringArgument deleteCertKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); deleteCertKeystoreType.addLongIdentifier("key-store-type", true); deleteCertKeystoreType.addLongIdentifier("keystoreType", true); deleteCertKeystoreType.addLongIdentifier("keystore-format", true); deleteCertKeystoreType.addLongIdentifier("key-store-format", true); deleteCertKeystoreType.addLongIdentifier("keystoreFormat", true); deleteCertKeystoreType.addLongIdentifier("storetype", true); deleteCertParser.addArgument(deleteCertKeystoreType); final StringArgument deleteCertAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_ALIAS_DESC.get()); deleteCertAlias.addLongIdentifier("nickname", true); deleteCertParser.addArgument(deleteCertAlias); final BooleanArgument deleteCertNoPrompt = new BooleanArgument(null, "no-prompt", 1, INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_NO_PROMPT_DESC.get()); deleteCertNoPrompt.addLongIdentifier("noPrompt", true); deleteCertParser.addArgument(deleteCertNoPrompt); final BooleanArgument deleteCertDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_DELETE_CERT_ARG_DISPLAY_COMMAND_DESC.get()); deleteCertDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); deleteCertDisplayCommand.addLongIdentifier("show-keytool-command", true); deleteCertDisplayCommand.addLongIdentifier("showKeytoolCommand", true); deleteCertParser.addArgument(deleteCertDisplayCommand); deleteCertParser.addExclusiveArgumentSet(deleteCertKeystorePassword, deleteCertKeystorePasswordFile, deleteCertPromptForKeystorePassword); deleteCertParser.addRequiredArgumentSet(deleteCertKeystorePassword, deleteCertKeystorePasswordFile, deleteCertPromptForKeystorePassword); final LinkedHashMap deleteCertExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); deleteCertExamples.put( new String[] { "delete-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--alias", "server-cert" }, INFO_MANAGE_CERTS_SC_DELETE_CERT_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"))); final SubCommand deleteCertSubCommand = new SubCommand("delete-certificate", INFO_MANAGE_CERTS_SC_DELETE_CERT_DESC.get(), deleteCertParser, deleteCertExamples); deleteCertSubCommand.addName("deleteCertificate", true); deleteCertSubCommand.addName("remove-certificate", true); deleteCertSubCommand.addName("removeCertificate", true); deleteCertSubCommand.addName("delete", true); deleteCertSubCommand.addName("remove", true); parser.addSubCommand(deleteCertSubCommand); // Define the "generate-self-signed-certificate" subcommand and all of its // arguments. final ArgumentParser genCertParser = new ArgumentParser( "generate-self-signed-certificate", INFO_MANAGE_CERTS_SC_GEN_CERT_DESC.get()); final FileArgument genCertKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KS_DESC.get(), false, true, true, false); genCertKeystore.addLongIdentifier("keystore-path", true); genCertKeystore.addLongIdentifier("keystorePath", true); genCertKeystore.addLongIdentifier("keystore-file", true); genCertKeystore.addLongIdentifier("keystoreFile", true); genCertParser.addArgument(genCertKeystore); final StringArgument genCertKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KS_PW_DESC.get()); genCertKeystorePassword.addLongIdentifier("keystorePassword", true); genCertKeystorePassword.addLongIdentifier("keystore-passphrase", true); genCertKeystorePassword.addLongIdentifier("keystorePassphrase", true); genCertKeystorePassword.addLongIdentifier("keystore-pin", true); genCertKeystorePassword.addLongIdentifier("keystorePIN", true); genCertKeystorePassword.addLongIdentifier("storepass", true); genCertKeystorePassword.setSensitive(true); genCertParser.addArgument(genCertKeystorePassword); final FileArgument genCertKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); genCertKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); genCertKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); genCertKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); genCertKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); genCertKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); genCertParser.addArgument(genCertKeystorePasswordFile); final BooleanArgument genCertPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_PROMPT_FOR_KS_PW_DESC.get()); genCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); genCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); genCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); genCertPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); genCertPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); genCertParser.addArgument(genCertPromptForKeystorePassword); final StringArgument genCertPKPassword = new StringArgument(null, "private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_PK_PW_DESC.get()); genCertPKPassword.addLongIdentifier("privateKeyPassword", true); genCertPKPassword.addLongIdentifier("private-key-passphrase", true); genCertPKPassword.addLongIdentifier("privateKeyPassphrase", true); genCertPKPassword.addLongIdentifier("private-key-pin", true); genCertPKPassword.addLongIdentifier("privateKeyPIN", true); genCertPKPassword.addLongIdentifier("key-password", true); genCertPKPassword.addLongIdentifier("keyPassword", true); genCertPKPassword.addLongIdentifier("key-passphrase", true); genCertPKPassword.addLongIdentifier("keyPassphrase", true); genCertPKPassword.addLongIdentifier("key-pin", true); genCertPKPassword.addLongIdentifier("keyPIN", true); genCertPKPassword.addLongIdentifier("keypass", true); genCertPKPassword.setSensitive(true); genCertParser.addArgument(genCertPKPassword); final FileArgument genCertPKPasswordFile = new FileArgument(null, "private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_PK_PW_FILE_DESC.get(), true, true, true, false); genCertPKPasswordFile.addLongIdentifier("privateKeyPasswordFile", true); genCertPKPasswordFile.addLongIdentifier("private-key-passphrase-file", true); genCertPKPasswordFile.addLongIdentifier("privateKeyPassphraseFile", true); genCertPKPasswordFile.addLongIdentifier("private-key-pin-file", true); genCertPKPasswordFile.addLongIdentifier("privateKeyPINFile", true); genCertPKPasswordFile.addLongIdentifier("key-password-file", true); genCertPKPasswordFile.addLongIdentifier("keyPasswordFile", true); genCertPKPasswordFile.addLongIdentifier("key-passphrase-file", true); genCertPKPasswordFile.addLongIdentifier("keyPassphraseFile", true); genCertPKPasswordFile.addLongIdentifier("key-pin-file", true); genCertPKPasswordFile.addLongIdentifier("keyPINFile", true); genCertParser.addArgument(genCertPKPasswordFile); final BooleanArgument genCertPromptForPKPassword = new BooleanArgument(null, "prompt-for-private-key-password", INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_PROMPT_FOR_PK_PW_DESC.get()); genCertPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassword", true); genCertPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-passphrase", true); genCertPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassphrase", true); genCertPromptForPKPassword.addLongIdentifier("prompt-for-private-key-pin", true); genCertPromptForPKPassword.addLongIdentifier("promptForPrivateKeyPIN", true); genCertPromptForPKPassword.addLongIdentifier("prompt-for-key-password", true); genCertPromptForPKPassword.addLongIdentifier("promptForKeyPassword", true); genCertPromptForPKPassword.addLongIdentifier( "prompt-for-key-passphrase", true); genCertPromptForPKPassword.addLongIdentifier( "promptForKeyPassphrase", true); genCertPromptForPKPassword.addLongIdentifier("prompt-for-key-pin", true); genCertPromptForPKPassword.addLongIdentifier("promptForKeyPIN", true); genCertParser.addArgument(genCertPromptForPKPassword); final StringArgument genCertKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); genCertKeystoreType.addLongIdentifier("key-store-type", true); genCertKeystoreType.addLongIdentifier("keystoreType", true); genCertKeystoreType.addLongIdentifier("keystore-format", true); genCertKeystoreType.addLongIdentifier("key-store-format", true); genCertKeystoreType.addLongIdentifier("keystoreFormat", true); genCertKeystoreType.addLongIdentifier("storetype", true); genCertParser.addArgument(genCertKeystoreType); final StringArgument genCertAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_ALIAS_DESC.get()); genCertAlias.addLongIdentifier("nickname", true); genCertParser.addArgument(genCertAlias); final BooleanArgument genCertUseExistingKeyPair = new BooleanArgument(null, "use-existing-key-pair", 1, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_USE_EXISTING_KP_DESC.get()); genCertUseExistingKeyPair.addLongIdentifier("use-existing-keypair", true); genCertUseExistingKeyPair.addLongIdentifier("useExistingKeypair", true); genCertUseExistingKeyPair.addLongIdentifier("replace-existing-certificate", true); genCertUseExistingKeyPair.addLongIdentifier("replaceExistingCertificate", true); genCertUseExistingKeyPair.addLongIdentifier("replace-certificate", true); genCertUseExistingKeyPair.addLongIdentifier("replaceCertificate", true); genCertUseExistingKeyPair.addLongIdentifier("replace-existing", true); genCertUseExistingKeyPair.addLongIdentifier("replaceExisting", true); genCertUseExistingKeyPair.addLongIdentifier("replace", true); genCertParser.addArgument(genCertUseExistingKeyPair); final DNArgument genCertSubjectDN = new DNArgument(null, "subject-dn", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SUBJECT_DN_DESC.get()); genCertSubjectDN.addLongIdentifier("subjectDN", true); genCertSubjectDN.addLongIdentifier("subject", true); genCertSubjectDN.addLongIdentifier("dname", true); genCertParser.addArgument(genCertSubjectDN); final IntegerArgument genCertDaysValid = new IntegerArgument(null, "days-valid", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_DAYS_VALID_DESC.get(), 1, Integer.MAX_VALUE); genCertDaysValid.addLongIdentifier("daysValid", true); genCertDaysValid.addLongIdentifier("validity", true); genCertParser.addArgument(genCertDaysValid); final TimestampArgument genCertNotBefore = new TimestampArgument(null, "validity-start-time", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TIMESTAMP.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_VALIDITY_START_TIME_DESC.get( "20180102123456")); genCertNotBefore.addLongIdentifier("validityStartTime", true); genCertNotBefore.addLongIdentifier("not-before", true); genCertNotBefore.addLongIdentifier("notBefore", true); genCertParser.addArgument(genCertNotBefore); final StringArgument genCertKeyAlgorithm = new StringArgument(null, "key-algorithm", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KEY_ALGORITHM_DESC.get()); genCertKeyAlgorithm.addLongIdentifier("keyAlgorithm", true); genCertKeyAlgorithm.addLongIdentifier("key-alg", true); genCertKeyAlgorithm.addLongIdentifier("keyAlg", true); genCertParser.addArgument(genCertKeyAlgorithm); final IntegerArgument genCertKeySizeBits = new IntegerArgument(null, "key-size-bits", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_BITS.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KEY_SIZE_BITS_DESC.get(), 1, Integer.MAX_VALUE); genCertKeySizeBits.addLongIdentifier("keySizeBits", true); genCertKeySizeBits.addLongIdentifier("key-length-bits", true); genCertKeySizeBits.addLongIdentifier("keyLengthBits", true); genCertKeySizeBits.addLongIdentifier("key-size", true); genCertKeySizeBits.addLongIdentifier("keySize", true); genCertKeySizeBits.addLongIdentifier("key-length", true); genCertKeySizeBits.addLongIdentifier("keyLength", true); genCertParser.addArgument(genCertKeySizeBits); final StringArgument genCertSignatureAlgorithm = new StringArgument(null, "signature-algorithm", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SIG_ALG_DESC.get()); genCertSignatureAlgorithm.addLongIdentifier("signatureAlgorithm", true); genCertSignatureAlgorithm.addLongIdentifier("signature-alg", true); genCertSignatureAlgorithm.addLongIdentifier("signatureAlg", true); genCertSignatureAlgorithm.addLongIdentifier("sig-alg", true); genCertSignatureAlgorithm.addLongIdentifier("sigAlg", true); genCertParser.addArgument(genCertSignatureAlgorithm); final BooleanArgument genCertInheritExtensions = new BooleanArgument(null, "inherit-extensions", 1, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_INHERIT_EXT_DESC.get()); genCertInheritExtensions.addLongIdentifier("inheritExtensions", true); genCertParser.addArgument(genCertInheritExtensions); final StringArgument genCertSubjectAltDNS = new StringArgument(null, "subject-alternative-name-dns", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SAN_DNS_DESC.get()); genCertSubjectAltDNS.addLongIdentifier("subjectAlternativeNameDNS", true); genCertSubjectAltDNS.addLongIdentifier("subject-alt-name-dns", true); genCertSubjectAltDNS.addLongIdentifier("subjectAltNameDNS", true); genCertSubjectAltDNS.addLongIdentifier("subject-alternative-dns", true); genCertSubjectAltDNS.addLongIdentifier("subjectAlternativeDNS", true); genCertSubjectAltDNS.addLongIdentifier("subject-alt-dns", true); genCertSubjectAltDNS.addLongIdentifier("subjectAltDNS", true); genCertSubjectAltDNS.addLongIdentifier("san-dns", true); genCertSubjectAltDNS.addLongIdentifier("sanDNS", true); genCertSubjectAltDNS.addValueValidator( new IA5StringArgumentValueValidator(false)); genCertParser.addArgument(genCertSubjectAltDNS); final StringArgument genCertSubjectAltIP = new StringArgument(null, "subject-alternative-name-ip-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SAN_IP_DESC.get()); genCertSubjectAltIP.addLongIdentifier("subjectAlternativeNameIPAddress", true); genCertSubjectAltIP.addLongIdentifier("subject-alternative-name-ip", true); genCertSubjectAltIP.addLongIdentifier("subjectAlternativeNameIP", true); genCertSubjectAltIP.addLongIdentifier("subject-alt-name-ip-address", true); genCertSubjectAltIP.addLongIdentifier("subjectAltNameIPAddress", true); genCertSubjectAltIP.addLongIdentifier("subject-alt-name-ip", true); genCertSubjectAltIP.addLongIdentifier("subjectAltNameIP", true); genCertSubjectAltIP.addLongIdentifier("subject-alternative-ip-address", true); genCertSubjectAltIP.addLongIdentifier("subjectAlternativeIPAddress", true); genCertSubjectAltIP.addLongIdentifier("subject-alternative-ip", true); genCertSubjectAltIP.addLongIdentifier("subjectAlternativeIP", true); genCertSubjectAltIP.addLongIdentifier("subject-alt-ip-address", true); genCertSubjectAltIP.addLongIdentifier("subjectAltIPAddress", true); genCertSubjectAltIP.addLongIdentifier("subject-alt-ip", true); genCertSubjectAltIP.addLongIdentifier("subjectAltIP", true); genCertSubjectAltIP.addLongIdentifier("san-ip-address", true); genCertSubjectAltIP.addLongIdentifier("sanIPAddress", true); genCertSubjectAltIP.addLongIdentifier("san-ip", true); genCertSubjectAltIP.addLongIdentifier("sanIP", true); genCertSubjectAltIP.addValueValidator( new IPAddressArgumentValueValidator(true, true)); genCertParser.addArgument(genCertSubjectAltIP); final StringArgument genCertSubjectAltEmail = new StringArgument(null, "subject-alternative-name-email-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SAN_EMAIL_DESC.get()); genCertSubjectAltEmail.addLongIdentifier( "subjectAlternativeNameEmailAddress", true); genCertSubjectAltEmail.addLongIdentifier("subject-alternative-name-email", true); genCertSubjectAltEmail.addLongIdentifier("subjectAlternativeNameEmail", true); genCertSubjectAltEmail.addLongIdentifier("subject-alt-name-email-address", true); genCertSubjectAltEmail.addLongIdentifier("subjectAltNameEmailAddress", true); genCertSubjectAltEmail.addLongIdentifier("subject-alt-name-email", true); genCertSubjectAltEmail.addLongIdentifier("subjectAltNameEmail", true); genCertSubjectAltEmail.addLongIdentifier( "subject-alternative-email-address", true); genCertSubjectAltEmail.addLongIdentifier("subjectAlternativeEmailAddress", true); genCertSubjectAltEmail.addLongIdentifier("subject-alternative-email", true); genCertSubjectAltEmail.addLongIdentifier("subjectAlternativeEmail", true); genCertSubjectAltEmail.addLongIdentifier("subject-alt-email-address", true); genCertSubjectAltEmail.addLongIdentifier("subjectAltEmailAddress", true); genCertSubjectAltEmail.addLongIdentifier("subject-alt-email", true); genCertSubjectAltEmail.addLongIdentifier("subjectAltEmail", true); genCertSubjectAltEmail.addLongIdentifier("san-email-address", true); genCertSubjectAltEmail.addLongIdentifier("sanEmailAddress", true); genCertSubjectAltEmail.addLongIdentifier("san-email", true); genCertSubjectAltEmail.addLongIdentifier("sanEmail", true); genCertSubjectAltEmail.addValueValidator( new IA5StringArgumentValueValidator(false)); genCertParser.addArgument(genCertSubjectAltEmail); final StringArgument genCertSubjectAltURI = new StringArgument(null, "subject-alternative-name-uri", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_URI.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SAN_URI_DESC.get()); genCertSubjectAltURI.addLongIdentifier("subjectAlternativeNameURI", true); genCertSubjectAltURI.addLongIdentifier("subject-alt-name-uri", true); genCertSubjectAltURI.addLongIdentifier("subjectAltNameURI", true); genCertSubjectAltURI.addLongIdentifier("subject-alternative-uri", true); genCertSubjectAltURI.addLongIdentifier("subjectAlternativeURI", true); genCertSubjectAltURI.addLongIdentifier("subject-alt-uri", true); genCertSubjectAltURI.addLongIdentifier("subjectAltURI", true); genCertSubjectAltURI.addLongIdentifier("san-uri", true); genCertSubjectAltURI.addLongIdentifier("sanURI", true); genCertParser.addArgument(genCertSubjectAltURI); final StringArgument genCertSubjectAltOID = new StringArgument(null, "subject-alternative-name-oid", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_OID.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_SAN_OID_DESC.get()); genCertSubjectAltOID.addLongIdentifier("subjectAlternativeNameOID", true); genCertSubjectAltOID.addLongIdentifier("subject-alt-name-oid", true); genCertSubjectAltOID.addLongIdentifier("subjectAltNameOID", true); genCertSubjectAltOID.addLongIdentifier("subject-alternative-oid", true); genCertSubjectAltOID.addLongIdentifier("subjectAlternativeOID", true); genCertSubjectAltOID.addLongIdentifier("subject-alt-oid", true); genCertSubjectAltOID.addLongIdentifier("subjectAltOID", true); genCertSubjectAltOID.addLongIdentifier("san-oid", true); genCertSubjectAltOID.addLongIdentifier("sanOID", true); genCertSubjectAltOID.addValueValidator(new OIDArgumentValueValidator(true)); genCertParser.addArgument(genCertSubjectAltOID); final BooleanValueArgument genCertBasicConstraintsIsCA = new BooleanValueArgument(null, "basic-constraints-is-ca", false, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_BC_IS_CA_DESC.get()); genCertBasicConstraintsIsCA.addLongIdentifier("basicConstraintsIsCA", true); genCertBasicConstraintsIsCA.addLongIdentifier("bc-is-ca", true); genCertBasicConstraintsIsCA.addLongIdentifier("bcIsCA", true); genCertParser.addArgument(genCertBasicConstraintsIsCA); final IntegerArgument genCertBasicConstraintsPathLength = new IntegerArgument(null, "basic-constraints-maximum-path-length", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_BC_PATH_LENGTH_DESC.get(), 0, Integer.MAX_VALUE); genCertBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsMaximumPathLength", true); genCertBasicConstraintsPathLength.addLongIdentifier( "basic-constraints-max-path-length", true); genCertBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsMaxPathLength", true); genCertBasicConstraintsPathLength.addLongIdentifier( "basic-constraints-path-length", true); genCertBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsPathLength", true); genCertBasicConstraintsPathLength.addLongIdentifier( "bc-maximum-path-length", true); genCertBasicConstraintsPathLength.addLongIdentifier("bcMaximumPathLength", true); genCertBasicConstraintsPathLength.addLongIdentifier("bc-max-path-length", true); genCertBasicConstraintsPathLength.addLongIdentifier("bcMaxPathLength", true); genCertBasicConstraintsPathLength.addLongIdentifier("bc-path-length", true); genCertBasicConstraintsPathLength.addLongIdentifier("bcPathLength", true); genCertParser.addArgument(genCertBasicConstraintsPathLength); final StringArgument genCertKeyUsage = new StringArgument(null, "key-usage", false, 0, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_KU_DESC.get()); genCertKeyUsage.addLongIdentifier("keyUsage", true); genCertParser.addArgument(genCertKeyUsage); final StringArgument genCertExtendedKeyUsage = new StringArgument(null, "extended-key-usage", false, 0, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_EKU_DESC.get()); genCertExtendedKeyUsage.addLongIdentifier("extendedKeyUsage", true); genCertParser.addArgument(genCertExtendedKeyUsage); final StringArgument genCertExtension = new StringArgument(null, "extension", false, 0, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_EXT_DESC.get()); genCertExtension.addLongIdentifier("ext", true); genCertParser.addArgument(genCertExtension); final FileArgument genCertOutputFile = new FileArgument(null, "output-file", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_OUTPUT_FILE_DESC.get(), false, true, true, false); genCertOutputFile.addLongIdentifier("outputFile", true); genCertOutputFile.addLongIdentifier("filename", true); genCertOutputFile.addLongIdentifier("file", true); genCertParser.addArgument(genCertOutputFile); final Set genCertOutputFormatAllowedValues = StaticUtils.setOf( "PEM", "text", "txt", "RFC", "DER", "binary", "bin"); final StringArgument genCertOutputFormat = new StringArgument(null, "output-format", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_FORMAT.get(), INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_FORMAT_DESC.get(), genCertOutputFormatAllowedValues, "PEM"); genCertOutputFormat.addLongIdentifier("outputFormat", true); genCertParser.addArgument(genCertOutputFormat); final BooleanArgument genCertDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_DISPLAY_COMMAND_DESC.get()); genCertDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); genCertDisplayCommand.addLongIdentifier("show-keytool-command", true); genCertDisplayCommand.addLongIdentifier("showKeytoolCommand", true); genCertParser.addArgument(genCertDisplayCommand); genCertParser.addRequiredArgumentSet(genCertKeystorePassword, genCertKeystorePasswordFile, genCertPromptForKeystorePassword); genCertParser.addExclusiveArgumentSet(genCertKeystorePassword, genCertKeystorePasswordFile, genCertPromptForKeystorePassword); genCertParser.addExclusiveArgumentSet(genCertPKPassword, genCertPKPasswordFile, genCertPromptForPKPassword); genCertParser.addExclusiveArgumentSet(genCertUseExistingKeyPair, genCertKeyAlgorithm); genCertParser.addExclusiveArgumentSet(genCertUseExistingKeyPair, genCertKeySizeBits); genCertParser.addExclusiveArgumentSet(genCertUseExistingKeyPair, genCertSignatureAlgorithm); genCertParser.addDependentArgumentSet(genCertBasicConstraintsPathLength, genCertBasicConstraintsIsCA); genCertParser.addDependentArgumentSet(genCertOutputFormat, genCertOutputFile); final LinkedHashMap genCertExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(4)); genCertExamples.put( new String[] { "generate-self-signed-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--subject-dn", "CN=ldap.example.com,O=Example Corp,C=US" }, INFO_MANAGE_CERTS_SC_GEN_CERT_EXAMPLE_1.get()); genCertExamples.put( new String[] { "generate-self-signed-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--use-existing-key-pair", "--inherit-extensions" }, INFO_MANAGE_CERTS_SC_GEN_CERT_EXAMPLE_2.get()); genCertExamples.put( new String[] { "generate-self-signed-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--subject-dn", "CN=ldap.example.com,O=Example Corp,C=US", "--days-valid", "3650", "--validity-start-time", "20170101000000", "--key-algorithm", "RSA", "--key-size-bits", "4096", "--signature-algorithm", "SHA256withRSA", "--subject-alternative-name-dns", "ldap1.example.com", "--subject-alternative-name-dns", "ldap2.example.com", "--subject-alternative-name-ip-address", "1.2.3.4", "--subject-alternative-name-ip-address", "1.2.3.5", "--extended-key-usage", "server-auth", "--extended-key-usage", "client-auth", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_GEN_CERT_EXAMPLE_3.get()); genCertExamples.put( new String[] { "generate-self-signed-certificate", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "ca-cert", "--subject-dn", "CN=Example Certification Authority,O=Example Corp,C=US", "--days-valid", "7300", "--validity-start-time", "20170101000000", "--key-algorithm", "EC", "--key-size-bits", "256", "--signature-algorithm", "SHA256withECDSA", "--basic-constraints-is-ca", "true", "--key-usage", "key-cert-sign", "--key-usage", "crl-sign", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_GEN_CERT_EXAMPLE_4.get()); final SubCommand genCertSubCommand = new SubCommand( "generate-self-signed-certificate", INFO_MANAGE_CERTS_SC_GEN_CERT_DESC.get(), genCertParser, genCertExamples); genCertSubCommand.addName("generateSelfSignedCertificate", true); genCertSubCommand.addName("generate-certificate", true); genCertSubCommand.addName("generateCertificate", true); genCertSubCommand.addName("self-signed-certificate", true); genCertSubCommand.addName("selfSignedCertificate", true); genCertSubCommand.addName("selfcert", true); parser.addSubCommand(genCertSubCommand); // Define the "generate-certificate-signing-request" subcommand and all of // its arguments. final ArgumentParser genCSRParser = new ArgumentParser( "generate-certificate-signing-request", INFO_MANAGE_CERTS_SC_GEN_CSR_DESC.get()); final Set genCSROutputFormatAllowedValues = StaticUtils.setOf( "PEM", "text", "txt", "RFC", "DER", "binary", "bin"); final StringArgument genCSROutputFormat = new StringArgument(null, "output-format", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_FORMAT.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_FORMAT_DESC.get(), genCSROutputFormatAllowedValues, "PEM"); genCSROutputFormat.addLongIdentifier("outputFormat", true); genCSRParser.addArgument(genCSROutputFormat); final FileArgument genCSROutputFile = new FileArgument(null, "output-file", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_OUTPUT_FILE_DESC.get(), false, true, true, false); genCSROutputFile.addLongIdentifier("outputFile", true); genCSROutputFile.addLongIdentifier("filename", true); genCSROutputFile.addLongIdentifier("file", true); genCSRParser.addArgument(genCSROutputFile); final FileArgument genCSRKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KS_DESC.get(), false, true, true, false); genCSRKeystore.addLongIdentifier("keystore-path", true); genCSRKeystore.addLongIdentifier("keystorePath", true); genCSRKeystore.addLongIdentifier("keystore-file", true); genCSRKeystore.addLongIdentifier("keystoreFile", true); genCSRParser.addArgument(genCSRKeystore); final StringArgument genCSRKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KS_PW_DESC.get()); genCSRKeystorePassword.addLongIdentifier("keystorePassword", true); genCSRKeystorePassword.addLongIdentifier("keystore-passphrase", true); genCSRKeystorePassword.addLongIdentifier("keystorePassphrase", true); genCSRKeystorePassword.addLongIdentifier("keystore-pin", true); genCSRKeystorePassword.addLongIdentifier("keystorePIN", true); genCSRKeystorePassword.addLongIdentifier("storepass", true); genCSRKeystorePassword.setSensitive(true); genCSRParser.addArgument(genCSRKeystorePassword); final FileArgument genCSRKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); genCSRKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); genCSRKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); genCSRKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); genCSRKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); genCSRKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); genCSRParser.addArgument(genCSRKeystorePasswordFile); final BooleanArgument genCSRPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_PROMPT_FOR_KS_PW_DESC.get()); genCSRPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); genCSRPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); genCSRPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); genCSRPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); genCSRPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); genCSRParser.addArgument(genCSRPromptForKeystorePassword); final StringArgument genCSRPKPassword = new StringArgument(null, "private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_PK_PW_DESC.get()); genCSRPKPassword.addLongIdentifier("privateKeyPassword", true); genCSRPKPassword.addLongIdentifier("private-key-passphrase", true); genCSRPKPassword.addLongIdentifier("privateKeyPassphrase", true); genCSRPKPassword.addLongIdentifier("private-key-pin", true); genCSRPKPassword.addLongIdentifier("privateKeyPIN", true); genCSRPKPassword.addLongIdentifier("key-password", true); genCSRPKPassword.addLongIdentifier("keyPassword", true); genCSRPKPassword.addLongIdentifier("key-passphrase", true); genCSRPKPassword.addLongIdentifier("keyPassphrase", true); genCSRPKPassword.addLongIdentifier("key-pin", true); genCSRPKPassword.addLongIdentifier("keyPIN", true); genCSRPKPassword.addLongIdentifier("keypass", true); genCSRPKPassword.setSensitive(true); genCSRParser.addArgument(genCSRPKPassword); final FileArgument genCSRPKPasswordFile = new FileArgument(null, "private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_PK_PW_FILE_DESC.get(), true, true, true, false); genCSRPKPasswordFile.addLongIdentifier("privateKeyPasswordFile", true); genCSRPKPasswordFile.addLongIdentifier("private-key-passphrase-file", true); genCSRPKPasswordFile.addLongIdentifier("privateKeyPassphraseFile", true); genCSRPKPasswordFile.addLongIdentifier("private-key-pin-file", true); genCSRPKPasswordFile.addLongIdentifier("privateKeyPINFile", true); genCSRPKPasswordFile.addLongIdentifier("key-password-file", true); genCSRPKPasswordFile.addLongIdentifier("keyPasswordFile", true); genCSRPKPasswordFile.addLongIdentifier("key-passphrase-file", true); genCSRPKPasswordFile.addLongIdentifier("keyPassphraseFile", true); genCSRPKPasswordFile.addLongIdentifier("key-pin-file", true); genCSRPKPasswordFile.addLongIdentifier("keyPINFile", true); genCSRParser.addArgument(genCSRPKPasswordFile); final BooleanArgument genCSRPromptForPKPassword = new BooleanArgument(null, "prompt-for-private-key-password", INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_PROMPT_FOR_PK_PW_DESC.get()); genCSRPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassword", true); genCSRPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-passphrase", true); genCSRPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassphrase", true); genCSRPromptForPKPassword.addLongIdentifier("prompt-for-private-key-pin", true); genCSRPromptForPKPassword.addLongIdentifier("promptForPrivateKeyPIN", true); genCSRPromptForPKPassword.addLongIdentifier("prompt-for-key-password", true); genCSRPromptForPKPassword.addLongIdentifier("promptForKeyPassword", true); genCSRPromptForPKPassword.addLongIdentifier( "prompt-for-key-passphrase", true); genCSRPromptForPKPassword.addLongIdentifier( "promptForKeyPassphrase", true); genCSRPromptForPKPassword.addLongIdentifier("prompt-for-key-pin", true); genCSRPromptForPKPassword.addLongIdentifier("promptForKeyPIN", true); genCSRParser.addArgument(genCSRPromptForPKPassword); final StringArgument genCSRKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); genCSRKeystoreType.addLongIdentifier("key-store-type", true); genCSRKeystoreType.addLongIdentifier("keystoreType", true); genCSRKeystoreType.addLongIdentifier("keystore-format", true); genCSRKeystoreType.addLongIdentifier("key-store-format", true); genCSRKeystoreType.addLongIdentifier("keystoreFormat", true); genCSRKeystoreType.addLongIdentifier("storetype", true); genCSRParser.addArgument(genCSRKeystoreType); final StringArgument genCSRAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_ALIAS_DESC.get()); genCSRAlias.addLongIdentifier("nickname", true); genCSRParser.addArgument(genCSRAlias); final BooleanArgument genCSRUseExistingKeyPair = new BooleanArgument(null, "use-existing-key-pair", 1, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_USE_EXISTING_KP_DESC.get()); genCSRUseExistingKeyPair.addLongIdentifier("use-existing-keypair", true); genCSRUseExistingKeyPair.addLongIdentifier("useExistingKeyPair", true); genCSRUseExistingKeyPair.addLongIdentifier("replace-existing-certificate", true); genCSRUseExistingKeyPair.addLongIdentifier("replaceExistingCertificate", true); genCSRUseExistingKeyPair.addLongIdentifier("replace-certificate", true); genCSRUseExistingKeyPair.addLongIdentifier("replaceCertificate", true); genCSRUseExistingKeyPair.addLongIdentifier("replace-existing", true); genCSRUseExistingKeyPair.addLongIdentifier("replaceExisting", true); genCSRUseExistingKeyPair.addLongIdentifier("replace", true); genCSRParser.addArgument(genCSRUseExistingKeyPair); final DNArgument genCSRSubjectDN = new DNArgument(null, "subject-dn", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SUBJECT_DN_DESC.get()); genCSRSubjectDN.addLongIdentifier("subjectDN", true); genCSRSubjectDN.addLongIdentifier("subject", true); genCSRSubjectDN.addLongIdentifier("dname", true); genCSRParser.addArgument(genCSRSubjectDN); final StringArgument genCSRKeyAlgorithm = new StringArgument(null, "key-algorithm", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KEY_ALGORITHM_DESC.get()); genCSRKeyAlgorithm.addLongIdentifier("keyAlgorithm", true); genCSRKeyAlgorithm.addLongIdentifier("key-alg", true); genCSRKeyAlgorithm.addLongIdentifier("keyAlg", true); genCSRParser.addArgument(genCSRKeyAlgorithm); final IntegerArgument genCSRKeySizeBits = new IntegerArgument(null, "key-size-bits", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_BITS.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KEY_SIZE_BITS_DESC.get(), 1, Integer.MAX_VALUE); genCSRKeySizeBits.addLongIdentifier("keySizeBits", true); genCSRKeySizeBits.addLongIdentifier("key-length-bits", true); genCSRKeySizeBits.addLongIdentifier("keyLengthBits", true); genCSRKeySizeBits.addLongIdentifier("key-size", true); genCSRKeySizeBits.addLongIdentifier("keySize", true); genCSRKeySizeBits.addLongIdentifier("key-length", true); genCSRKeySizeBits.addLongIdentifier("keyLength", true); genCSRParser.addArgument(genCSRKeySizeBits); final StringArgument genCSRSignatureAlgorithm = new StringArgument(null, "signature-algorithm", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SIG_ALG_DESC.get()); genCSRSignatureAlgorithm.addLongIdentifier("signatureAlgorithm", true); genCSRSignatureAlgorithm.addLongIdentifier("signature-alg", true); genCSRSignatureAlgorithm.addLongIdentifier("signatureAlg", true); genCSRSignatureAlgorithm.addLongIdentifier("sig-alg", true); genCSRSignatureAlgorithm.addLongIdentifier("sigAlg", true); genCSRParser.addArgument(genCSRSignatureAlgorithm); final BooleanArgument genCSRInheritExtensions = new BooleanArgument(null, "inherit-extensions", 1, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_INHERIT_EXT_DESC.get()); genCSRInheritExtensions.addLongIdentifier("inheritExtensions", true); genCSRParser.addArgument(genCSRInheritExtensions); final StringArgument genCSRSubjectAltDNS = new StringArgument(null, "subject-alternative-name-dns", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SAN_DNS_DESC.get()); genCSRSubjectAltDNS.addLongIdentifier("subjectAlternativeNameDNS", true); genCSRSubjectAltDNS.addLongIdentifier("subject-alt-name-dns", true); genCSRSubjectAltDNS.addLongIdentifier("subjectAltNameDNS", true); genCSRSubjectAltDNS.addLongIdentifier("subject-alternative-dns", true); genCSRSubjectAltDNS.addLongIdentifier("subjectAlternativeDNS", true); genCSRSubjectAltDNS.addLongIdentifier("subject-alt-dns", true); genCSRSubjectAltDNS.addLongIdentifier("subjectAltDNS", true); genCSRSubjectAltDNS.addLongIdentifier("san-dns", true); genCSRSubjectAltDNS.addLongIdentifier("sanDNS", true); genCSRSubjectAltDNS.addValueValidator( new IA5StringArgumentValueValidator(false)); genCSRParser.addArgument(genCSRSubjectAltDNS); final StringArgument genCSRSubjectAltIP = new StringArgument(null, "subject-alternative-name-ip-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SAN_IP_DESC.get()); genCSRSubjectAltIP.addLongIdentifier("subjectAlternativeNameIPAddress", true); genCSRSubjectAltIP.addLongIdentifier("subject-alternative-name-ip", true); genCSRSubjectAltIP.addLongIdentifier("subjectAlternativeNameIP", true); genCSRSubjectAltIP.addLongIdentifier("subject-alt-name-ip-address", true); genCSRSubjectAltIP.addLongIdentifier("subjectAltNameIPAddress", true); genCSRSubjectAltIP.addLongIdentifier("subject-alt-name-ip", true); genCSRSubjectAltIP.addLongIdentifier("subjectAltNameIP", true); genCSRSubjectAltIP.addLongIdentifier("subject-alternative-ip-address", true); genCSRSubjectAltIP.addLongIdentifier("subjectAlternativeIPAddress", true); genCSRSubjectAltIP.addLongIdentifier("subject-alternative-ip", true); genCSRSubjectAltIP.addLongIdentifier("subjectAlternativeIP", true); genCSRSubjectAltIP.addLongIdentifier("subject-alt-ip-address", true); genCSRSubjectAltIP.addLongIdentifier("subjectAltIPAddress", true); genCSRSubjectAltIP.addLongIdentifier("subject-alt-ip", true); genCSRSubjectAltIP.addLongIdentifier("subjectAltIP", true); genCSRSubjectAltIP.addLongIdentifier("san-ip-address", true); genCSRSubjectAltIP.addLongIdentifier("sanIPAddress", true); genCSRSubjectAltIP.addLongIdentifier("san-ip", true); genCSRSubjectAltIP.addLongIdentifier("sanIP", true); genCSRSubjectAltIP.addValueValidator( new IPAddressArgumentValueValidator(true, true)); genCSRParser.addArgument(genCSRSubjectAltIP); final StringArgument genCSRSubjectAltEmail = new StringArgument(null, "subject-alternative-name-email-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SAN_EMAIL_DESC.get()); genCSRSubjectAltEmail.addLongIdentifier( "subjectAlternativeNameEmailAddress", true); genCSRSubjectAltEmail.addLongIdentifier("subject-alternative-name-email", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAlternativeNameEmail", true); genCSRSubjectAltEmail.addLongIdentifier("subject-alt-name-email-address", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAltNameEmailAddress", true); genCSRSubjectAltEmail.addLongIdentifier("subject-alt-name-email", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAltNameEmail", true); genCSRSubjectAltEmail.addLongIdentifier( "subject-alternative-email-address", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAlternativeEmailAddress", true); genCSRSubjectAltEmail.addLongIdentifier("subject-alternative-email", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAlternativeEmail", true); genCSRSubjectAltEmail.addLongIdentifier("subject-alt-email-address", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAltEmailAddress", true); genCSRSubjectAltEmail.addLongIdentifier("subject-alt-email", true); genCSRSubjectAltEmail.addLongIdentifier("subjectAltEmail", true); genCSRSubjectAltEmail.addLongIdentifier("san-email-address", true); genCSRSubjectAltEmail.addLongIdentifier("sanEmailAddress", true); genCSRSubjectAltEmail.addLongIdentifier("san-email", true); genCSRSubjectAltEmail.addLongIdentifier("sanEmail", true); genCSRSubjectAltEmail.addValueValidator( new IA5StringArgumentValueValidator(false)); genCSRParser.addArgument(genCSRSubjectAltEmail); final StringArgument genCSRSubjectAltURI = new StringArgument(null, "subject-alternative-name-uri", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_URI.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SAN_URI_DESC.get()); genCSRSubjectAltURI.addLongIdentifier("subjectAlternativeNameURI", true); genCSRSubjectAltURI.addLongIdentifier("subject-alt-name-uri", true); genCSRSubjectAltURI.addLongIdentifier("subjectAltNameURI", true); genCSRSubjectAltURI.addLongIdentifier("subject-alternative-uri", true); genCSRSubjectAltURI.addLongIdentifier("subjectAlternativeURI", true); genCSRSubjectAltURI.addLongIdentifier("subject-alt-uri", true); genCSRSubjectAltURI.addLongIdentifier("subjectAltURI", true); genCSRSubjectAltURI.addLongIdentifier("san-uri", true); genCSRSubjectAltURI.addLongIdentifier("sanURI", true); genCSRParser.addArgument(genCSRSubjectAltURI); final StringArgument genCSRSubjectAltOID = new StringArgument(null, "subject-alternative-name-oid", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_OID.get(), INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_SAN_OID_DESC.get()); genCSRSubjectAltOID.addLongIdentifier("subjectAlternativeNameOID", true); genCSRSubjectAltOID.addLongIdentifier("subject-alt-name-oid", true); genCSRSubjectAltOID.addLongIdentifier("subjectAltNameOID", true); genCSRSubjectAltOID.addLongIdentifier("subject-alternative-oid", true); genCSRSubjectAltOID.addLongIdentifier("subjectAlternativeOID", true); genCSRSubjectAltOID.addLongIdentifier("subject-alt-oid", true); genCSRSubjectAltOID.addLongIdentifier("subjectAltOID", true); genCSRSubjectAltOID.addLongIdentifier("san-oid", true); genCSRSubjectAltOID.addLongIdentifier("sanOID", true); genCSRSubjectAltOID.addValueValidator(new OIDArgumentValueValidator(true)); genCSRParser.addArgument(genCSRSubjectAltOID); final BooleanValueArgument genCSRBasicConstraintsIsCA = new BooleanValueArgument(null, "basic-constraints-is-ca", false, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_BC_IS_CA_DESC.get()); genCSRBasicConstraintsIsCA.addLongIdentifier("basicConstraintsIsCA", true); genCSRBasicConstraintsIsCA.addLongIdentifier("bc-is-ca", true); genCSRBasicConstraintsIsCA.addLongIdentifier("bcIsCA", true); genCSRParser.addArgument(genCSRBasicConstraintsIsCA); final IntegerArgument genCSRBasicConstraintsPathLength = new IntegerArgument(null, "basic-constraints-maximum-path-length", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_BC_PATH_LENGTH_DESC.get(), 0, Integer.MAX_VALUE); genCSRBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsMaximumPathLength", true); genCSRBasicConstraintsPathLength.addLongIdentifier( "basic-constraints-max-path-length", true); genCSRBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsMaxPathLength", true); genCSRBasicConstraintsPathLength.addLongIdentifier( "basic-constraints-path-length", true); genCSRBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsPathLength", true); genCSRBasicConstraintsPathLength.addLongIdentifier( "bc-maximum-path-length", true); genCSRBasicConstraintsPathLength.addLongIdentifier("bcMaximumPathLength", true); genCSRBasicConstraintsPathLength.addLongIdentifier("bc-max-path-length", true); genCSRBasicConstraintsPathLength.addLongIdentifier("bcMaxPathLength", true); genCSRBasicConstraintsPathLength.addLongIdentifier("bc-path-length", true); genCSRBasicConstraintsPathLength.addLongIdentifier("bcPathLength", true); genCSRParser.addArgument(genCSRBasicConstraintsPathLength); final StringArgument genCSRKeyUsage = new StringArgument(null, "key-usage", false, 0, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_KU_DESC.get()); genCSRKeyUsage.addLongIdentifier("keyUsage", true); genCSRParser.addArgument(genCSRKeyUsage); final StringArgument genCSRExtendedKeyUsage = new StringArgument(null, "extended-key-usage", false, 0, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_EKU_DESC.get()); genCSRExtendedKeyUsage.addLongIdentifier("extendedKeyUsage", true); genCSRParser.addArgument(genCSRExtendedKeyUsage); final StringArgument genCSRExtension = new StringArgument(null, "extension", false, 0, null, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_EXT_DESC.get()); genCSRExtension.addLongIdentifier("ext", true); genCSRParser.addArgument(genCSRExtension); final BooleanArgument genCSRDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_GEN_CSR_ARG_DISPLAY_COMMAND_DESC.get()); genCSRDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); genCSRDisplayCommand.addLongIdentifier("show-keytool-command", true); genCSRDisplayCommand.addLongIdentifier("showKeytoolCommand", true); genCSRParser.addArgument(genCSRDisplayCommand); genCSRParser.addRequiredArgumentSet(genCSRKeystorePassword, genCSRKeystorePasswordFile, genCSRPromptForKeystorePassword); genCSRParser.addExclusiveArgumentSet(genCSRKeystorePassword, genCSRKeystorePasswordFile, genCSRPromptForKeystorePassword); genCSRParser.addExclusiveArgumentSet(genCSRPKPassword, genCSRPKPasswordFile, genCSRPromptForPKPassword); genCSRParser.addExclusiveArgumentSet(genCSRUseExistingKeyPair, genCSRKeyAlgorithm); genCSRParser.addExclusiveArgumentSet(genCSRUseExistingKeyPair, genCSRKeySizeBits); genCSRParser.addExclusiveArgumentSet(genCSRUseExistingKeyPair, genCSRSignatureAlgorithm); genCSRParser.addDependentArgumentSet(genCSRBasicConstraintsPathLength, genCSRBasicConstraintsIsCA); final LinkedHashMap genCSRExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(3)); genCSRExamples.put( new String[] { "generate-certificate-signing-request", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--subject-dn", "CN=ldap.example.com,O=Example Corp,C=US" }, INFO_MANAGE_CERTS_SC_GEN_CSR_EXAMPLE_1.get()); genCSRExamples.put( new String[] { "generate-certificate-signing-request", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--use-existing-key-pair", "--inherit-extensions", "--output-file", "server-cert.csr" }, INFO_MANAGE_CERTS_SC_GEN_CSR_EXAMPLE_2.get()); genCSRExamples.put( new String[] { "generate-certificate-signing-request", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--subject-dn", "CN=ldap.example.com,O=Example Corp,C=US", "--key-algorithm", "EC", "--key-size-bits", "256", "--signature-algorithm", "SHA256withECDSA", "--subject-alternative-name-dns", "ldap1.example.com", "--subject-alternative-name-dns", "ldap2.example.com", "--subject-alternative-name-ip-address", "1.2.3.4", "--subject-alternative-name-ip-address", "1.2.3.5", "--extended-key-usage", "server-auth", "--extended-key-usage", "client-auth", "--output-file", "server-cert.csr", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_GEN_CSR_EXAMPLE_3.get()); final SubCommand genCSRSubCommand = new SubCommand( "generate-certificate-signing-request", INFO_MANAGE_CERTS_SC_GEN_CSR_DESC.get(), genCSRParser, genCSRExamples); genCSRSubCommand.addName("generateCertificateSigningRequest", true); genCSRSubCommand.addName("generate-certificate-request", true); genCSRSubCommand.addName("generateCertificateRequest", true); genCSRSubCommand.addName("generate-csr", true); genCSRSubCommand.addName("generateCSR", true); genCSRSubCommand.addName("certificate-signing-request", true); genCSRSubCommand.addName("certificateSigningRequest", true); genCSRSubCommand.addName("csr", true); genCSRSubCommand.addName("certreq", true); parser.addSubCommand(genCSRSubCommand); // Define the "sign-certificate-signing-request" subcommand and all of its // arguments. final ArgumentParser signCSRParser = new ArgumentParser( "sign-certificate-signing-request", INFO_MANAGE_CERTS_SC_SIGN_CSR_DESC.get()); final FileArgument signCSRInputFile = new FileArgument(null, "request-input-file", true, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_INPUT_FILE_DESC.get(), true, true, true, false); signCSRInputFile.addLongIdentifier("requestInputFile", true); signCSRInputFile.addLongIdentifier("certificate-signing-request", true); signCSRInputFile.addLongIdentifier("certificateSigningRequest", true); signCSRInputFile.addLongIdentifier("input-file", false); signCSRInputFile.addLongIdentifier("inputFile", true); signCSRInputFile.addLongIdentifier("csr", true); signCSRParser.addArgument(signCSRInputFile); final FileArgument signCSROutputFile = new FileArgument(null, "certificate-output-file", false, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_OUTPUT_FILE_DESC.get(), false, true, true, false); signCSROutputFile.addLongIdentifier("certificateOutputFile", true); signCSROutputFile.addLongIdentifier("output-file", false); signCSROutputFile.addLongIdentifier("outputFile", true); signCSROutputFile.addLongIdentifier("certificate-file", true); signCSROutputFile.addLongIdentifier("certificateFile", true); signCSRParser.addArgument(signCSROutputFile); final Set signCSROutputFormatAllowedValues = StaticUtils.setOf( "PEM", "text", "txt", "RFC", "DER", "binary", "bin"); final StringArgument signCSROutputFormat = new StringArgument(null, "output-format", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_FORMAT.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_FORMAT_DESC.get(), signCSROutputFormatAllowedValues, "PEM"); signCSROutputFormat.addLongIdentifier("outputFormat", true); signCSRParser.addArgument(signCSROutputFormat); final FileArgument signCSRKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_KS_DESC.get(), true, true, true, false); signCSRKeystore.addLongIdentifier("keystore-path", true); signCSRKeystore.addLongIdentifier("keystorePath", true); signCSRKeystore.addLongIdentifier("keystore-file", true); signCSRKeystore.addLongIdentifier("keystoreFile", true); signCSRParser.addArgument(signCSRKeystore); final StringArgument signCSRKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_KS_PW_DESC.get()); signCSRKeystorePassword.addLongIdentifier("keystorePassword", true); signCSRKeystorePassword.addLongIdentifier("keystore-passphrase", true); signCSRKeystorePassword.addLongIdentifier("keystorePassphrase", true); signCSRKeystorePassword.addLongIdentifier("keystore-pin", true); signCSRKeystorePassword.addLongIdentifier("keystorePIN", true); signCSRKeystorePassword.addLongIdentifier("storepass", true); signCSRKeystorePassword.setSensitive(true); signCSRParser.addArgument(signCSRKeystorePassword); final FileArgument signCSRKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); signCSRKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); signCSRKeystorePasswordFile.addLongIdentifier("keystore-passphrase-file", true); signCSRKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); signCSRKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); signCSRKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); signCSRParser.addArgument(signCSRKeystorePasswordFile); final BooleanArgument signCSRPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_PROMPT_FOR_KS_PW_DESC.get()); signCSRPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); signCSRPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); signCSRPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); signCSRPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); signCSRPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); signCSRParser.addArgument(signCSRPromptForKeystorePassword); final StringArgument signCSRPKPassword = new StringArgument(null, "private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_PK_PW_DESC.get()); signCSRPKPassword.addLongIdentifier("privateKeyPassword", true); signCSRPKPassword.addLongIdentifier("private-key-passphrase", true); signCSRPKPassword.addLongIdentifier("privateKeyPassphrase", true); signCSRPKPassword.addLongIdentifier("private-key-pin", true); signCSRPKPassword.addLongIdentifier("privateKeyPIN", true); signCSRPKPassword.addLongIdentifier("key-password", true); signCSRPKPassword.addLongIdentifier("keyPassword", true); signCSRPKPassword.addLongIdentifier("key-passphrase", true); signCSRPKPassword.addLongIdentifier("keyPassphrase", true); signCSRPKPassword.addLongIdentifier("key-pin", true); signCSRPKPassword.addLongIdentifier("keyPIN", true); signCSRPKPassword.addLongIdentifier("keypass", true); signCSRPKPassword.setSensitive(true); signCSRParser.addArgument(signCSRPKPassword); final FileArgument signCSRPKPasswordFile = new FileArgument(null, "private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_PK_PW_FILE_DESC.get(), true, true, true, false); signCSRPKPasswordFile.addLongIdentifier("privateKeyPasswordFile", true); signCSRPKPasswordFile.addLongIdentifier("private-key-passphrase-file", true); signCSRPKPasswordFile.addLongIdentifier("privateKeyPassphraseFile", true); signCSRPKPasswordFile.addLongIdentifier("private-key-pin-file", true); signCSRPKPasswordFile.addLongIdentifier("privateKeyPINFile", true); signCSRPKPasswordFile.addLongIdentifier("key-password-file", true); signCSRPKPasswordFile.addLongIdentifier("keyPasswordFile", true); signCSRPKPasswordFile.addLongIdentifier("key-passphrase-file", true); signCSRPKPasswordFile.addLongIdentifier("keyPassphraseFile", true); signCSRPKPasswordFile.addLongIdentifier("key-pin-file", true); signCSRPKPasswordFile.addLongIdentifier("keyPINFile", true); signCSRParser.addArgument(signCSRPKPasswordFile); final BooleanArgument signCSRPromptForPKPassword = new BooleanArgument(null, "prompt-for-private-key-password", INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_PROMPT_FOR_PK_PW_DESC.get()); signCSRPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassword", true); signCSRPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-passphrase", true); signCSRPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassphrase", true); signCSRPromptForPKPassword.addLongIdentifier("prompt-for-private-key-pin", true); signCSRPromptForPKPassword.addLongIdentifier("promptForPrivateKeyPIN", true); signCSRPromptForPKPassword.addLongIdentifier("prompt-for-key-password", true); signCSRPromptForPKPassword.addLongIdentifier("promptForKeyPassword", true); signCSRPromptForPKPassword.addLongIdentifier( "prompt-for-key-passphrase", true); signCSRPromptForPKPassword.addLongIdentifier( "promptForKeyPassphrase", true); signCSRPromptForPKPassword.addLongIdentifier("prompt-for-key-pin", true); signCSRPromptForPKPassword.addLongIdentifier("promptForKeyPIN", true); signCSRParser.addArgument(signCSRPromptForPKPassword); final StringArgument signCSRKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); signCSRKeystoreType.addLongIdentifier("key-store-type", true); signCSRKeystoreType.addLongIdentifier("keystoreType", true); signCSRKeystoreType.addLongIdentifier("keystore-format", true); signCSRKeystoreType.addLongIdentifier("key-store-format", true); signCSRKeystoreType.addLongIdentifier("keystoreFormat", true); signCSRKeystoreType.addLongIdentifier("storetype", true); signCSRParser.addArgument(signCSRKeystoreType); final StringArgument signCSRAlias = new StringArgument(null, "signing-certificate-alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_ALIAS_DESC.get()); signCSRAlias.addLongIdentifier("signingCertificateAlias", true); signCSRAlias.addLongIdentifier("signing-certificate-nickname", true); signCSRAlias.addLongIdentifier("signingCertificateNickname", true); signCSRAlias.addLongIdentifier("alias", true); signCSRAlias.addLongIdentifier("nickname", true); signCSRParser.addArgument(signCSRAlias); final DNArgument signCSRSubjectDN = new DNArgument(null, "subject-dn", false, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SUBJECT_DN_DESC.get()); signCSRSubjectDN.addLongIdentifier("subjectDN", true); signCSRSubjectDN.addLongIdentifier("subject", true); signCSRSubjectDN.addLongIdentifier("dname", true); signCSRParser.addArgument(signCSRSubjectDN); final IntegerArgument signCSRDaysValid = new IntegerArgument(null, "days-valid", false, 1, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_DAYS_VALID_DESC.get(), 1, Integer.MAX_VALUE); signCSRDaysValid.addLongIdentifier("daysValid", true); signCSRDaysValid.addLongIdentifier("validity", true); signCSRParser.addArgument(signCSRDaysValid); final TimestampArgument signCSRNotBefore = new TimestampArgument(null, "validity-start-time", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TIMESTAMP.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_VALIDITY_START_TIME_DESC.get( "20180102123456")); signCSRNotBefore.addLongIdentifier("validityStartTime", true); signCSRNotBefore.addLongIdentifier("not-before", true); signCSRNotBefore.addLongIdentifier("notBefore", true); signCSRParser.addArgument(signCSRNotBefore); final StringArgument signCSRSignatureAlgorithm = new StringArgument(null, "signature-algorithm", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SIG_ALG_DESC.get()); signCSRSignatureAlgorithm.addLongIdentifier("signatureAlgorithm", true); signCSRSignatureAlgorithm.addLongIdentifier("signature-alg", true); signCSRSignatureAlgorithm.addLongIdentifier("signatureAlg", true); signCSRSignatureAlgorithm.addLongIdentifier("sig-alg", true); signCSRSignatureAlgorithm.addLongIdentifier("sigAlg", true); signCSRParser.addArgument(signCSRSignatureAlgorithm); final BooleanArgument signCSRIncludeExtensions = new BooleanArgument(null, "include-requested-extensions", 1, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_INCLUDE_EXT_DESC.get()); signCSRIncludeExtensions.addLongIdentifier("includeRequestedExtensions", true); signCSRParser.addArgument(signCSRIncludeExtensions); final StringArgument signCSRSubjectAltDNS = new StringArgument(null, "subject-alternative-name-dns", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SAN_DNS_DESC.get()); signCSRSubjectAltDNS.addLongIdentifier("subjectAlternativeNameDNS", true); signCSRSubjectAltDNS.addLongIdentifier("subject-alt-name-dns", true); signCSRSubjectAltDNS.addLongIdentifier("subjectAltNameDNS", true); signCSRSubjectAltDNS.addLongIdentifier("subject-alternative-dns", true); signCSRSubjectAltDNS.addLongIdentifier("subjectAlternativeDNS", true); signCSRSubjectAltDNS.addLongIdentifier("subject-alt-dns", true); signCSRSubjectAltDNS.addLongIdentifier("subjectAltDNS", true); signCSRSubjectAltDNS.addLongIdentifier("san-dns", true); signCSRSubjectAltDNS.addLongIdentifier("sanDNS", true); signCSRSubjectAltDNS.addValueValidator( new IA5StringArgumentValueValidator(false)); signCSRParser.addArgument(signCSRSubjectAltDNS); final StringArgument signCSRSubjectAltIP = new StringArgument(null, "subject-alternative-name-ip-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SAN_IP_DESC.get()); signCSRSubjectAltIP.addLongIdentifier("subjectAlternativeNameIPAddress", true); signCSRSubjectAltIP.addLongIdentifier("subject-alternative-name-ip", true); signCSRSubjectAltIP.addLongIdentifier("subjectAlternativeNameIP", true); signCSRSubjectAltIP.addLongIdentifier("subject-alt-name-ip-address", true); signCSRSubjectAltIP.addLongIdentifier("subjectAltNameIPAddress", true); signCSRSubjectAltIP.addLongIdentifier("subject-alt-name-ip", true); signCSRSubjectAltIP.addLongIdentifier("subjectAltNameIP", true); signCSRSubjectAltIP.addLongIdentifier("subject-alternative-ip-address", true); signCSRSubjectAltIP.addLongIdentifier("subjectAlternativeIPAddress", true); signCSRSubjectAltIP.addLongIdentifier("subject-alternative-ip", true); signCSRSubjectAltIP.addLongIdentifier("subjectAlternativeIP", true); signCSRSubjectAltIP.addLongIdentifier("subject-alt-ip-address", true); signCSRSubjectAltIP.addLongIdentifier("subjectAltIPAddress", true); signCSRSubjectAltIP.addLongIdentifier("subject-alt-ip", true); signCSRSubjectAltIP.addLongIdentifier("subjectAltIP", true); signCSRSubjectAltIP.addLongIdentifier("san-ip-address", true); signCSRSubjectAltIP.addLongIdentifier("sanIPAddress", true); signCSRSubjectAltIP.addLongIdentifier("san-ip", true); signCSRSubjectAltIP.addLongIdentifier("sanIP", true); signCSRSubjectAltIP.addValueValidator( new IPAddressArgumentValueValidator(true, true)); signCSRParser.addArgument(signCSRSubjectAltIP); final StringArgument signCSRSubjectAltEmail = new StringArgument(null, "subject-alternative-name-email-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SAN_EMAIL_DESC.get()); signCSRSubjectAltEmail.addLongIdentifier( "subjectAlternativeNameEmailAddress", true); signCSRSubjectAltEmail.addLongIdentifier("subject-alternative-name-email", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAlternativeNameEmail", true); signCSRSubjectAltEmail.addLongIdentifier("subject-alt-name-email-address", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAltNameEmailAddress", true); signCSRSubjectAltEmail.addLongIdentifier("subject-alt-name-email", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAltNameEmail", true); signCSRSubjectAltEmail.addLongIdentifier( "subject-alternative-email-address", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAlternativeEmailAddress", true); signCSRSubjectAltEmail.addLongIdentifier("subject-alternative-email", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAlternativeEmail", true); signCSRSubjectAltEmail.addLongIdentifier("subject-alt-email-address", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAltEmailAddress", true); signCSRSubjectAltEmail.addLongIdentifier("subject-alt-email", true); signCSRSubjectAltEmail.addLongIdentifier("subjectAltEmail", true); signCSRSubjectAltEmail.addLongIdentifier("san-email-address", true); signCSRSubjectAltEmail.addLongIdentifier("sanEmailAddress", true); signCSRSubjectAltEmail.addLongIdentifier("san-email", true); signCSRSubjectAltEmail.addLongIdentifier("sanEmail", true); signCSRSubjectAltEmail.addValueValidator( new IA5StringArgumentValueValidator(false)); signCSRParser.addArgument(signCSRSubjectAltEmail); final StringArgument signCSRSubjectAltURI = new StringArgument(null, "subject-alternative-name-uri", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_URI.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SAN_URI_DESC.get()); signCSRSubjectAltURI.addLongIdentifier("subjectAlternativeNameURI", true); signCSRSubjectAltURI.addLongIdentifier("subject-alt-name-uri", true); signCSRSubjectAltURI.addLongIdentifier("subjectAltNameURI", true); signCSRSubjectAltURI.addLongIdentifier("subject-alternative-uri", true); signCSRSubjectAltURI.addLongIdentifier("subjectAlternativeURI", true); signCSRSubjectAltURI.addLongIdentifier("subject-alt-uri", true); signCSRSubjectAltURI.addLongIdentifier("subjectAltURI", true); signCSRSubjectAltURI.addLongIdentifier("san-uri", true); signCSRSubjectAltURI.addLongIdentifier("sanURI", true); signCSRParser.addArgument(signCSRSubjectAltURI); final StringArgument signCSRSubjectAltOID = new StringArgument(null, "subject-alternative-name-oid", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_OID.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_SAN_OID_DESC.get()); signCSRSubjectAltOID.addLongIdentifier("subjectAlternativeNameOID", true); signCSRSubjectAltOID.addLongIdentifier("subject-alt-name-oid", true); signCSRSubjectAltOID.addLongIdentifier("subjectAltNameOID", true); signCSRSubjectAltOID.addLongIdentifier("subject-alternative-oid", true); signCSRSubjectAltOID.addLongIdentifier("subjectAlternativeOID", true); signCSRSubjectAltOID.addLongIdentifier("subject-alt-oid", true); signCSRSubjectAltOID.addLongIdentifier("subjectAltOID", true); signCSRSubjectAltOID.addLongIdentifier("san-oid", true); signCSRSubjectAltOID.addLongIdentifier("sanOID", true); signCSRSubjectAltOID.addValueValidator(new OIDArgumentValueValidator(true)); signCSRParser.addArgument(signCSRSubjectAltOID); final StringArgument signCSRIssuerAltDNS = new StringArgument(null, "issuer-alternative-name-dns", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_IAN_DNS_DESC.get()); signCSRIssuerAltDNS.addLongIdentifier("issuerAlternativeNameDNS", true); signCSRIssuerAltDNS.addLongIdentifier("issuer-alt-name-dns", true); signCSRIssuerAltDNS.addLongIdentifier("issuerAltNameDNS", true); signCSRIssuerAltDNS.addLongIdentifier("issuer-alternative-dns", true); signCSRIssuerAltDNS.addLongIdentifier("issuerAlternativeDNS", true); signCSRIssuerAltDNS.addLongIdentifier("issuer-alt-dns", true); signCSRIssuerAltDNS.addLongIdentifier("issuerAltDNS", true); signCSRIssuerAltDNS.addLongIdentifier("ian-dns", true); signCSRIssuerAltDNS.addLongIdentifier("ianDNS", true); signCSRIssuerAltDNS.addValueValidator( new IA5StringArgumentValueValidator(false)); signCSRParser.addArgument(signCSRIssuerAltDNS); final StringArgument signCSRIssuerAltIP = new StringArgument(null, "issuer-alternative-name-ip-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_IAN_IP_DESC.get()); signCSRIssuerAltIP.addLongIdentifier("issuerAlternativeNameIPAddress", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alternative-name-ip", true); signCSRIssuerAltIP.addLongIdentifier("issuerAlternativeNameIP", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alt-name-ip-address", true); signCSRIssuerAltIP.addLongIdentifier("issuerAltNameIPAddress", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alt-name-ip", true); signCSRIssuerAltIP.addLongIdentifier("issuerAltNameIP", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alternative-ip-address", true); signCSRIssuerAltIP.addLongIdentifier("issuerAlternativeIPAddress", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alternative-ip", true); signCSRIssuerAltIP.addLongIdentifier("issuerAlternativeIP", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alt-ip-address", true); signCSRIssuerAltIP.addLongIdentifier("issuerAltIPAddress", true); signCSRIssuerAltIP.addLongIdentifier("issuer-alt-ip", true); signCSRIssuerAltIP.addLongIdentifier("issuerAltIP", true); signCSRIssuerAltIP.addLongIdentifier("ian-ip-address", true); signCSRIssuerAltIP.addLongIdentifier("ianIPAddress", true); signCSRIssuerAltIP.addLongIdentifier("ian-ip", true); signCSRIssuerAltIP.addLongIdentifier("ianIP", true); signCSRIssuerAltIP.addValueValidator( new IPAddressArgumentValueValidator(true, true)); signCSRParser.addArgument(signCSRIssuerAltIP); final StringArgument signCSRIssuerAltEmail = new StringArgument(null, "issuer-alternative-name-email-address", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_NAME.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_IAN_EMAIL_DESC.get()); signCSRIssuerAltEmail.addLongIdentifier( "issuerAlternativeNameEmailAddress", true); signCSRIssuerAltEmail.addLongIdentifier("issuer-alternative-name-email", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAlternativeNameEmail", true); signCSRIssuerAltEmail.addLongIdentifier("issuer-alt-name-email-address", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAltNameEmailAddress", true); signCSRIssuerAltEmail.addLongIdentifier("issuer-alt-name-email", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAltNameEmail", true); signCSRIssuerAltEmail.addLongIdentifier( "issuer-alternative-email-address", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAlternativeEmailAddress", true); signCSRIssuerAltEmail.addLongIdentifier("issuer-alternative-email", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAlternativeEmail", true); signCSRIssuerAltEmail.addLongIdentifier("issuer-alt-email-address", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAltEmailAddress", true); signCSRIssuerAltEmail.addLongIdentifier("issuer-alt-email", true); signCSRIssuerAltEmail.addLongIdentifier("issuerAltEmail", true); signCSRIssuerAltEmail.addLongIdentifier("ian-email-address", true); signCSRIssuerAltEmail.addLongIdentifier("ianEmailAddress", true); signCSRIssuerAltEmail.addLongIdentifier("ian-email", true); signCSRIssuerAltEmail.addLongIdentifier("ianEmail", true); signCSRIssuerAltEmail.addValueValidator( new IA5StringArgumentValueValidator(false)); signCSRParser.addArgument(signCSRIssuerAltEmail); final StringArgument signCSRIssuerAltURI = new StringArgument(null, "issuer-alternative-name-uri", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_URI.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_IAN_URI_DESC.get()); signCSRIssuerAltURI.addLongIdentifier("issuerAlternativeNameURI", true); signCSRIssuerAltURI.addLongIdentifier("issuer-alt-name-uri", true); signCSRIssuerAltURI.addLongIdentifier("issuerAltNameURI", true); signCSRIssuerAltURI.addLongIdentifier("issuer-alternative-uri", true); signCSRIssuerAltURI.addLongIdentifier("issuerAlternativeURI", true); signCSRIssuerAltURI.addLongIdentifier("issuer-alt-uri", true); signCSRIssuerAltURI.addLongIdentifier("issuerAltURI", true); signCSRIssuerAltURI.addLongIdentifier("ian-uri", true); signCSRIssuerAltURI.addLongIdentifier("ianURI", true); signCSRParser.addArgument(signCSRIssuerAltURI); final StringArgument signCSRIssuerAltOID = new StringArgument(null, "issuer-alternative-name-oid", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_OID.get(), INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_IAN_OID_DESC.get()); signCSRIssuerAltOID.addLongIdentifier("issuerAlternativeNameOID", true); signCSRIssuerAltOID.addLongIdentifier("issuer-alt-name-oid", true); signCSRIssuerAltOID.addLongIdentifier("issuerAltNameOID", true); signCSRIssuerAltOID.addLongIdentifier("issuer-alternative-oid", true); signCSRIssuerAltOID.addLongIdentifier("issuerAlternativeOID", true); signCSRIssuerAltOID.addLongIdentifier("issuer-alt-oid", true); signCSRIssuerAltOID.addLongIdentifier("issuerAltOID", true); signCSRIssuerAltOID.addLongIdentifier("ian-oid", true); signCSRIssuerAltOID.addLongIdentifier("ianOID", true); signCSRIssuerAltOID.addValueValidator(new OIDArgumentValueValidator(true)); signCSRParser.addArgument(signCSRIssuerAltOID); final BooleanValueArgument signCSRBasicConstraintsIsCA = new BooleanValueArgument(null, "basic-constraints-is-ca", false, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_BC_IS_CA_DESC.get()); signCSRBasicConstraintsIsCA.addLongIdentifier("basicConstraintsIsCA", true); signCSRBasicConstraintsIsCA.addLongIdentifier("bc-is-ca", true); signCSRBasicConstraintsIsCA.addLongIdentifier("bcIsCA", true); signCSRParser.addArgument(signCSRBasicConstraintsIsCA); final IntegerArgument signCSRBasicConstraintsPathLength = new IntegerArgument(null, "basic-constraints-maximum-path-length", false, 1, null, INFO_MANAGE_CERTS_SC_GEN_CERT_ARG_BC_PATH_LENGTH_DESC.get(), 0, Integer.MAX_VALUE); signCSRBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsMaximumPathLength", true); signCSRBasicConstraintsPathLength.addLongIdentifier( "basic-constraints-max-path-length", true); signCSRBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsMaxPathLength", true); signCSRBasicConstraintsPathLength.addLongIdentifier( "basic-constraints-path-length", true); signCSRBasicConstraintsPathLength.addLongIdentifier( "basicConstraintsPathLength", true); signCSRBasicConstraintsPathLength.addLongIdentifier( "bc-maximum-path-length", true); signCSRBasicConstraintsPathLength.addLongIdentifier("bcMaximumPathLength", true); signCSRBasicConstraintsPathLength.addLongIdentifier("bc-max-path-length", true); signCSRBasicConstraintsPathLength.addLongIdentifier("bcMaxPathLength", true); signCSRBasicConstraintsPathLength.addLongIdentifier("bc-path-length", true); signCSRBasicConstraintsPathLength.addLongIdentifier("bcPathLength", true); signCSRParser.addArgument(signCSRBasicConstraintsPathLength); final StringArgument signCSRKeyUsage = new StringArgument(null, "key-usage", false, 0, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_KU_DESC.get()); signCSRKeyUsage.addLongIdentifier("keyUsage", true); signCSRParser.addArgument(signCSRKeyUsage); final StringArgument signCSRExtendedKeyUsage = new StringArgument(null, "extended-key-usage", false, 0, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_EKU_DESC.get()); signCSRExtendedKeyUsage.addLongIdentifier("extendedKeyUsage", true); signCSRParser.addArgument(signCSRExtendedKeyUsage); final StringArgument signCSRExtension = new StringArgument(null, "extension", false, 0, null, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_EXT_DESC.get()); signCSRExtension.addLongIdentifier("ext", true); signCSRParser.addArgument(signCSRExtension); final BooleanArgument signCSRNoPrompt = new BooleanArgument(null, "no-prompt", 1, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_NO_PROMPT_DESC.get()); signCSRNoPrompt.addLongIdentifier("noPrompt", true); signCSRParser.addArgument(signCSRNoPrompt); final BooleanArgument signCSRDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_SIGN_CSR_ARG_DISPLAY_COMMAND_DESC.get()); signCSRDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); signCSRDisplayCommand.addLongIdentifier("show-keytool-command", true); signCSRDisplayCommand.addLongIdentifier("showKeytoolCommand", true); signCSRParser.addArgument(signCSRDisplayCommand); signCSRParser.addRequiredArgumentSet(signCSRKeystorePassword, signCSRKeystorePasswordFile, signCSRPromptForKeystorePassword); signCSRParser.addExclusiveArgumentSet(signCSRKeystorePassword, signCSRKeystorePasswordFile, signCSRPromptForKeystorePassword); signCSRParser.addExclusiveArgumentSet(signCSRPKPassword, signCSRPKPasswordFile, signCSRPromptForPKPassword); signCSRParser.addDependentArgumentSet(signCSRBasicConstraintsPathLength, signCSRBasicConstraintsIsCA); final LinkedHashMap signCSRExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); signCSRExamples.put( new String[] { "sign-certificate-signing-request", "--request-input-file", "server-cert.csr", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--signing-certificate-alias", "ca-cert", "--include-requested-extensions" }, INFO_MANAGE_CERTS_SC_SIGN_CSR_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"))); signCSRExamples.put( new String[] { "sign-certificate-signing-request", "--request-input-file", "server-cert.csr", "--certificate-output-file", "server-cert.der", "--output-format", "DER", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--signing-certificate-alias", "ca-cert", "--days-valid", "730", "--validity-start-time", "20170101000000", "--include-requested-extensions", "--issuer-alternative-name-email-address", "[email protected]", }, INFO_MANAGE_CERTS_SC_SIGN_CSR_EXAMPLE_2.get( getPlatformSpecificPath("config", "keystore"))); final SubCommand signCSRSubCommand = new SubCommand( "sign-certificate-signing-request", INFO_MANAGE_CERTS_SC_SIGN_CSR_DESC.get(), signCSRParser, signCSRExamples); signCSRSubCommand.addName("signCertificateSigningRequest", true); signCSRSubCommand.addName("sign-certificate-request", true); signCSRSubCommand.addName("signCertificateRequest", true); signCSRSubCommand.addName("sign-certificate", true); signCSRSubCommand.addName("signCertificate", true); signCSRSubCommand.addName("sign-csr", true); signCSRSubCommand.addName("signCSR", true); signCSRSubCommand.addName("sign", true); signCSRSubCommand.addName("gencert", true); parser.addSubCommand(signCSRSubCommand); // Define the "change-certificate-alias" subcommand and all of its // arguments. final ArgumentParser changeAliasParser = new ArgumentParser( "change-certificate-alias", INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_DESC.get()); final FileArgument changeAliasKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_KS_DESC.get(), true, true, true, false); changeAliasKeystore.addLongIdentifier("keystore-path", true); changeAliasKeystore.addLongIdentifier("keystorePath", true); changeAliasKeystore.addLongIdentifier("keystore-file", true); changeAliasKeystore.addLongIdentifier("keystoreFile", true); changeAliasParser.addArgument(changeAliasKeystore); final StringArgument changeAliasKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_KS_PW_DESC.get()); changeAliasKeystorePassword.addLongIdentifier("keystorePassword", true); changeAliasKeystorePassword.addLongIdentifier("keystore-passphrase", true); changeAliasKeystorePassword.addLongIdentifier("keystorePassphrase", true); changeAliasKeystorePassword.addLongIdentifier("keystore-pin", true); changeAliasKeystorePassword.addLongIdentifier("keystorePIN", true); changeAliasKeystorePassword.addLongIdentifier("storepass", true); changeAliasKeystorePassword.setSensitive(true); changeAliasParser.addArgument(changeAliasKeystorePassword); final FileArgument changeAliasKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); changeAliasKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); changeAliasKeystorePasswordFile.addLongIdentifier( "keystore-passphrase-file", true); changeAliasKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); changeAliasKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); changeAliasKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); changeAliasParser.addArgument(changeAliasKeystorePasswordFile); final BooleanArgument changeAliasPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_PROMPT_FOR_KS_PW_DESC.get()); changeAliasPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); changeAliasPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); changeAliasPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); changeAliasPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); changeAliasPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); changeAliasParser.addArgument(changeAliasPromptForKeystorePassword); final StringArgument changeAliasPKPassword = new StringArgument(null, "private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_PK_PW_DESC.get()); changeAliasPKPassword.addLongIdentifier("privateKeyPassword", true); changeAliasPKPassword.addLongIdentifier("private-key-passphrase", true); changeAliasPKPassword.addLongIdentifier("privateKeyPassphrase", true); changeAliasPKPassword.addLongIdentifier("private-key-pin", true); changeAliasPKPassword.addLongIdentifier("privateKeyPIN", true); changeAliasPKPassword.addLongIdentifier("key-password", true); changeAliasPKPassword.addLongIdentifier("keyPassword", true); changeAliasPKPassword.addLongIdentifier("key-passphrase", true); changeAliasPKPassword.addLongIdentifier("keyPassphrase", true); changeAliasPKPassword.addLongIdentifier("key-pin", true); changeAliasPKPassword.addLongIdentifier("keyPIN", true); changeAliasPKPassword.addLongIdentifier("keypass", true); changeAliasPKPassword.setSensitive(true); changeAliasParser.addArgument(changeAliasPKPassword); final FileArgument changeAliasPKPasswordFile = new FileArgument(null, "private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_PK_PW_FILE_DESC.get(), true, true, true, false); changeAliasPKPasswordFile.addLongIdentifier("privateKeyPasswordFile", true); changeAliasPKPasswordFile.addLongIdentifier("private-key-passphrase-file", true); changeAliasPKPasswordFile.addLongIdentifier("privateKeyPassphraseFile", true); changeAliasPKPasswordFile.addLongIdentifier("private-key-pin-file", true); changeAliasPKPasswordFile.addLongIdentifier("privateKeyPINFile", true); changeAliasPKPasswordFile.addLongIdentifier("key-password-file", true); changeAliasPKPasswordFile.addLongIdentifier("keyPasswordFile", true); changeAliasPKPasswordFile.addLongIdentifier("key-passphrase-file", true); changeAliasPKPasswordFile.addLongIdentifier("keyPassphraseFile", true); changeAliasPKPasswordFile.addLongIdentifier("key-pin-file", true); changeAliasPKPasswordFile.addLongIdentifier("keyPINFile", true); changeAliasParser.addArgument(changeAliasPKPasswordFile); final BooleanArgument changeAliasPromptForPKPassword = new BooleanArgument(null, "prompt-for-private-key-password", INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_PROMPT_FOR_PK_PW_DESC.get()); changeAliasPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassword", true); changeAliasPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-passphrase", true); changeAliasPromptForPKPassword.addLongIdentifier( "promptForPrivateKeyPassphrase", true); changeAliasPromptForPKPassword.addLongIdentifier( "prompt-for-private-key-pin", true); changeAliasPromptForPKPassword.addLongIdentifier("promptForPrivateKeyPIN", true); changeAliasPromptForPKPassword.addLongIdentifier("prompt-for-key-password", true); changeAliasPromptForPKPassword.addLongIdentifier("promptForKeyPassword", true); changeAliasPromptForPKPassword.addLongIdentifier( "prompt-for-key-passphrase", true); changeAliasPromptForPKPassword.addLongIdentifier( "promptForKeyPassphrase", true); changeAliasPromptForPKPassword.addLongIdentifier("prompt-for-key-pin", true); changeAliasPromptForPKPassword.addLongIdentifier("promptForKeyPIN", true); changeAliasParser.addArgument(changeAliasPromptForPKPassword); final StringArgument changeAliasKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); changeAliasKeystoreType.addLongIdentifier("key-store-type", true); changeAliasKeystoreType.addLongIdentifier("keystoreType", true); changeAliasKeystoreType.addLongIdentifier("keystore-format", true); changeAliasKeystoreType.addLongIdentifier("key-store-format", true); changeAliasKeystoreType.addLongIdentifier("keystoreFormat", true); changeAliasKeystoreType.addLongIdentifier("storetype", true); changeAliasParser.addArgument(changeAliasKeystoreType); final StringArgument changeAliasCurrentAlias = new StringArgument(null, "current-alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_CURRENT_ALIAS_DESC.get()); changeAliasCurrentAlias.addLongIdentifier("currentAlias", true); changeAliasCurrentAlias.addLongIdentifier("old-alias", true); changeAliasCurrentAlias.addLongIdentifier("oldAlias", true); changeAliasCurrentAlias.addLongIdentifier("source-alias", true); changeAliasCurrentAlias.addLongIdentifier("sourceAlias", true); changeAliasCurrentAlias.addLongIdentifier("alias", true); changeAliasCurrentAlias.addLongIdentifier("current-nickname", true); changeAliasCurrentAlias.addLongIdentifier("currentNickname", true); changeAliasCurrentAlias.addLongIdentifier("old-nickname", true); changeAliasCurrentAlias.addLongIdentifier("oldNickname", true); changeAliasCurrentAlias.addLongIdentifier("source-nickname", true); changeAliasCurrentAlias.addLongIdentifier("sourceNickname", true); changeAliasCurrentAlias.addLongIdentifier("nickname", true); changeAliasCurrentAlias.addLongIdentifier("from", false); changeAliasParser.addArgument(changeAliasCurrentAlias); final StringArgument changeAliasNewAlias = new StringArgument(null, "new-alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_NEW_ALIAS_DESC.get()); changeAliasNewAlias.addLongIdentifier("newAlias", true); changeAliasNewAlias.addLongIdentifier("destination-alias", true); changeAliasNewAlias.addLongIdentifier("destinationAlias", true); changeAliasNewAlias.addLongIdentifier("new-nickname", true); changeAliasNewAlias.addLongIdentifier("newNickname", true); changeAliasNewAlias.addLongIdentifier("destination-nickname", true); changeAliasNewAlias.addLongIdentifier("destinationNickname", true); changeAliasNewAlias.addLongIdentifier("to", false); changeAliasParser.addArgument(changeAliasNewAlias); final BooleanArgument changeAliasDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_ARG_DISPLAY_COMMAND_DESC.get()); changeAliasDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); changeAliasDisplayCommand.addLongIdentifier("show-keytool-command", true); changeAliasDisplayCommand.addLongIdentifier("showKeytoolCommand", true); changeAliasParser.addArgument(changeAliasDisplayCommand); changeAliasParser.addRequiredArgumentSet(changeAliasKeystorePassword, changeAliasKeystorePasswordFile, changeAliasPromptForKeystorePassword); changeAliasParser.addExclusiveArgumentSet(changeAliasKeystorePassword, changeAliasKeystorePasswordFile, changeAliasPromptForKeystorePassword); changeAliasParser.addExclusiveArgumentSet(changeAliasPKPassword, changeAliasPKPasswordFile, changeAliasPromptForPKPassword); final LinkedHashMap changeAliasExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); changeAliasExamples.put( new String[] { "change-certificate-alias", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--current-alias", "server-cert", "--new-alias", "server-certificate", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_EXAMPLE_1.get()); final SubCommand changeAliasSubCommand = new SubCommand( "change-certificate-alias", INFO_MANAGE_CERTS_SC_CHANGE_ALIAS_DESC.get(), changeAliasParser, changeAliasExamples); changeAliasSubCommand.addName("changeCertificateAlias", true); changeAliasSubCommand.addName("change-alias", true); changeAliasSubCommand.addName("changeAlias", true); changeAliasSubCommand.addName("rename-certificate", true); changeAliasSubCommand.addName("renameCertificate", true); changeAliasSubCommand.addName("rename", true); parser.addSubCommand(changeAliasSubCommand); // Define the "change-keystore-password" subcommand and all of its // arguments. final ArgumentParser changeKSPWParser = new ArgumentParser( "change-keystore-password", INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_DESC.get()); final FileArgument changeKSPWKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_KS_DESC.get(), true, true, true, false); changeKSPWKeystore.addLongIdentifier("keystore-path", true); changeKSPWKeystore.addLongIdentifier("keystorePath", true); changeKSPWKeystore.addLongIdentifier("keystore-file", true); changeKSPWKeystore.addLongIdentifier("keystoreFile", true); changeKSPWParser.addArgument(changeKSPWKeystore); final StringArgument changeKSPWCurrentPassword = new StringArgument(null, "current-keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_CURRENT_PW_DESC.get()); changeKSPWCurrentPassword.addLongIdentifier("currentKeystorePassword", true); changeKSPWCurrentPassword.addLongIdentifier("current-keystore-passphrase", true); changeKSPWCurrentPassword.addLongIdentifier("currentKeystorePassphrase", true); changeKSPWCurrentPassword.addLongIdentifier("current-keystore-pin", true); changeKSPWCurrentPassword.addLongIdentifier("currentKeystorePIN", true); changeKSPWCurrentPassword.addLongIdentifier("storepass", true); changeKSPWCurrentPassword.setSensitive(true); changeKSPWParser.addArgument(changeKSPWCurrentPassword); final FileArgument changeKSPWCurrentPasswordFile = new FileArgument(null, "current-keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_CURRENT_PW_FILE_DESC.get(), true, true, true, false); changeKSPWCurrentPasswordFile.addLongIdentifier( "currentKeystorePasswordFile", true); changeKSPWCurrentPasswordFile.addLongIdentifier( "current-keystore-passphrase-file", true); changeKSPWCurrentPasswordFile.addLongIdentifier( "currentKeystorePassphraseFile", true); changeKSPWCurrentPasswordFile.addLongIdentifier("current-keystore-pin-file", true); changeKSPWCurrentPasswordFile.addLongIdentifier("currentKeystorePINFile", true); changeKSPWParser.addArgument(changeKSPWCurrentPasswordFile); final BooleanArgument changeKSPWPromptForCurrentPassword = new BooleanArgument(null, "prompt-for-current-keystore-password", INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_PROMPT_FOR_CURRENT_PW_DESC.get()); changeKSPWPromptForCurrentPassword.addLongIdentifier( "promptForCurrentKeystorePassword", true); changeKSPWPromptForCurrentPassword.addLongIdentifier( "prompt-for-current-keystore-passphrase", true); changeKSPWPromptForCurrentPassword.addLongIdentifier( "promptForCurrentKeystorePassphrase", true); changeKSPWPromptForCurrentPassword.addLongIdentifier( "prompt-for-current-keystore-pin", true); changeKSPWPromptForCurrentPassword.addLongIdentifier( "promptForCurrentKeystorePIN", true); changeKSPWParser.addArgument(changeKSPWPromptForCurrentPassword); final StringArgument changeKSPWNewPassword = new StringArgument(null, "new-keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_NEW_PW_DESC.get()); changeKSPWNewPassword.addLongIdentifier("newKeystorePassword", true); changeKSPWNewPassword.addLongIdentifier("new-keystore-passphrase", true); changeKSPWNewPassword.addLongIdentifier("newKeystorePassphrase", true); changeKSPWNewPassword.addLongIdentifier("new-keystore-pin", true); changeKSPWNewPassword.addLongIdentifier("newKeystorePIN", true); changeKSPWNewPassword.addLongIdentifier("new", true); changeKSPWNewPassword.setSensitive(true); changeKSPWParser.addArgument(changeKSPWNewPassword); final FileArgument changeKSPWNewPasswordFile = new FileArgument(null, "new-keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_NEW_PW_FILE_DESC.get(), true, true, true, false); changeKSPWNewPasswordFile.addLongIdentifier("newKeystorePasswordFile", true); changeKSPWNewPasswordFile.addLongIdentifier("new-keystore-passphrase-file", true); changeKSPWNewPasswordFile.addLongIdentifier("newKeystorePassphraseFile", true); changeKSPWNewPasswordFile.addLongIdentifier("new-keystore-pin-file", true); changeKSPWNewPasswordFile.addLongIdentifier("newKeystorePINFile", true); changeKSPWParser.addArgument(changeKSPWNewPasswordFile); final BooleanArgument changeKSPWPromptForNewPassword = new BooleanArgument(null, "prompt-for-new-keystore-password", INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_PROMPT_FOR_NEW_PW_DESC.get()); changeKSPWPromptForNewPassword.addLongIdentifier( "promptForNewKeystorePassword", true); changeKSPWPromptForNewPassword.addLongIdentifier( "prompt-for-new-keystore-passphrase", true); changeKSPWPromptForNewPassword.addLongIdentifier( "promptForNewKeystorePassphrase", true); changeKSPWPromptForNewPassword.addLongIdentifier( "prompt-for-new-keystore-pin", true); changeKSPWPromptForNewPassword.addLongIdentifier( "promptForNewKeystorePIN", true); changeKSPWParser.addArgument(changeKSPWPromptForNewPassword); final BooleanArgument changeKSPWDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_ARG_DISPLAY_COMMAND_DESC.get()); changeKSPWDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); changeKSPWDisplayCommand.addLongIdentifier("show-keytool-command", true); changeKSPWDisplayCommand.addLongIdentifier("showKeytoolCommand", true); changeKSPWParser.addArgument(changeKSPWDisplayCommand); changeKSPWParser.addRequiredArgumentSet(changeKSPWCurrentPassword, changeKSPWCurrentPasswordFile, changeKSPWPromptForCurrentPassword); changeKSPWParser.addExclusiveArgumentSet(changeKSPWCurrentPassword, changeKSPWCurrentPasswordFile, changeKSPWPromptForCurrentPassword); changeKSPWParser.addRequiredArgumentSet(changeKSPWNewPassword, changeKSPWNewPasswordFile, changeKSPWPromptForNewPassword); changeKSPWParser.addExclusiveArgumentSet(changeKSPWNewPassword, changeKSPWNewPasswordFile, changeKSPWPromptForNewPassword); final LinkedHashMap changeKSPWExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); changeKSPWExamples.put( new String[] { "change-keystore-password", "--keystore", getPlatformSpecificPath("config", "keystore"), "--current-keystore-password-file", getPlatformSpecificPath("config", "current.pin"), "--new-keystore-password-file", getPlatformSpecificPath("config", "new.pin"), "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"), getPlatformSpecificPath("config", "current.pin"), getPlatformSpecificPath("config", "new.pin"))); final SubCommand changeKSPWSubCommand = new SubCommand( "change-keystore-password", INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_DESC.get(), changeKSPWParser, changeKSPWExamples); changeKSPWSubCommand.addName("changeKeystorePassword", true); changeKSPWSubCommand.addName("change-keystore-passphrase", true); changeKSPWSubCommand.addName("changeKeystorePassphrase", true); changeKSPWSubCommand.addName("change-keystore-pin", true); changeKSPWSubCommand.addName("changeKeystorePIN", true); changeKSPWSubCommand.addName("storepasswd", true); parser.addSubCommand(changeKSPWSubCommand); // Define the "change-private-key-password" subcommand and all of its // arguments. final ArgumentParser changePKPWParser = new ArgumentParser( "change-private-key-password", INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_DESC.get()); final FileArgument changePKPWKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_KS_DESC.get(), true, true, true, false); changePKPWKeystore.addLongIdentifier("keystore-path", true); changePKPWKeystore.addLongIdentifier("keystorePath", true); changePKPWKeystore.addLongIdentifier("keystore-file", true); changePKPWKeystore.addLongIdentifier("keystoreFile", true); changePKPWParser.addArgument(changePKPWKeystore); final StringArgument changePKPWKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_KS_PW_DESC.get()); changePKPWKeystorePassword.addLongIdentifier("keystorePassword", true); changePKPWKeystorePassword.addLongIdentifier("keystore-passphrase", true); changePKPWKeystorePassword.addLongIdentifier("keystorePassphrase", true); changePKPWKeystorePassword.addLongIdentifier("keystore-pin", true); changePKPWKeystorePassword.addLongIdentifier("keystorePIN", true); changePKPWKeystorePassword.addLongIdentifier("storepass", true); changePKPWKeystorePassword.setSensitive(true); changePKPWParser.addArgument(changePKPWKeystorePassword); final FileArgument changePKPWKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); changePKPWKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); changePKPWKeystorePasswordFile.addLongIdentifier( "keystore-passphrase-file", true); changePKPWKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); changePKPWKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); changePKPWKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); changePKPWParser.addArgument(changePKPWKeystorePasswordFile); final BooleanArgument changePKPWPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_PROMPT_FOR_KS_PW_DESC.get()); changePKPWPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); changePKPWPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); changePKPWPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); changePKPWPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); changePKPWPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); changePKPWParser.addArgument(changePKPWPromptForKeystorePassword); final StringArgument changePKPWKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); changePKPWKeystoreType.addLongIdentifier("key-store-type", true); changePKPWKeystoreType.addLongIdentifier("keystoreType", true); changePKPWKeystoreType.addLongIdentifier("keystore-format", true); changePKPWKeystoreType.addLongIdentifier("key-store-format", true); changePKPWKeystoreType.addLongIdentifier("keystoreFormat", true); changePKPWKeystoreType.addLongIdentifier("storetype", true); changePKPWParser.addArgument(changePKPWKeystoreType); final StringArgument changePKPWAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_ALIAS_DESC.get()); changePKPWAlias.addLongIdentifier("nickname", true); changePKPWParser.addArgument(changePKPWAlias); final StringArgument changePKPWCurrentPassword = new StringArgument(null, "current-private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_CURRENT_PW_DESC.get()); changePKPWCurrentPassword.addLongIdentifier("currentPrivateKeyPassword", true); changePKPWCurrentPassword.addLongIdentifier( "current-private-key-passphrase", true); changePKPWCurrentPassword.addLongIdentifier("currentPrivateKeyPassphrase", true); changePKPWCurrentPassword.addLongIdentifier("current-private-key-pin", true); changePKPWCurrentPassword.addLongIdentifier("currentPrivateKeyPIN", true); changePKPWCurrentPassword.addLongIdentifier("keypass", true); changePKPWCurrentPassword.setSensitive(true); changePKPWParser.addArgument(changePKPWCurrentPassword); final FileArgument changePKPWCurrentPasswordFile = new FileArgument(null, "current-private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_CURRENT_PW_FILE_DESC.get(), true, true, true, false); changePKPWCurrentPasswordFile.addLongIdentifier( "currentPrivateKeyPasswordFile", true); changePKPWCurrentPasswordFile.addLongIdentifier( "current-private-key-passphrase-file", true); changePKPWCurrentPasswordFile.addLongIdentifier( "currentPrivateKeyPassphraseFile", true); changePKPWCurrentPasswordFile.addLongIdentifier( "current-private-key-pin-file", true); changePKPWCurrentPasswordFile.addLongIdentifier("currentPrivateKeyPINFile", true); changePKPWParser.addArgument(changePKPWCurrentPasswordFile); final BooleanArgument changePKPWPromptForCurrentPassword = new BooleanArgument(null, "prompt-for-current-private-key-password", INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_PROMPT_FOR_CURRENT_PW_DESC.get()); changePKPWPromptForCurrentPassword.addLongIdentifier( "promptForCurrentPrivateKeyPassword", true); changePKPWPromptForCurrentPassword.addLongIdentifier( "prompt-for-current-private-key-passphrase", true); changePKPWPromptForCurrentPassword.addLongIdentifier( "promptForCurrentPrivateKeyPassphrase", true); changePKPWPromptForCurrentPassword.addLongIdentifier( "prompt-for-current-private-key-pin", true); changePKPWPromptForCurrentPassword.addLongIdentifier( "promptForCurrentPrivateKeyPIN", true); changePKPWParser.addArgument(changePKPWPromptForCurrentPassword); final StringArgument changePKPWNewPassword = new StringArgument(null, "new-private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_NEW_PW_DESC.get()); changePKPWNewPassword.addLongIdentifier("newPrivateKeyPassword", true); changePKPWNewPassword.addLongIdentifier("new-private-key-passphrase", true); changePKPWNewPassword.addLongIdentifier("newPrivateKeyPassphrase", true); changePKPWNewPassword.addLongIdentifier("new-private-key-pin", true); changePKPWNewPassword.addLongIdentifier("newPrivateKeyPIN", true); changePKPWNewPassword.addLongIdentifier("new", true); changePKPWNewPassword.setSensitive(true); changePKPWParser.addArgument(changePKPWNewPassword); final FileArgument changePKPWNewPasswordFile = new FileArgument(null, "new-private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_NEW_PW_FILE_DESC.get(), true, true, true, false); changePKPWNewPasswordFile.addLongIdentifier("newPrivateKeyPasswordFile", true); changePKPWNewPasswordFile.addLongIdentifier( "new-private-key-passphrase-file", true); changePKPWNewPasswordFile.addLongIdentifier("newPrivateKeyPassphraseFile", true); changePKPWNewPasswordFile.addLongIdentifier("new-private-key-pin-file", true); changePKPWNewPasswordFile.addLongIdentifier("newPrivateKeyPINFile", true); changePKPWParser.addArgument(changePKPWNewPasswordFile); final BooleanArgument changePKPWPromptForNewPassword = new BooleanArgument(null, "prompt-for-new-private-key-password", INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_PROMPT_FOR_NEW_PW_DESC.get()); changePKPWPromptForNewPassword.addLongIdentifier( "promptForNewPrivateKeyPassword", true); changePKPWPromptForNewPassword.addLongIdentifier( "prompt-for-new-private-key-passphrase", true); changePKPWPromptForNewPassword.addLongIdentifier( "promptForNewPrivateKeyPassphrase", true); changePKPWPromptForNewPassword.addLongIdentifier( "prompt-for-new-private-key-pin", true); changePKPWPromptForNewPassword.addLongIdentifier( "promptForNewPrivateKeyPIN", true); changePKPWParser.addArgument(changePKPWPromptForNewPassword); final BooleanArgument changePKPWDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_ARG_DISPLAY_COMMAND_DESC.get()); changePKPWDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); changePKPWDisplayCommand.addLongIdentifier("show-keytool-command", true); changePKPWDisplayCommand.addLongIdentifier("showKeytoolCommand", true); changePKPWParser.addArgument(changePKPWDisplayCommand); changePKPWParser.addRequiredArgumentSet(changePKPWKeystorePassword, changePKPWKeystorePasswordFile, changePKPWPromptForKeystorePassword); changePKPWParser.addExclusiveArgumentSet(changePKPWKeystorePassword, changePKPWKeystorePasswordFile, changePKPWPromptForKeystorePassword); changePKPWParser.addRequiredArgumentSet(changePKPWCurrentPassword, changePKPWCurrentPasswordFile, changePKPWPromptForCurrentPassword); changePKPWParser.addExclusiveArgumentSet(changePKPWCurrentPassword, changePKPWCurrentPasswordFile, changePKPWPromptForCurrentPassword); changePKPWParser.addRequiredArgumentSet(changePKPWNewPassword, changePKPWNewPasswordFile, changePKPWPromptForNewPassword); changePKPWParser.addExclusiveArgumentSet(changePKPWNewPassword, changePKPWNewPasswordFile, changePKPWPromptForNewPassword); final LinkedHashMap changePKPWExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); changePKPWExamples.put( new String[] { "change-private-key-password", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert", "--current-private-key-password-file", getPlatformSpecificPath("config", "current.pin"), "--new-private-key-password-file", getPlatformSpecificPath("config", "new.pin"), "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"), getPlatformSpecificPath("config", "current.pin"), getPlatformSpecificPath("config", "new.pin"))); final SubCommand changePKPWSubCommand = new SubCommand( "change-private-key-password", INFO_MANAGE_CERTS_SC_CHANGE_PK_PW_DESC.get(), changePKPWParser, changePKPWExamples); changePKPWSubCommand.addName("changePrivateKeyPassword", true); changePKPWSubCommand.addName("change-private-key-passphrase", true); changePKPWSubCommand.addName("changePrivateKeyPassphrase", true); changePKPWSubCommand.addName("change-private-key-pin", true); changePKPWSubCommand.addName("changePrivateKeyPIN", true); changePKPWSubCommand.addName("change-key-password", true); changePKPWSubCommand.addName("changeKeyPassword", true); changePKPWSubCommand.addName("change-key-passphrase", true); changePKPWSubCommand.addName("changeKeyPassphrase", true); changePKPWSubCommand.addName("change-key-pin", true); changePKPWSubCommand.addName("changeKeyPIN", true); changePKPWSubCommand.addName("keypasswd", true); parser.addSubCommand(changePKPWSubCommand); // Define the "copy-keystore" subcommand and all of its arguments. final ArgumentParser copyKSParser = new ArgumentParser("copy-keystore", INFO_MANAGE_CERTS_SC_COPY_KS_DESC.get()); final FileArgument copyKSSourceKeystore = new FileArgument(null, "source-keystore", true, 1, null, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_SRC_KS_DESC.get(), true, true, true, false); copyKSSourceKeystore.addLongIdentifier("sourceKeystore", true); copyKSSourceKeystore.addLongIdentifier("source-keystore-path", true); copyKSSourceKeystore.addLongIdentifier("sourceKeystorePath", true); copyKSSourceKeystore.addLongIdentifier("source-keystore-file", true); copyKSSourceKeystore.addLongIdentifier("sourceKeystoreFile", true); copyKSParser.addArgument(copyKSSourceKeystore); final StringArgument copyKSSourceKeystorePassword = new StringArgument(null, "source-keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_SRC_KS_PW_DESC.get()); copyKSSourceKeystorePassword.addLongIdentifier("sourceKeystorePassword", true); copyKSSourceKeystorePassword.addLongIdentifier("source-keystore-passphrase", true); copyKSSourceKeystorePassword.addLongIdentifier("sourceKeystorePassphrase", true); copyKSSourceKeystorePassword.addLongIdentifier("source-keystore-pin", true); copyKSSourceKeystorePassword.addLongIdentifier("sourceKeystorePIN", true); copyKSParser.addArgument(copyKSSourceKeystorePassword); final FileArgument copyKSSourceKeystorePasswordFile = new FileArgument(null, "source-keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_SRC_KS_PW_FILE_DESC.get(), true, true, true, false); copyKSSourceKeystorePasswordFile.addLongIdentifier( "sourceKeystorePasswordFile", true); copyKSSourceKeystorePasswordFile.addLongIdentifier( "source-keystore-passphrase-file", true); copyKSSourceKeystorePasswordFile.addLongIdentifier( "sourceKeystorePassphraseFile", true); copyKSSourceKeystorePasswordFile.addLongIdentifier( "source-keystore-pin-file", true); copyKSSourceKeystorePasswordFile.addLongIdentifier( "sourceKeystorePINFile", true); copyKSParser.addArgument(copyKSSourceKeystorePasswordFile); final BooleanArgument copyKSPromptForSourceKeystorePassword = new BooleanArgument(null, "prompt-for-source-keystore-password", 1, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_PROMPT_FOR_SRC_KS_PW.get()); copyKSPromptForSourceKeystorePassword.addLongIdentifier( "promptForSourceKeystorePassword", true); copyKSPromptForSourceKeystorePassword.addLongIdentifier( "prompt-for-source-keystore-passphrase", true); copyKSPromptForSourceKeystorePassword.addLongIdentifier( "promptForSourceKeystorePassphrase", true); copyKSPromptForSourceKeystorePassword.addLongIdentifier( "prompt-for-source-keystore-pin", true); copyKSPromptForSourceKeystorePassword.addLongIdentifier( "promptForSourceKeystorePIN", true); copyKSParser.addArgument(copyKSPromptForSourceKeystorePassword); final StringArgument copyKSSourcePKPassword = new StringArgument(null, "source-private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_SRC_PK_PW_DESC.get()); copyKSSourcePKPassword.addLongIdentifier("sourcePrivateKeyPassword", true); copyKSSourcePKPassword.addLongIdentifier("source-private-key-passphrase", true); copyKSSourcePKPassword.addLongIdentifier("sourcePrivateKeyPassphrase", true); copyKSSourcePKPassword.addLongIdentifier("source-private-key-pin", true); copyKSSourcePKPassword.addLongIdentifier("sourcePrivateKeyPIN", true); copyKSParser.addArgument(copyKSSourcePKPassword); final FileArgument copyKSSourcePKPasswordFile = new FileArgument(null, "source-private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_SRC_PK_PW_FILE_DESC.get(), true, true, true, false); copyKSSourcePKPasswordFile.addLongIdentifier( "sourcePrivateKeyPasswordFile", true); copyKSSourcePKPasswordFile.addLongIdentifier( "source-private-key-passphrase-file", true); copyKSSourcePKPasswordFile.addLongIdentifier( "sourcePrivateKeyPassphraseFile", true); copyKSSourcePKPasswordFile.addLongIdentifier( "source-private-key-pin-file", true); copyKSSourcePKPasswordFile.addLongIdentifier( "sourcePrivateKeyPINFile", true); copyKSParser.addArgument(copyKSSourcePKPasswordFile); final BooleanArgument copyKSPromptForSourcePKPassword = new BooleanArgument(null, "prompt-for-source-private-key-password", 1, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_PROMPT_FOR_SRC_PK_PW.get()); copyKSPromptForSourcePKPassword.addLongIdentifier( "promptForSourcePrivateKeyPassword", true); copyKSPromptForSourcePKPassword.addLongIdentifier( "prompt-for-source-private-key-passphrase", true); copyKSPromptForSourcePKPassword.addLongIdentifier( "promptForSourcePrivateKeyPassphrase", true); copyKSPromptForSourcePKPassword.addLongIdentifier( "prompt-for-source-private-key-pin", true); copyKSPromptForSourcePKPassword.addLongIdentifier( "promptForSourcePrivateKeyPIN", true); copyKSParser.addArgument(copyKSPromptForSourcePKPassword); final StringArgument copyKSSourceKeystoreType = new StringArgument(null, "source-keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_SRC_KS_TYPE.get(), ALLOWED_KEYSTORE_TYPE_VALUES); copyKSSourceKeystoreType.addLongIdentifier("source-key-store-type", true); copyKSSourceKeystoreType.addLongIdentifier("sourceKeystoreType", true); copyKSSourceKeystoreType.addLongIdentifier("source-keystore-format", true); copyKSSourceKeystoreType.addLongIdentifier("source-key-store-format", true); copyKSSourceKeystoreType.addLongIdentifier("sourceKeystoreFormat", true); copyKSParser.addArgument(copyKSSourceKeystoreType); final FileArgument copyKSDestKeystore = new FileArgument(null, "destination-keystore", true, 1, null, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_DST_KS_DESC.get(), false, true, true, false); copyKSDestKeystore.addLongIdentifier("destinationKeystore", true); copyKSDestKeystore.addLongIdentifier("destination-keystore-path", true); copyKSDestKeystore.addLongIdentifier("destinationKeystorePath", true); copyKSDestKeystore.addLongIdentifier("destination-keystore-file", true); copyKSDestKeystore.addLongIdentifier("destinationKeystoreFile", true); copyKSDestKeystore.addLongIdentifier("target-keystore", true); copyKSDestKeystore.addLongIdentifier("targetKeystore", true); copyKSDestKeystore.addLongIdentifier("target-keystore-path", true); copyKSDestKeystore.addLongIdentifier("targetKeystorePath", true); copyKSDestKeystore.addLongIdentifier("target-keystore-file", true); copyKSDestKeystore.addLongIdentifier("targetKeystoreFile", true); copyKSParser.addArgument(copyKSDestKeystore); final StringArgument copyKSDestKeystorePassword = new StringArgument(null, "destination-keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_DST_KS_PW_DESC.get()); copyKSDestKeystorePassword.addLongIdentifier("destinationKeystorePassword", true); copyKSDestKeystorePassword.addLongIdentifier( "destination-keystore-passphrase", true); copyKSDestKeystorePassword.addLongIdentifier( "destinationKeystorePassphrase", true); copyKSDestKeystorePassword.addLongIdentifier("destination-keystore-pin", true); copyKSDestKeystorePassword.addLongIdentifier("destinationKeystorePIN", true); copyKSDestKeystorePassword.addLongIdentifier("target-keystore-password", true); copyKSDestKeystorePassword.addLongIdentifier("targetKeystorePassword", true); copyKSDestKeystorePassword.addLongIdentifier("target-keystore-passphrase", true); copyKSDestKeystorePassword.addLongIdentifier("targetKeystorePassphrase", true); copyKSDestKeystorePassword.addLongIdentifier("target-keystore-pin", true); copyKSDestKeystorePassword.addLongIdentifier("targetKeystorePIN", true); copyKSParser.addArgument(copyKSDestKeystorePassword); final FileArgument copyKSDestKeystorePasswordFile = new FileArgument(null, "destination-keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_DST_KS_PW_FILE_DESC.get(), true, true, true, false); copyKSDestKeystorePasswordFile.addLongIdentifier( "destinationKeystorePasswordFile", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "destination-keystore-passphrase-file", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "destinationKeystorePassphraseFile", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "destination-keystore-pin-file", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "destinationKeystorePINFile", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "target-keystore-password-file", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "targetKeystorePasswordFile", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "target-keystore-passphrase-file", true); copyKSDestKeystorePasswordFile.addLongIdentifier( "targetKeystorePassphraseFile", true); copyKSDestKeystorePasswordFile.addLongIdentifier("target-keystore-pin-file", true); copyKSDestKeystorePasswordFile.addLongIdentifier("targetKeystorePINFile", true); copyKSParser.addArgument(copyKSDestKeystorePasswordFile); final BooleanArgument copyKSPromptForDestKeystorePassword = new BooleanArgument(null, "prompt-for-destination-keystore-password", 1, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_PROMPT_FOR_DST_KS_PW.get()); copyKSPromptForDestKeystorePassword.addLongIdentifier( "promptForDestinationKeystorePassword", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "prompt-for-Destination-keystore-passphrase", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "promptForDestinationKeystorePassphrase", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "prompt-for-Destination-keystore-pin", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "promptForDestinationKeystorePIN", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "prompt-for-target-keystore-password", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "promptForTargetKeystorePassword", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "prompt-for-Target-keystore-passphrase", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "promptForTargetKeystorePassphrase", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "prompt-for-Target-keystore-pin", true); copyKSPromptForDestKeystorePassword.addLongIdentifier( "promptForTargetKeystorePIN", true); copyKSParser.addArgument(copyKSPromptForDestKeystorePassword); final StringArgument copyKSDestPKPassword = new StringArgument(null, "destination-private-key-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_DST_PK_PW_DESC.get()); copyKSDestPKPassword.addLongIdentifier("destinationPrivateKeyPassword", true); copyKSDestPKPassword.addLongIdentifier("destination-private-key-passphrase", true); copyKSDestPKPassword.addLongIdentifier("destinationPrivateKeyPassphrase", true); copyKSDestPKPassword.addLongIdentifier("destination-private-key-pin", true); copyKSDestPKPassword.addLongIdentifier("destinationPrivateKeyPIN", true); copyKSDestPKPassword.addLongIdentifier("target-private-key-password", true); copyKSDestPKPassword.addLongIdentifier("targetPrivateKeyPassword", true); copyKSDestPKPassword.addLongIdentifier("target-private-key-passphrase", true); copyKSDestPKPassword.addLongIdentifier("targetPrivateKeyPassphrase", true); copyKSDestPKPassword.addLongIdentifier("target-private-key-pin", true); copyKSDestPKPassword.addLongIdentifier("targetPrivateKeyPIN", true); copyKSParser.addArgument(copyKSDestPKPassword); final FileArgument copyKSDestPKPasswordFile = new FileArgument(null, "destination-private-key-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_DST_PK_PW_FILE_DESC.get(), true, true, true, false); copyKSDestPKPasswordFile.addLongIdentifier( "destinationPrivateKeyPasswordFile", true); copyKSDestPKPasswordFile.addLongIdentifier( "destination-private-key-passphrase-file", true); copyKSDestPKPasswordFile.addLongIdentifier( "destinationPrivateKeyPassphraseFile", true); copyKSDestPKPasswordFile.addLongIdentifier( "destination-private-key-pin-file", true); copyKSDestPKPasswordFile.addLongIdentifier( "destinationPrivateKeyPINFile", true); copyKSDestPKPasswordFile.addLongIdentifier( "target-private-key-password-file", true); copyKSDestPKPasswordFile.addLongIdentifier( "targetPrivateKeyPasswordFile", true); copyKSDestPKPasswordFile.addLongIdentifier( "target-private-key-passphrase-file", true); copyKSDestPKPasswordFile.addLongIdentifier( "targetPrivateKeyPassphraseFile", true); copyKSDestPKPasswordFile.addLongIdentifier( "target-private-key-pin-file", true); copyKSDestPKPasswordFile.addLongIdentifier( "targetPrivateKeyPINFile", true); copyKSParser.addArgument(copyKSDestPKPasswordFile); final BooleanArgument copyKSPromptForDestPKPassword = new BooleanArgument(null, "prompt-for-destination-private-key-password", 1, INFO_MANAGE_CERTS_SC_COPY_KS_ARG_PROMPT_FOR_DST_PK_PW.get()); copyKSPromptForDestPKPassword.addLongIdentifier( "promptForDestinationPrivateKeyPassword", true); copyKSPromptForDestPKPassword.addLongIdentifier( "prompt-for-Destination-private-key-passphrase", true); copyKSPromptForDestPKPassword.addLongIdentifier( "promptForDestinationPrivateKeyPassphrase", true); copyKSPromptForDestPKPassword.addLongIdentifier( "prompt-for-Destination-private-key-pin", true); copyKSPromptForDestPKPassword.addLongIdentifier( "promptForDestinationPrivateKeyPIN", true); copyKSPromptForDestPKPassword.addLongIdentifier( "prompt-for-target-private-key-password", true); copyKSPromptForDestPKPassword.addLongIdentifier( "promptForTargetPrivateKeyPassword", true); copyKSPromptForDestPKPassword.addLongIdentifier( "prompt-for-Target-private-key-passphrase", true); copyKSPromptForDestPKPassword.addLongIdentifier( "promptForTargetPrivateKeyPassphrase", true); copyKSPromptForDestPKPassword.addLongIdentifier( "prompt-for-Target-private-key-pin", true); copyKSPromptForDestPKPassword.addLongIdentifier( "promptForTargetPrivateKeyPIN", true); copyKSParser.addArgument(copyKSPromptForDestPKPassword); final StringArgument copyKSDestKeystoreType = new StringArgument(null, "destination-keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_DST_KS_TYPE.get(), ALLOWED_KEYSTORE_TYPE_VALUES); copyKSDestKeystoreType.addLongIdentifier("destination-key-store-type", true); copyKSDestKeystoreType.addLongIdentifier("destinationKeystoreType", true); copyKSDestKeystoreType.addLongIdentifier("destination-keystore-format", true); copyKSDestKeystoreType.addLongIdentifier("destination-key-store-format", true); copyKSDestKeystoreType.addLongIdentifier("destinationKeystoreFormat", true); copyKSDestKeystoreType.addLongIdentifier("target-key-store-type", true); copyKSDestKeystoreType.addLongIdentifier("targetKeystoreType", true); copyKSDestKeystoreType.addLongIdentifier("target-keystore-format", true); copyKSDestKeystoreType.addLongIdentifier("target-key-store-format", true); copyKSDestKeystoreType.addLongIdentifier("targetKeystoreFormat", true); copyKSParser.addArgument(copyKSDestKeystoreType); final StringArgument copyKSAlias = new StringArgument(null, "alias", false, 0, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_COPY_KS_ARG_ALIAS.get()); copyKSAlias.addLongIdentifier("nickname", true); copyKSParser.addArgument(copyKSAlias); copyKSParser.addRequiredArgumentSet(copyKSSourceKeystorePassword, copyKSSourceKeystorePasswordFile, copyKSPromptForSourceKeystorePassword); copyKSParser.addExclusiveArgumentSet(copyKSSourceKeystorePassword, copyKSSourceKeystorePasswordFile, copyKSPromptForSourceKeystorePassword); copyKSParser.addExclusiveArgumentSet(copyKSSourcePKPassword, copyKSSourcePKPasswordFile, copyKSPromptForDestPKPassword); copyKSParser.addExclusiveArgumentSet(copyKSDestKeystorePassword, copyKSDestKeystorePasswordFile, copyKSPromptForDestKeystorePassword); copyKSParser.addExclusiveArgumentSet(copyKSDestPKPassword, copyKSDestPKPasswordFile, copyKSPromptForDestPKPassword); final LinkedHashMap copyKeyStoreExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); copyKeyStoreExamples.put( new String[] { "copy-keystore", "--source-keystore", getPlatformSpecificPath("config", "keystore.jks"), "--source-keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--source-keystore-type", "JKS", "--destination-keystore", getPlatformSpecificPath("config", "keystore.p12"), "--destination-keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--destination-keystore-type", "PKCS12" }, INFO_MANAGE_CERTS_SC_COPY_KS_EXAMPLE_1.get("keystore.jks", "keystore.p12")); final SubCommand copyKeyStoreSubCommand = new SubCommand("copy-keystore", INFO_MANAGE_CERTS_SC_COPY_KS_DESC.get(), copyKSParser, copyKeyStoreExamples); copyKeyStoreSubCommand.addName("copy-key-store", true); copyKeyStoreSubCommand.addName("copyKeyStore", true); copyKeyStoreSubCommand.addName("import-keystore", true); copyKeyStoreSubCommand.addName("import-key-store", true); copyKeyStoreSubCommand.addName("importKeyStore", true); copyKeyStoreSubCommand.addName("convert-keystore", true); copyKeyStoreSubCommand.addName("convert-key-store", true); copyKeyStoreSubCommand.addName("convertKeyStore", true); parser.addSubCommand(copyKeyStoreSubCommand); // Define the "retrieve-server-certificate" subcommand and all of its // arguments. final ArgumentParser retrieveCertParser = new ArgumentParser( "retrieve-server-certificate", INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_DESC.get()); final StringArgument retrieveCertHostname = new StringArgument('h', "hostname", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_HOST.get(), INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_HOSTNAME_DESC.get()); retrieveCertHostname.addLongIdentifier("server-address", true); retrieveCertHostname.addLongIdentifier("serverAddress", true); retrieveCertHostname.addLongIdentifier("address", true); retrieveCertParser.addArgument(retrieveCertHostname); final IntegerArgument retrieveCertPort = new IntegerArgument('p', "port", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PORT.get(), INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_PORT_DESC.get(), 1, 65_535); retrieveCertPort.addLongIdentifier("server-port", true); retrieveCertPort.addLongIdentifier("serverPort", true); retrieveCertParser.addArgument(retrieveCertPort); final BooleanArgument retrieveCertUseStartTLS = new BooleanArgument('q', "use-ldap-start-tls", 1, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_USE_START_TLS_DESC.get()); retrieveCertUseStartTLS.addLongIdentifier("use-ldap-starttls", true); retrieveCertUseStartTLS.addLongIdentifier("useLDAPStartTLS", true); retrieveCertUseStartTLS.addLongIdentifier("use-start-tls", true); retrieveCertUseStartTLS.addLongIdentifier("use-starttls", true); retrieveCertUseStartTLS.addLongIdentifier("useStartTLS", true); retrieveCertParser.addArgument(retrieveCertUseStartTLS); final FileArgument retrieveCertOutputFile = new FileArgument(null, "output-file", false, 1, null, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_FILE_DESC.get(), false, true, true, false); retrieveCertOutputFile.addLongIdentifier("outputFile", true); retrieveCertOutputFile.addLongIdentifier("export-file", true); retrieveCertOutputFile.addLongIdentifier("exportFile", true); retrieveCertOutputFile.addLongIdentifier("certificate-file", true); retrieveCertOutputFile.addLongIdentifier("certificateFile", true); retrieveCertOutputFile.addLongIdentifier("file", true); retrieveCertOutputFile.addLongIdentifier("filename", true); retrieveCertParser.addArgument(retrieveCertOutputFile); final Set retrieveCertOutputFormatAllowedValues = StaticUtils.setOf( "PEM", "text", "txt", "RFC", "DER", "binary", "bin"); final StringArgument retrieveCertOutputFormat = new StringArgument(null, "output-format", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_FORMAT.get(), INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_FORMAT_DESC.get(), retrieveCertOutputFormatAllowedValues, "PEM"); retrieveCertOutputFormat.addLongIdentifier("outputFormat", true); retrieveCertParser.addArgument(retrieveCertOutputFormat); final BooleanArgument retrieveCertOnlyPeer = new BooleanArgument(null, "only-peer-certificate", 1, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_ONLY_PEER_DESC.get()); retrieveCertOnlyPeer.addLongIdentifier("onlyPeerCertificate", true); retrieveCertOnlyPeer.addLongIdentifier("only-peer", true); retrieveCertOnlyPeer.addLongIdentifier("onlyPeer", true); retrieveCertOnlyPeer.addLongIdentifier("peer-certificate-only", true); retrieveCertOnlyPeer.addLongIdentifier("peerCertificateOnly", true); retrieveCertOnlyPeer.addLongIdentifier("peer-only", true); retrieveCertOnlyPeer.addLongIdentifier("peerOnly", true); retrieveCertParser.addArgument(retrieveCertOnlyPeer); final BooleanArgument retrieveCertEnableSSLDebugging = new BooleanArgument( null, "enableSSLDebugging", 1, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_ENABLE_SSL_DEBUGGING_DESC. get()); retrieveCertEnableSSLDebugging.addLongIdentifier("enableTLSDebugging", true); retrieveCertEnableSSLDebugging.addLongIdentifier("enableStartTLSDebugging", true); retrieveCertEnableSSLDebugging.addLongIdentifier("enable-ssl-debugging", true); retrieveCertEnableSSLDebugging.addLongIdentifier("enable-tls-debugging", true); retrieveCertEnableSSLDebugging.addLongIdentifier( "enable-starttls-debugging", true); retrieveCertEnableSSLDebugging.addLongIdentifier( "enable-start-tls-debugging", true); retrieveCertParser.addArgument(retrieveCertEnableSSLDebugging); addEnableSSLDebuggingArgument(retrieveCertEnableSSLDebugging); final BooleanArgument retrieveCertVerbose = new BooleanArgument(null, "verbose", 1, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_ARG_VERBOSE_DESC.get()); retrieveCertParser.addArgument(retrieveCertVerbose); retrieveCertParser.addDependentArgumentSet(retrieveCertOutputFormat, retrieveCertOutputFile); final LinkedHashMap retrieveCertExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); retrieveCertExamples.put( new String[] { "retrieve-server-certificate", "--hostname", "ds.example.com", "--port", "636" }, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_EXAMPLE_1.get( getPlatformSpecificPath("config", "truststore"))); retrieveCertExamples.put( new String[] { "retrieve-server-certificate", "--hostname", "ds.example.com", "--port", "389", "--use-ldap-start-tls", "--only-peer-certificate", "--output-file", "ds-cert.pem", "--output-format", "PEM", "--verbose" }, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_EXAMPLE_2.get( getPlatformSpecificPath("config", "truststore"))); final SubCommand retrieveCertSubCommand = new SubCommand( "retrieve-server-certificate", INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_DESC.get(), retrieveCertParser, retrieveCertExamples); retrieveCertSubCommand.addName("retrieveServerCertificate", true); retrieveCertSubCommand.addName("retrieve-certificate", true); retrieveCertSubCommand.addName("retrieveCertificate", true); retrieveCertSubCommand.addName("get-server-certificate", true); retrieveCertSubCommand.addName("getServerCertificate", true); retrieveCertSubCommand.addName("get-certificate", true); retrieveCertSubCommand.addName("getCertificate", true); retrieveCertSubCommand.addName("display-server-certificate", true); retrieveCertSubCommand.addName("displayServerCertificate", true); parser.addSubCommand(retrieveCertSubCommand); // Define the "trust-server-certificate" subcommand and all of its // arguments. final ArgumentParser trustServerParser = new ArgumentParser( "trust-server-certificate", INFO_MANAGE_CERTS_SC_TRUST_SERVER_DESC.get()); final StringArgument trustServerHostname = new StringArgument('h', "hostname", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_HOST.get(), INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_HOSTNAME_DESC.get()); trustServerHostname.addLongIdentifier("server-address", true); trustServerHostname.addLongIdentifier("serverAddress", true); trustServerHostname.addLongIdentifier("address", true); trustServerParser.addArgument(trustServerHostname); final IntegerArgument trustServerPort = new IntegerArgument('p', "port", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PORT.get(), INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_PORT_DESC.get(), 1, 65_535); trustServerPort.addLongIdentifier("server-port", true); trustServerPort.addLongIdentifier("serverPort", true); trustServerParser.addArgument(trustServerPort); final BooleanArgument trustServerUseStartTLS = new BooleanArgument('q', "use-ldap-start-tls", 1, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_USE_START_TLS_DESC.get()); trustServerUseStartTLS.addLongIdentifier("use-ldap-starttls", true); trustServerUseStartTLS.addLongIdentifier("useLDAPStartTLS", true); trustServerUseStartTLS.addLongIdentifier("use-start-tls", true); trustServerUseStartTLS.addLongIdentifier("use-starttls", true); trustServerUseStartTLS.addLongIdentifier("useStartTLS", true); trustServerParser.addArgument(trustServerUseStartTLS); final FileArgument trustServerKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_KS_DESC.get(), false, true, true, false); trustServerKeystore.addLongIdentifier("keystore-path", true); trustServerKeystore.addLongIdentifier("keystorePath", true); trustServerKeystore.addLongIdentifier("keystore-file", true); trustServerKeystore.addLongIdentifier("keystoreFile", true); trustServerParser.addArgument(trustServerKeystore); final StringArgument trustServerKeystorePassword = new StringArgument(null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_KS_PW_DESC.get()); trustServerKeystorePassword.addLongIdentifier("keystorePassword", true); trustServerKeystorePassword.addLongIdentifier("keystore-passphrase", true); trustServerKeystorePassword.addLongIdentifier("keystorePassphrase", true); trustServerKeystorePassword.addLongIdentifier("keystore-pin", true); trustServerKeystorePassword.addLongIdentifier("keystorePIN", true); trustServerKeystorePassword.addLongIdentifier("storepass", true); trustServerKeystorePassword.setSensitive(true); trustServerParser.addArgument(trustServerKeystorePassword); final FileArgument trustServerKeystorePasswordFile = new FileArgument(null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); trustServerKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); trustServerKeystorePasswordFile.addLongIdentifier( "keystore-passphrase-file", true); trustServerKeystorePasswordFile.addLongIdentifier("keystorePassphraseFile", true); trustServerKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); trustServerKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); trustServerParser.addArgument(trustServerKeystorePasswordFile); final BooleanArgument trustServerPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_PROMPT_FOR_KS_PW_DESC.get()); trustServerPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); trustServerPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); trustServerPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); trustServerPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); trustServerPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); trustServerParser.addArgument(trustServerPromptForKeystorePassword); final StringArgument trustServerKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); trustServerKeystoreType.addLongIdentifier("key-store-type", true); trustServerKeystoreType.addLongIdentifier("keystoreType", true); trustServerKeystoreType.addLongIdentifier("keystore-format", true); trustServerKeystoreType.addLongIdentifier("key-store-format", true); trustServerKeystoreType.addLongIdentifier("keystoreFormat", true); trustServerKeystoreType.addLongIdentifier("storetype", true); trustServerParser.addArgument(trustServerKeystoreType); final StringArgument trustServerAlias = new StringArgument(null, "alias", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_ALIAS_DESC.get()); trustServerAlias.addLongIdentifier("nickname", true); trustServerParser.addArgument(trustServerAlias); final BooleanArgument trustServerIssuersOnly = new BooleanArgument(null, "issuers-only", 1, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_ISSUERS_ONLY_DESC.get()); trustServerIssuersOnly.addLongIdentifier("issuersOnly", true); trustServerIssuersOnly.addLongIdentifier("issuer-certificates-only", true); trustServerIssuersOnly.addLongIdentifier("issuerCertificatesOnly", true); trustServerIssuersOnly.addLongIdentifier("only-issuers", true); trustServerIssuersOnly.addLongIdentifier("onlyIssuers", true); trustServerIssuersOnly.addLongIdentifier("only-issuer-certificates", true); trustServerIssuersOnly.addLongIdentifier("onlyIssuerCertificates", true); trustServerParser.addArgument(trustServerIssuersOnly); final BooleanArgument trustServerEnableSSLDebugging = new BooleanArgument( null, "enableSSLDebugging", 1, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_ENABLE_SSL_DEBUGGING_DESC.get()); trustServerEnableSSLDebugging.addLongIdentifier("enableTLSDebugging", true); trustServerEnableSSLDebugging.addLongIdentifier("enableStartTLSDebugging", true); trustServerEnableSSLDebugging.addLongIdentifier("enable-ssl-debugging", true); trustServerEnableSSLDebugging.addLongIdentifier("enable-tls-debugging", true); trustServerEnableSSLDebugging.addLongIdentifier("enable-starttls-debugging", true); trustServerEnableSSLDebugging.addLongIdentifier( "enable-start-tls-debugging", true); trustServerParser.addArgument(trustServerEnableSSLDebugging); addEnableSSLDebuggingArgument(trustServerEnableSSLDebugging); final BooleanArgument trustServerVerbose = new BooleanArgument(null, "verbose", 1, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_VERBOSE_DESC.get()); trustServerParser.addArgument(trustServerVerbose); final BooleanArgument trustServerNoPrompt = new BooleanArgument(null, "no-prompt", 1, INFO_MANAGE_CERTS_SC_TRUST_SERVER_ARG_NO_PROMPT_DESC.get()); trustServerNoPrompt.addLongIdentifier("noPrompt", true); trustServerParser.addArgument(trustServerNoPrompt); trustServerParser.addRequiredArgumentSet(trustServerKeystorePassword, trustServerKeystorePasswordFile, trustServerPromptForKeystorePassword); trustServerParser.addExclusiveArgumentSet(trustServerKeystorePassword, trustServerKeystorePasswordFile, trustServerPromptForKeystorePassword); final LinkedHashMap trustServerExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); trustServerExamples.put( new String[] { "trust-server-certificate", "--hostname", "ds.example.com", "--port", "636", "--keystore", getPlatformSpecificPath("config", "truststore"), "--keystore-password-file", getPlatformSpecificPath("config", "truststore.pin"), "--verbose" }, INFO_MANAGE_CERTS_SC_TRUST_SERVER_EXAMPLE_1.get( getPlatformSpecificPath("config", "truststore"))); trustServerExamples.put( new String[] { "trust-server-certificate", "--hostname", "ds.example.com", "--port", "389", "--use-ldap-start-tls", "--keystore", getPlatformSpecificPath("config", "truststore"), "--keystore-password-file", getPlatformSpecificPath("config", "truststore.pin"), "--issuers-only", "--alias", "ds-start-tls-cert", "--no-prompt" }, INFO_MANAGE_CERTS_SC_TRUST_SERVER_EXAMPLE_2.get( getPlatformSpecificPath("config", "truststore"))); final SubCommand trustServerSubCommand = new SubCommand( "trust-server-certificate", INFO_MANAGE_CERTS_SC_TRUST_SERVER_DESC.get(), trustServerParser, trustServerExamples); trustServerSubCommand.addName("trustServerCertificate", true); trustServerSubCommand.addName("trust-server", true); trustServerSubCommand.addName("trustServer", true); parser.addSubCommand(trustServerSubCommand); // Define the "check-certificate-usability" subcommand and all of its // arguments. final ArgumentParser checkUsabilityParser = new ArgumentParser( "check-certificate-usability", INFO_MANAGE_CERTS_SC_CHECK_USABILITY_DESC.get()); final FileArgument checkUsabilityKeystore = new FileArgument(null, "keystore", true, 1, null, INFO_MANAGE_CERTS_SC_CHECK_USABILITY_ARG_KS_DESC.get(), true, true, true, false); checkUsabilityKeystore.addLongIdentifier("keystore-path", true); checkUsabilityKeystore.addLongIdentifier("keystorePath", true); checkUsabilityKeystore.addLongIdentifier("keystore-file", true); checkUsabilityKeystore.addLongIdentifier("keystoreFile", true); checkUsabilityParser.addArgument(checkUsabilityKeystore); final StringArgument checkUsabilityKeystorePassword = new StringArgument( null, "keystore-password", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_PASSWORD.get(), INFO_MANAGE_CERTS_SC_CHECK_USABILITY_ARG_KS_PW_DESC.get()); checkUsabilityKeystorePassword.addLongIdentifier("keystorePassword", true); checkUsabilityKeystorePassword.addLongIdentifier("keystore-passphrase", true); checkUsabilityKeystorePassword.addLongIdentifier("keystorePassphrase", true); checkUsabilityKeystorePassword.addLongIdentifier("keystore-pin", true); checkUsabilityKeystorePassword.addLongIdentifier("keystorePIN", true); checkUsabilityKeystorePassword.addLongIdentifier("storepass", true); checkUsabilityKeystorePassword.setSensitive(true); checkUsabilityParser.addArgument(checkUsabilityKeystorePassword); final FileArgument checkUsabilityKeystorePasswordFile = new FileArgument( null, "keystore-password-file", false, 1, null, INFO_MANAGE_CERTS_SC_CHECK_USABILITY_ARG_KS_PW_FILE_DESC.get(), true, true, true, false); checkUsabilityKeystorePasswordFile.addLongIdentifier("keystorePasswordFile", true); checkUsabilityKeystorePasswordFile.addLongIdentifier( "keystore-passphrase-file", true); checkUsabilityKeystorePasswordFile.addLongIdentifier( "keystorePassphraseFile", true); checkUsabilityKeystorePasswordFile.addLongIdentifier("keystore-pin-file", true); checkUsabilityKeystorePasswordFile.addLongIdentifier("keystorePINFile", true); checkUsabilityParser.addArgument(checkUsabilityKeystorePasswordFile); final BooleanArgument checkUsabilityPromptForKeystorePassword = new BooleanArgument(null, "prompt-for-keystore-password", INFO_MANAGE_CERTS_SC_CHECK_USABILITY_ARG_PROMPT_FOR_KS_PW_DESC.get()); checkUsabilityPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassword", true); checkUsabilityPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-passphrase", true); checkUsabilityPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePassphrase", true); checkUsabilityPromptForKeystorePassword.addLongIdentifier( "prompt-for-keystore-pin", true); checkUsabilityPromptForKeystorePassword.addLongIdentifier( "promptForKeystorePIN", true); checkUsabilityParser.addArgument(checkUsabilityPromptForKeystorePassword); final StringArgument checkUsabilityKeystoreType = new StringArgument(null, "keystore-type", false, 1, INFO_MANAGE_CERTS_PLACEHOLDER_TYPE.get(), INFO_MANAGE_CERTS_SC_CHECK_USABILITY_ARG_KS_TYPE_DESC.get(), ALLOWED_KEYSTORE_TYPE_VALUES); checkUsabilityKeystoreType.addLongIdentifier("key-store-type", true); checkUsabilityKeystoreType.addLongIdentifier("keystoreType", true); checkUsabilityKeystoreType.addLongIdentifier("keystore-format", true); checkUsabilityKeystoreType.addLongIdentifier("key-store-format", true); checkUsabilityKeystoreType.addLongIdentifier("keystoreFormat", true); checkUsabilityKeystoreType.addLongIdentifier("storetype", true); checkUsabilityParser.addArgument(checkUsabilityKeystoreType); final StringArgument checkUsabilityAlias = new StringArgument(null, "alias", true, 1, INFO_MANAGE_CERTS_PLACEHOLDER_ALIAS.get(), INFO_MANAGE_CERTS_SC_CHECK_USABILITY_ARG_ALIAS_DESC.get()); checkUsabilityAlias.addLongIdentifier("nickname", true); checkUsabilityParser.addArgument(checkUsabilityAlias); final BooleanArgument checkUsabilityIgnoreSHA1Signature = new BooleanArgument(null, "allow-sha-1-signature-for-issuer-certificates", 1, INFO_MANAGE_CERTS_SC_CHECK_USABILITY_IGNORE_SHA1_WARNING_DESC. get()); checkUsabilityIgnoreSHA1Signature.addLongIdentifier( "allow-sha1-signature-for-issuer-certificates", true); checkUsabilityIgnoreSHA1Signature.addLongIdentifier( "allowSHA1SignatureForIssuerCertificates", true); checkUsabilityParser.addArgument(checkUsabilityIgnoreSHA1Signature); checkUsabilityParser.addRequiredArgumentSet(checkUsabilityKeystorePassword, checkUsabilityKeystorePasswordFile, checkUsabilityPromptForKeystorePassword); checkUsabilityParser.addExclusiveArgumentSet(checkUsabilityKeystorePassword, checkUsabilityKeystorePasswordFile, checkUsabilityPromptForKeystorePassword); final LinkedHashMap checkUsabilityExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); checkUsabilityExamples.put( new String[] { "check-certificate-usability", "--keystore", getPlatformSpecificPath("config", "keystore"), "--keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--alias", "server-cert" }, INFO_MANAGE_CERTS_SC_CHECK_USABILITY_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"))); final SubCommand checkUsabilitySubCommand = new SubCommand( "check-certificate-usability", INFO_MANAGE_CERTS_SC_CHECK_USABILITY_DESC.get(), checkUsabilityParser, checkUsabilityExamples); checkUsabilitySubCommand.addName("checkCertificateUsability", true); checkUsabilitySubCommand.addName("check-usability", true); checkUsabilitySubCommand.addName("checkUsability", true); parser.addSubCommand(checkUsabilitySubCommand); // Define the "display-certificate-file" subcommand and all of its // arguments. final ArgumentParser displayCertParser = new ArgumentParser( "display-certificate-file", INFO_MANAGE_CERTS_SC_DISPLAY_CERT_DESC.get()); final FileArgument displayCertFile = new FileArgument(null, "certificate-file", true, 1, null, INFO_MANAGE_CERTS_SC_DISPLAY_CERT_ARG_FILE_DESC.get(), true, true, true, false); displayCertFile.addLongIdentifier("certificateFile", true); displayCertFile.addLongIdentifier("input-file", true); displayCertFile.addLongIdentifier("inputFile", true); displayCertFile.addLongIdentifier("file", true); displayCertFile.addLongIdentifier("filename", true); displayCertParser.addArgument(displayCertFile); final BooleanArgument displayCertVerbose = new BooleanArgument(null, "verbose", 1, INFO_MANAGE_CERTS_SC_DISPLAY_CERT_ARG_VERBOSE_DESC.get()); displayCertParser.addArgument(displayCertVerbose); final BooleanArgument displayCertDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_DISPLAY_CERT_ARG_DISPLAY_COMMAND_DESC.get()); displayCertDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); displayCertDisplayCommand.addLongIdentifier("show-keytool-command", true); displayCertDisplayCommand.addLongIdentifier("showKeytoolCommand", true); displayCertParser.addArgument(displayCertDisplayCommand); final LinkedHashMap displayCertExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); displayCertExamples.put( new String[] { "display-certificate-file", "--certificate-file", "certificate.pem", }, INFO_MANAGE_CERTS_SC_DISPLAY_CERT_EXAMPLE_1.get("certificate.pem")); displayCertExamples.put( new String[] { "display-certificate-file", "--certificate-file", "certificate.pem", "--verbose", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_DISPLAY_CERT_EXAMPLE_2.get("certificate.pem")); final SubCommand displayCertSubCommand = new SubCommand( "display-certificate-file", INFO_MANAGE_CERTS_SC_DISPLAY_CERT_DESC.get(), displayCertParser, displayCertExamples); displayCertSubCommand.addName("displayCertificateFile", true); displayCertSubCommand.addName("display-certificate", true); displayCertSubCommand.addName("displayCertificate", true); displayCertSubCommand.addName("display-certificates", true); displayCertSubCommand.addName("displayCertificates", true); displayCertSubCommand.addName("show-certificate", true); displayCertSubCommand.addName("showCertificate", true); displayCertSubCommand.addName("show-certificate-file", true); displayCertSubCommand.addName("showCertificateFile", true); displayCertSubCommand.addName("show-certificates", true); displayCertSubCommand.addName("showCertificates", true); displayCertSubCommand.addName("print-certificate-file", true); displayCertSubCommand.addName("printCertificateFile", true); displayCertSubCommand.addName("print-certificate", true); displayCertSubCommand.addName("printCertificate", true); displayCertSubCommand.addName("print-certificates", true); displayCertSubCommand.addName("printCertificates", true); displayCertSubCommand.addName("printcert", true); parser.addSubCommand(displayCertSubCommand); // Define the "display-certificate-signing-request-file" subcommand and all // of its arguments. final ArgumentParser displayCSRParser = new ArgumentParser( "display-certificate-signing-request-file", INFO_MANAGE_CERTS_SC_DISPLAY_CSR_DESC.get()); final FileArgument displayCSRFile = new FileArgument(null, "certificate-signing-request-file", true, 1, null, INFO_MANAGE_CERTS_SC_DISPLAY_CSR_ARG_FILE_DESC.get(), true, true, true, false); displayCSRFile.addLongIdentifier("certificateSigningRequestFile", true); displayCSRFile.addLongIdentifier("request-file", true); displayCSRFile.addLongIdentifier("requestFile", true); displayCSRFile.addLongIdentifier("input-file", true); displayCSRFile.addLongIdentifier("inputFile", true); displayCSRFile.addLongIdentifier("file", true); displayCSRFile.addLongIdentifier("filename", true); displayCSRParser.addArgument(displayCSRFile); final BooleanArgument displayCSRVerbose = new BooleanArgument(null, "verbose", 1, INFO_MANAGE_CERTS_SC_DISPLAY_CSR_ARG_VERBOSE_DESC.get()); displayCSRParser.addArgument(displayCSRVerbose); final BooleanArgument displayCSRDisplayCommand = new BooleanArgument(null, "display-keytool-command", 1, INFO_MANAGE_CERTS_SC_DISPLAY_CSR_ARG_DISPLAY_COMMAND_DESC.get()); displayCSRDisplayCommand.addLongIdentifier("displayKeytoolCommand", true); displayCSRDisplayCommand.addLongIdentifier("show-keytool-command", true); displayCSRDisplayCommand.addLongIdentifier("showKeytoolCommand", true); displayCSRParser.addArgument(displayCSRDisplayCommand); final LinkedHashMap displayCSRExamples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); displayCSRExamples.put( new String[] { "display-certificate-signing-request-file", "--certificate-signing-request-file", "server-cert.csr", "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_DISPLAY_CSR_EXAMPLE_1.get("server-cert.csr")); final SubCommand displayCSRSubCommand = new SubCommand( "display-certificate-signing-request-file", INFO_MANAGE_CERTS_SC_DISPLAY_CSR_DESC.get(), displayCSRParser, displayCSRExamples); displayCSRSubCommand.addName("displayCertificateSigningRequestFile", true); displayCSRSubCommand.addName("display-certificate-signing-request", true); displayCSRSubCommand.addName("displayCertificateSigningRequest", true); displayCSRSubCommand.addName("display-certificate-request-file", true); displayCSRSubCommand.addName("displayCertificateRequestFile", true); displayCSRSubCommand.addName("display-certificate-request", true); displayCSRSubCommand.addName("displayCertificateRequest", true); displayCSRSubCommand.addName("display-csr-file", true); displayCSRSubCommand.addName("displayCSRFile", true); displayCSRSubCommand.addName("display-csr", true); displayCSRSubCommand.addName("displayCSR", true); displayCSRSubCommand.addName("show-certificate-signing-request-file", true); displayCSRSubCommand.addName("showCertificateSigningRequestFile", true); displayCSRSubCommand.addName("show-certificate-signing-request", true); displayCSRSubCommand.addName("showCertificateSigningRequest", true); displayCSRSubCommand.addName("show-certificate-request-file", true); displayCSRSubCommand.addName("showCertificateRequestFile", true); displayCSRSubCommand.addName("show-certificate-request", true); displayCSRSubCommand.addName("showCertificateRequest", true); displayCSRSubCommand.addName("show-csr-file", true); displayCSRSubCommand.addName("showCSRFile", true); displayCSRSubCommand.addName("show-csr", true); displayCSRSubCommand.addName("showCSR", true); displayCSRSubCommand.addName("print-certificate-signing-request-file", true); displayCSRSubCommand.addName("printCertificateSigningRequestFile", true); displayCSRSubCommand.addName("print-certificate-signing-request", true); displayCSRSubCommand.addName("printCertificateSigningRequest", true); displayCSRSubCommand.addName("print-certificate-request-file", true); displayCSRSubCommand.addName("printCertificateRequestFile", true); displayCSRSubCommand.addName("print-certificate-request", true); displayCSRSubCommand.addName("printCertificateRequest", true); displayCSRSubCommand.addName("print-csr-file", true); displayCSRSubCommand.addName("printCSRFile", true); displayCSRSubCommand.addName("print-csr", true); displayCSRSubCommand.addName("printCSR", true); displayCSRSubCommand.addName("printcertreq", true); parser.addSubCommand(displayCSRSubCommand); } /** * Constructs a platform-specific relative path from the provided elements. * * @param pathElements The elements of the path to construct. It must not * be {@code null} or empty. * * @return The constructed path. */ @NotNull() private static String getPlatformSpecificPath( @NotNull final String... pathElements) { final StringBuilder buffer = new StringBuilder(); for (int i=0; i < pathElements.length; i++) { if (i > 0) { buffer.append(File.separatorChar); } buffer.append(pathElements[i]); } return buffer.toString(); } /** * Performs the core set of processing for this tool. * * @return A result code that indicates whether the processing completed * successfully. */ @Override() @NotNull() public ResultCode doToolProcessing() { final SubCommand selectedSubCommand = globalParser.getSelectedSubCommand(); if (selectedSubCommand == null) { // This should never happen. wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_NO_SUBCOMMAND.get()); return ResultCode.PARAM_ERROR; } subCommandParser = selectedSubCommand.getArgumentParser(); if (selectedSubCommand.hasName("list-certificates")) { return doListCertificates(); } else if (selectedSubCommand.hasName("export-certificate")) { return doExportCertificate(); } else if (selectedSubCommand.hasName("export-private-key")) { return doExportPrivateKey(); } else if (selectedSubCommand.hasName("import-certificate")) { return doImportCertificate(); } else if (selectedSubCommand.hasName("delete-certificate")) { return doDeleteCertificate(); } else if (selectedSubCommand.hasName("generate-self-signed-certificate")) { return doGenerateOrSignCertificateOrCSR(); } else if (selectedSubCommand.hasName("generate-certificate-signing-request")) { return doGenerateOrSignCertificateOrCSR(); } else if (selectedSubCommand.hasName("sign-certificate-signing-request")) { return doGenerateOrSignCertificateOrCSR(); } else if (selectedSubCommand.hasName("change-certificate-alias")) { return doChangeCertificateAlias(); } else if (selectedSubCommand.hasName("change-keystore-password")) { return doChangeKeystorePassword(); } else if (selectedSubCommand.hasName("change-private-key-password")) { return doChangePrivateKeyPassword(); } else if (selectedSubCommand.hasName("copy-keystore")) { return doCopyKeystore(); } else if (selectedSubCommand.hasName("retrieve-server-certificate")) { return doRetrieveServerCertificate(); } else if (selectedSubCommand.hasName("trust-server-certificate")) { return doTrustServerCertificate(); } else if (selectedSubCommand.hasName("check-certificate-usability")) { return doCheckCertificateUsability(); } else if (selectedSubCommand.hasName("display-certificate-file")) { return doDisplayCertificateFile(); } else if (selectedSubCommand.hasName( "display-certificate-signing-request-file")) { return doDisplayCertificateSigningRequestFile(); } else { // This should never happen. wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_UNKNOWN_SUBCOMMAND.get( selectedSubCommand.getPrimaryName())); return ResultCode.PARAM_ERROR; } } /** * Performs the necessary processing for the list-certificates subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doListCertificates() { // Get the values of a number of configured arguments. final BooleanArgument displayPEMArgument = subCommandParser.getBooleanArgument("display-pem-certificate"); final boolean displayPEM = ((displayPEMArgument != null) && displayPEMArgument.isPresent()); final BooleanArgument verboseArgument = subCommandParser.getBooleanArgument("verbose"); final boolean verbose = ((verboseArgument != null) && verboseArgument.isPresent()); final Map missingAliases; final Set aliases; final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); if ((aliasArgument == null) || (! aliasArgument.isPresent())) { aliases = Collections.emptySet(); missingAliases = Collections.emptyMap(); } else { final List values = aliasArgument.getValues(); aliases = new LinkedHashSet<>(StaticUtils.computeMapCapacity( values.size())); missingAliases = new LinkedHashMap<>(StaticUtils.computeMapCapacity(values.size())); for (final String alias : values) { final String lowerAlias = StaticUtils.toLowerCase(alias); aliases.add(StaticUtils.toLowerCase(lowerAlias)); missingAliases.put(lowerAlias, alias); } } final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArgs = new ArrayList<>(10); keytoolArgs.add("-list"); keytoolArgs.add("-keystore"); keytoolArgs.add(keystorePath.getAbsolutePath()); keytoolArgs.add("-storetype"); keytoolArgs.add(keystoreType); if (keystorePassword != null) { keytoolArgs.add("-storepass"); keytoolArgs.add("*****REDACTED*****"); } for (final String alias : missingAliases.values()) { keytoolArgs.add("-alias"); keytoolArgs.add(alias); } if (displayPEM) { keytoolArgs.add("-rfc"); } if (verbose) { keytoolArgs.add("-v"); } displayKeytoolCommand(keytoolArgs); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Display a message with the keystore type. wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_LIST_KEYSTORE_TYPE.get(keystoreType)); // Iterate through the keystore and display the appropriate certificates. final Enumeration aliasEnumeration; try { aliasEnumeration = keystore.aliases(); } catch (final Exception e) { Debug.debugException(e); err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_LIST_CERTS_CANNOT_GET_ALIASES.get( keystorePath.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } int listedCount = 0; ResultCode resultCode = ResultCode.SUCCESS; while (aliasEnumeration.hasMoreElements()) { final String alias = aliasEnumeration.nextElement(); final String lowerAlias = StaticUtils.toLowerCase(alias); if ((!aliases.isEmpty()) && (missingAliases.remove(lowerAlias) == null)) { // We don't care about this alias. continue; } final X509Certificate[] certificateChain; try { // NOTE: Keystore entries that have private keys may have a certificate // chain associated with them (the end certificate plus all of the // issuer certificates). In that case all of those certificates in the // chain will be stored under the same alias, and the only way we can // access them is to call the getCertificateChain method. However, if // the keystore only has a certificate for the alias but no private key, // then the entry will not have a chain, and the call to // getCertificateChain will return null for that alias. We want to be // able to handle both of these cases, so we will first try // getCertificateChain to see if we can get a complete chain, but if // that returns null, then use getCertificate to see if we can get a // single certificate. That call to getCertificate can also return null // because the entry with this alias might be some other type of entry, // like a secret key entry. Certificate[] chain = keystore.getCertificateChain(alias); if ((chain == null) || (chain.length == 0)) { final Certificate cert = keystore.getCertificate(alias); if (cert == null) { continue; } else { chain = new Certificate[] { cert }; } } certificateChain = new X509Certificate[chain.length]; for (int i = 0; i < chain.length; i++) { certificateChain[i] = new X509Certificate(chain[i].getEncoded()); } } catch (final Exception e) { Debug.debugException(e); err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_LIST_CERTS_ERROR_GETTING_CERT.get(alias, StaticUtils.getExceptionMessage(e))); resultCode = ResultCode.LOCAL_ERROR; continue; } listedCount++; for (int i = 0; i < certificateChain.length; i++) { out(); if (certificateChain.length == 1) { out(INFO_MANAGE_CERTS_LIST_CERTS_LABEL_ALIAS_WITHOUT_CHAIN.get( alias)); } else { out(INFO_MANAGE_CERTS_LIST_CERTS_LABEL_ALIAS_WITH_CHAIN.get(alias, (i + 1), certificateChain.length)); } printCertificate(certificateChain[i], "", verbose); if (i == 0) { if (hasKeyAlias(keystore, alias)) { out(INFO_MANAGE_CERTS_LIST_CERTS_LABEL_HAS_PK_YES.get()); } else { out(INFO_MANAGE_CERTS_LIST_CERTS_LABEL_HAS_PK_NO.get()); } } CertException signatureVerificationException = null; if (certificateChain[i].isSelfSigned()) { try { certificateChain[i].verifySignature(null); } catch (final CertException ce) { Debug.debugException(ce); signatureVerificationException = ce; } } else { X509Certificate issuerCertificate = null; try { final AtomicReference jvmDefaultTrustStoreRef = new AtomicReference<>(); final AtomicReference missingIssuerRef = new AtomicReference<>(); issuerCertificate = getIssuerCertificate(certificateChain[i], keystore, jvmDefaultTrustStoreRef, missingIssuerRef); } catch (final Exception e) { Debug.debugException(e); } if (issuerCertificate == null) { signatureVerificationException = new CertException( ERR_MANAGE_CERTS_LIST_CERTS_VERIFY_SIGNATURE_NO_ISSUER.get( certificateChain[i].getIssuerDN())); } else { try { certificateChain[i].verifySignature(issuerCertificate); } catch (final CertException ce) { Debug.debugException(ce); signatureVerificationException = ce; } } } if (signatureVerificationException == null) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_LIST_CERTS_SIGNATURE_VALID.get()); } else { wrapErr(0, WRAP_COLUMN, signatureVerificationException.getMessage()); } if (displayPEM) { out(INFO_MANAGE_CERTS_LIST_CERTS_LABEL_PEM.get()); writePEMCertificate(getOut(), certificateChain[i].getX509CertificateBytes()); } } } if (! missingAliases.isEmpty()) { err(); for (final String missingAlias : missingAliases.values()) { wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_LIST_CERTS_ALIAS_NOT_IN_KS.get(missingAlias, keystorePath.getAbsolutePath())); resultCode = ResultCode.PARAM_ERROR; } } else if (listedCount == 0) { out(); if (keystorePassword == null) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_LIST_CERTS_NO_CERTS_OR_KEYS_WITHOUT_PW.get()); } else { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_LIST_CERTS_NO_CERTS_OR_KEYS_WITH_PW.get()); } } return resultCode; } /** * Performs the necessary processing for the export-certificate subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doExportCertificate() { // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); final BooleanArgument exportChainArgument = subCommandParser.getBooleanArgument("export-certificate-chain"); final boolean exportChain = ((exportChainArgument != null) && exportChainArgument.isPresent()); final BooleanArgument separateFilePerCertificateArgument = subCommandParser.getBooleanArgument("separate-file-per-certificate"); final boolean separateFilePerCertificate = ((separateFilePerCertificateArgument != null) && separateFilePerCertificateArgument.isPresent()); boolean exportPEM = true; final StringArgument outputFormatArgument = subCommandParser.getStringArgument("output-format"); if ((outputFormatArgument != null) && outputFormatArgument.isPresent()) { final String format = outputFormatArgument.getValue().toLowerCase(); if (format.equals("der") || format.equals("binary") || format.equals("bin")) { exportPEM = false; } } File outputFile = null; final FileArgument outputFileArgument = subCommandParser.getFileArgument("output-file"); if ((outputFileArgument != null) && outputFileArgument.isPresent()) { outputFile = outputFileArgument.getValue(); } if ((outputFile == null) && (! exportPEM)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_CERT_NO_FILE_WITH_DER.get()); return ResultCode.PARAM_ERROR; } final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArgs = new ArrayList<>(10); keytoolArgs.add("-list"); keytoolArgs.add("-keystore"); keytoolArgs.add(keystorePath.getAbsolutePath()); keytoolArgs.add("-storetype"); keytoolArgs.add(keystoreType); if (keystorePassword != null) { keytoolArgs.add("-storepass"); keytoolArgs.add("*****REDACTED*****"); } keytoolArgs.add("-alias"); keytoolArgs.add(alias); if (exportPEM) { keytoolArgs.add("-rfc"); } if (outputFile != null) { keytoolArgs.add("-file"); keytoolArgs.add(outputFile.getAbsolutePath()); } displayKeytoolCommand(keytoolArgs); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the certificates to export. If the --export-certificate-chain // argument was provided, this can be multiple certificates. Otherwise, it // there will only be one. DN missingIssuerDN = null; final X509Certificate[] certificatesToExport; if (exportChain) { try { final AtomicReference missingIssuerRef = new AtomicReference<>(); certificatesToExport = getCertificateChain(alias, keystore, missingIssuerRef); missingIssuerDN = missingIssuerRef.get(); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } else { try { final Certificate cert = keystore.getCertificate(alias); if (cert == null) { certificatesToExport = new X509Certificate[0]; } else { certificatesToExport = new X509Certificate[] { new X509Certificate(cert.getEncoded()) }; } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_CERT_ERROR_GETTING_CERT.get(alias, keystorePath.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } if (certificatesToExport.length == 0) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_CERT_NO_CERT_WITH_ALIAS.get(alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } // Get a PrintStream to use for the output. int fileCounter = 1; String filename = null; PrintStream printStream; if (outputFile == null) { printStream = getOut(); } else { try { if ((certificatesToExport.length > 1) && separateFilePerCertificate) { filename = outputFile.getAbsolutePath() + '.' + fileCounter; } else { filename = outputFile.getAbsolutePath(); } printStream = new PrintStream(filename); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_CERT_ERROR_OPENING_OUTPUT.get( outputFile.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } try { for (final X509Certificate certificate : certificatesToExport) { try { if (separateFilePerCertificate && (certificatesToExport.length > 1)) { if (fileCounter > 1) { printStream.close(); filename = outputFile.getAbsolutePath() + '.' + fileCounter; printStream = new PrintStream(filename); } fileCounter++; } if (exportPEM) { writePEMCertificate(printStream, certificate.getX509CertificateBytes()); } else { printStream.write(certificate.getX509CertificateBytes()); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_CERT_ERROR_WRITING_CERT.get(alias, certificate.getSubjectDN())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } if (outputFile != null) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_EXPORT_CERT_EXPORT_SUCCESSFUL.get(filename)); printCertificate(certificate, "", false); } } } finally { printStream.flush(); if (outputFile != null) { printStream.close(); } } if (missingIssuerDN != null) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_EXPORT_CERT_MISSING_CERT_IN_CHAIN.get( missingIssuerDN, keystorePath.getAbsolutePath())); return ResultCode.NO_SUCH_OBJECT; } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the export-private-key subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doExportPrivateKey() { // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); boolean exportPEM = true; final StringArgument outputFormatArgument = subCommandParser.getStringArgument("output-format"); if ((outputFormatArgument != null) && outputFormatArgument.isPresent()) { final String format = outputFormatArgument.getValue().toLowerCase(); if (format.equals("der") || format.equals("binary") || format.equals("bin")) { exportPEM = false; } } File outputFile = null; final FileArgument outputFileArgument = subCommandParser.getFileArgument("output-file"); if ((outputFileArgument != null) && outputFileArgument.isPresent()) { outputFile = outputFileArgument.getValue(); } if ((outputFile == null) && (! exportPEM)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_KEY_NO_FILE_WITH_DER.get()); return ResultCode.PARAM_ERROR; } final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // See if we need to use a private key password that is different from the // keystore password. final char[] privateKeyPassword; try { privateKeyPassword = getPrivateKeyPassword(keystore, alias, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the password to use to encrypt the private key when it is exported. final char[] encryptionPassword; try { encryptionPassword = getPrivateKeyEncryptionPassword(false); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the private key to export. final PrivateKey privateKey; try { final Key key = keystore.getKey(alias, privateKeyPassword); if (key == null) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_KEY_NO_KEY_WITH_ALIAS.get(alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } privateKey = (PrivateKey) key; } catch (final UnrecoverableKeyException e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_KEY_WRONG_KEY_PW.get(alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_KEY_ERROR_GETTING_KEY.get(alias, keystorePath.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Get a PrintStream to use for the output. final PrintStream printStream; if (outputFile == null) { printStream = getOut(); } else { try { printStream = new PrintStream(outputFile); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_KEY_ERROR_OPENING_OUTPUT.get( outputFile.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } try { try { if (exportPEM) { writePEMPrivateKey(printStream, privateKey.getEncoded(), encryptionPassword); } else { if (encryptionPassword == null) { printStream.write(privateKey.getEncoded()); } else { final byte[] encryptedPrivateKey = PKCS8EncryptionHandler.encryptPrivateKey( privateKey.getEncoded(), encryptionPassword, new PKCS8EncryptionProperties()); printStream.write(encryptedPrivateKey); } } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_EXPORT_KEY_ERROR_WRITING_KEY.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } if (outputFile != null) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_EXPORT_KEY_EXPORT_SUCCESSFUL.get()); } } finally { printStream.flush(); if (outputFile != null) { printStream.close(); } } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the import-certificate subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doImportCertificate() { // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); final FileArgument certificateFileArgument = subCommandParser.getFileArgument("certificate-file"); final List certFiles = certificateFileArgument.getValues(); final File privateKeyFile; final FileArgument privateKeyFileArgument = subCommandParser.getFileArgument("private-key-file"); if ((privateKeyFileArgument != null) && privateKeyFileArgument.isPresent()) { privateKeyFile = privateKeyFileArgument.getValue(); } else { privateKeyFile = null; } final BooleanArgument noPromptArgument = subCommandParser.getBooleanArgument("no-prompt"); final boolean noPrompt = ((noPromptArgument != null) && noPromptArgument.isPresent()); final String keystoreType; final File keystorePath = getKeystorePath(); final boolean isNewKeystore = (! keystorePath.exists()); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Read the contents of the certificate files. final ArrayList certList = new ArrayList<>(5); for (final File certFile : certFiles) { try { final List certs = readCertificatesFromFile(certFile); if (certs.isEmpty()) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_NO_CERTS_IN_FILE.get( certFile.getAbsolutePath())); return ResultCode.PARAM_ERROR; } certList.addAll(certs); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // See if there is a password to use to decrypt the private key that is // being imported. final char[] encryptionPassword; try { encryptionPassword = getPrivateKeyEncryptionPassword(true); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // If a private key file was specified, then read the private key. final PKCS8PrivateKey privateKey; if (privateKeyFile == null) { privateKey = null; } else { try { privateKey = readPrivateKeyFromFile(privateKeyFile, encryptionPassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // If there is a private key, then see if we need to use a private key // password that is different from the keystore password. final char[] privateKeyPassword; try { privateKeyPassword = getPrivateKeyPassword(keystore, alias, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // If we should display an equivalent keytool command, then do that now. final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArgs = new ArrayList<>(10); keytoolArgs.add("-import"); keytoolArgs.add("-keystore"); keytoolArgs.add(keystorePath.getAbsolutePath()); keytoolArgs.add("-storetype"); keytoolArgs.add(keystoreType); keytoolArgs.add("-storepass"); keytoolArgs.add("*****REDACTED*****"); keytoolArgs.add("-keypass"); keytoolArgs.add("*****REDACTED*****"); keytoolArgs.add("-alias"); keytoolArgs.add(alias); keytoolArgs.add("-file"); keytoolArgs.add(certFiles.get(0).getAbsolutePath()); keytoolArgs.add("-trustcacerts"); displayKeytoolCommand(keytoolArgs); } // Look at all the certificates to be imported. Make sure that every // subsequent certificate in the chain is the issuer for the previous. final Iterator certIterator = certList.iterator(); X509Certificate subjectCert = certIterator.next(); while (true) { if (subjectCert.isSelfSigned()) { if (certIterator.hasNext()) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_SELF_SIGNED_NOT_LAST.get( subjectCert.getSubjectDN())); return ResultCode.PARAM_ERROR; } } if (! certIterator.hasNext()) { break; } final X509Certificate issuerCert = certIterator.next(); final StringBuilder notIssuerReason = new StringBuilder(); if (! issuerCert.isIssuerFor(subjectCert, notIssuerReason)) { // In some cases, the process of signing a certificate can put two // certificates in the output file (both the signed certificate and its // issuer. If the same certificate is in the chain twice, then we'll // silently ignore it. if (Arrays.equals(issuerCert.getX509CertificateBytes(), subjectCert.getX509CertificateBytes())) { certIterator.remove(); } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_NEXT_NOT_ISSUER_OF_PREV.get( notIssuerReason.toString())); return ResultCode.PARAM_ERROR; } } subjectCert = issuerCert; } // If the last certificate in the chain is not self-signed, then make sure // that we can complete the chain using other certificates in the keystore // or in the JVM's set of default trusted issuers. If we can't complete // the chain, then that's an error, although we'll go ahead and proceed // anyway with the import if we're not also importing a private key. final ArrayList chain; if (certList.get(certList.size() - 1).isSelfSigned()) { chain = certList; } else { chain = new ArrayList<>(certList.size() + 5); chain.addAll(certList); final AtomicReference jvmDefaultTrustStoreRef = new AtomicReference<>(); final AtomicReference missingIssuerRef = new AtomicReference<>(); X509Certificate c = certList.get(certList.size() - 1); while (! c.isSelfSigned()) { final X509Certificate issuer; try { issuer = getIssuerCertificate(c, keystore, jvmDefaultTrustStoreRef, missingIssuerRef); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_CANNOT_GET_ISSUER.get( c.getIssuerDN())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } if (issuer == null) { final byte[] authorityKeyIdentifier = getAuthorityKeyIdentifier(c); // We couldn't find the issuer certificate. If we're importing a // private key, or if the keystore already has a key entry with the // same alias that we're going to use, then this is definitely an // error because we can only write a key entry if we have a complete // certificate chain. // // If we weren't explicitly provided with a private key, then it's // still an undesirable thing to import a certificate without having // the complete set of issuers, but we'll go ahead and let it slide // with just a warning. if ((privateKey != null) || hasKeyAlias(keystore, alias)) { if (authorityKeyIdentifier == null) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_NO_ISSUER_NO_AKI.get( c.getIssuerDN())); } else { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_NO_ISSUER_WITH_AKI.get( c.getIssuerDN(), toColonDelimitedHex(authorityKeyIdentifier))); } return ResultCode.PARAM_ERROR; } else { if (authorityKeyIdentifier == null) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_IMPORT_CERT_NO_ISSUER_NO_AKI.get( c.getIssuerDN())); } else { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_IMPORT_CERT_NO_ISSUER_WITH_AKI.get( c.getIssuerDN(), toColonDelimitedHex(authorityKeyIdentifier))); } break; } } else { chain.add(issuer); c = issuer; } } } // If we're going to import a private key with a certificate chain, then // perform the necessary validation and do the import. if (privateKey != null) { // Make sure that the keystore doesn't already have a key or certificate // with the specified alias. if (hasKeyAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_WITH_PK_KEY_ALIAS_CONFLICT.get( alias)); return ResultCode.PARAM_ERROR; } else if (hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_WITH_PK_CERT_ALIAS_CONFLICT.get( alias)); return ResultCode.PARAM_ERROR; } // Make sure that the private key has a key algorithm of either RSA or EC, // and convert it into a Java PrivateKey object. final PrivateKey javaPrivateKey; try { javaPrivateKey = privateKey.toPrivateKey(); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_CONVERTING_KEY.get( privateKeyFile.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Convert the certificate chain into a Java Certificate[]. final Certificate[] javaCertificateChain = new Certificate[chain.size()]; for (int i=0; i < javaCertificateChain.length; i++) { final X509Certificate c = chain.get(i); try { javaCertificateChain[i] = c.toCertificate(); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_CONVERTING_CERT.get( c.getSubjectDN())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } // Prompt the user to confirm the import, if appropriate. if (! noPrompt) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_CONFIRM_IMPORT_CHAIN_NEW_KEY.get( alias)); for (final X509Certificate c : chain) { out(); printCertificate(c, "", false); } out(); try { if (! promptForYesNo( INFO_MANAGE_CERTS_IMPORT_CERT_PROMPT_IMPORT_CHAIN.get())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_CANCELED.get()); return ResultCode.USER_CANCELED; } } catch (final LDAPException le) { Debug.debugException(le); err(); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Set the private key entry in the keystore. try { keystore.setKeyEntry(alias, javaPrivateKey, privateKeyPassword, javaCertificateChain); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_UPDATING_KS_WITH_CHAIN.get( alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Write the updated keystore to disk. try { writeKeystore(keystore, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } if (isNewKeystore) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_CREATED_KEYSTORE.get( getUserFriendlyKeystoreType(keystoreType))); } out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_IMPORTED_CHAIN_WITH_PK.get()); return ResultCode.SUCCESS; } // If we've gotten here, then we were given one or more certificates but no // private key. See if the keystore already has a certificate entry with // the specified alias. If so, then that's always an error. if (hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_WITH_CONFLICTING_CERT_ALIAS.get(alias)); return ResultCode.PARAM_ERROR; } // See if the keystore already has a key entry with the specified alias. // If so, then it may or may not be an error. This can happen if we // generated a certificate signing request from an existing key pair, and // now want to import the signed certificate. If that is the case, then we // will replace the existing key entry with a new one that contains the full // new certificate chain and the existing private key, but only if the // new certificate uses the same public key as the certificate at the head // of the existing chain in that alias. if (hasKeyAlias(keystore, alias)) { // Make sure that the existing key pair uses the same public key as the // new certificate we are importing. final PrivateKey existingPrivateKey; final Certificate[] existingChain; final X509Certificate existingEndCertificate; try { existingPrivateKey = (PrivateKey) keystore.getKey(alias, privateKeyPassword); existingChain = keystore.getCertificateChain(alias); existingEndCertificate = new X509Certificate(existingChain[0].getEncoded()); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_INTO_KEY_ALIAS_CANNOT_GET_KEY.get( alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } final boolean[] existingPublicKeyBits = existingEndCertificate.getEncodedPublicKey().getBits(); final boolean[] newPublicKeyBits = chain.get(0).getEncodedPublicKey().getBits(); if (! Arrays.equals(existingPublicKeyBits, newPublicKeyBits)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_INTO_KEY_ALIAS_KEY_MISMATCH.get( alias)); return ResultCode.PARAM_ERROR; } // Prepare the new certificate chain to store in the alias. final Certificate[] newChain = new Certificate[chain.size()]; for (int i=0; i < chain.size(); i++) { final X509Certificate c = chain.get(i); try { newChain[i] = c.toCertificate(); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_CONVERTING_CERT.get( c.getSubjectDN())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } // Prompt the user to confirm the import, if appropriate. if (! noPrompt) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_CONFIRM_IMPORT_CHAIN_EXISTING_KEY. get(alias)); for (final X509Certificate c : chain) { out(); printCertificate(c, "", false); } out(); try { if (! promptForYesNo( INFO_MANAGE_CERTS_IMPORT_CERT_PROMPT_IMPORT_CHAIN.get())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_CANCELED.get()); return ResultCode.USER_CANCELED; } } catch (final LDAPException le) { Debug.debugException(le); err(); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Set the private key entry in the keystore. try { keystore.setKeyEntry(alias, existingPrivateKey, privateKeyPassword, newChain); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_UPDATING_KS_WITH_CHAIN.get( alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Write the updated keystore to disk. try { writeKeystore(keystore, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } out(); if (isNewKeystore) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_CREATED_KEYSTORE.get( getUserFriendlyKeystoreType(keystoreType))); } wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_IMPORTED_CHAIN_WITHOUT_PK.get()); return ResultCode.SUCCESS; } // If we've gotten here, then we know that we're just going to add // certificate entries to the keystore. Iterate through the certificates // and add them to the keystore under the appropriate aliases, first making // sure that the alias isn't already in use. final LinkedHashMap certMap = new LinkedHashMap<>(StaticUtils.computeMapCapacity(certList.size())); for (int i=0; i < certList.size(); i++) { final X509Certificate x509Certificate = certList.get(i); final Certificate javaCertificate; try { javaCertificate = x509Certificate.toCertificate(); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_CONVERTING_CERT.get( x509Certificate.getSubjectDN())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } final String certAlias; if (i == 0) { certAlias = alias; } else if (certList.size() > 2) { certAlias = alias + "-issuer-" + i; } else { certAlias = alias + "-issuer"; } certMap.put(certAlias, x509Certificate); if (hasKeyAlias(keystore, certAlias) || hasCertificateAlias(keystore, certAlias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_WITH_CONFLICTING_ISSUER_ALIAS.get( x509Certificate.getSubjectDN(), certAlias)); return ResultCode.PARAM_ERROR; } try { keystore.setCertificateEntry(certAlias, javaCertificate); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_ERROR_UPDATING_KS_WITH_CERT.get( x509Certificate.getSubjectDN(), alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } // Prompt about whether to perform the import, if appropriate. if (! noPrompt) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_CONFIRM_IMPORT_CHAIN_NO_KEY. get(alias)); for (final Map.Entry e : certMap.entrySet()) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_LABEL_ALIAS.get(e.getKey())); printCertificate(e.getValue(), "", false); } out(); try { if (! promptForYesNo( INFO_MANAGE_CERTS_IMPORT_CERT_PROMPT_IMPORT_CHAIN.get())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_IMPORT_CERT_CANCELED.get()); return ResultCode.USER_CANCELED; } } catch (final LDAPException le) { Debug.debugException(le); err(); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Write the updated keystore to disk. try { writeKeystore(keystore, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } out(); if (isNewKeystore) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_CREATED_KEYSTORE.get( getUserFriendlyKeystoreType(keystoreType))); } wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_IMPORT_CERT_IMPORTED_CHAIN_WITHOUT_PK.get()); return ResultCode.SUCCESS; } /** * Performs the necessary processing for the delete-certificate subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doDeleteCertificate() { // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); final BooleanArgument noPromptArgument = subCommandParser.getBooleanArgument("no-prompt"); final boolean noPrompt = ((noPromptArgument != null) && noPromptArgument.isPresent()); final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArgs = new ArrayList<>(10); keytoolArgs.add("-delete"); keytoolArgs.add("-keystore"); keytoolArgs.add(keystorePath.getAbsolutePath()); keytoolArgs.add("-storetype"); keytoolArgs.add(keystoreType); keytoolArgs.add("-storepass"); keytoolArgs.add("*****REDACTED*****"); keytoolArgs.add("-alias"); keytoolArgs.add(alias); displayKeytoolCommand(keytoolArgs); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the entry for the specified alias. final boolean hasPrivateKey; final ArrayList certList = new ArrayList<>(5); if (hasCertificateAlias(keystore, alias)) { try { hasPrivateKey = false; certList.add( new X509Certificate(keystore.getCertificate(alias).getEncoded())); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_DELETE_CERT_ERROR_GETTING_CERT.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } else if (hasKeyAlias(keystore, alias)) { try { hasPrivateKey = true; for (final Certificate c : keystore.getCertificateChain(alias)) { certList.add(new X509Certificate(c.getEncoded())); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_DELETE_CERT_ERROR_GETTING_CHAIN.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_DELETE_CERT_ERROR_ALIAS_NOT_CERT_OR_KEY.get(alias)); return ResultCode.PARAM_ERROR; } // Prompt about whether to perform the delete, if appropriate. if (! noPrompt) { out(); if (! hasPrivateKey) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_DELETE_CERT_CONFIRM_DELETE_CERT.get()); } else { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_DELETE_CERT_CONFIRM_DELETE_CHAIN.get()); } for (final X509Certificate c : certList) { out(); printCertificate(c, "", false); } out(); try { if (! promptForYesNo( INFO_MANAGE_CERTS_DELETE_CERT_PROMPT_DELETE.get())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_DELETE_CERT_CANCELED.get()); return ResultCode.USER_CANCELED; } } catch (final LDAPException le) { Debug.debugException(le); err(); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Delete the entry from the keystore. try { keystore.deleteEntry(alias); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_DELETE_CERT_DELETE_ERROR.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Write the updated keystore to disk. try { writeKeystore(keystore, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } if (certList.size() == 1) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_DELETE_CERT_DELETED_CERT.get()); } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_DELETE_CERT_DELETED_CHAIN.get()); } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the generate-self-signed-certificate, * generate-certificate-signing-request, and sign-certificate-signing-request * subcommands. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doGenerateOrSignCertificateOrCSR() { // Figure out which subcommand we're processing. final boolean isGenerateCertificate; final boolean isGenerateCSR; final boolean isSignCSR; final SubCommand selectedSubCommand = globalParser.getSelectedSubCommand(); if (selectedSubCommand.hasName("generate-self-signed-certificate")) { isGenerateCertificate = true; isGenerateCSR = false; isSignCSR = false; } else if (selectedSubCommand.hasName("generate-certificate-signing-request")) { isGenerateCertificate = false; isGenerateCSR = true; isSignCSR = false; } else { Validator.ensureTrue( selectedSubCommand.hasName("sign-certificate-signing-request")); isGenerateCertificate = false; isGenerateCSR = false; isSignCSR = true; } // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); final File keystorePath = getKeystorePath(); final boolean isNewKeystore = (! keystorePath.exists()); DN subjectDN = null; final DNArgument subjectDNArgument = subCommandParser.getDNArgument("subject-dn"); if ((subjectDNArgument != null) && subjectDNArgument.isPresent()) { subjectDN = subjectDNArgument.getValue(); } File inputFile = null; final FileArgument inputFileArgument = subCommandParser.getFileArgument("input-file"); if ((inputFileArgument != null) && inputFileArgument.isPresent()) { inputFile = inputFileArgument.getValue(); } File outputFile = null; final FileArgument outputFileArgument = subCommandParser.getFileArgument("output-file"); if ((outputFileArgument != null) && outputFileArgument.isPresent()) { outputFile = outputFileArgument.getValue(); } boolean outputPEM = true; final StringArgument outputFormatArgument = subCommandParser.getStringArgument("output-format"); if ((outputFormatArgument != null) && outputFormatArgument.isPresent()) { final String format = outputFormatArgument.getValue().toLowerCase(); if (format.equals("der") || format.equals("binary") || format.equals("bin")) { outputPEM = false; } } if ((! outputPEM) && (outputFile == null)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_NO_FILE_WITH_DER.get()); return ResultCode.PARAM_ERROR; } final BooleanArgument useExistingKeyPairArgument = subCommandParser.getBooleanArgument("use-existing-key-pair"); final boolean useExistingKeyPair = ((useExistingKeyPairArgument != null) && useExistingKeyPairArgument.isPresent()); if (useExistingKeyPair && (! keystorePath.exists())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_USE_EXISTING_KP_WITHOUT_KS.get()); return ResultCode.PARAM_ERROR; } final BooleanArgument inheritExtensionsArgument = subCommandParser.getBooleanArgument("inherit-extensions"); final boolean inheritExtensions = ((inheritExtensionsArgument != null) && inheritExtensionsArgument.isPresent()); final BooleanArgument includeRequestedExtensionsArgument = subCommandParser.getBooleanArgument("include-requested-extensions"); final boolean includeRequestedExtensions = ((includeRequestedExtensionsArgument != null) && includeRequestedExtensionsArgument.isPresent()); final BooleanArgument noPromptArgument = subCommandParser.getBooleanArgument("no-prompt"); final boolean noPrompt = ((noPromptArgument != null) && noPromptArgument.isPresent()); final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); final boolean displayKeytoolCommand = ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()); int daysValid = 365; final IntegerArgument daysValidArgument = subCommandParser.getIntegerArgument("days-valid"); if ((daysValidArgument != null) && daysValidArgument.isPresent()) { daysValid = daysValidArgument.getValue(); } Date validityStartTime = null; final TimestampArgument validityStartTimeArgument = subCommandParser.getTimestampArgument("validity-start-time"); if ((validityStartTimeArgument != null) && validityStartTimeArgument.isPresent()) { validityStartTime = validityStartTimeArgument.getValue(); } PublicKeyAlgorithmIdentifier keyAlgorithmIdentifier = null; String keyAlgorithmName = null; final StringArgument keyAlgorithmArgument = subCommandParser.getStringArgument("key-algorithm"); if ((keyAlgorithmArgument != null) && keyAlgorithmArgument.isPresent()) { final String name = keyAlgorithmArgument.getValue(); keyAlgorithmIdentifier = PublicKeyAlgorithmIdentifier.forName(name); if (keyAlgorithmIdentifier == null) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_UNKNOWN_KEY_ALG.get(name)); return ResultCode.PARAM_ERROR; } else { keyAlgorithmName = keyAlgorithmIdentifier.getName(); } } Integer keySizeBits = null; final IntegerArgument keySizeBitsArgument = subCommandParser.getIntegerArgument("key-size-bits"); if ((keySizeBitsArgument != null) && keySizeBitsArgument.isPresent()) { keySizeBits = keySizeBitsArgument.getValue(); } if ((keyAlgorithmIdentifier != null) && (keyAlgorithmIdentifier != PublicKeyAlgorithmIdentifier.RSA) && (keySizeBits == null)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_NO_KEY_SIZE_FOR_NON_RSA_KEY.get()); return ResultCode.PARAM_ERROR; } String signatureAlgorithmName = null; SignatureAlgorithmIdentifier signatureAlgorithmIdentifier = null; final StringArgument signatureAlgorithmArgument = subCommandParser.getStringArgument("signature-algorithm"); if ((signatureAlgorithmArgument != null) && signatureAlgorithmArgument.isPresent()) { final String name = signatureAlgorithmArgument.getValue(); signatureAlgorithmIdentifier = SignatureAlgorithmIdentifier.forName(name); if (signatureAlgorithmIdentifier == null) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_UNKNOWN_SIG_ALG.get(name)); return ResultCode.PARAM_ERROR; } else { signatureAlgorithmName = signatureAlgorithmIdentifier.getJavaName(); } } if ((keyAlgorithmIdentifier != null) && (keyAlgorithmIdentifier != PublicKeyAlgorithmIdentifier.RSA) && (signatureAlgorithmIdentifier == null)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_NO_SIG_ALG_FOR_NON_RSA_KEY.get()); return ResultCode.PARAM_ERROR; } // Build a subject alternative name extension, if appropriate. final ArrayList extensionList = new ArrayList<>(10); final GeneralNamesBuilder sanBuilder = new GeneralNamesBuilder(); final LinkedHashSet sanValues = new LinkedHashSet<>(StaticUtils.computeMapCapacity(10)); final StringArgument sanDNSArgument = subCommandParser.getStringArgument("subject-alternative-name-dns"); if ((sanDNSArgument != null) && sanDNSArgument.isPresent()) { for (final String value : sanDNSArgument.getValues()) { sanBuilder.addDNSName(value); sanValues.add("DNS:" + value); } } final StringArgument sanIPArgument = subCommandParser.getStringArgument( "subject-alternative-name-ip-address"); if ((sanIPArgument != null) && sanIPArgument.isPresent()) { for (final String value : sanIPArgument.getValues()) { try { sanBuilder.addIPAddress(LDAPConnectionOptions.DEFAULT_NAME_RESOLVER. getByName(value)); sanValues.add("IP:" + value); } catch (final Exception e) { // This should never happen. Debug.debugException(e); throw new RuntimeException(e); } } } final StringArgument sanEmailArgument = subCommandParser.getStringArgument( "subject-alternative-name-email-address"); if ((sanEmailArgument != null) && sanEmailArgument.isPresent()) { for (final String value : sanEmailArgument.getValues()) { sanBuilder.addRFC822Name(value); sanValues.add("EMAIL:" + value); } } final StringArgument sanURIArgument = subCommandParser.getStringArgument("subject-alternative-name-uri"); if ((sanURIArgument != null) && sanURIArgument.isPresent()) { for (final String value : sanURIArgument.getValues()) { sanBuilder.addUniformResourceIdentifier(value); sanValues.add("URI:" + value); } } final StringArgument sanOIDArgument = subCommandParser.getStringArgument("subject-alternative-name-oid"); if ((sanOIDArgument != null) && sanOIDArgument.isPresent()) { for (final String value : sanOIDArgument.getValues()) { sanBuilder.addRegisteredID(new OID(value)); sanValues.add("OID:" + value); } } if (! sanValues.isEmpty()) { try { extensionList.add( new SubjectAlternativeNameExtension(false, sanBuilder.build())); } catch (final Exception e) { // This should never happen. Debug.debugException(e); throw new RuntimeException(e); } } // Build a set of issuer alternative name extension values. final GeneralNamesBuilder ianBuilder = new GeneralNamesBuilder(); final LinkedHashSet ianValues = new LinkedHashSet<>(StaticUtils.computeMapCapacity(10)); final StringArgument ianDNSArgument = subCommandParser.getStringArgument("issuer-alternative-name-dns"); if ((ianDNSArgument != null) && ianDNSArgument.isPresent()) { for (final String value : ianDNSArgument.getValues()) { ianBuilder.addDNSName(value); ianValues.add("DNS:" + value); } } final StringArgument ianIPArgument = subCommandParser.getStringArgument( "issuer-alternative-name-ip-address"); if ((ianIPArgument != null) && ianIPArgument.isPresent()) { for (final String value : ianIPArgument.getValues()) { try { ianBuilder.addIPAddress(LDAPConnectionOptions.DEFAULT_NAME_RESOLVER. getByName(value)); ianValues.add("IP:" + value); } catch (final Exception e) { // This should never happen. Debug.debugException(e); throw new RuntimeException(e); } } } final StringArgument ianEmailArgument = subCommandParser.getStringArgument( "issuer-alternative-name-email-address"); if ((ianEmailArgument != null) && ianEmailArgument.isPresent()) { for (final String value : ianEmailArgument.getValues()) { ianBuilder.addRFC822Name(value); ianValues.add("EMAIL:" + value); } } final StringArgument ianURIArgument = subCommandParser.getStringArgument("issuer-alternative-name-uri"); if ((ianURIArgument != null) && ianURIArgument.isPresent()) { for (final String value : ianURIArgument.getValues()) { ianBuilder.addUniformResourceIdentifier(value); ianValues.add("URI:" + value); } } final StringArgument ianOIDArgument = subCommandParser.getStringArgument("issuer-alternative-name-oid"); if ((ianOIDArgument != null) && ianOIDArgument.isPresent()) { for (final String value : ianOIDArgument.getValues()) { ianBuilder.addRegisteredID(new OID(value)); ianValues.add("OID:" + value); } } if (! ianValues.isEmpty()) { try { extensionList.add( new IssuerAlternativeNameExtension(false, ianBuilder.build())); } catch (final Exception e) { // This should never happen. Debug.debugException(e); throw new RuntimeException(e); } } // Build a basic constraints extension, if appropriate. BasicConstraintsExtension basicConstraints = null; final BooleanValueArgument basicConstraintsIsCAArgument = subCommandParser.getBooleanValueArgument("basic-constraints-is-ca"); if ((basicConstraintsIsCAArgument != null) && basicConstraintsIsCAArgument.isPresent()) { final boolean isCA = basicConstraintsIsCAArgument.getValue(); Integer pathLength = null; final IntegerArgument pathLengthArgument = subCommandParser.getIntegerArgument( "basic-constraints-maximum-path-length"); if ((pathLengthArgument != null) && pathLengthArgument.isPresent()) { if (isCA) { pathLength = pathLengthArgument.getValue(); } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_BC_PATH_LENGTH_WITHOUT_CA.get()); return ResultCode.PARAM_ERROR; } } basicConstraints = new BasicConstraintsExtension(false, isCA, pathLength); extensionList.add(basicConstraints); } // Build a key usage extension, if appropriate. KeyUsageExtension keyUsage = null; final StringArgument keyUsageArgument = subCommandParser.getStringArgument("key-usage"); if ((keyUsageArgument != null) && keyUsageArgument.isPresent()) { boolean digitalSignature = false; boolean nonRepudiation = false; boolean keyEncipherment = false; boolean dataEncipherment = false; boolean keyAgreement = false; boolean keyCertSign = false; boolean crlSign = false; boolean encipherOnly = false; boolean decipherOnly = false; for (final String value : keyUsageArgument.getValues()) { if (value.equalsIgnoreCase("digital-signature") || value.equalsIgnoreCase("digitalSignature")) { digitalSignature = true; } else if (value.equalsIgnoreCase("non-repudiation") || value.equalsIgnoreCase("nonRepudiation") || value.equalsIgnoreCase("content-commitment") || value.equalsIgnoreCase("contentCommitment")) { nonRepudiation = true; } else if (value.equalsIgnoreCase("key-encipherment") || value.equalsIgnoreCase("keyEncipherment")) { keyEncipherment = true; } else if (value.equalsIgnoreCase("data-encipherment") || value.equalsIgnoreCase("dataEncipherment")) { dataEncipherment = true; } else if (value.equalsIgnoreCase("key-agreement") || value.equalsIgnoreCase("keyAgreement")) { keyAgreement = true; } else if (value.equalsIgnoreCase("key-cert-sign") || value.equalsIgnoreCase("keyCertSign")) { keyCertSign = true; } else if (value.equalsIgnoreCase("crl-sign") || value.equalsIgnoreCase("crlSign")) { crlSign = true; } else if (value.equalsIgnoreCase("encipher-only") || value.equalsIgnoreCase("encipherOnly")) { encipherOnly = true; } else if (value.equalsIgnoreCase("decipher-only") || value.equalsIgnoreCase("decipherOnly")) { decipherOnly = true; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_INVALID_KEY_USAGE.get(value)); return ResultCode.PARAM_ERROR; } } keyUsage = new KeyUsageExtension(false, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, crlSign, encipherOnly, decipherOnly); extensionList.add(keyUsage); } // Build an extended key usage extension, if appropriate. ExtendedKeyUsageExtension extendedKeyUsage = null; final StringArgument extendedKeyUsageArgument = subCommandParser.getStringArgument("extended-key-usage"); if ((extendedKeyUsageArgument != null) && extendedKeyUsageArgument.isPresent()) { final List values = extendedKeyUsageArgument.getValues(); final ArrayList keyPurposeIDs = new ArrayList<>(values.size()); for (final String value : values) { if (value.equalsIgnoreCase("server-auth") || value.equalsIgnoreCase("serverAuth") || value.equalsIgnoreCase("server-authentication") || value.equalsIgnoreCase("serverAuthentication") || value.equalsIgnoreCase("tls-server-authentication") || value.equalsIgnoreCase("tlsServerAuthentication")) { keyPurposeIDs.add( ExtendedKeyUsageID.TLS_SERVER_AUTHENTICATION.getOID()); } else if (value.equalsIgnoreCase("client-auth") || value.equalsIgnoreCase("clientAuth") || value.equalsIgnoreCase("client-authentication") || value.equalsIgnoreCase("clientAuthentication") || value.equalsIgnoreCase("tls-client-authentication") || value.equalsIgnoreCase("tlsClientAuthentication")) { keyPurposeIDs.add( ExtendedKeyUsageID.TLS_CLIENT_AUTHENTICATION.getOID()); } else if (value.equalsIgnoreCase("code-signing") || value.equalsIgnoreCase("codeSigning")) { keyPurposeIDs.add(ExtendedKeyUsageID.CODE_SIGNING.getOID()); } else if (value.equalsIgnoreCase("email-protection") || value.equalsIgnoreCase("emailProtection")) { keyPurposeIDs.add(ExtendedKeyUsageID.EMAIL_PROTECTION.getOID()); } else if (value.equalsIgnoreCase("time-stamping") || value.equalsIgnoreCase("timeStamping")) { keyPurposeIDs.add(ExtendedKeyUsageID.TIME_STAMPING.getOID()); } else if (value.equalsIgnoreCase("ocsp-signing") || value.equalsIgnoreCase("ocspSigning")) { keyPurposeIDs.add(ExtendedKeyUsageID.OCSP_SIGNING.getOID()); } else if (OID.isStrictlyValidNumericOID(value)) { keyPurposeIDs.add(new OID(value)); } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_INVALID_EXTENDED_KEY_USAGE.get(value)); return ResultCode.PARAM_ERROR; } } try { extendedKeyUsage = new ExtendedKeyUsageExtension(false, keyPurposeIDs); } catch (final Exception e) { // This should never happen. Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_EXTENDED_KEY_USAGE_ERROR.get()); e.printStackTrace(getErr()); return ResultCode.PARAM_ERROR; } extensionList.add(extendedKeyUsage); } // Build a list of generic extensions. final ArrayList genericExtensions = new ArrayList<>(5); final StringArgument extensionArgument = subCommandParser.getStringArgument("extension"); if ((extensionArgument != null) && extensionArgument.isPresent()) { for (final String value : extensionArgument.getValues()) { try { final int firstColonPos = value.indexOf(':'); final int secondColonPos = value.indexOf(':', firstColonPos + 1); final OID oid = new OID(value.substring(0, firstColonPos)); if (! oid.isStrictlyValidNumericOID()) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_EXT_MALFORMED_OID.get(value, oid.toString())); return ResultCode.PARAM_ERROR; } final boolean criticality; final String criticalityString = value.substring(firstColonPos + 1, secondColonPos); if (criticalityString.equalsIgnoreCase("true") || criticalityString.equalsIgnoreCase("t") || criticalityString.equalsIgnoreCase("yes") || criticalityString.equalsIgnoreCase("y") || criticalityString.equalsIgnoreCase("on") || criticalityString.equalsIgnoreCase("1")) { criticality = true; } else if (criticalityString.equalsIgnoreCase("false") || criticalityString.equalsIgnoreCase("f") || criticalityString.equalsIgnoreCase("no") || criticalityString.equalsIgnoreCase("n") || criticalityString.equalsIgnoreCase("off") || criticalityString.equalsIgnoreCase("0")) { criticality = false; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_EXT_INVALID_CRITICALITY.get( value, criticalityString)); return ResultCode.PARAM_ERROR; } final byte[] valueBytes; try { valueBytes = StaticUtils.fromHex(value.substring(secondColonPos+1)); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_EXT_INVALID_VALUE.get(value)); return ResultCode.PARAM_ERROR; } final X509CertificateExtension extension = new X509CertificateExtension(oid, criticality, valueBytes); genericExtensions.add(extension); extensionList.add(extension); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_EXT_MALFORMED.get(value)); return ResultCode.PARAM_ERROR; } } } final String keystoreType; try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // If there is a private key, then see if we need to use a private key // password that is different from the keystore password. final char[] privateKeyPassword; try { privateKeyPassword = getPrivateKeyPassword(keystore, alias, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // If we're going to replace an existing certificate in the keystore, then // perform the appropriate processing for that. if (useExistingKeyPair) { // Make sure that the keystore already has a private key entry with the // specified alias. if (! hasKeyAlias(keystore, alias)) { if (hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_USE_EXISTING_KP_ALIAS_IS_CERT.get( alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_USE_EXISTING_KP_NO_SUCH_ALIAS.get( alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } } // Get the certificate to replace, along with its key pair. final X509Certificate certToReplace; final KeyPair keyPair; try { final Certificate[] chain = keystore.getCertificateChain(alias); certToReplace = new X509Certificate(chain[0].getEncoded()); final PublicKey publicKey = chain[0].getPublicKey(); final PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, privateKeyPassword); keyPair = new KeyPair(publicKey, privateKey); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_USE_EXISTING_KP_COULD_NOT_GET_CERT.get( alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Assign the remaining values using information in the existing // certificate. signatureAlgorithmIdentifier = SignatureAlgorithmIdentifier.forOID( certToReplace.getSignatureAlgorithmOID()); if (signatureAlgorithmIdentifier == null) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_UNKNOWN_SIG_ALG_IN_CERT.get( certToReplace.getSignatureAlgorithmOID())); return ResultCode.PARAM_ERROR; } else { signatureAlgorithmName = signatureAlgorithmIdentifier.getJavaName(); } if (subjectDN == null) { subjectDN = certToReplace.getSubjectDN(); } if (inheritExtensions) { for (final X509CertificateExtension extension : certToReplace.getExtensions()) { if ((extension instanceof AuthorityKeyIdentifierExtension) || (extension instanceof IssuerAlternativeNameExtension)) { // This extension applies to the issuer. We won't include this in // the set of inherited extensions. } else if (extension instanceof SubjectKeyIdentifierExtension) { // The generated certificate will automatically include a subject // key identifier extension, so we don't need to include it. } else if (extension instanceof BasicConstraintsExtension) { // Don't override a value already provided on the command line. if (basicConstraints == null) { basicConstraints = (BasicConstraintsExtension) extension; extensionList.add(basicConstraints); } } else if (extension instanceof ExtendedKeyUsageExtension) { // Don't override a value already provided on the command line. if (extendedKeyUsage == null) { extendedKeyUsage = (ExtendedKeyUsageExtension) extension; extensionList.add(extendedKeyUsage); } } else if (extension instanceof KeyUsageExtension) { // Don't override a value already provided on the command line. if (keyUsage == null) { keyUsage = (KeyUsageExtension) extension; extensionList.add(keyUsage); } } else if (extension instanceof SubjectAlternativeNameExtension) { // Although we could merge values, it's safer to not do that if any // subject alternative name values were provided on the command // line. if (sanValues.isEmpty()) { final SubjectAlternativeNameExtension e = (SubjectAlternativeNameExtension) extension; for (final String dnsName : e.getDNSNames()) { sanValues.add("DNS:" + dnsName); } for (final InetAddress ipAddress : e.getIPAddresses()) { sanValues.add("IP:" + ipAddress.getHostAddress()); } for (final String emailAddress : e.getRFC822Names()) { sanValues.add("EMAIL:" + emailAddress); } for (final String uri : e.getUniformResourceIdentifiers()) { sanValues.add("URI:" + uri); } for (final OID oid : e.getRegisteredIDs()) { sanValues.add("OID:" + oid.toString()); } extensionList.add(extension); } } else { genericExtensions.add(extension); extensionList.add(extension); } } } // Create an array with the final set of extensions to include in the // certificate or certificate signing request. final X509CertificateExtension[] extensions = new X509CertificateExtension[extensionList.size()]; extensionList.toArray(extensions); // If we're generating a self-signed certificate or a certificate signing // request, then we should now have everything we need to do that. Build // a keytool command that we could use to accomplish it. if (isGenerateCertificate) { if (displayKeytoolCommand) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-selfcert"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(alias); keytoolArguments.add("-dname"); keytoolArguments.add(subjectDN.toString()); keytoolArguments.add("-sigalg"); keytoolArguments.add(signatureAlgorithmName); keytoolArguments.add("-validity"); keytoolArguments.add(String.valueOf(daysValid)); if (validityStartTime != null) { keytoolArguments.add("-startdate"); keytoolArguments.add(formatValidityStartTime(validityStartTime)); } addExtensionArguments(keytoolArguments, basicConstraints, keyUsage, extendedKeyUsage, sanValues, ianValues, genericExtensions); displayKeytoolCommand(keytoolArguments); } // Generate the self-signed certificate. final long notBefore; if (validityStartTime == null) { notBefore = System.currentTimeMillis(); } else { notBefore = validityStartTime.getTime(); } final long notAfter = notBefore + TimeUnit.DAYS.toMillis(daysValid); final X509Certificate certificate; final Certificate[] chain; try { certificate = X509Certificate.generateSelfSignedCertificate( signatureAlgorithmIdentifier, keyPair, subjectDN, notBefore, notAfter, extensions); chain = new Certificate[] { certificate.toCertificate() }; } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_GENERATING_CERT.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Update the keystore with the new certificate. try { keystore.setKeyEntry(alias, keyPair.getPrivate(), privateKeyPassword, chain); writeKeystore(keystore, keystorePath, keystorePassword); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_UPDATING_KEYSTORE.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Display the certificate we just generated to the end user. out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SUCCESSFULLY_GENERATED_SELF_CERT. get()); printCertificate(certificate, "", false); // If we should write an output file, then do that now. if (outputFile != null) { try (PrintStream ps = new PrintStream(outputFile)) { final byte[] certBytes = certificate.getX509CertificateBytes(); if (outputPEM) { writePEMCertificate(ps, certBytes); } else { ps.write(certBytes); } out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_WROTE_OUTPUT_FILE.get( outputFile.getAbsolutePath())); } catch (final Exception e) { Debug.debugException(e); err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_WRITING_CERT.get( outputFile.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } return ResultCode.SUCCESS; } else { // Build the keytool command used to generate the certificate signing // request. Validator.ensureTrue(isGenerateCSR); if (displayKeytoolCommand) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-certreq"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(alias); keytoolArguments.add("-dname"); keytoolArguments.add(subjectDN.toString()); keytoolArguments.add("-sigalg"); keytoolArguments.add(signatureAlgorithmName); addExtensionArguments(keytoolArguments, basicConstraints, keyUsage, extendedKeyUsage, sanValues, ianValues, genericExtensions); if (outputFile != null) { keytoolArguments.add("-file"); keytoolArguments.add(outputFile.getAbsolutePath()); } displayKeytoolCommand(keytoolArguments); } // Generate the certificate signing request. final PKCS10CertificateSigningRequest certificateSigningRequest; try { certificateSigningRequest = PKCS10CertificateSigningRequest. generateCertificateSigningRequest(signatureAlgorithmIdentifier, keyPair, subjectDN, extensions); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_GENERATING_CSR.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Write the generated certificate signing request to the appropriate // location. try { final PrintStream ps; if (outputFile == null) { ps = getOut(); } else { ps = new PrintStream(outputFile); } if (outputPEM) { writePEMCertificateSigningRequest(ps, certificateSigningRequest. getPKCS10CertificateSigningRequestBytes()); } else { ps.write(certificateSigningRequest. getPKCS10CertificateSigningRequestBytes()); } if (outputFile != null) { ps.close(); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_WRITING_CSR.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // If the certificate signing request was written to an output file, // then let the user know that it was successful. If it was written to // standard output, then we don't need to tell them because they'll be // able to see it. if (outputFile != null) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SUCCESSFULLY_GENERATED_CSR.get( outputFile.getAbsolutePath())); } return ResultCode.SUCCESS; } } // If we've gotten here, then we know we're not replacing an existing // certificate. Perform any remaining argument assignment and validation. if ((subjectDN == null) && (! isSignCSR)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_NO_SUBJECT_DN_WITHOUT_USE_EXISTING_KP. get()); return ResultCode.PARAM_ERROR; } if (keyAlgorithmIdentifier == null) { keyAlgorithmIdentifier = PublicKeyAlgorithmIdentifier.RSA; keyAlgorithmName = keyAlgorithmIdentifier.getName(); } if (keySizeBits == null) { keySizeBits = 2048; } if ((signatureAlgorithmIdentifier == null) && (! isSignCSR)) { signatureAlgorithmIdentifier = SignatureAlgorithmIdentifier.SHA_256_WITH_RSA; signatureAlgorithmName = signatureAlgorithmIdentifier.getJavaName(); } // If we're going to generate a self-signed certificate or a certificate // signing request, then we first need to generate a key pair. Put together // the appropriate set of keytool arguments and then generate a self-signed // certificate. if (isGenerateCertificate || isGenerateCSR) { // Make sure that the specified alias is not already in use in the // keystore. if (hasKeyAlias(keystore, alias) || hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ALIAS_EXISTS_WITHOUT_USE_EXISTING_KP.get( alias)); return ResultCode.PARAM_ERROR; } if (displayKeytoolCommand) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-genkeypair"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(alias); keytoolArguments.add("-dname"); keytoolArguments.add(subjectDN.toString()); keytoolArguments.add("-keyalg"); keytoolArguments.add(keyAlgorithmName); keytoolArguments.add("-keysize"); keytoolArguments.add(String.valueOf(keySizeBits)); keytoolArguments.add("-sigalg"); keytoolArguments.add(signatureAlgorithmName); keytoolArguments.add("-validity"); keytoolArguments.add(String.valueOf(daysValid)); if (validityStartTime != null) { keytoolArguments.add("-startdate"); keytoolArguments.add(formatValidityStartTime(validityStartTime)); } addExtensionArguments(keytoolArguments, basicConstraints, keyUsage, extendedKeyUsage, sanValues, ianValues, genericExtensions); displayKeytoolCommand(keytoolArguments); } // Generate the self-signed certificate. final long notBefore; if (validityStartTime == null) { notBefore = System.currentTimeMillis(); } else { notBefore = validityStartTime.getTime(); } final long notAfter = notBefore + TimeUnit.DAYS.toMillis(daysValid); final X509CertificateExtension[] extensions = new X509CertificateExtension[extensionList.size()]; extensionList.toArray(extensions); final Certificate[] chain; final KeyPair keyPair; final X509Certificate certificate; try { final ObjectPair p = X509Certificate.generateSelfSignedCertificate( signatureAlgorithmIdentifier, keyAlgorithmIdentifier, keySizeBits, subjectDN, notBefore, notAfter, extensions); certificate = p.getFirst(); chain = new Certificate[] { certificate.toCertificate() }; keyPair = p.getSecond(); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_GENERATING_CERT.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Update the keystore with the new certificate. try { keystore.setKeyEntry(alias, keyPair.getPrivate(), privateKeyPassword, chain); writeKeystore(keystore, keystorePath, keystorePassword); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_UPDATING_KEYSTORE.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } if (isNewKeystore) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_CERT_CREATED_KEYSTORE.get( getUserFriendlyKeystoreType(keystoreType))); } // If we're just generating a self-signed certificate, then display the // certificate that we generated and potentially write it to an output // file. if (isGenerateCertificate) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SUCCESSFULLY_GENERATED_SELF_CERT.get()); printCertificate(certificate, "", false); // If we should write an output file, then do that now. if (outputFile != null) { try (PrintStream ps = new PrintStream(outputFile)) { final byte[] certBytes = certificate.getX509CertificateBytes(); if (outputPEM) { writePEMCertificate(ps, certBytes); } else { ps.write(certBytes); } out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_WROTE_OUTPUT_FILE.get( outputFile.getAbsolutePath())); } catch (final Exception e) { Debug.debugException(e); err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_WRITING_CERT.get( outputFile.getAbsolutePath())); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } return ResultCode.SUCCESS; } // If we're generating a certificate signing request, then put together // the appropriate set of arguments for that. Validator.ensureTrue(isGenerateCSR); out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SUCCESSFULLY_GENERATED_KEYPAIR.get()); if (displayKeytoolCommand) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-certreq"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(alias); keytoolArguments.add("-dname"); keytoolArguments.add(subjectDN.toString()); keytoolArguments.add("-sigalg"); keytoolArguments.add(signatureAlgorithmName); addExtensionArguments(keytoolArguments, basicConstraints, keyUsage, extendedKeyUsage, sanValues, ianValues, genericExtensions); if (outputFile != null) { keytoolArguments.add("-file"); keytoolArguments.add(outputFile.getAbsolutePath()); } displayKeytoolCommand(keytoolArguments); } // Generate the certificate signing request. final PKCS10CertificateSigningRequest certificateSigningRequest; try { certificateSigningRequest = PKCS10CertificateSigningRequest. generateCertificateSigningRequest(signatureAlgorithmIdentifier, keyPair, subjectDN, extensions); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_GENERATING_CSR.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Write the generated certificate signing request to the appropriate // location. try { final PrintStream ps; if (outputFile == null) { ps = getOut(); } else { ps = new PrintStream(outputFile); } if (outputPEM) { writePEMCertificateSigningRequest(ps, certificateSigningRequest. getPKCS10CertificateSigningRequestBytes()); } else { ps.write(certificateSigningRequest. getPKCS10CertificateSigningRequestBytes()); } if (outputFile != null) { ps.close(); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_WRITING_CSR.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // If the certificate signing request was written to an output file, // then let the user know that it was successful. If it was written to // standard output, then we don't need to tell them because they'll be // able to see it. if (outputFile != null) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SUCCESSFULLY_GENERATED_CSR.get( outputFile.getAbsolutePath())); } return ResultCode.SUCCESS; } // If we've gotten here, then we should be signing a certificate signing // request. Make sure that the keystore already has a private key entry // with the specified alias. Validator.ensureTrue(isSignCSR); if (! hasKeyAlias(keystore, alias)) { if (hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_SIGN_ALIAS_IS_CERT.get(alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_SIGN_NO_SUCH_ALIAS.get(alias, keystorePath.getAbsolutePath())); return ResultCode.PARAM_ERROR; } } // Get the signing certificate and its key pair. final PrivateKey issuerPrivateKey; final X509Certificate issuerCertificate; try { final Certificate[] chain = keystore.getCertificateChain(alias); issuerCertificate = new X509Certificate(chain[0].getEncoded()); issuerPrivateKey = (PrivateKey) keystore.getKey(alias, privateKeyPassword); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_SIGN_CANNOT_GET_SIGNING_CERT.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Make sure that we can decode the certificate signing request. final PKCS10CertificateSigningRequest csr; try { csr = readCertificateSigningRequestFromFile(inputFile); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Make sure that we can verify the certificate signing request's signature. try { csr.verifySignature(); } catch (final CertException ce) { Debug.debugException(ce); wrapErr(0, WRAP_COLUMN, ce.getMessage()); return ResultCode.PARAM_ERROR; } // Prompt about whether to sign the request, if appropriate. if (! noPrompt) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SIGN_CONFIRM.get()); out(); printCertificateSigningRequest(csr, false, ""); out(); try { if (! promptForYesNo( INFO_MANAGE_CERTS_GEN_CERT_PROMPT_SIGN.get())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_SIGN_CANCELED.get()); return ResultCode.USER_CANCELED; } } catch (final LDAPException le) { Debug.debugException(le); err(); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Read the certificate signing request and see if we need to take values // from it. if ((subjectDN == null) || (signatureAlgorithmIdentifier == null) || includeRequestedExtensions) { if (subjectDN == null) { subjectDN = csr.getSubjectDN(); } if (signatureAlgorithmIdentifier == null) { signatureAlgorithmIdentifier = SignatureAlgorithmIdentifier.forOID( csr.getSignatureAlgorithmOID()); if (signatureAlgorithmIdentifier == null) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_UNKNOWN_SIG_ALG_IN_CSR.get( csr.getSignatureAlgorithmOID())); return ResultCode.PARAM_ERROR; } else { signatureAlgorithmName = signatureAlgorithmIdentifier.getJavaName(); } } if (includeRequestedExtensions) { for (final X509CertificateExtension extension : csr.getExtensions()) { if ((extension instanceof AuthorityKeyIdentifierExtension) || (extension instanceof IssuerAlternativeNameExtension)) { // This extension applies to the issuer. We won't include this in // the set of inherited extensions. } else if (extension instanceof SubjectKeyIdentifierExtension) { // The generated certificate will automatically include a subject // key identifier extension, so we don't need to include it. } else if (extension instanceof BasicConstraintsExtension) { // Don't override a value already provided on the command line. if (basicConstraints == null) { basicConstraints = (BasicConstraintsExtension) extension; extensionList.add(basicConstraints); } } else if (extension instanceof ExtendedKeyUsageExtension) { // Don't override a value already provided on the command line. if (extendedKeyUsage == null) { extendedKeyUsage = (ExtendedKeyUsageExtension) extension; extensionList.add(extendedKeyUsage); } } else if (extension instanceof KeyUsageExtension) { // Don't override a value already provided on the command line. if (keyUsage == null) { keyUsage = (KeyUsageExtension) extension; extensionList.add(keyUsage); } } else if (extension instanceof SubjectAlternativeNameExtension) { // Although we could merge values, it's safer to not do that if any // subject alternative name values were provided on the command // line. if (sanValues.isEmpty()) { final SubjectAlternativeNameExtension e = (SubjectAlternativeNameExtension) extension; for (final String dnsName : e.getDNSNames()) { sanBuilder.addDNSName(dnsName); sanValues.add("DNS:" + dnsName); } for (final InetAddress ipAddress : e.getIPAddresses()) { sanBuilder.addIPAddress(ipAddress); sanValues.add("IP:" + ipAddress.getHostAddress()); } for (final String emailAddress : e.getRFC822Names()) { sanBuilder.addRFC822Name(emailAddress); sanValues.add("EMAIL:" + emailAddress); } for (final String uri : e.getUniformResourceIdentifiers()) { sanBuilder.addUniformResourceIdentifier(uri); sanValues.add("URI:" + uri); } for (final OID oid : e.getRegisteredIDs()) { sanBuilder.addRegisteredID(oid); sanValues.add("OID:" + oid.toString()); } try { extensionList.add( new SubjectAlternativeNameExtension(false, sanBuilder.build())); } catch (final Exception ex) { // This should never happen. Debug.debugException(ex); throw new RuntimeException(ex); } } } else { genericExtensions.add(extension); extensionList.add(extension); } } } } // Generate the keytool arguments to use to sign the requested certificate. final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-gencert"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(alias); keytoolArguments.add("-dname"); keytoolArguments.add(subjectDN.toString()); keytoolArguments.add("-sigalg"); keytoolArguments.add(signatureAlgorithmName); keytoolArguments.add("-validity"); keytoolArguments.add(String.valueOf(daysValid)); if (validityStartTime != null) { keytoolArguments.add("-startdate"); keytoolArguments.add(formatValidityStartTime(validityStartTime)); } addExtensionArguments(keytoolArguments, basicConstraints, keyUsage, extendedKeyUsage, sanValues, ianValues, genericExtensions); keytoolArguments.add("-infile"); keytoolArguments.add(inputFile.getAbsolutePath()); if (outputFile != null) { keytoolArguments.add("-outfile"); keytoolArguments.add(outputFile.getAbsolutePath()); } if (outputPEM) { keytoolArguments.add("-rfc"); } if (displayKeytoolCommand) { displayKeytoolCommand(keytoolArguments); } // Generate the signed certificate. final long notBefore; if (validityStartTime == null) { notBefore = System.currentTimeMillis(); } else { notBefore = validityStartTime.getTime(); } final long notAfter = notBefore + TimeUnit.DAYS.toMillis(daysValid); final X509CertificateExtension[] extensions = new X509CertificateExtension[extensionList.size()]; extensionList.toArray(extensions); final X509Certificate signedCertificate; try { signedCertificate = X509Certificate.generateIssuerSignedCertificate( signatureAlgorithmIdentifier, issuerCertificate, issuerPrivateKey, csr.getPublicKeyAlgorithmOID(), csr.getPublicKeyAlgorithmParameters(), csr.getEncodedPublicKey(), csr.getDecodedPublicKey(), subjectDN, notBefore, notAfter, extensions); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_SIGNING_CERT.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Write the signed certificate signing request to the appropriate location. try { final PrintStream ps; if (outputFile == null) { ps = getOut(); } else { ps = new PrintStream(outputFile); } if (outputPEM) { writePEMCertificate(ps, signedCertificate.getX509CertificateBytes()); } else { ps.write(signedCertificate.getX509CertificateBytes()); } if (outputFile != null) { ps.close(); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GEN_CERT_ERROR_WRITING_SIGNED_CERT.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // If the certificate signing request was written to an output file, // then let the user know that it was successful. If it was written to // standard output, then we don't need to tell them because they'll be // able to see it. if (outputFile != null) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GEN_CERT_SUCCESSFULLY_SIGNED_CERT.get( outputFile.getAbsolutePath())); } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the change-certificate-alias * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doChangeCertificateAlias() { // Get the values of a number of configured arguments. final StringArgument currentAliasArgument = subCommandParser.getStringArgument("current-alias"); final String currentAlias = currentAliasArgument.getValue(); final StringArgument newAliasArgument = subCommandParser.getStringArgument("new-alias"); final String newAlias = newAliasArgument.getValue(); final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // See if we need to use a private key password that is different from the // keystore password. final char[] privateKeyPassword; try { privateKeyPassword = getPrivateKeyPassword(keystore, currentAlias, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Make sure that the keystore has an existing entry with the current alias. // It must be either a certificate entry or a private key entry. final Certificate existingCertificate; final Certificate[] existingCertificateChain; final PrivateKey existingPrivateKey; try { if (hasCertificateAlias(keystore, currentAlias)) { existingCertificate = keystore.getCertificate(currentAlias); existingCertificateChain = null; existingPrivateKey = null; } else if (hasKeyAlias(keystore, currentAlias)) { existingCertificateChain = keystore.getCertificateChain(currentAlias); existingPrivateKey = (PrivateKey) keystore.getKey(currentAlias, privateKeyPassword); existingCertificate = null; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_ALIAS_NO_SUCH_ALIAS.get(currentAlias)); return ResultCode.PARAM_ERROR; } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_ALIAS_CANNOT_GET_EXISTING_ENTRY.get( currentAlias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Make sure that the keystore does not have an entry with the new alias. if (hasCertificateAlias(keystore, newAlias) || hasKeyAlias(keystore, newAlias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_ALIAS_NEW_ALIAS_IN_USE.get(newAlias)); return ResultCode.PARAM_ERROR; } // Generate the keytool arguments to use to change the certificate alias. final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-changealias"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(currentAlias); keytoolArguments.add("-destalias"); keytoolArguments.add(newAlias); displayKeytoolCommand(keytoolArguments); } // Update the keystore to remove the entry with the current alias and // re-write it with the new alias. try { keystore.deleteEntry(currentAlias); if (existingCertificate != null) { keystore.setCertificateEntry(newAlias, existingCertificate); } else { keystore.setKeyEntry(newAlias, existingPrivateKey, privateKeyPassword, existingCertificateChain); } writeKeystore(keystore, keystorePath, keystorePassword); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_ALIAS_CANNOT_UPDATE_KEYSTORE.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHANGE_ALIAS_SUCCESSFUL.get(currentAlias, newAlias)); return ResultCode.SUCCESS; } /** * Performs the necessary processing for the change-keystore-password * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doChangeKeystorePassword() { // Get the values of a number of configured arguments. final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] currentKeystorePassword; try { currentKeystorePassword = getKeystorePassword(keystorePath, "current"); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] newKeystorePassword; try { newKeystorePassword = getKeystorePassword(keystorePath, "new"); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, currentKeystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Generate the keytool arguments to use to change the keystore password. final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-storepasswd"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-new"); keytoolArguments.add("*****REDACTED*****"); displayKeytoolCommand(keytoolArguments); } // Rewrite the keystore with the new password. try { writeKeystore(keystore, keystorePath, newKeystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHANGE_KS_PW_SUCCESSFUL.get( keystorePath.getAbsolutePath())); return ResultCode.SUCCESS; } /** * Performs the necessary processing for the change-private-key-password * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doChangePrivateKeyPassword() { // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Make sure that the keystore has a key entry with the specified alias. if (hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_PK_PW_ALIAS_IS_CERT.get(alias)); return ResultCode.PARAM_ERROR; } else if (! hasKeyAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_PK_PW_NO_SUCH_ALIAS.get(alias)); return ResultCode.PARAM_ERROR; } // Get the current and new private key passwords. final char[] currentPrivateKeyPassword; try { currentPrivateKeyPassword = getPrivateKeyPassword(keystore, alias, "current", keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] newPrivateKeyPassword; try { newPrivateKeyPassword = getPrivateKeyPassword(keystore, alias, "new", keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Generate the keytool arguments to use to change the private key. final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArguments = new ArrayList<>(30); keytoolArguments.add("-keypasswd"); keytoolArguments.add("-keystore"); keytoolArguments.add(keystorePath.getAbsolutePath()); keytoolArguments.add("-storetype"); keytoolArguments.add(keystoreType); keytoolArguments.add("-storepass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-alias"); keytoolArguments.add(alias); keytoolArguments.add("-keypass"); keytoolArguments.add("*****REDACTED*****"); keytoolArguments.add("-new"); keytoolArguments.add("*****REDACTED*****"); displayKeytoolCommand(keytoolArguments); } // Get the contents of the private key entry. final Certificate[] chain; final PrivateKey privateKey; try { chain = keystore.getCertificateChain(alias); privateKey = (PrivateKey) keystore.getKey(alias, currentPrivateKeyPassword); } catch (final UnrecoverableKeyException e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_PK_PW_WRONG_PK_PW.get(alias)); return ResultCode.PARAM_ERROR; } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_PK_PW_CANNOT_GET_PK.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } // Remove the existing key entry and re-add it with the new password. try { keystore.deleteEntry(alias); keystore.setKeyEntry(alias, privateKey, newPrivateKeyPassword, chain); writeKeystore(keystore, keystorePath, keystorePassword); } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHANGE_PK_PW_CANNOT_UPDATE_KS.get()); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHANGE_PK_PW_SUCCESSFUL.get(alias)); return ResultCode.SUCCESS; } /** * Performs the necessary processing for the copy-keystore subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doCopyKeystore() { // Get the source key store. final String sourceKeyStoreType; final File sourceKeyStorePath = getKeystorePath("source-keystore"); try { sourceKeyStoreType = inferKeystoreType(sourceKeyStorePath, "source"); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] sourceKeyStorePassword; try { sourceKeyStorePassword = getKeystorePassword(sourceKeyStorePath, "source"); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final KeyStore sourceKeyStore; try { sourceKeyStore = getKeystore(sourceKeyStoreType, sourceKeyStorePath, sourceKeyStorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the destination key store. final String destinationKeyStoreType; final File destinationKeyStorePath = getKeystorePath("destination-keystore"); try { destinationKeyStoreType = inferKeystoreType(destinationKeyStorePath, "destination"); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final boolean destinationExists = destinationKeyStorePath.exists(); char[] destinationKeyStorePassword; try { destinationKeyStorePassword = getKeystorePassword(destinationKeyStorePath, "destination"); if (destinationKeyStorePassword == null) { destinationKeyStorePassword = sourceKeyStorePassword; } } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final KeyStore destinationKeyStore; try { destinationKeyStore = getKeystore(destinationKeyStoreType, destinationKeyStorePath, destinationKeyStorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the value of the aliases argument, if it was provided. final Set aliases = new LinkedHashSet<>(); try { final StringArgument aliasArg = subCommandParser.getStringArgument("alias"); if ((aliasArg != null) && aliasArg.isPresent()) { for (final String alias : aliasArg.getValues()) { aliases.add(alias); if (! sourceKeyStore.containsAlias(alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_COPY_KS_NO_SUCH_SOURCE_ALIAS.get( sourceKeyStorePath.getAbsolutePath(), alias)); return ResultCode.PARAM_ERROR; } } } else { final Enumeration sourceAliases = sourceKeyStore.aliases(); while (sourceAliases.hasMoreElements()) { aliases.add(sourceAliases.nextElement()); } } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_COPY_KS_CANNOT_GET_SOURCE_ALIASES.get( sourceKeyStorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } // If the set of aliases is empty and the destination key store already // exists, then exit without doing anything. if (aliases.isEmpty() && destinationExists) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_COPY_KS_NO_CERTS_COPIED_EXISTING_KS.get( sourceKeyStorePath.getAbsolutePath(), destinationKeyStorePath.getAbsolutePath())); return ResultCode.SUCCESS; } // Make sure that none of the target aliases exist in the destination key // store. for (final String alias : aliases) { try { if (destinationKeyStore.containsAlias(alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_COPY_KS_CONFLICTING_ALIAS.get(alias, destinationKeyStorePath.getAbsolutePath(), subCommandParser.getCommandName())); return ResultCode.CONSTRAINT_VIOLATION; } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_COPY_KS_CANNOT_CHECK_DEST_ALIAS.get(alias, destinationKeyStorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } } // Copy each of the targeted entries from the source key store into the // destination key store. char[] sourcePrivateKeyPassword = null; char[] destinationPrivateKeyPassword = null; for (final String alias : aliases) { try { if (sourceKeyStore.isCertificateEntry(alias)) { final Certificate certificate = sourceKeyStore.getCertificate(alias); destinationKeyStore.setCertificateEntry(alias, certificate); } else { if (sourcePrivateKeyPassword == null) { sourcePrivateKeyPassword = getPrivateKeyPassword(sourceKeyStore, alias, "source", sourceKeyStorePassword); } if (destinationPrivateKeyPassword == null) { destinationPrivateKeyPassword = getPrivateKeyPassword( destinationKeyStore, alias, "destination", destinationKeyStorePassword); } final Certificate[] chain = sourceKeyStore.getCertificateChain(alias); final Key key = sourceKeyStore.getKey(alias, sourcePrivateKeyPassword); destinationKeyStore.setKeyEntry(alias, key, destinationPrivateKeyPassword, chain); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_COPY_KS_ERROR_COPYING_ENTRY.get(alias, sourceKeyStorePath.getAbsolutePath(), destinationKeyStorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } } // Rewrite the destination keystore. try { writeKeystore(destinationKeyStore, destinationKeyStorePath, destinationKeyStorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } if (aliases.isEmpty()) { // This should only happen if the alias argument was not provided, the // source key store is empty, and the destination key store doesn't exist. // In that case, the destination key store will have been created. wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_COPY_KS_NO_CERTS_COPIED_KS_CREATED.get( sourceKeyStorePath.getAbsolutePath(), destinationKeyStoreType, destinationKeyStorePath.getAbsolutePath())); } else { // Write a message about the entries that were successfully copied. wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_COPY_KS_CERTS_COPIED_HEADER.get( sourceKeyStorePath.getAbsolutePath(), destinationKeyStoreType, destinationKeyStorePath.getAbsolutePath())); for (final String alias : aliases) { out("* ", alias); } } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the retrieve-server-certificate * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doRetrieveServerCertificate() { // Get the values of a number of configured arguments. final StringArgument hostnameArgument = subCommandParser.getStringArgument("hostname"); final String hostname = hostnameArgument.getValue(); final IntegerArgument portArgument = subCommandParser.getIntegerArgument("port"); final int port = portArgument.getValue(); final BooleanArgument useLDAPStartTLSArgument = subCommandParser.getBooleanArgument("use-ldap-start-tls"); final boolean useLDAPStartTLS = ((useLDAPStartTLSArgument != null) && useLDAPStartTLSArgument.isPresent()); final BooleanArgument onlyPeerArgument = subCommandParser.getBooleanArgument("only-peer-certificate"); final boolean onlyPeer = ((onlyPeerArgument != null) && onlyPeerArgument.isPresent()); final BooleanArgument verboseArgument = subCommandParser.getBooleanArgument("verbose"); final boolean verbose = ((verboseArgument != null) && verboseArgument.isPresent()); boolean outputPEM = true; final StringArgument outputFormatArgument = subCommandParser.getStringArgument("output-format"); if ((outputFormatArgument != null) && outputFormatArgument.isPresent()) { final String format = outputFormatArgument.getValue().toLowerCase(); if (format.equals("der") || format.equals("binary") || format.equals("bin")) { outputPEM = false; } } File outputFile = null; final FileArgument outputFileArgument = subCommandParser.getFileArgument("output-file"); if ((outputFileArgument != null) && outputFileArgument.isPresent()) { outputFile = outputFileArgument.getValue(); } // Spawn a background thread to establish a connection and get the // certificate chain from the target server. final LinkedBlockingQueue responseQueue = new LinkedBlockingQueue<>(10); final ManageCertificatesServerCertificateCollector certificateCollector = new ManageCertificatesServerCertificateCollector(this, hostname, port, useLDAPStartTLS, verbose, responseQueue); certificateCollector.start(); Object responseObject = ERR_MANAGE_CERTS_RETRIEVE_CERT_NO_CERT_CHAIN_RECEIVED.get( hostname + ':' + port); try { responseObject = responseQueue.poll(90L, TimeUnit.SECONDS); } catch (final Exception e) { Debug.debugException(e); } final X509Certificate[] chain; if (responseObject instanceof X509Certificate[]) { chain = (X509Certificate[]) responseObject; if (chain.length == 0) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_RETRIEVE_CERT_EMPTY_CHAIN.get()); return ResultCode.NO_RESULTS_RETURNED; } } else if (responseObject instanceof CertException) { // The error message will have already been recorded by the collector // thread, so we can just return a non-success result. return ResultCode.LOCAL_ERROR; } else { wrapErr(0, WRAP_COLUMN, String.valueOf(responseObject)); return ResultCode.LOCAL_ERROR; } try { certificateCollector.join(10_000L); } catch (final Exception e) { Debug.debugException(e); } // If the certificates should be written to a file, then do that now. if (outputFile != null) { try (PrintStream s = new PrintStream(outputFile)) { for (final X509Certificate c : chain) { if (outputPEM) { writePEMCertificate(s, c.getX509CertificateBytes()); } else { s.write(c.getX509CertificateBytes()); } if (onlyPeer) { break; } } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_RETRIEVE_CERT_CANNOT_WRITE_TO_FILE.get( outputFile.getAbsolutePath(), StaticUtils.getExceptionMessage(e))); return ResultCode.LOCAL_ERROR; } } // Display information about the certificates. for (int i=0; i < chain.length; i++) { if (verbose || (i > 0)) { out(); out(); } if ((! onlyPeer) && (chain.length > 1)) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_RETRIEVE_CERT_DISPLAY_HEADER.get((i+1), chain.length)); out(); } final X509Certificate c = chain[i]; writePEMCertificate(getOut(), c.getX509CertificateBytes()); out(); printCertificate(c, "", verbose); if (onlyPeer) { break; } } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the trust-server-certificate * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doTrustServerCertificate() { // Get the values of a number of configured arguments. final StringArgument hostnameArgument = subCommandParser.getStringArgument("hostname"); final String hostname = hostnameArgument.getValue(); final IntegerArgument portArgument = subCommandParser.getIntegerArgument("port"); final int port = portArgument.getValue(); final String alias; final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); if ((aliasArgument != null) && aliasArgument.isPresent()) { alias = aliasArgument.getValue(); } else { alias = hostname + ':' + port; } final BooleanArgument useLDAPStartTLSArgument = subCommandParser.getBooleanArgument("use-ldap-start-tls"); final boolean useLDAPStartTLS = ((useLDAPStartTLSArgument != null) && useLDAPStartTLSArgument.isPresent()); final BooleanArgument issuersOnlyArgument = subCommandParser.getBooleanArgument("issuers-only"); final boolean issuersOnly = ((issuersOnlyArgument != null) && issuersOnlyArgument.isPresent()); final BooleanArgument noPromptArgument = subCommandParser.getBooleanArgument("no-prompt"); final boolean noPrompt = ((noPromptArgument != null) && noPromptArgument.isPresent()); final BooleanArgument verboseArgument = subCommandParser.getBooleanArgument("verbose"); final boolean verbose = ((verboseArgument != null) && verboseArgument.isPresent()); final String keystoreType; final File keystorePath = getKeystorePath(); final boolean isNewKeystore = (! keystorePath.exists()); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Make sure that the specified alias is not already in use. if (hasCertificateAlias(keystore, alias) || hasKeyAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_TRUST_SERVER_ALIAS_IN_USE.get(alias)); return ResultCode.PARAM_ERROR; } // Spawn a background thread to establish a connection and get the // certificate chain from the target server. final LinkedBlockingQueue responseQueue = new LinkedBlockingQueue<>(10); final ManageCertificatesServerCertificateCollector certificateCollector = new ManageCertificatesServerCertificateCollector(this, hostname, port, useLDAPStartTLS, verbose, responseQueue); certificateCollector.start(); Object responseObject = ERR_MANAGE_CERTS_TRUST_SERVER_NO_CERT_CHAIN_RECEIVED.get( hostname + ':' + port); try { responseObject = responseQueue.poll(90L, TimeUnit.SECONDS); } catch (final Exception e) { Debug.debugException(e); } final X509Certificate[] chain; if (responseObject instanceof X509Certificate[]) { chain = (X509Certificate[]) responseObject; } else if (responseObject instanceof CertException) { // The error message will have already been recorded by the collector // thread, so we can just return a non-success result. return ResultCode.LOCAL_ERROR; } else { wrapErr(0, WRAP_COLUMN, String.valueOf(responseObject)); return ResultCode.LOCAL_ERROR; } try { certificateCollector.join(10_000L); } catch (final Exception e) { Debug.debugException(e); } // If we should prompt the user about whether to trust the certificates, // then do so now. if (! noPrompt) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_TRUST_SERVER_RETRIEVED_CHAIN.get( hostname + ':' + port)); boolean isFirst = true; for (final X509Certificate c : chain) { out(); if (isFirst) { isFirst = false; if (issuersOnly && (chain.length > 1)) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_TRUST_SERVER_NOTE_OMITTED.get()); out(); } } printCertificate(c, "", verbose); } out(); try { if (! promptForYesNo(INFO_MANAGE_CERTS_TRUST_SERVER_PROMPT_TRUST.get())) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_TRUST_SERVER_CHAIN_REJECTED.get()); return ResultCode.USER_CANCELED; } } catch (final LDAPException le) { Debug.debugException(le); err(); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } } // Add the certificates to the keystore. final LinkedHashMap certsByAlias = new LinkedHashMap<>(StaticUtils.computeMapCapacity(chain.length)); for (int i=0; i < chain.length; i++) { if (i == 0) { if (issuersOnly && (chain.length > 1)) { continue; } certsByAlias.put(alias, chain[i]); } else if ((i == 1) && (chain.length == 2)) { certsByAlias.put(alias + "-issuer", chain[i]); } else { certsByAlias.put(alias + "-issuer-" + i, chain[i]); } } for (final Map.Entry e : certsByAlias.entrySet()) { final String certAlias = e.getKey(); final X509Certificate cert = e.getValue(); try { Validator.ensureFalse( (hasCertificateAlias(keystore, certAlias) || hasKeyAlias(keystore, certAlias)), "ERROR: Alias '" + certAlias + "' is already in use in the " + "keystore."); keystore.setCertificateEntry(certAlias, cert.toCertificate()); } catch (final Exception ex) { Debug.debugException(ex); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_TRUST_SERVER_ERROR_ADDING_CERT_TO_KS.get( cert.getSubjectDN())); ex.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } // Save the updated keystore. try { writeKeystore(keystore, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } if (isNewKeystore) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_TRUST_SERVER_CERT_CREATED_KEYSTORE.get( getUserFriendlyKeystoreType(keystoreType))); } out(); if (certsByAlias.size() == 1) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_TRUST_SERVER_ADDED_CERT_TO_KS.get()); } else { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_TRUST_SERVER_ADDED_CERTS_TO_KS.get( certsByAlias.size())); } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the check-certificate-usability * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doCheckCertificateUsability() { // Get the values of a number of configured arguments. final StringArgument aliasArgument = subCommandParser.getStringArgument("alias"); final String alias = aliasArgument.getValue(); final String keystoreType; final File keystorePath = getKeystorePath(); try { keystoreType = inferKeystoreType(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } final char[] keystorePassword; try { keystorePassword = getKeystorePassword(keystorePath); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Get the keystore. final KeyStore keystore; try { keystore = getKeystore(keystoreType, keystorePath, keystorePassword); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // Make sure that the specified entry exists in the keystore and is // associated with a certificate chain and a private key. final X509Certificate[] chain; if (hasKeyAlias(keystore, alias)) { try { final Certificate[] genericChain = keystore.getCertificateChain(alias); Validator.ensureTrue((genericChain.length > 0), "ERROR: The keystore has a private key entry for alias '" + alias + "', but the associated certificate chain is empty."); chain = new X509Certificate[genericChain.length]; for (int i=0; i < genericChain.length; i++) { chain[i] = new X509Certificate(genericChain[i].getEncoded()); } out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_GOT_CHAIN.get(alias)); for (final X509Certificate c : chain) { out(); printCertificate(c, "", false); } } catch (final Exception e) { Debug.debugException(e); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_CANNOT_GET_CHAIN.get(alias)); e.printStackTrace(getErr()); return ResultCode.LOCAL_ERROR; } } else if (hasCertificateAlias(keystore, alias)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_NO_PRIVATE_KEY.get(alias)); return ResultCode.PARAM_ERROR; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_NO_SUCH_ALIAS.get(alias)); return ResultCode.PARAM_ERROR; } // Check to see if the certificate is self-signed. If so, then that's a // warning. If not, then make sure that the chain is complete and that each // subsequent certificate is the issuer of the previous. int numWarnings = 0; int numErrors = 0; if (chain[0].isSelfSigned()) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_CERT_IS_SELF_SIGNED.get( chain[0].getSubjectDN())); numWarnings++; } else if ((chain.length == 1) || (! chain[chain.length - 1].isSelfSigned())) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_END_OF_CHAIN_NOT_SELF_SIGNED.get( alias)); numErrors++; } else { boolean chainError = false; final StringBuilder nonMatchReason = new StringBuilder(); for (int i=1; i < chain.length; i++) { if (! chain[i].isIssuerFor(chain[i-1], nonMatchReason)) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_CHAIN_ISSUER_MISMATCH.get( alias, chain[i].getSubjectDN(), chain[i-1].getSubjectDN(), nonMatchReason)); numErrors++; chainError = true; } } if (! chainError) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_CHAIN_COMPLETE.get()); } } // If there are multiple certificates in the chain, and if the last // certificate in the chain is self-signed, then check to see if it is // contained in the JVM-default trust manager. If it isn't, then we'll // display a notice, but we won't consider it a warning in and of itself. if ((chain.length > 1) && chain[chain.length-1].isSelfSigned()) { final X509Certificate caCert = chain[chain.length-1]; try { final String jvmDefaultTrustStoreType = inferKeystoreType(JVM_DEFAULT_CACERTS_FILE); final KeyStore jvmDefaultTrustStore = CryptoHelper.getKeyStore(jvmDefaultTrustStoreType); try (FileInputStream inputStream = new FileInputStream(JVM_DEFAULT_CACERTS_FILE)) { jvmDefaultTrustStore.load(inputStream, null); } boolean found = false; final Enumeration aliases = jvmDefaultTrustStore.aliases(); while (aliases.hasMoreElements()) { final String jvmDefaultCertAlias = aliases.nextElement(); if (jvmDefaultTrustStore.isCertificateEntry(jvmDefaultCertAlias)) { final Certificate c = jvmDefaultTrustStore.getCertificate(jvmDefaultCertAlias); final X509Certificate xc = new X509Certificate(c.getEncoded()); if ((caCert.getSubjectDN().equals(xc.getSubjectDN())) && Arrays.equals(caCert.getSignatureValue().getBits(), xc.getSignatureValue().getBits())) { found = true; break; } } } if (found) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_CA_TRUSTED_OK.get( caCert.getSubjectDN())); } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_CA_NOT_IN_JVM_DEFAULT_TS.get( caCert.getSubjectDN())); } } catch (final Exception e) { Debug.debugException(e); err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_CHECK_CA_IN_TS_ERROR.get( caCert.getSubjectDN(), StaticUtils.getExceptionMessage(e))); numWarnings++; } } // Make sure that the signature is valid for each certificate in the // chain. If any certificate has an invalid signature, then that's an // error. for (int i=0; i < chain.length; i++) { final X509Certificate c = chain[i]; try { if (c.isSelfSigned()) { c.verifySignature(null); } else if ((i + 1) < chain.length) { c.verifySignature(chain[i+1]); } out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_CERT_SIGNATURE_VALID.get( c.getSubjectDN())); } catch (final CertException ce) { err(); wrapErr(0, WRAP_COLUMN, ce.getMessage()); numErrors++; } } // Check the validity window for each certificate in the chain. If any of // them is expired or not yet valid, then that's an error. If any of them // will expire in the near future, then that's a warning. final long currentTime = System.currentTimeMillis(); final long thirtyDaysFromNow = currentTime + (30L * 24L * 60L * 60L * 1000L); for (int i=0; i < chain.length; i++) { final X509Certificate c = chain[i]; if (c.getNotBeforeTime() > currentTime) { err(); if (i == 0) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_END_CERT_NOT_YET_VALID.get( c.getSubjectDN(), formatDateAndTime(c.getNotBeforeDate()))); } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_NOT_YET_VALID.get( c.getSubjectDN(), formatDateAndTime(c.getNotBeforeDate()))); } numErrors++; } else if (c.getNotAfterTime() < currentTime) { err(); if (i == 0) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_END_CERT_EXPIRED.get( c.getSubjectDN(), formatDateAndTime(c.getNotAfterDate()))); } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_EXPIRED.get( c.getSubjectDN(), formatDateAndTime(c.getNotAfterDate()))); } numErrors++; } else if (c.getNotAfterTime() < thirtyDaysFromNow) { err(); if (i == 0) { wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_END_CERT_NEAR_EXPIRATION.get( c.getSubjectDN(), formatDateAndTime(c.getNotAfterDate()))); } else { wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_NEAR_EXPIRATION. get(c.getSubjectDN(), formatDateAndTime(c.getNotAfterDate()))); } numWarnings++; } else { if (i == 0) { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_END_CERT_VALIDITY_OK.get( c.getSubjectDN(), formatDateAndTime(c.getNotAfterDate()))); } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_VALIDITY_OK.get( c.getSubjectDN(), formatDateAndTime(c.getNotAfterDate()))); } } } // Look at all of the extensions for all of the certificates and perform the // following validation: // - If the certificate at the head of the chain has an extended key usage // extension, then make sure it includes the serverAuth usage. If it // does not include an extended key usage extension, then warn that it // should. // - If any of the issuer certificates has a basic constraints extension, // then make sure it indicates that the associated certificate is a // certification authority. Further, if it has a path length constraint, // then make sure the chain does not exceed that length. If any issuer // certificate does not have a basic constraints extension, then warn that // it should. // - If any of the issuer certificates has a key usage extension, then // make sure it has the certSign usage. If any issuer certificate does // not have a key usage extension, then warn that it should. // - TODO: If any certificate has a CRL distribution points extension, then // retrieve the CRL and make sure the certificate hasn't been revoked. // - TODO: If any certificate has an authority information access // extension that points to an OCSP service, then consult that service to // determine whether the certificate has been revoked. for (int i=0; i < chain.length; i++) { boolean basicConstraintsFound = false; boolean extendedKeyUsageFound = false; boolean keyUsageFound = false; final X509Certificate c = chain[i]; for (final X509CertificateExtension extension : c.getExtensions()) { if (extension instanceof ExtendedKeyUsageExtension) { extendedKeyUsageFound = true; if (i == 0) { final ExtendedKeyUsageExtension e = (ExtendedKeyUsageExtension) extension; if (!e.getKeyPurposeIDs().contains( ExtendedKeyUsageID.TLS_SERVER_AUTHENTICATION.getOID())) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_END_CERT_BAD_EKU.get( c.getSubjectDN())); numErrors++; } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_END_CERT_GOOD_EKU.get( c.getSubjectDN())); } } } else if (extension instanceof BasicConstraintsExtension) { basicConstraintsFound = true; if (i > 0) { final BasicConstraintsExtension e = (BasicConstraintsExtension) extension; if (!e.isCA()) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_BAD_BC_CA.get( c.getSubjectDN())); numErrors++; } else if ((e.getPathLengthConstraint() != null) && ((i - 1) > e.getPathLengthConstraint())) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_BAD_BC_LENGTH. get(c.getSubjectDN(), e.getPathLengthConstraint(), chain[0].getSubjectDN(), (i-1))); numErrors++; } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_ISSUER_CERT_GOOD_BC.get( c.getSubjectDN())); } } } else if (extension instanceof KeyUsageExtension) { keyUsageFound = true; if (i > 0) { final KeyUsageExtension e = (KeyUsageExtension) extension; if (! e.isKeyCertSignBitSet()) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ISSUER_NO_CERT_SIGN_KU.get( c.getSubjectDN())); numErrors++; } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_ISSUER_GOOD_KU.get( c.getSubjectDN())); } } } } if (i == 0) { if (! extendedKeyUsageFound) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_NO_EKU.get( c.getSubjectDN())); numWarnings++; } } else { if (! basicConstraintsFound) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_NO_BC.get( c.getSubjectDN())); numWarnings++; } if (! keyUsageFound) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_NO_KU.get( c.getSubjectDN())); numWarnings++; } } } // Make sure that none of the certificates has a signature algorithm that // uses MD5 or SHA-1. If it uses an unrecognized signature algorithm, then // that's a warning. boolean isIssuer = false; final BooleanArgument ignoreSHA1WarningArg = subCommandParser.getBooleanArgument( "allow-sha-1-signature-for-issuer-certificates"); final boolean ignoreSHA1SignatureWarningForIssuerCertificates = ((ignoreSHA1WarningArg != null) && ignoreSHA1WarningArg.isPresent()); for (final X509Certificate c : chain) { final OID signatureAlgorithmOID = c.getSignatureAlgorithmOID(); final SignatureAlgorithmIdentifier id = SignatureAlgorithmIdentifier.forOID(signatureAlgorithmOID); if (id == null) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_UNKNOWN_SIG_ALG.get( c.getSubjectDN(), signatureAlgorithmOID)); numWarnings++; } else { switch (id) { case MD2_WITH_RSA: case MD5_WITH_RSA: err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_WEAK_SIG_ALG.get( c.getSubjectDN(), id.getUserFriendlyName())); numErrors++; break; case SHA_1_WITH_RSA: case SHA_1_WITH_DSA: case SHA_1_WITH_ECDSA: if (isIssuer && ignoreSHA1SignatureWarningForIssuerCertificates) { err(); wrapErr(0, WRAP_COLUMN, WARN_MANAGE_CERTS_CHECK_USABILITY_ISSUER_WITH_SHA1_SIG.get( c.getSubjectDN(), id.getUserFriendlyName(), ignoreSHA1WarningArg.getIdentifierString())); } else { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_WEAK_SIG_ALG.get( c.getSubjectDN(), id.getUserFriendlyName())); numErrors++; } break; case SHA_224_WITH_RSA: case SHA_224_WITH_DSA: case SHA_224_WITH_ECDSA: case SHA_256_WITH_RSA: case SHA_256_WITH_DSA: case SHA_256_WITH_ECDSA: case SHA_384_WITH_RSA: case SHA_384_WITH_ECDSA: case SHA_512_WITH_RSA: case SHA_512_WITH_ECDSA: out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_SIG_ALG_OK.get( c.getSubjectDN(), id.getUserFriendlyName())); break; } } isIssuer = true; } // Make sure that none of the certificates that uses the RSA key algorithm // has a public modulus size smaller than 2048 bits. for (final X509Certificate c : chain) { if ((c.getDecodedPublicKey() != null) && (c.getDecodedPublicKey() instanceof RSAPublicKey)) { final RSAPublicKey rsaPublicKey = (RSAPublicKey) c.getDecodedPublicKey(); final byte[] modulusBytes = rsaPublicKey.getModulus().toByteArray(); int modulusSizeBits = modulusBytes.length * 8; if (((modulusBytes.length % 2) != 0) && (modulusBytes[0] == 0x00)) { modulusSizeBits -= 8; } if (modulusSizeBits < 2048) { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_WEAK_RSA_MODULUS.get( c.getSubjectDN(), modulusSizeBits)); numErrors++; } else { out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_RSA_MODULUS_OK.get( c.getSubjectDN(), modulusSizeBits)); } } } switch (numErrors) { case 0: break; case 1: err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ONE_ERROR.get()); return ResultCode.PARAM_ERROR; default: err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_MULTIPLE_ERRORS.get(numErrors)); return ResultCode.PARAM_ERROR; } switch (numWarnings) { case 0: out(); wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_CHECK_USABILITY_NO_ERRORS_OR_WARNINGS.get()); return ResultCode.SUCCESS; case 1: err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_ONE_WARNING.get()); return ResultCode.PARAM_ERROR; default: err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_CHECK_USABILITY_MULTIPLE_WARNINGS.get( numWarnings)); return ResultCode.PARAM_ERROR; } } /** * Performs the necessary processing for the display-certificate-file * subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doDisplayCertificateFile() { // Get the values of a number of configured arguments. final FileArgument certificateFileArgument = subCommandParser.getFileArgument("certificate-file"); final File certificateFile = certificateFileArgument.getValue(); final BooleanArgument verboseArgument = subCommandParser.getBooleanArgument("verbose"); final boolean verbose = ((verboseArgument != null) && verboseArgument.isPresent()); final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArgs = new ArrayList<>(10); keytoolArgs.add("-printcert"); keytoolArgs.add("-file"); keytoolArgs.add(certificateFile.getAbsolutePath()); if (verbose) { keytoolArgs.add("-v"); } displayKeytoolCommand(keytoolArgs); } // Read the certificates from the specified file. final List certificates; try { certificates = readCertificatesFromFile(certificateFile); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } // If there aren't any certificates in the file, print that. if (certificates.isEmpty()) { wrapOut(0, WRAP_COLUMN, INFO_MANAGE_CERTS_DISPLAY_CERT_NO_CERTS.get( certificateFile.getAbsolutePath())); } else { for (final X509Certificate c : certificates) { out(); printCertificate(c, "", verbose); } } return ResultCode.SUCCESS; } /** * Performs the necessary processing for the * display-certificate-signing-request-file subcommand. * * @return A result code that indicates whether the processing completed * successfully. */ @NotNull() private ResultCode doDisplayCertificateSigningRequestFile() { // Get the values of a number of configured arguments. final FileArgument csrFileArgument = subCommandParser.getFileArgument("certificate-signing-request-file"); final File csrFile = csrFileArgument.getValue(); final BooleanArgument verboseArgument = subCommandParser.getBooleanArgument("verbose"); final boolean verbose = ((verboseArgument != null) && verboseArgument.isPresent()); final BooleanArgument displayKeytoolCommandArgument = subCommandParser.getBooleanArgument("display-keytool-command"); if ((displayKeytoolCommandArgument != null) && displayKeytoolCommandArgument.isPresent()) { final ArrayList keytoolArgs = new ArrayList<>(10); keytoolArgs.add("-printcertreq"); keytoolArgs.add("-file"); keytoolArgs.add(csrFile.getAbsolutePath()); keytoolArgs.add("-v"); displayKeytoolCommand(keytoolArgs); } // Read the certificate signing request from the specified file. final PKCS10CertificateSigningRequest csr; try { csr = readCertificateSigningRequestFromFile(csrFile); } catch (final LDAPException le) { Debug.debugException(le); wrapErr(0, WRAP_COLUMN, le.getMessage()); return le.getResultCode(); } out(); printCertificateSigningRequest(csr, verbose, ""); return ResultCode.SUCCESS; } /** * Prints a string representation of the provided certificate to standard * output. * * @param certificate The certificate to be printed. * @param indent The string to place at the beginning of each line to * indent that line. * @param verbose Indicates whether to display verbose information about * the certificate. */ private void printCertificate(@NotNull final X509Certificate certificate, @NotNull final String indent, final boolean verbose) { if (verbose) { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_VERSION.get( certificate.getVersion().getName())); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SUBJECT_DN.get( certificate.getSubjectDN())); out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_ISSUER_DN.get( certificate.getIssuerDN())); if (verbose) { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SERIAL_NUMBER.get( toColonDelimitedHex( certificate.getSerialNumber().toByteArray()))); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_VALIDITY_START.get( formatDateAndTime(certificate.getNotBeforeDate()))); out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_VALIDITY_END.get( formatDateAndTime(certificate.getNotAfterDate()))); final long currentTime = System.currentTimeMillis(); if (currentTime < certificate.getNotBeforeTime()) { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_VALIDITY_STATE_NOT_YET_VALID. get()); } else if (currentTime > certificate.getNotAfterTime()) { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_VALIDITY_STATE_EXPIRED.get()); } else { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_VALIDITY_STATE_VALID.get()); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SIG_ALG.get( certificate.getSignatureAlgorithmNameOrOID())); if (verbose) { String signatureString; try { signatureString = toColonDelimitedHex(certificate.getSignatureValue().getBytes()); } catch (final Exception e) { Debug.debugException(e); signatureString = certificate.getSignatureValue().toString(); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SIG_VALUE.get()); for (final String line : StaticUtils.wrapLine(signatureString, 78)) { out(indent + " " + line); } } final String pkAlg; final String pkSummary = getPublicKeySummary( certificate.getPublicKeyAlgorithmOID(), certificate.getDecodedPublicKey(), certificate.getPublicKeyAlgorithmParameters()); if (pkSummary == null) { pkAlg = certificate.getPublicKeyAlgorithmNameOrOID(); } else { pkAlg = certificate.getPublicKeyAlgorithmNameOrOID() + " (" + pkSummary + ')'; } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_PK_ALG.get(pkAlg)); if (verbose) { printPublicKey(certificate.getEncodedPublicKey(), certificate.getDecodedPublicKey(), certificate.getPublicKeyAlgorithmParameters(), indent); if (certificate.getSubjectUniqueID() != null) { String subjectUniqueID; try { subjectUniqueID = toColonDelimitedHex( certificate.getSubjectUniqueID().getBytes()); } catch (final Exception e) { Debug.debugException(e); subjectUniqueID = certificate.getSubjectUniqueID().toString(); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SUBJECT_UNIQUE_ID.get()); for (final String line : StaticUtils.wrapLine(subjectUniqueID, 78)) { out(indent + " " + line); } } if (certificate.getIssuerUniqueID() != null) { String issuerUniqueID; try { issuerUniqueID = toColonDelimitedHex( certificate.getIssuerUniqueID().getBytes()); } catch (final Exception e) { Debug.debugException(e); issuerUniqueID = certificate.getIssuerUniqueID().toString(); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_ISSUER_UNIQUE_ID.get()); for (final String line : StaticUtils.wrapLine(issuerUniqueID, 78)) { out(indent + " " + line); } } printExtensions(certificate.getExtensions(), indent); } try { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_FINGERPRINT.get("SHA-1", toColonDelimitedHex(certificate.getSHA1Fingerprint()))); } catch (final Exception e) { Debug.debugException(e); } try { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_FINGERPRINT.get("SHA-256", toColonDelimitedHex(certificate.getSHA256Fingerprint()))); } catch (final Exception e) { Debug.debugException(e); } } /** * Prints a string representation of the provided certificate signing request * to standard output. * * @param csr The certificate signing request to be printed. * @param verbose Indicates whether to display verbose information about * the contents of the request. * @param indent The string to place at the beginning of each line to * indent that line. */ private void printCertificateSigningRequest( @NotNull final PKCS10CertificateSigningRequest csr, final boolean verbose, @NotNull final String indent) { out(indent + INFO_MANAGE_CERTS_PRINT_CSR_LABEL_VERSION.get( csr.getVersion().getName())); out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SUBJECT_DN.get( csr.getSubjectDN())); out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SIG_ALG.get( csr.getSignatureAlgorithmNameOrOID())); if (verbose) { String signatureString; try { signatureString = toColonDelimitedHex(csr.getSignatureValue().getBytes()); } catch (final Exception e) { Debug.debugException(e); signatureString = csr.getSignatureValue().toString(); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_SIG_VALUE.get()); for (final String line : StaticUtils.wrapLine(signatureString, 78)) { out(indent + " " + line); } } final String pkAlg; final String pkSummary = getPublicKeySummary(csr.getPublicKeyAlgorithmOID(), csr.getDecodedPublicKey(), csr.getPublicKeyAlgorithmParameters()); if (pkSummary == null) { pkAlg = csr.getPublicKeyAlgorithmNameOrOID(); } else { pkAlg = csr.getPublicKeyAlgorithmNameOrOID() + " (" + pkSummary + ')'; } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_PK_ALG.get(pkAlg)); if (verbose) { printPublicKey(csr.getEncodedPublicKey(), csr.getDecodedPublicKey(), csr.getPublicKeyAlgorithmParameters(), indent); printExtensions(csr.getExtensions(), indent); } } /** * Prints information about the provided public key. * * @param encodedPublicKey The encoded representation of the public key. * This must not be {@code null}. * @param decodedPublicKey The decoded representation of the public key, if * available. * @param parameters The public key algorithm parameters, if any. * @param indent The string to place at the beginning of each * line to indent that line. */ private void printPublicKey(@NotNull final ASN1BitString encodedPublicKey, @Nullable final DecodedPublicKey decodedPublicKey, @Nullable final ASN1Element parameters, @NotNull final String indent) { if (decodedPublicKey == null) { String pkString; try { pkString = toColonDelimitedHex(encodedPublicKey.getBytes()); } catch (final Exception e) { Debug.debugException(e); pkString = encodedPublicKey.toString(); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_ENCODED_PK.get()); for (final String line : StaticUtils.wrapLine(pkString, 78)) { out(indent + " " + line); } return; } if (decodedPublicKey instanceof RSAPublicKey) { final RSAPublicKey rsaPublicKey = (RSAPublicKey) decodedPublicKey; final byte[] modulusBytes = rsaPublicKey.getModulus().toByteArray(); int modulusSizeBits = modulusBytes.length * 8; if (((modulusBytes.length % 2) != 0) && (modulusBytes[0] == 0x00)) { modulusSizeBits -= 8; } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_RSA_MODULUS.get( modulusSizeBits)); final String modulusHex = toColonDelimitedHex(modulusBytes); for (final String line : StaticUtils.wrapLine(modulusHex, 78)) { out(indent + " " + line); } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_RSA_EXPONENT.get( toColonDelimitedHex( rsaPublicKey.getPublicExponent().toByteArray()))); } else if (decodedPublicKey instanceof EllipticCurvePublicKey) { final EllipticCurvePublicKey ecPublicKey = (EllipticCurvePublicKey) decodedPublicKey; out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EC_IS_COMPRESSED.get( String.valueOf(ecPublicKey.usesCompressedForm()))); out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EC_X.get( String.valueOf(ecPublicKey.getXCoordinate()))); if (ecPublicKey.getYCoordinate() == null) { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EC_Y_IS_EVEN.get( String.valueOf(ecPublicKey.yCoordinateIsEven()))); } else { out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EC_Y.get( String.valueOf(ecPublicKey.getYCoordinate()))); } } } /** * Retrieves a short summary of the provided public key, if available. For * RSA keys, this will be the modulus size in bits. For elliptic curve keys, * this will be the named curve, if available. * * @param publicKeyAlgorithmOID The OID that identifies the type of public * key. * @param publicKey The decoded public key. This may be * {@code null} if the decoded public key is * not available. * @param parameters The encoded public key algorithm parameters. * This may be {@code null} if no public key * algorithm parameters are available. * * @return A short summary of the provided public key, or {@code null} if * no summary is available. */ @NotNull() private static String getPublicKeySummary( @NotNull final OID publicKeyAlgorithmOID, @Nullable final DecodedPublicKey publicKey, @Nullable final ASN1Element parameters) { if (publicKey instanceof RSAPublicKey) { final RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; final byte[] modulusBytes = rsaPublicKey.getModulus().toByteArray(); int modulusSizeBits = modulusBytes.length * 8; if (((modulusBytes.length % 2) != 0) && (modulusBytes[0] == 0x00)) { modulusSizeBits -= 8; } return INFO_MANAGE_CERTS_GET_PK_SUMMARY_RSA_MODULUS_SIZE.get( modulusSizeBits); } else if ((parameters != null) && publicKeyAlgorithmOID.equals(PublicKeyAlgorithmIdentifier.EC.getOID())) { try { final OID namedCurveOID = parameters.decodeAsObjectIdentifier().getOID(); return NamedCurve.getNameOrOID(namedCurveOID); } catch (final Exception e) { Debug.debugException(e); } } return null; } /** * Prints information about the provided extensions. * * @param extensions The list of extensions to be printed. * @param indent The string to place at the beginning of each line to * indent that line. */ void printExtensions(@NotNull final List extensions, @NotNull final String indent) { if (extensions.isEmpty()) { return; } out(indent + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXTENSIONS.get()); for (final X509CertificateExtension extension : extensions) { if (extension instanceof AuthorityKeyIdentifierExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_AUTH_KEY_ID_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final AuthorityKeyIdentifierExtension e = (AuthorityKeyIdentifierExtension) extension; if (e.getKeyIdentifier() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_AUTH_KEY_ID_ID.get()); final String idHex = toColonDelimitedHex(e.getKeyIdentifier().getValue()); for (final String line : StaticUtils.wrapLine(idHex, 78)) { out(indent + " " + line); } } if (e.getAuthorityCertIssuer() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_AUTH_KEY_ID_ISSUER. get()); printGeneralNames(e.getAuthorityCertIssuer(), indent + " "); } if (e.getAuthorityCertSerialNumber() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_AUTH_KEY_ID_SERIAL.get( toColonDelimitedHex(e.getAuthorityCertSerialNumber(). toByteArray()))); } } else if (extension instanceof BasicConstraintsExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_BASIC_CONST_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final BasicConstraintsExtension e = (BasicConstraintsExtension) extension; out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_BASIC_CONST_IS_CA.get( String.valueOf(e.isCA()))); if (e.getPathLengthConstraint() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_BASIC_CONST_LENGTH.get( e.getPathLengthConstraint())); } } else if (extension instanceof CRLDistributionPointsExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_CRL_DP_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final CRLDistributionPointsExtension crlDPE = (CRLDistributionPointsExtension) extension; for (final CRLDistributionPoint dp : crlDPE.getCRLDistributionPoints()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_CRL_DP_HEADER.get()); if (dp.getFullName() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_CRL_DP_FULL_NAME. get()); printGeneralNames(dp.getFullName(), indent + " "); } if (dp.getNameRelativeToCRLIssuer() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_CRL_DP_REL_NAME.get( dp.getNameRelativeToCRLIssuer())); } if (! dp.getPotentialRevocationReasons().isEmpty()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_CRL_DP_REASON.get()); for (final CRLDistributionPointRevocationReason r : dp.getPotentialRevocationReasons()) { out(indent + " " + r.getName()); } } if (dp.getCRLIssuer() != null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_CRL_DP_CRL_ISSUER. get()); printGeneralNames(dp.getCRLIssuer(), indent + " "); } } } else if (extension instanceof ExtendedKeyUsageExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_EKU_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final ExtendedKeyUsageExtension e = (ExtendedKeyUsageExtension) extension; for (final OID oid : e.getKeyPurposeIDs()) { final ExtendedKeyUsageID id = ExtendedKeyUsageID.forOID(oid); if (id == null) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_EKU_ID.get(oid)); } else { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_EKU_ID.get( id.getName())); } } } else if (extension instanceof IssuerAlternativeNameExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IAN_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final IssuerAlternativeNameExtension e = (IssuerAlternativeNameExtension) extension; printGeneralNames(e.getGeneralNames(), indent + " "); } else if (extension instanceof KeyUsageExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_USAGES.get()); final KeyUsageExtension kue = (KeyUsageExtension) extension; if (kue.isDigitalSignatureBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_DS.get()); } if (kue.isNonRepudiationBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_NR.get()); } if (kue.isKeyEnciphermentBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_KE.get()); } if (kue.isDataEnciphermentBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_DE.get()); } if (kue.isKeyAgreementBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_KA.get()); } if (kue.isKeyCertSignBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_KCS.get()); } if (kue.isCRLSignBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_CRL_SIGN.get()); } if (kue.isEncipherOnlyBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_EO.get()); } if (kue.isDecipherOnlyBitSet()) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_KU_DO.get()); } } else if (extension instanceof SubjectAlternativeNameExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_SAN_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final SubjectAlternativeNameExtension e = (SubjectAlternativeNameExtension) extension; printGeneralNames(e.getGeneralNames(), indent + " "); } else if (extension instanceof SubjectKeyIdentifierExtension) { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_SKI_EXT.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final SubjectKeyIdentifierExtension e = (SubjectKeyIdentifierExtension) extension; final String idHex = toColonDelimitedHex(e.getKeyIdentifier().getValue()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_SKI_ID.get()); for (final String line : StaticUtils.wrapLine(idHex, 78)) { out(indent + " " + line); } } else { out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_GENERIC.get()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_OID.get( extension.getOID().toString())); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_IS_CRITICAL.get( String.valueOf(extension.isCritical()))); final String valueHex = toColonDelimitedHex(extension.getValue()); out(indent + " " + INFO_MANAGE_CERTS_PRINT_CERT_LABEL_EXT_VALUE.get()); getOut().print(StaticUtils.toHexPlusASCII(extension.getValue(), (indent.length() + 15))); } } } /** * Prints information about the contents of the provided general names object. * * @param generalNames The general names object to print. * @param indent The string to place at the beginning of each line to * indent that line. */ private void printGeneralNames(@NotNull final GeneralNames generalNames, @NotNull final String indent) { for (final String dnsName : generalNames.getDNSNames()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_DNS.get(dnsName)); } for (final InetAddress ipAddress : generalNames.getIPAddresses()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_IP.get( ipAddress.getHostAddress())); } for (final String name : generalNames.getRFC822Names()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_RFC_822_NAME.get(name)); } for (final DN dn : generalNames.getDirectoryNames()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_DIRECTORY_NAME.get( String.valueOf(dn))); } for (final String uri : generalNames.getUniformResourceIdentifiers()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_URI.get(uri)); } for (final OID oid : generalNames.getRegisteredIDs()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_REGISTERED_ID.get( oid.toString())); } if (! generalNames.getOtherNames().isEmpty()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_OTHER_NAME_COUNT.get( generalNames.getOtherNames().size())); } if (! generalNames.getX400Addresses().isEmpty()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_X400_ADDR_COUNT.get( generalNames.getX400Addresses().size())); } if (! generalNames.getEDIPartyNames().isEmpty()) { out(indent + INFO_MANAGE_CERTS_GENERAL_NAMES_LABEL_EDI_PARTY_NAME_COUNT.get( generalNames.getEDIPartyNames().size())); } } /** * Writes a PEM-encoded representation of the provided encoded certificate to * the given print stream. * * @param printStream The print stream to which the PEM-encoded * certificate should be written. It must not be * {@code null}. * @param encodedCertificate The bytes that comprise the encoded * certificate. It must not be {@code null}. */ private static void writePEMCertificate( @NotNull final PrintStream printStream, @NotNull final byte[] encodedCertificate) { final String certBase64 = Base64.encode(encodedCertificate); printStream.println("-----BEGIN CERTIFICATE-----"); for (final String line : StaticUtils.wrapLine(certBase64, 64)) { printStream.println(line); } printStream.println("-----END CERTIFICATE-----"); } /** * Writes a PEM-encoded representation of the provided encoded certificate * signing request to the given print stream. * * @param printStream The print stream to which the PEM-encoded certificate * signing request should be written. It must not be * {@code null}. * @param encodedCSR The bytes that comprise the encoded certificate * signing request. It must not be {@code null}. */ private static void writePEMCertificateSigningRequest( @NotNull final PrintStream printStream, @NotNull final byte[] encodedCSR) { final String certBase64 = Base64.encode(encodedCSR); printStream.println("-----BEGIN CERTIFICATE REQUEST-----"); for (final String line : StaticUtils.wrapLine(certBase64, 64)) { printStream.println(line); } printStream.println("-----END CERTIFICATE REQUEST-----"); } /** * Writes a PEM-encoded representation of the provided encoded private key to * the given print stream. * * @param printStream The print stream to which the PEM-encoded * private key should be written. It must not be * {@code null}. * @param encodedPrivateKey The bytes that comprise the encoded private * key. It must not be {@code null}. * @param encryptionPassword The password to use to encrypt the private key. * It may be {@code null} if the private key * should not be encrypted. * * @throws LDAPException If a problem occurs while trying write the private * key. */ private static void writePEMPrivateKey( @NotNull final PrintStream printStream, @NotNull final byte[] encodedPrivateKey, @Nullable final char[] encryptionPassword) throws LDAPException { if (encryptionPassword == null) { final String certBase64 = Base64.encode(encodedPrivateKey); printStream.println("-----BEGIN PRIVATE KEY-----"); for (final String line : StaticUtils.wrapLine(certBase64, 64)) { printStream.println(line); } printStream.println("-----END PRIVATE KEY-----"); } else { final byte[] encryptedPrivateKey; try { encryptedPrivateKey = PKCS8EncryptionHandler.encryptPrivateKey( encodedPrivateKey, encryptionPassword, new PKCS8EncryptionProperties()); } catch (final CertException e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, e.getMessage(), e); } final String encryptedCertBase64 = Base64.encode(encryptedPrivateKey); printStream.println("-----BEGIN ENCRYPTED PRIVATE KEY-----"); for (final String line : StaticUtils.wrapLine(encryptedCertBase64, 64)) { printStream.println(line); } printStream.println("-----END ENCRYPTED PRIVATE KEY-----"); } } /** * Displays the keytool command that can be invoked to produce approximately * equivalent functionality. * * @param keytoolArgs The arguments to provide to the keytool command. */ private void displayKeytoolCommand(@NotNull final List keytoolArgs) { final StringBuilder buffer = new StringBuilder(); buffer.append("# keytool"); boolean lastWasArgName = false; for (final String arg : keytoolArgs) { if (arg.startsWith("-")) { buffer.append(' '); buffer.append(StaticUtils.getCommandLineContinuationString()); buffer.append(StaticUtils.EOL); buffer.append("# "); buffer.append(arg); lastWasArgName = true; } else if (lastWasArgName) { buffer.append(' '); buffer.append(StaticUtils.cleanExampleCommandLineArgument(arg)); lastWasArgName = false; } else { buffer.append(' '); buffer.append(StaticUtils.getCommandLineContinuationString()); buffer.append(StaticUtils.EOL); buffer.append("# "); buffer.append(arg); lastWasArgName = false; } } out(); out(INFO_MANAGE_CERTS_APPROXIMATE_KEYTOOL_COMMAND.get()); out(buffer); out(); } /** * Retrieves the path to the target key store file. * * @return The path to the target key store file, or {@code null} if no * keystore path was configured. */ @Nullable() private File getKeystorePath() { return getKeystorePath("keystore"); } /** * Retrieves the path to the target key store file. * * @param keystoreArgumentName The name of the argument used to specify the * path to the target key store. * * @return The path to the target keystore file, or {@code null} if no * keystore path was configured. */ @Nullable() private File getKeystorePath(@NotNull final String keystoreArgumentName) { final FileArgument keystoreArgument = subCommandParser.getFileArgument(keystoreArgumentName); if ((keystoreArgument != null) && keystoreArgument.isPresent()) { return keystoreArgument.getValue(); } final BooleanArgument useJVMDefaultTrustStoreArgument = subCommandParser.getBooleanArgument("useJVMDefaultTrustStore"); if ((useJVMDefaultTrustStoreArgument != null) && useJVMDefaultTrustStoreArgument.isPresent()) { return JVM_DEFAULT_CACERTS_FILE; } return null; } /** * Retrieves the password needed to access the keystore. * * @param keystoreFile The path to the keystore file for which to get the * password. * * @return The password needed to access the keystore, or {@code null} if * no keystore password was configured. * * @throws LDAPException If a problem is encountered while trying to get the * keystore password. */ @Nullable() private char[] getKeystorePassword(@NotNull final File keystoreFile) throws LDAPException { return getKeystorePassword(keystoreFile, null); } /** * Retrieves the password needed to access the keystore. * * @param keystoreFile The path to the keystore file for which to get the * password. * @param prefix The prefix string to use for the arguments. This may * be {@code null} if no prefix is needed. * * @return The password needed to access the keystore, or {@code null} if * no keystore password was configured. * * @throws LDAPException If a problem is encountered while trying to get the * keystore password. */ @Nullable() private char[] getKeystorePassword(@NotNull final File keystoreFile, @Nullable final String prefix) throws LDAPException { final String prefixDash; if (prefix == null) { prefixDash = ""; } else { prefixDash = prefix + '-'; } final StringArgument keystorePasswordArgument = subCommandParser.getStringArgument(prefixDash + "keystore-password"); if ((keystorePasswordArgument != null) && keystorePasswordArgument.isPresent()) { final char[] keystorePWChars = keystorePasswordArgument.getValue().toCharArray(); if ((! keystoreFile.exists()) && (keystorePWChars.length < 6)) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_GET_KS_PW_TOO_SHORT.get()); } return keystorePWChars; } final FileArgument keystorePasswordFileArgument = subCommandParser.getFileArgument( prefixDash + "keystore-password-file"); if ((keystorePasswordFileArgument != null) && keystorePasswordFileArgument.isPresent()) { final File f = keystorePasswordFileArgument.getValue(); try { final char[] passwordChars = getPasswordFileReader().readPassword(f); if (passwordChars.length < 6) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_GET_KS_PW_TOO_SHORT.get()); } return passwordChars; } catch (final LDAPException e) { Debug.debugException(e); throw e; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_KS_PW_ERROR_READING_FILE.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } final BooleanArgument promptArgument = subCommandParser.getBooleanArgument( "prompt-for-" + prefixDash + "keystore-password"); if ((promptArgument != null) && promptArgument.isPresent()) { out(); if (keystoreFile.exists() && (! "new".equals(prefix))) { // We're only going to prompt once. if ((prefix != null) && prefix.equals("current")) { return promptForPassword( INFO_MANAGE_CERTS_KEY_KS_PW_EXISTING_CURRENT_PROMPT.get( keystoreFile.getAbsolutePath()), false); } else { return promptForPassword( INFO_MANAGE_CERTS_KEY_KS_PW_EXISTING_PROMPT.get( keystoreFile.getAbsolutePath()), false); } } else { // We're creating a new keystore, so we should prompt for the password // twice to prevent setting the wrong password because of a typo. while (true) { final String prompt1; if ("new".equals(prefix)) { prompt1 = INFO_MANAGE_CERTS_KEY_KS_PW_EXISTING_NEW_PROMPT.get(); } else { prompt1 = INFO_MANAGE_CERTS_KEY_KS_PW_NEW_PROMPT_1.get( keystoreFile.getAbsolutePath()); } final char[] pwChars = promptForPassword(prompt1, false); if (pwChars.length < 6) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GET_KS_PW_TOO_SHORT.get()); err(); continue; } final char[] confirmChars = promptForPassword( INFO_MANAGE_CERTS_KEY_KS_PW_NEW_PROMPT_2.get(), true); if (Arrays.equals(pwChars, confirmChars)) { Arrays.fill(confirmChars, '\u0000'); return pwChars; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_KEY_KS_PW_PROMPT_MISMATCH.get()); err(); } } } } return null; } /** * Retrieves the password used to encrypt a private key. * * @param forDecrypt Indicates whether the password will be used to decrypt * the private key rather than to encrypt it. * * @return The password used to encrypt a private key, or {@code null} if no * encryption password was specified. * * @throws LDAPException If a problem is encountered while trying to get the * keystore password. */ @Nullable() private char[] getPrivateKeyEncryptionPassword(final boolean forDecrypt) throws LDAPException { final StringArgument passwordArgument = subCommandParser.getStringArgument("encryption-password"); if ((passwordArgument != null) && passwordArgument.isPresent()) { return passwordArgument.getValue().toCharArray(); } final FileArgument passwordFileArgument = subCommandParser.getFileArgument("encryption-password-file"); if ((passwordFileArgument != null) && passwordFileArgument.isPresent()) { final File f = passwordFileArgument.getValue(); try { return getPasswordFileReader().readPassword(f); } catch (final LDAPException e) { Debug.debugException(e); throw e; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_PK_ENC_PW_ERROR_READING_FILE.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } final BooleanArgument promptArgument = subCommandParser.getBooleanArgument( "prompt-for-encryption-password"); if ((promptArgument != null) && promptArgument.isPresent()) { out(); if (forDecrypt) { // We'll be decrypting an existing private key, so we only need to // prompt for the password once. return promptForPassword( INFO_MANAGE_CERTS_GET_PK_ENC_PW_PROMPT_DECRYPT.get(), false); } else { // We'll be encrypting the private key, so we need to prompt twice to // confirm that the entered password is what the user intended. while (true) { final char[] pwChars = promptForPassword( INFO_MANAGE_CERTS_GET_PK_ENC_PW_PROMPT_ENCRYPT_1.get(), false); final char[] confirmChars = promptForPassword( INFO_MANAGE_CERTS_GET_PK_ENC_PW_PROMPT_ENCRYPT_2.get(), true); if (Arrays.equals(pwChars, confirmChars)) { Arrays.fill(confirmChars, '\u0000'); return pwChars; } else { wrapErr(0, WRAP_COLUMN, INFO_MANAGE_CERTS_GET_PK_ENC_PW_PROMPT_MISMATCH.get()); err(); } } } } return null; } /** * Prompts for a password and retrieves the value that the user entered. * * @param prompt The prompt to display to the user. * @param allowEmpty Indicates whether to allow the password to be empty. * * @return The password that was read, or an empty array if the user did not * type a password before pressing ENTER. * * @throws LDAPException If a problem is encountered while reading the * password. */ @NotNull() private char[] promptForPassword(@NotNull final String prompt, final boolean allowEmpty) throws LDAPException { final Iterator iterator = StaticUtils.wrapLine(prompt, WRAP_COLUMN).iterator(); while (iterator.hasNext()) { final String line = iterator.next(); if (iterator.hasNext()) { out(line); } else { getOut().print(line); } } final char[] passwordChars = PasswordReader.readPasswordChars(); if ((passwordChars.length == 0) && (! allowEmpty)) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_PROMPT_FOR_PW_EMPTY_PW.get()); err(); return promptForPassword(prompt, allowEmpty); } return passwordChars; } /** * Prompts the user for a yes or no response. * * @param prompt The prompt to display to the end user. * * @return {@code true} if the user chooses the "yes" response, or * {@code false} if the user chooses the "no" throws. * * @throws LDAPException If a problem is encountered while reading data from * the client. */ private boolean promptForYesNo(@NotNull final String prompt) throws LDAPException { while (true) { final List lines = StaticUtils.wrapLine((prompt + ' '), WRAP_COLUMN); final Iterator lineIterator = lines.iterator(); while (lineIterator.hasNext()) { final String line = lineIterator.next(); if (lineIterator.hasNext()) { out(line); } else { getOut().print(line); } } try { final String response = readLineFromIn(); if (response.equalsIgnoreCase("yes") || response.equalsIgnoreCase("y")) { return true; } else if (response.equalsIgnoreCase("no") || response.equalsIgnoreCase("n")) { return false; } else { err(); wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_PROMPT_FOR_YES_NO_INVALID_RESPONSE.get()); err(); } } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_PROMPT_FOR_YES_NO_READ_ERROR.get( StaticUtils.getExceptionMessage(e)), e); } } } /** * Reads a line of input from standard input. * * @return The line read from standard input. * * @throws IOException If a problem is encountered while reading from * standard input. */ @NotNull() private String readLineFromIn() throws IOException { final ByteStringBuffer buffer = new ByteStringBuffer(); while (true) { final int byteRead = in.read(); if (byteRead < 0) { if (buffer.isEmpty()) { return null; } else { return buffer.toString(); } } if (byteRead == '\n') { return buffer.toString(); } else if (byteRead == '\r') { final int nextByteRead = in.read(); Validator.ensureTrue(((nextByteRead < 0) || (nextByteRead == '\n')), "ERROR: Read a carriage return from standard input that was " + "not followed by a new line."); return buffer.toString(); } else { buffer.append((byte) (byteRead & 0xFF)); } } } /** * Retrieves the password needed to access the private key. * * @param keystore The keystore that contains the target private * key. This must not be {@code null}. * @param alias The alias of the target private key. This must * not be {@code null}. * @param keystorePassword The keystore password to use if no specific * private key password was provided. * * @return The password needed to access the private key, or the provided * keystore password if no arguments were provided to specify a * different private key password. * * @throws LDAPException If a problem is encountered while trying to get the * private key password. */ @Nullable() private char[] getPrivateKeyPassword(@NotNull final KeyStore keystore, @NotNull final String alias, @Nullable final char[] keystorePassword) throws LDAPException { return getPrivateKeyPassword(keystore, alias, null, keystorePassword); } /** * Retrieves the password needed to access the private key. * * @param keystore The keystore that contains the target private * key. This must not be {@code null}. * @param alias The alias of the target private key. This must * not be {@code null}. * @param prefix The prefix string to use for the arguments. This * may be {@code null} if no prefix is needed. * @param keystorePassword The keystore password to use if no specific * private key password was provided. * * @return The password needed to access the private key, or the provided * keystore password if no arguments were provided to specify a * different private key password. * * @throws LDAPException If a problem is encountered while trying to get the * private key password. */ @Nullable() private char[] getPrivateKeyPassword(@NotNull final KeyStore keystore, @NotNull final String alias, @Nullable final String prefix, @Nullable final char[] keystorePassword) throws LDAPException { final String prefixDash; if (prefix == null) { prefixDash = ""; } else { prefixDash = prefix + '-'; } final StringArgument privateKeyPasswordArgument = subCommandParser.getStringArgument( prefixDash + "private-key-password"); if ((privateKeyPasswordArgument != null) && privateKeyPasswordArgument.isPresent()) { final char[] pkPasswordChars = privateKeyPasswordArgument.getValue().toCharArray(); if ((pkPasswordChars.length < 6) && (! (hasCertificateAlias(keystore, alias) || hasKeyAlias(keystore, alias)))) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_TOO_SHORT.get()); } return pkPasswordChars; } final FileArgument privateKeyPasswordFileArgument = subCommandParser.getFileArgument( prefixDash + "private-key-password-file"); if ((privateKeyPasswordFileArgument != null) && privateKeyPasswordFileArgument.isPresent()) { final File f = privateKeyPasswordFileArgument.getValue(); try { final char[] passwordChars = getPasswordFileReader().readPassword(f); if (passwordChars.length < 6) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_EMPTY_FILE.get(f.getAbsolutePath())); } return passwordChars; } catch (final LDAPException e) { Debug.debugException(e); throw e; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_ERROR_READING_FILE.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } final BooleanArgument promptArgument = subCommandParser.getBooleanArgument( "prompt-for-" + prefixDash + "private-key-password"); if ((promptArgument != null) && promptArgument.isPresent()) { out(); try { if ((hasKeyAlias(keystore, alias) || hasCertificateAlias(keystore, alias)) && (! "new".equals(prefix)) && (! "destination".equals(prefix))) { // This means that the private key already exists, so we just need to // prompt once. final String prompt; if ("current".equals(prefix)) { prompt = INFO_MANAGE_CERTS_GET_PK_PW_CURRENT_PROMPT.get(alias); } else { prompt = INFO_MANAGE_CERTS_GET_PK_PW_EXISTING_PROMPT.get(alias); } return promptForPassword(prompt, false); } else { // This means that we'll be creating a new private key, so we need to // prompt twice. while (true) { final String prompt; if ("new".equals(prefix)) { prompt = INFO_MANAGE_CERTS_GET_PK_PW_NEW_PROMPT.get(); } else { prompt = INFO_MANAGE_CERTS_GET_PK_PW_NEW_PROMPT_1.get(alias); } final char[] pwChars = promptForPassword(prompt, false); if (pwChars.length < 6) { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GET_PK_PW_TOO_SHORT.get()); err(); continue; } final char[] confirmChars = promptForPassword( INFO_MANAGE_CERTS_GET_PK_PW_NEW_PROMPT_2.get(), true); if (Arrays.equals(pwChars, confirmChars)) { Arrays.fill(confirmChars, '\u0000'); return pwChars; } else { wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GET_PK_PW_PROMPT_MISMATCH.get()); err(); } } } } catch (final LDAPException le) { Debug.debugException(le); throw le; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_PROMPT_ERROR.get(alias, StaticUtils.getExceptionMessage(e)), e); } } return keystorePassword; } /** * Infers the keystore type from the provided keystore file. * * @param keystorePath The path to the file to examine. * * @return The keystore type inferred from the provided keystore file. * * @throws LDAPException If a problem is encountered while trying to infer * the keystore type. */ @NotNull() private String inferKeystoreType(@NotNull final File keystorePath) throws LDAPException { return inferKeystoreType(keystorePath, null); } /** * Infers the keystore type from the provided keystore file. * * @param keystorePath The path to the file to examine. * @param prefix The prefix string to use for the arguments. This * may be {@code null} if no prefix is needed. * * @return The keystore type inferred from the provided keystore file. * * @throws LDAPException If a problem is encountered while trying to infer * the keystore type. */ @NotNull() private String inferKeystoreType(@NotNull final File keystorePath, @Nullable final String prefix) throws LDAPException { // If the keystore type argument was specified, then use its value. final StringArgument keystoreTypeArgument; if (prefix == null) { keystoreTypeArgument = subCommandParser.getStringArgument("keystore-type"); } else { keystoreTypeArgument = subCommandParser.getStringArgument(prefix + "-keystore-type"); } if ((keystoreTypeArgument != null) && keystoreTypeArgument.isPresent()) { final String ktaValue = keystoreTypeArgument.getValue(); if (ktaValue.equalsIgnoreCase("PKCS11") || ktaValue.equalsIgnoreCase("PKCS 11") || ktaValue.equalsIgnoreCase("PKCS#11") || ktaValue.equalsIgnoreCase("PKCS #11")) { return CryptoHelper.KEY_STORE_TYPE_PKCS_11; } else if (ktaValue.equalsIgnoreCase("PKCS12") || ktaValue.equalsIgnoreCase("PKCS 12") || ktaValue.equalsIgnoreCase("PKCS#12") || ktaValue.equalsIgnoreCase("PKCS #12")) { return CryptoHelper.KEY_STORE_TYPE_PKCS_12; } else if (ktaValue.equalsIgnoreCase(BCFKS_KEYSTORE_TYPE)) { return BCFKS_KEYSTORE_TYPE; } else { return CryptoHelper.KEY_STORE_TYPE_JKS; } } // If we've gotten here, then the keystore type was not explicitly specified // so we will need to infer it. If the LDAP SDK is running in FIPS mode, // then we'll always use the BCFKS key store type. if (CryptoHelper.usingFIPSMode()) { return BouncyCastleFIPSHelper.FIPS_KEY_STORE_TYPE; } // If the key store file doesn't exist, then we must be creating it. Use // the default key store type. if (! keystorePath.exists()) { return DEFAULT_KEYSTORE_TYPE; } try { return CryptoHelper.inferKeyStoreType(keystorePath); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, e.getMessage(), e); } } /** * Retrieves a user-friendly representation of the provided keystore type. * * @param keystoreType The keystore type for which to get the user-friendly * name. * * @return "JKS" if the provided keystore type is for a JKS keystore, * "PKCS #12" if the provided keystore type is for a PKCS #12 * keystore, or the provided string if it is for some other keystore * type. */ @NotNull() static String getUserFriendlyKeystoreType(@NotNull final String keystoreType) { if (keystoreType.equalsIgnoreCase("JKS")) { return "JKS"; } else if (keystoreType.equalsIgnoreCase("PKCS11") || keystoreType.equalsIgnoreCase("PKCS 11") || keystoreType.equalsIgnoreCase("PKCS#11") || keystoreType.equalsIgnoreCase("PKCS #11")) { return "PKCS #11"; } else if (keystoreType.equalsIgnoreCase("PKCS12") || keystoreType.equalsIgnoreCase("PKCS 12") || keystoreType.equalsIgnoreCase("PKCS#12") || keystoreType.equalsIgnoreCase("PKCS #12")) { return "PKCS #12"; } else if (keystoreType.equalsIgnoreCase(BCFKS_KEYSTORE_TYPE)) { return BCFKS_KEYSTORE_TYPE; } else { return keystoreType; } } /** * Gets access to a keystore based on information included in command-line * arguments. * * @param keystoreType The keystore type for the keystore to access. * @param keystorePath The path to the keystore file. * @param keystorePassword The password to use to access the keystore. * * @return The configured keystore instance. * * @throws LDAPException If it is not possible to access the keystore. */ @NotNull() static KeyStore getKeystore(@NotNull final String keystoreType, @NotNull final File keystorePath, @Nullable final char[] keystorePassword) throws LDAPException { // Instantiate a keystore instance of the desired keystore type. final KeyStore keystore; try { if (keystoreType.equals(CryptoHelper.KEY_STORE_TYPE_PKCS_11)) { // NOTE: For PKCS #11 key store types, the key store path will be // treated as the path to the provider configuration file. final Provider pkcs11Provider = PKCS11KeyManager.getProvider(null, keystorePath, keystoreType, true); keystore = CryptoHelper.getKeyStore(keystoreType, pkcs11Provider); } else if (keystoreType.equals(BCFKS_KEYSTORE_TYPE)) { keystore = CryptoHelper.getKeyStore(keystoreType, BouncyCastleFIPSHelper.getBouncyCastleFIPSProvider()); } else { keystore = CryptoHelper.getKeyStore(keystoreType); } } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_CANNOT_INSTANTIATE_KS_TYPE.get(keystoreType, StaticUtils.getExceptionMessage(e)), e); } // Get an input stream that may be used to access the keystore. final InputStream inputStream; try { if (keystorePath.exists() && (! keystoreType.equals(CryptoHelper.KEY_STORE_TYPE_PKCS_11))) { inputStream = new FileInputStream(keystorePath); } else { inputStream = null; } } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_CANNOT_OPEN_KS_FILE_FOR_READING.get( keystorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } try { keystore.load(inputStream, keystorePassword); } catch (final Exception e) { Debug.debugException(e); final Throwable cause = e.getCause(); if ((e instanceof IOException) && (cause != null) && (cause instanceof UnrecoverableKeyException) && (keystorePassword != null)) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_CANNOT_LOAD_KS_WRONG_PW.get( keystorePath.getAbsolutePath()), e); } else { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_ERROR_CANNOT_LOAD_KS.get( keystorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } finally { try { if (inputStream != null) { inputStream.close(); } } catch (final Exception e) { Debug.debugException(e); } } return keystore; } /** * Reads all of the certificates contained in the specified file. The file * must exist and may contain zero or more certificates that are either all in * PEM format or all in DER format. * * @param f The path to the certificate file to read. It must not be * {@code null}. * * @return A list of the certificates read from the specified file. * * @throws LDAPException If a problem is encountered while reading * certificates from the specified file. */ @NotNull() public static List readCertificatesFromFile( @NotNull final File f) throws LDAPException { // Read the first byte of the file to see if it contains DER-formatted data, // which we can determine by seeing if the first byte is 0x30. try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(f))) { inputStream.mark(1); final int firstByte = inputStream.read(); if (firstByte < 0) { // This means that the file is empty. return Collections.emptyList(); } else { inputStream.reset(); } final ArrayList certList = new ArrayList<>(5); if ((firstByte & 0xFF) == 0x30) { // It is a DER-encoded file. Read ASN.1 elements and decode them as // X.509 certificates. while (true) { final ASN1Element certElement; try { certElement = ASN1Element.readFrom(inputStream); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_DER_NOT_VALID_ASN1.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } if (certElement == null) { // We've reached the end of the input stream. return certList; } try { certList.add(new X509Certificate(certElement.encode())); } catch (final CertException e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_DER_NOT_VALID_CERT.get( f.getAbsolutePath(), e.getMessage()), e); } } } else { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { boolean inCert = false; final StringBuilder buffer = new StringBuilder(); while (true) { String line = reader.readLine(); if (line == null) { if (inCert) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_EOF_WITHOUT_END.get( f.getAbsolutePath())); } return certList; } line = line.trim(); if (line.isEmpty() || line.startsWith("#")) { continue; } if (line.equals("-----BEGIN CERTIFICATE-----")) { if (inCert) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_MULTIPLE_BEGIN.get( f.getAbsolutePath())); } else { inCert = true; } } else if (line.equals("-----END CERTIFICATE-----")) { if (! inCert) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_END_WITHOUT_BEGIN. get(f.getAbsolutePath())); } inCert = false; final byte[] certBytes; try { certBytes = Base64.decode(buffer.toString()); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_PEM_CERT_NOT_BASE64. get(f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } try { certList.add(new X509Certificate(certBytes)); } catch (final CertException e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_PEM_CERT_NOT_CERT. get(f.getAbsolutePath(), e.getMessage()), e); } buffer.setLength(0); } else if (inCert) { buffer.append(line); } else { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_DATA_WITHOUT_BEGIN.get( f.getAbsolutePath())); } } } } } catch (final LDAPException le) { Debug.debugException(le); throw le; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_READ_CERTS_FROM_FILE_READ_ERROR.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } /** * Reads a private key from the specified file. The file must exist and must * contain exactly one PEM-encoded or DER-encoded PKCS #8 private key. * * @param f The path to the private key file to read. It * must not be {@code null}. * @param encryptionPassword The password to use to encrypt the private key. * It may be {@code null} if the private key is * not encrypted. * * @return The private key read from the file. * * @throws LDAPException If a problem is encountered while reading the * private key. */ @NotNull() static PKCS8PrivateKey readPrivateKeyFromFile(@NotNull final File f, @Nullable final char[] encryptionPassword) throws LDAPException { // Read the first byte of the file to see if it contains DER-formatted data, // which we can determine by seeing if the first byte is 0x30. try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(f))) { inputStream.mark(1); final int firstByte = inputStream.read(); if (firstByte < 0) { // This means that the file is empty. throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_EMPTY_FILE.get( f.getAbsolutePath())); } else { inputStream.reset(); } PKCS8PrivateKey privateKey = null; if ((firstByte & 0xFF) == 0x30) { // It is a DER-encoded file. Read an ASN.1 element and decode it as a // certificate. while (true) { final ASN1Element pkElement; try { pkElement = ASN1Element.readFrom(inputStream); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_DER_NOT_VALID_ASN1.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } if (pkElement == null) { // We've reached the end of the input stream. if (privateKey == null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_EMPTY_FILE.get( f.getAbsolutePath())); } else { return privateKey; } } else if (privateKey == null) { try { if (encryptionPassword == null) { privateKey = new PKCS8PrivateKey(pkElement.encode()); } else { privateKey = PKCS8EncryptionHandler.decryptPrivateKey( pkElement.encode(), encryptionPassword); } } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_DER_NOT_VALID_PK.get( f.getAbsolutePath(), e.getMessage()), e); } } else { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_MULTIPLE_KEYS.get( f.getAbsolutePath())); } } } else { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { boolean inKey = false; boolean isRSAKey = false; boolean isEncryptedKey = false; final StringBuilder buffer = new StringBuilder(); while (true) { String line = reader.readLine(); if (line == null) { if (inKey) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_EOF_WITHOUT_END.get( f.getAbsolutePath())); } if (privateKey == null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_EMPTY_FILE.get( f.getAbsolutePath())); } else { return privateKey; } } line = line.trim(); if (line.isEmpty() || line.startsWith("#")) { continue; } if (line.equals("-----BEGIN PRIVATE KEY-----") || line.equals("-----BEGIN RSA PRIVATE KEY-----") || line.equals("-----BEGIN ENCRYPTED PRIVATE KEY-----")) { if (inKey) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_MULTIPLE_BEGIN.get( f.getAbsolutePath())); } else if (privateKey != null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_MULTIPLE_KEYS.get( f.getAbsolutePath())); } else { inKey = true; if (line.equals("-----BEGIN RSA PRIVATE KEY-----")) { isRSAKey = true; } else if (line.equals("-----BEGIN ENCRYPTED PRIVATE KEY-----")) { isEncryptedKey = true; if (encryptionPassword == null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_PK_ENCRYPTED_NO_PW. get(f.getAbsolutePath())); } } } } else if (line.equals("-----END PRIVATE KEY-----") || line.equals("-----END RSA PRIVATE KEY-----") || line.equals("-----END ENCRYPTED PRIVATE KEY-----")) { if (! inKey) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_END_WITHOUT_BEGIN.get( f.getAbsolutePath())); } inKey = false; byte[] pkBytes; try { pkBytes = Base64.decode(buffer.toString()); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_PEM_PK_NOT_BASE64.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } if (isRSAKey) { pkBytes = PKCS8PrivateKey.wrapRSAPrivateKey(pkBytes); } try { if (isEncryptedKey) { privateKey = PKCS8EncryptionHandler. decryptPrivateKey(pkBytes, encryptionPassword); } else { privateKey = new PKCS8PrivateKey(pkBytes); } } catch (final CertException e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_PEM_PK_NOT_PK.get( f.getAbsolutePath(), e.getMessage()), e); } buffer.setLength(0); } else if (inKey) { buffer.append(line); } else { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_DATA_WITHOUT_BEGIN.get( f.getAbsolutePath())); } } } } } catch (final LDAPException le) { Debug.debugException(le); throw le; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_READ_PK_FROM_FILE_READ_ERROR.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } /** * Reads a certificate signing request from the specified file. The file must * exist and must contain exactly one PEM-encoded or DER-encoded PKCS #10 * certificate signing request. * * @param f The path to the private key file to read. It must not be * {@code null}. * * @return The certificate signing request read from the file. * * @throws LDAPException If a problem is encountered while reading the * certificate signing request. */ @NotNull() public static PKCS10CertificateSigningRequest readCertificateSigningRequestFromFile( @NotNull final File f) throws LDAPException { // Read the first byte of the file to see if it contains DER-formatted data, // which we can determine by seeing if the first byte is 0x30. try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(f))) { inputStream.mark(1); final int firstByte = inputStream.read(); if (firstByte < 0) { // This means that the file is empty. throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_EMPTY_FILE.get( f.getAbsolutePath())); } else { inputStream.reset(); } PKCS10CertificateSigningRequest csr = null; if ((firstByte & 0xFF) == 0x30) { // It is a DER-encoded file. Read an ASN.1 element and decode it as a // certificate. while (true) { final ASN1Element csrElement; try { csrElement = ASN1Element.readFrom(inputStream); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_DER_NOT_VALID_ASN1.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } if (csrElement == null) { // We've reached the end of the input stream. if (csr == null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_EMPTY_FILE.get( f.getAbsolutePath())); } else { return csr; } } else if (csr == null) { try { csr = new PKCS10CertificateSigningRequest(csrElement.encode()); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_DER_NOT_VALID_CSR.get( f.getAbsolutePath(), e.getMessage()), e); } } else { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_MULTIPLE_CSRS.get( f.getAbsolutePath())); } } } else { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { boolean inCSR = false; final StringBuilder buffer = new StringBuilder(); while (true) { String line = reader.readLine(); if (line == null) { if (inCSR) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_EOF_WITHOUT_END.get( f.getAbsolutePath())); } if (csr == null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_EMPTY_FILE.get( f.getAbsolutePath())); } else { return csr; } } line = line.trim(); if (line.isEmpty() || line.startsWith("#")) { continue; } if (line.equals("-----BEGIN CERTIFICATE REQUEST-----") || line.equals("-----BEGIN NEW CERTIFICATE REQUEST-----")) { if (inCSR) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_MULTIPLE_BEGIN.get( f.getAbsolutePath())); } else if (csr != null) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_MULTIPLE_CSRS.get( f.getAbsolutePath())); } else { inCSR = true; } } else if (line.equals("-----END CERTIFICATE REQUEST-----") || line.equals("-----END NEW CERTIFICATE REQUEST-----")) { if (! inCSR) { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_END_WITHOUT_BEGIN.get( f.getAbsolutePath())); } inCSR = false; final byte[] csrBytes; try { csrBytes = Base64.decode(buffer.toString()); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_PEM_CSR_NOT_BASE64.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } try { csr = new PKCS10CertificateSigningRequest(csrBytes); } catch (final CertException e) { Debug.debugException(e); throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_PEM_CSR_NOT_CSR.get( f.getAbsolutePath(), e.getMessage()), e); } buffer.setLength(0); } else if (inCSR) { buffer.append(line); } else { throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_DATA_WITHOUT_BEGIN.get( f.getAbsolutePath())); } } } } } catch (final LDAPException le) { Debug.debugException(le); throw le; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_READ_CSR_FROM_FILE_READ_ERROR.get( f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } /** * Retrieves a colon-delimited hexadecimal representation of the contents of * the provided byte array. * * @param bytes The byte array for which to get the hexadecimal * representation. It must not be {@code null}. * * @return A colon-delimited hexadecimal representation of the contents of * the provided byte array. */ @NotNull() private static String toColonDelimitedHex(@NotNull final byte... bytes) { final StringBuilder buffer = new StringBuilder(bytes.length * 3); StaticUtils.toHex(bytes, ":", buffer); return buffer.toString(); } /** * Retrieves a formatted representation of the provided date in a * human-readable format that includes an offset from the current time. * * @param d The date to format. It must not be {@code null}. * * @return A formatted representation of the provided date. */ @NotNull() private static String formatDateAndTime(@NotNull final Date d) { // Example: Sunday, January 1, 2017 final String dateFormatString = "EEEE, MMMM d, yyyy"; final String formattedDate = new SimpleDateFormat(dateFormatString).format(d); // Example: 12:34:56 AM CDT final String timeFormatString = "hh:mm:ss aa z"; final String formattedTime = new SimpleDateFormat(timeFormatString).format(d); final long providedTime = d.getTime(); final long currentTime = System.currentTimeMillis(); if (providedTime > currentTime) { final long secondsInFuture = ((providedTime - currentTime) / 1000L); final String durationInFuture = StaticUtils.secondsToHumanReadableDuration(secondsInFuture); return INFO_MANAGE_CERTS_FORMAT_DATE_AND_TIME_IN_FUTURE.get(formattedDate, formattedTime, durationInFuture); } else { final long secondsInPast = ((currentTime - providedTime) / 1000L); final String durationInPast = StaticUtils.secondsToHumanReadableDuration(secondsInPast); return INFO_MANAGE_CERTS_FORMAT_DATE_AND_TIME_IN_PAST.get(formattedDate, formattedTime, durationInPast); } } /** * Retrieves a formatted representation of the provided date in a format * suitable for use as the validity start time value provided to the keytool * command. * * @param d The date to format. It must not be {@code null}. * * @return A formatted representation of the provided date. */ @NotNull() private static String formatValidityStartTime(@NotNull final Date d) { // Example: 2017/01/01 01:23:45 final String dateFormatString = "yyyy'/'MM'/'dd HH':'mm':'ss"; return new SimpleDateFormat(dateFormatString).format(d); } /** * Retrieves the certificate chain for the specified certificate from the * given keystore. If any issuer certificate is not in the provided keystore, * then the JVM-default trust store will be checked to see if it can be found * there. * * @param alias The alias of the certificate for which to get the * certificate chain. This must not be * {@code null}. * @param keystore The keystore from which to get the certificate * chain. This must not be {@code null}. * @param missingIssuerRef A reference that will be updated with the DN of a * missing issuer certificate, if any certificate in * the chain cannot be located. This must not be * {@code null}. * * @return The certificate chain for the specified certificate, or an empty * array if no certificate exists with the specified alias. * * @throws LDAPException If a problem is encountered while getting the * certificate chain. */ @NotNull() private static X509Certificate[] getCertificateChain( @NotNull final String alias, @NotNull final KeyStore keystore, @NotNull final AtomicReference missingIssuerRef) throws LDAPException { try { // First, see if the keystore will give us the certificate chain. This // will only happen if the alias references an entry that includes the // private key, but it will save us a lot of work. final Certificate[] chain = keystore.getCertificateChain(alias); if ((chain != null) && (chain.length > 0)) { final X509Certificate[] x509Chain = new X509Certificate[chain.length]; for (int i=0; i < chain.length; i++) { x509Chain[i] = new X509Certificate(chain[i].getEncoded()); } return x509Chain; } // We couldn't get the keystore to give us the chain, but see if we can // get a certificate with the specified alias. final Certificate endCert = keystore.getCertificate(alias); if (endCert == null) { // This means there isn't any certificate with the specified alias. // Return an empty chain. return new X509Certificate[0]; } final ArrayList chainList = new ArrayList<>(5); X509Certificate certificate = new X509Certificate(endCert.getEncoded()); chainList.add(certificate); final AtomicReference jvmDefaultTrustStoreRef = new AtomicReference<>(); while (true) { final X509Certificate issuerCertificate = getIssuerCertificate(certificate, keystore, jvmDefaultTrustStoreRef, missingIssuerRef); if (issuerCertificate == null) { break; } chainList.add(issuerCertificate); certificate = issuerCertificate; } final X509Certificate[] x509Chain = new X509Certificate[chainList.size()]; return chainList.toArray(x509Chain); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_CHAIN_ERROR.get(alias, StaticUtils.getExceptionMessage(e)), e); } } /** * Attempts to retrieve the issuer certificate for the provided certificate * from the given keystore or the JVM-default trust store. * * @param certificate The certificate for which to retrieve the * issuer certificate. * @param keystore The keystore in which to look for the * issuer certificate. * @param jvmDefaultTrustStoreRef A reference that will be used to hold the * JVM-default trust store if it is obtained * in the process of retrieving the issuer * certificate. * @param missingIssuerRef A reference that will be updated with the * DN of a missing issuer certificate, if any * certificate in the chain cannot be * located. This must not be {@code null}. * * @return The issuer certificate for the provided certificate, or * {@code null} if the issuer certificate could not be retrieved. * * @throws Exception If a problem is encountered while trying to retrieve * the issuer certificate. */ @Nullable() private static X509Certificate getIssuerCertificate( @NotNull final X509Certificate certificate, @NotNull final KeyStore keystore, @NotNull final AtomicReference jvmDefaultTrustStoreRef, @NotNull final AtomicReference missingIssuerRef) throws Exception { final DN subjectDN = certificate.getSubjectDN(); final DN issuerDN = certificate.getIssuerDN(); if (subjectDN.equals(issuerDN)) { // This means that the certificate is self-signed, so there is no issuer. return null; } // See if we can find the issuer certificate in the provided keystore. X509Certificate issuerCertificate = getIssuerCertificate(certificate, keystore); if (issuerCertificate != null) { return issuerCertificate; } // See if we can get the JVM-default trust store. KeyStore jvmDefaultTrustStore = jvmDefaultTrustStoreRef.get(); if (jvmDefaultTrustStore == null) { if (JVM_DEFAULT_CACERTS_FILE == null) { missingIssuerRef.set(issuerDN); return null; } final String[] keystoreTypes = { CryptoHelper.KEY_STORE_TYPE_JKS, CryptoHelper.KEY_STORE_TYPE_PKCS_12, BouncyCastleFIPSHelper.FIPS_KEY_STORE_TYPE }; for (final String keystoreType : keystoreTypes) { try { final KeyStore ks = CryptoHelper.getKeyStore(keystoreType, null, true); try (FileInputStream inputStream = new FileInputStream(JVM_DEFAULT_CACERTS_FILE)) { ks.load(inputStream, null); jvmDefaultTrustStore = ks; jvmDefaultTrustStoreRef.set(jvmDefaultTrustStore); break; } } catch (final Exception e) { Debug.debugException(e); } } } if (jvmDefaultTrustStore != null) { issuerCertificate = getIssuerCertificate(certificate, jvmDefaultTrustStore); } if (issuerCertificate == null) { missingIssuerRef.set(issuerDN); } return issuerCertificate; } /** * Attempts to retrieve the issuer certificate for the provided certificate * from the given keystore. * * @param certificate The certificate for which to retrieve the issuer * certificate. * @param keystore The keystore in which to look for the issuer * certificate. * * @return The issuer certificate for the provided certificate, or * {@code null} if the issuer certificate could not be retrieved. * * @throws Exception If a problem is encountered while trying to retrieve * the issuer certificate. */ @Nullable() private static X509Certificate getIssuerCertificate( @NotNull final X509Certificate certificate, @NotNull final KeyStore keystore) throws Exception { final Enumeration aliases = keystore.aliases(); while (aliases.hasMoreElements()) { final String alias = aliases.nextElement(); Certificate[] certs = null; if (hasCertificateAlias(keystore, alias)) { final Certificate c = keystore.getCertificate(alias); if (c == null) { continue; } certs = new Certificate[] { c }; } else if (hasKeyAlias(keystore, alias)) { certs = keystore.getCertificateChain(alias); } if (certs != null) { for (final Certificate c : certs) { final X509Certificate xc = new X509Certificate(c.getEncoded()); if (xc.isIssuerFor(certificate)) { return xc; } } } } return null; } /** * Retrieves the authority key identifier value for the provided certificate, * if present. * * @param c The certificate for which to retrieve the authority key * identifier. * * @return The authority key identifier value for the provided certificate, * or {@code null} if the certificate does not have an authority * key identifier. */ @Nullable() private static byte[] getAuthorityKeyIdentifier( @NotNull final X509Certificate c) { for (final X509CertificateExtension extension : c.getExtensions()) { if (extension instanceof AuthorityKeyIdentifierExtension) { final AuthorityKeyIdentifierExtension e = (AuthorityKeyIdentifierExtension) extension; if (e.getKeyIdentifier() != null) { return e.getKeyIdentifier().getValue(); } } } return null; } /** * Writes the provided keystore to the specified file. If the keystore file * already exists, a new temporary file will be created, the old file renamed * out of the way, the new file renamed into place, and the old file deleted. * If the keystore file does not exist, then it will simply be created in the * correct place. * * @param keystore The keystore to be written. * @param keystorePath The path to the keystore file to be written. * @param keystorePassword The password to use for the keystore. * * @throws LDAPException If a problem is encountered while writing the * keystore. */ static void writeKeystore(@NotNull final KeyStore keystore, @NotNull final File keystorePath, @Nullable final char[] keystorePassword) throws LDAPException { // If the key store type is PKCS #11, then we don't need to worry about a // key store file. if (keystore.getType().equals(CryptoHelper.KEY_STORE_TYPE_PKCS_11)) { try { keystore.store(null); return; } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_PKCS11_WRITE_ERROR.get( StaticUtils.getExceptionMessage(e)), e); } } File copyOfExistingKeystore = null; final String timestamp = StaticUtils.encodeGeneralizedTime(System.currentTimeMillis()); if (keystorePath.exists()) { copyOfExistingKeystore = new File(keystorePath.getAbsolutePath() + ".backup-" + timestamp); try { Files.copy(keystorePath.toPath(), copyOfExistingKeystore.toPath()); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_WRITE_KS_ERROR_COPYING_EXISTING_KS.get( keystorePath.getAbsolutePath(), copyOfExistingKeystore.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } try (FileOutputStream outputStream = new FileOutputStream(keystorePath)) { keystore.store(outputStream, keystorePassword); } catch (final Exception e) { Debug.debugException(e); if (copyOfExistingKeystore == null) { throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_WRITE_KS_ERROR_WRITING_NEW_KS.get( keystorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } else { throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_WRITE_KS_ERROR_OVERWRITING_KS.get( keystorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e), copyOfExistingKeystore.getAbsolutePath()), e); } } if (copyOfExistingKeystore != null) { try { Files.delete(copyOfExistingKeystore.toPath()); } catch (final Exception e) { Debug.debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_WRITE_KS_ERROR_DELETING_KS_BACKUP.get( copyOfExistingKeystore.getAbsolutePath(), keystorePath.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e); } } } /** * Indicates whether the provided keystore has a certificate entry with the * specified alias. * * @param keystore The keystore to examine. * @param alias The alias for which to make the determination. * * @return {@code true} if the keystore has a certificate entry with the * specified alias, or {@code false} if the alias doesn't exist or * is associated with some other type of entry (like a key). */ private static boolean hasCertificateAlias(@NotNull final KeyStore keystore, @NotNull final String alias) { try { return keystore.isCertificateEntry(alias); } catch (final Exception e) { // This should never happen. If it does, then we'll assume the alias // doesn't exist or isn't associated with a certificate. Debug.debugException(e); return false; } } /** * Indicates whether the provided keystore has a key entry with the specified * alias. * * @param keystore The keystore to examine. * @param alias The alias for which to make the determination. * * @return {@code true} if the keystore has a key entry with the specified * alias, or {@code false} if the alias doesn't exist or is * associated with some other type of entry (like a certificate). */ private static boolean hasKeyAlias(@NotNull final KeyStore keystore, @NotNull final String alias) { try { return keystore.isKeyEntry(alias); } catch (final Exception e) { // This should never happen. If it does, then we'll assume the alias // doesn't exist or isn't associated with a key. Debug.debugException(e); return false; } } /** * Adds arguments for each of the provided extensions to the given list. * * @param keytoolArguments The list to which the extension arguments should * be added. * @param basicConstraints The basic constraints extension to include. It * may be {@code null} if this extension should not * be included. * @param keyUsage The key usage extension to include. It may be * {@code null} if this extension should not be * included. * @param extendedKeyUsage The extended key usage extension to include. It * may be {@code null} if this extension should not * be included. * @param sanValues The list of subject alternative name values to * include. It must not be {@code null} but may be * empty. * @param ianValues The list of issuer alternative name values to * include. It must not be {@code null} but may be * empty. * @param genericExtensions The list of generic extensions to include. It * must not be {@code null} but may be empty. */ private static void addExtensionArguments( @NotNull final List keytoolArguments, @Nullable final BasicConstraintsExtension basicConstraints, @Nullable final KeyUsageExtension keyUsage, @Nullable final ExtendedKeyUsageExtension extendedKeyUsage, @NotNull final Set sanValues, @NotNull final Set ianValues, @NotNull final List genericExtensions) { if (basicConstraints != null) { final StringBuilder basicConstraintsValue = new StringBuilder(); basicConstraintsValue.append("ca:"); basicConstraintsValue.append(basicConstraints.isCA()); if (basicConstraints.getPathLengthConstraint() != null) { basicConstraintsValue.append(",pathlen:"); basicConstraintsValue.append( basicConstraints.getPathLengthConstraint()); } keytoolArguments.add("-ext"); keytoolArguments.add("BasicConstraints=" + basicConstraintsValue); } if (keyUsage != null) { final StringBuilder keyUsageValue = new StringBuilder(); if (keyUsage.isDigitalSignatureBitSet()) { commaAppend(keyUsageValue, "digitalSignature"); } if (keyUsage.isNonRepudiationBitSet()) { commaAppend(keyUsageValue, "nonRepudiation"); } if (keyUsage.isKeyEnciphermentBitSet()) { commaAppend(keyUsageValue, "keyEncipherment"); } if (keyUsage.isDataEnciphermentBitSet()) { commaAppend(keyUsageValue, "dataEncipherment"); } if (keyUsage.isKeyAgreementBitSet()) { commaAppend(keyUsageValue, "keyAgreement"); } if (keyUsage.isKeyCertSignBitSet()) { commaAppend(keyUsageValue, "keyCertSign"); } if (keyUsage.isCRLSignBitSet()) { commaAppend(keyUsageValue, "cRLSign"); } if (keyUsage.isEncipherOnlyBitSet()) { commaAppend(keyUsageValue, "encipherOnly"); } if (keyUsage.isEncipherOnlyBitSet()) { commaAppend(keyUsageValue, "decipherOnly"); } keytoolArguments.add("-ext"); keytoolArguments.add("KeyUsage=" + keyUsageValue); } if (extendedKeyUsage != null) { final StringBuilder extendedKeyUsageValue = new StringBuilder(); for (final OID oid : extendedKeyUsage.getKeyPurposeIDs()) { final ExtendedKeyUsageID id = ExtendedKeyUsageID.forOID(oid); if (id == null) { commaAppend(extendedKeyUsageValue, oid.toString()); } else { switch (id) { case TLS_SERVER_AUTHENTICATION: commaAppend(extendedKeyUsageValue, "serverAuth"); break; case TLS_CLIENT_AUTHENTICATION: commaAppend(extendedKeyUsageValue, "clientAuth"); break; case CODE_SIGNING: commaAppend(extendedKeyUsageValue, "codeSigning"); break; case EMAIL_PROTECTION: commaAppend(extendedKeyUsageValue, "emailProtection"); break; case TIME_STAMPING: commaAppend(extendedKeyUsageValue, "timeStamping"); break; case OCSP_SIGNING: commaAppend(extendedKeyUsageValue, "OCSPSigning"); break; default: // This should never happen. commaAppend(extendedKeyUsageValue, id.getOID().toString()); break; } } } keytoolArguments.add("-ext"); keytoolArguments.add("ExtendedKeyUsage=" + extendedKeyUsageValue); } if (! sanValues.isEmpty()) { final StringBuilder subjectAltNameValue = new StringBuilder(); for (final String sanValue : sanValues) { commaAppend(subjectAltNameValue, sanValue); } keytoolArguments.add("-ext"); keytoolArguments.add("SAN=" + subjectAltNameValue); } if (! ianValues.isEmpty()) { final StringBuilder issuerAltNameValue = new StringBuilder(); for (final String ianValue : ianValues) { commaAppend(issuerAltNameValue, ianValue); } keytoolArguments.add("-ext"); keytoolArguments.add("IAN=" + issuerAltNameValue); } for (final X509CertificateExtension e : genericExtensions) { keytoolArguments.add("-ext"); if (e.isCritical()) { keytoolArguments.add(e.getOID().toString() + ":critical=" + toColonDelimitedHex(e.getValue())); } else { keytoolArguments.add(e.getOID().toString() + '=' + toColonDelimitedHex(e.getValue())); } } } /** * Appends the provided value to the given buffer. If the buffer is not * empty, the new value will be preceded by a comma. There will not be any * spaces on either side of the comma. * * @param buffer The buffer to which the value should be appended. * @param value The value to append to the buffer. */ private static void commaAppend(@NotNull final StringBuilder buffer, @NotNull final String value) { if (buffer.length() > 0) { buffer.append(','); } buffer.append(value); } /** * Retrieves a set of information that may be used to generate example usage * information. Each element in the returned map should consist of a map * between an example set of arguments and a string that describes the * behavior of the tool when invoked with that set of arguments. * * @return A set of information that may be used to generate example usage * information. It may be {@code null} or empty if no example usage * information is available. */ @Override() @NotNull() public LinkedHashMap getExampleUsages() { final String keystorePath = getPlatformSpecificPath("config", "keystore"); final String keystorePWPath = getPlatformSpecificPath("config", "keystore.pin"); final String privateKeyPWPath = getPlatformSpecificPath("config", "server-cert-private-key.pin"); final String exportCertOutputFile = getPlatformSpecificPath("server-cert.crt"); final String exportKeyOutputFile = getPlatformSpecificPath("server-cert.private-key"); final String genCSROutputFile = getPlatformSpecificPath("server-cert.csr"); final String truststorePath = getPlatformSpecificPath("config", "truststore"); final String truststorePWPath = getPlatformSpecificPath("config", "truststore.pin"); final LinkedHashMap examples = new LinkedHashMap<>(StaticUtils.computeMapCapacity(20)); examples.put( new String[] { "list-certificates", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--verbose", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_LIST_1.get(keystorePath)); examples.put( new String[] { "export-certificate", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--alias", "server-cert", "--output-file", exportCertOutputFile, "--output-format", "PEM", "--verbose", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_EXPORT_CERT_1.get(keystorePath, exportCertOutputFile)); examples.put( new String[] { "export-private-key", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--private-key-password-file", privateKeyPWPath, "--alias", "server-cert", "--output-file", exportKeyOutputFile, "--output-format", "PEM", "--verbose", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_EXPORT_KEY_1.get(keystorePath, exportKeyOutputFile)); examples.put( new String[] { "import-certificate", "--keystore", keystorePath, "--keystore-type", "JKS", "--keystore-password-file", keystorePWPath, "--alias", "server-cert", "--certificate-file", exportCertOutputFile, "--private-key-file", exportKeyOutputFile, "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_IMPORT_1.get(exportCertOutputFile, exportKeyOutputFile, keystorePath)); examples.put( new String[] { "delete-certificate", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--alias", "server-cert" }, INFO_MANAGE_CERTS_EXAMPLE_DELETE_1.get(keystorePath)); examples.put( new String[] { "generate-self-signed-certificate", "--keystore", keystorePath, "--keystore-type", "PKCS12", "--keystore-password-file", keystorePWPath, "--alias", "ca-cert", "--subject-dn", "CN=Example Authority,O=Example Corporation,C=US", "--days-valid", "7300", "--validity-start-time", "20170101000000", "--key-algorithm", "RSA", "--key-size-bits", "4096", "--signature-algorithm", "SHA256withRSA", "--basic-constraints-is-ca", "true", "--key-usage", "key-cert-sign", "--key-usage", "crl-sign", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_GEN_CERT_1.get(keystorePath)); examples.put( new String[] { "generate-certificate-signing-request", "--keystore", keystorePath, "--keystore-type", "PKCS12", "--keystore-password-file", keystorePWPath, "--output-file", genCSROutputFile, "--alias", "server-cert", "--subject-dn", "CN=ldap.example.com,O=Example Corporation,C=US", "--key-algorithm", "EC", "--key-size-bits", "256", "--signature-algorithm", "SHA256withECDSA", "--subject-alternative-name-dns", "ldap1.example.com", "--subject-alternative-name-dns", "ldap2.example.com", "--extended-key-usage", "server-auth", "--extended-key-usage", "client-auth", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_GEN_CSR_1.get(keystorePath, genCSROutputFile)); examples.put( new String[] { "generate-certificate-signing-request", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--alias", "server-cert", "--use-existing-key-pair", "--inherit-extensions", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_GEN_CSR_2.get(keystorePath)); examples.put( new String[] { "sign-certificate-signing-request", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--request-input-file", genCSROutputFile, "--certificate-output-file", exportCertOutputFile, "--alias", "ca-cert", "--days-valid", "730", "--include-requested-extensions", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_SIGN_CERT_1.get(keystorePath, genCSROutputFile, exportCertOutputFile)); examples.put( new String[] { "change-certificate-alias", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--current-alias", "server-cert", "--new-alias", "server-certificate", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_CHANGE_ALIAS_1.get(keystorePath, genCSROutputFile, exportCertOutputFile)); examples.put( new String[] { "change-keystore-password", "--keystore", getPlatformSpecificPath("config", "keystore"), "--current-keystore-password-file", getPlatformSpecificPath("config", "current.pin"), "--new-keystore-password-file", getPlatformSpecificPath("config", "new.pin"), "--display-keytool-command" }, INFO_MANAGE_CERTS_SC_CHANGE_KS_PW_EXAMPLE_1.get( getPlatformSpecificPath("config", "keystore"), getPlatformSpecificPath("config", "current.pin"), getPlatformSpecificPath("config", "new.pin"))); examples.put( new String[] { "retrieve-server-certificate", "--hostname", "ds.example.com", "--port", "636" }, INFO_MANAGE_CERTS_SC_RETRIEVE_CERT_EXAMPLE_1.get( getPlatformSpecificPath("config", "truststore"))); examples.put( new String[] { "copy-keystore", "--source-keystore", getPlatformSpecificPath("config", "keystore.jks"), "--source-keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--source-keystore-type", "JKS", "--destination-keystore", getPlatformSpecificPath("config", "keystore.p12"), "--destination-keystore-password-file", getPlatformSpecificPath("config", "keystore.pin"), "--destination-keystore-type", "PKCS12" }, INFO_MANAGE_CERTS_SC_COPY_KS_EXAMPLE_1.get("keystore.jks", "keystore.p12")); examples.put( new String[] { "trust-server-certificate", "--hostname", "ldap.example.com", "--port", "636", "--keystore", truststorePath, "--keystore-password-file", truststorePWPath, "--alias", "ldap.example.com:636" }, INFO_MANAGE_CERTS_EXAMPLE_TRUST_SERVER_1.get(truststorePath)); examples.put( new String[] { "check-certificate-usability", "--keystore", keystorePath, "--keystore-password-file", keystorePWPath, "--alias", "server-cert" }, INFO_MANAGE_CERTS_EXAMPLE_CHECK_USABILITY_1.get(keystorePath)); examples.put( new String[] { "display-certificate-file", "--certificate-file", exportCertOutputFile, "--verbose", "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_DISPLAY_CERT_1.get(keystorePath)); examples.put( new String[] { "display-certificate-signing-request-file", "--certificate-signing-request-file", genCSROutputFile, "--display-keytool-command" }, INFO_MANAGE_CERTS_EXAMPLE_DISPLAY_CSR_1.get(keystorePath)); examples.put( new String[] { "--help-subcommands" }, INFO_MANAGE_CERTS_EXAMPLE_HELP_SUBCOMMANDS_1.get(keystorePath)); return examples; } }