diff --git a/messages/unboundid-ldapsdk-cert.properties b/messages/unboundid-ldapsdk-cert.properties index 57463677a..4e981f92d 100644 --- a/messages/unboundid-ldapsdk-cert.properties +++ b/messages/unboundid-ldapsdk-cert.properties @@ -415,6 +415,11 @@ INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_FILE_DESC=The path to the output file \ optional when using the PEM format, but required when using the DER \ format. If no output file is provided, then the exported certificate will \ be written to standard output. +INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_SEPARATE_FILE_DESC=Indicates that if \ + multiple certificates are to be exported, then each certificate should be \ + written to a different file rather than concatenating all of them into the \ + same file. This can only be used if both the --export-certificate-chain \ + and --output-file arguments are also provided. INFO_MANAGE_CERTS_SC_EXPORT_CERT_ARG_DISPLAY_COMMAND_DESC=Display a command \ that can be invoked to achieve a similar result with the Java keytool \ utility. Note that this may just be an approximation, since the \ @@ -1728,7 +1733,7 @@ WARN_MANAGE_CERTS_EXPORT_CERT_MISSING_CERT_IN_CHAIN=WARNING: Unable to \ ''{1}'' or in the JVM's default set of trusted certificates. The \ certificate chain is incomplete. INFO_MANAGE_CERTS_EXPORT_CERT_EXPORT_SUCCESSFUL=Successfully exported the \ - following certificate: + following certificate to ''{0}'': ERR_MANAGE_CERTS_EXPORT_KEY_NO_FILE_WITH_DER=ERROR: An output file must be \ specified when exporting a private key in the binary DER format. ERR_MANAGE_CERTS_EXPORT_KEY_NO_KEY_WITH_ALIAS=ERROR: There is no private key \ diff --git a/src/com/unboundid/util/ssl/cert/ManageCertificates.java b/src/com/unboundid/util/ssl/cert/ManageCertificates.java index 38cde580b..c42426f6a 100644 --- a/src/com/unboundid/util/ssl/cert/ManageCertificates.java +++ b/src/com/unboundid/util/ssl/cert/ManageCertificates.java @@ -644,6 +644,15 @@ public void addToolArguments(final ArgumentParser parser) 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()); @@ -654,6 +663,10 @@ public void addToolArguments(final ArgumentParser parser) exportCertParser.addExclusiveArgumentSet(exportCertKeystorePassword, exportCertKeystorePasswordFile, exportCertPromptForKeystorePassword); + exportCertParser.addDependentArgumentSet(exportCertSeparateFile, + exportCertChain); + exportCertParser.addDependentArgumentSet(exportCertSeparateFile, + exportCertOutputFile); final LinkedHashMap exportCertExamples = new LinkedHashMap<>(2); @@ -4225,6 +4238,12 @@ private ResultCode doExportCertificate() 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"); @@ -4388,7 +4407,9 @@ private ResultCode doExportCertificate() // Get a PrintStream to use for the output. - final PrintStream printStream; + int fileCounter = 1; + String filename = null; + PrintStream printStream; if (outputFile == null) { printStream = getOut(); @@ -4397,7 +4418,15 @@ private ResultCode doExportCertificate() { try { - printStream = new PrintStream(outputFile); + if ((certificatesToExport.length > 1) && separateFilePerCertificate) + { + filename = outputFile.getAbsolutePath() + '.' + fileCounter; + } + else + { + filename = outputFile.getAbsolutePath(); + } + printStream = new PrintStream(filename); } catch (final Exception e) { @@ -4416,6 +4445,18 @@ private ResultCode doExportCertificate() { try { + if (separateFilePerCertificate && (certificatesToExport.length > 1)) + { + if (fileCounter > 1) + { + printStream.close(); + filename = outputFile.getAbsolutePath() + '.' + fileCounter; + printStream = new PrintStream(filename); + } + + fileCounter++; + } + if (exportPEM) { writePEMCertificate(printStream, @@ -4440,7 +4481,7 @@ private ResultCode doExportCertificate() { out(); wrapOut(0, WRAP_COLUMN, - INFO_MANAGE_CERTS_EXPORT_CERT_EXPORT_SUCCESSFUL.get()); + INFO_MANAGE_CERTS_EXPORT_CERT_EXPORT_SUCCESSFUL.get(filename)); printCertificate(certificate, "", false); } } diff --git a/tests/unit/src/com/unboundid/util/ssl/cert/ManageCertificatesTestCase.java b/tests/unit/src/com/unboundid/util/ssl/cert/ManageCertificatesTestCase.java index f9e3ade13..805b9f389 100644 --- a/tests/unit/src/com/unboundid/util/ssl/cert/ManageCertificatesTestCase.java +++ b/tests/unit/src/com/unboundid/util/ssl/cert/ManageCertificatesTestCase.java @@ -914,15 +914,19 @@ public void testExportCertificate() "--export-certificate-chain", "--output-format", "PEM", "--output-file", outputFile.getAbsolutePath(), + "--separate-file-per-certificate", "--display-keytool-command"); - assertTrue(outputFile.exists()); - assertEquals(countPEMEntries(outputFile.getAbsolutePath()), 3); + assertFalse(outputFile.exists()); + assertTrue(new File(outputFile.getAbsolutePath() + ".1").exists()); + assertTrue(new File(outputFile.getAbsolutePath() + ".2").exists()); + assertTrue(new File(outputFile.getAbsolutePath() + ".3").exists()); // Test exporting a DER certificate chain for a JKS keystore with a private // key entry. - assertTrue(outputFile.delete()); - assertFalse(outputFile.exists()); + assertTrue(new File(outputFile.getAbsolutePath() + ".1").delete()); + assertTrue(new File(outputFile.getAbsolutePath() + ".2").delete()); + assertTrue(new File(outputFile.getAbsolutePath() + ".3").delete()); manageCertificates( "export-certificate", "--keystore", serverKeyStorePath,