[Pki-devel] [PATCH] 528 Added CLI to import/export certificates with private keys.
Fraser Tweedale
ftweedal at redhat.com
Thu Oct 9 05:56:50 UTC 2014
On Mon, Oct 06, 2014 at 06:01:37PM -0500, Endi Sukma Dewata wrote:
> New CLI commands have been added to import/export certificates and
> private keys into/from the client security database. The CLI can
> also be used to generate the file needed by Python client library
> for client certificate authentication.
>
> --
> Endi S. Dewata
Conditional ACK; one minor issue in command help. See inline.
> From 6b60698a2c35cb530a379a2970f7fc11af7e5798 Mon Sep 17 00:00:00 2001
> From: "Endi S. Dewata" <edewata at redhat.com>
> Date: Mon, 6 Oct 2014 12:20:42 -0400
> Subject: [PATCH] Added CLI to import/export certificates with private keys.
>
> New CLI commands have been added to import/export certificates and
> private keys into/from the client security database. The CLI can
> also be used to generate the file needed by Python client library
> for client certificate authentication.
> ---
> .../src/com/netscape/certsrv/client/PKIClient.java | 6 +
> base/java-tools/man/man1/pki-client.1 | 44 +++-
> .../src/com/netscape/cmstools/cli/MainCLI.java | 4 +-
> .../com/netscape/cmstools/client/ClientCLI.java | 2 +
> .../cmstools/client/ClientCertImportCLI.java | 172 +++++++++++---
> .../cmstools/client/ClientCertModifyCLI.java | 126 ++++++++++
> .../cmstools/client/ClientCertShowCLI.java | 256 +++++++++++++++++++++
> 7 files changed, 578 insertions(+), 32 deletions(-)
> create mode 100644 base/java-tools/src/com/netscape/cmstools/client/ClientCertModifyCLI.java
> create mode 100644 base/java-tools/src/com/netscape/cmstools/client/ClientCertShowCLI.java
>
> diff --git a/base/common/src/com/netscape/certsrv/client/PKIClient.java b/base/common/src/com/netscape/certsrv/client/PKIClient.java
> index c23e8b600b125d0a2da14dcec1880fb05598f42a..e06b4db54569d5ed46fdd138af3ded93e6fd1878 100644
> --- a/base/common/src/com/netscape/certsrv/client/PKIClient.java
> +++ b/base/common/src/com/netscape/certsrv/client/PKIClient.java
> @@ -104,6 +104,12 @@ public class PKIClient {
> this.verbose = verbose;
> }
>
> + public X509Certificate getCert(String nickname)
> + throws NotInitializedException, ObjectNotFoundException, TokenException {
> + CryptoManager manager = CryptoManager.getInstance();
> + return manager.findCertByNickname(nickname);
> + }
> +
> public X509Certificate[] getCerts() throws NotInitializedException {
> CryptoManager manager = CryptoManager.getInstance();
> return manager.getPermCerts();
> diff --git a/base/java-tools/man/man1/pki-client.1 b/base/java-tools/man/man1/pki-client.1
> index 0364f84efb97a7263194799bf44ce625519311e1..87da255ff0fd5e385aec845f9364ad977d9f7aad 100644
> --- a/base/java-tools/man/man1/pki-client.1
> +++ b/base/java-tools/man/man1/pki-client.1
> @@ -22,7 +22,9 @@ pki-client \- Command-Line Interface for managing the security database on Certi
> \fBpki\fR [CLI options] \fBclient-init\fR [command options]
> \fBpki\fR [CLI options] \fBclient-cert-find\fR [command options]
> \fBpki\fR [CLI options] \fBclient-cert-request\fR <subject DN> [command options]
> -\fBpki\fR [CLI options] \fBclient-cert-import\fR <nickname> [command options]
> +\fBpki\fR [CLI options] \fBclient-cert-import\fR [nickname] [command options]
> +\fBpki\fR [CLI options] \fBclient-cert-mod\fR <nickname> [command options]
> +\fBpki\fR [CLI options] \fBclient-cert-show\fR <nickname> [command options]
> \fBpki\fR [CLI options] \fBclient-cert-del\fR <nickname> [command options]
> .fi
>
> @@ -50,7 +52,17 @@ This command is to list certificates in the client security database.
> This command is to generate and submit a certificate request.
> .RE
> .PP
> -\fBpki\fR [CLI options] \fBclient-cert-import\fR <nickname> [command options]
> +\fBpki\fR [CLI options] \fBclient-cert-import\fR [nickname] [command options]
> +.RS 4
> +This command is to import a certificate into the client security database.
> +.RE
> +.PP
> +\fBpki\fR [CLI options] \fBclient-cert-mod\fR <nickname> [command options]
> +.RS 4
> +This command is to modify a certificate in the client security database.
> +.RE
> +.PP
> +\fBpki\fR [CLI options] \fBclient-cert-show\fR <nickname> [command options]
> .RS 4
> This command is to view a certificate in the client security database.
> .RE
> @@ -80,11 +92,15 @@ To request a certificate:
>
> To import a certificate from a file into the security database:
>
> -.B pki -d <security database location> -c <security database password> client-cert-import <nickname> --cert <certificate file>
> +.B pki -d <security database location> -c <security database password> client-cert-import <nickname> --cert <path>
>
> To import a CA certificate from a file into the security database:
>
> -.B pki -d <security database location> -c <security database password> client-cert-import <nickname> --ca-cert <CA certificate file>
> +.B pki -d <security database location> -c <security database password> client-cert-import <nickname> --ca-cert <path>
> +
> +To import certificates and private keys from a PKCS #12 file into the security database:
> +
> +.B pki -d <security database location> -c <security database password> client-cert-import --pkcs12 <path> --pkcs12-password <password>
>
> To import a certificate from CA server into the security database:
>
> @@ -94,6 +110,26 @@ To import a CA certificate from CA server into the security database:
>
> .B pki -d <security database location> -c <security database password> client-cert-import <nickname> --ca-server
>
> +To modify a certificate's trust attributes in the security database:
> +
> +.B pki -d <security database location> -c <security database password> client-cert-mod <nickname> --trust <trust attributes>
> +
> +To display a certificate in the security database:
> +
> +.B pki -d <security database location> -c <security database password> client-cert-show <nickname>
> +
> +To export a certificate from the security database into a PEM file:
> +
> +.B pki -d <security database location> -c <security database password> client-cert-show <nickname> --cert <file>
> +
> +To export a certificate chain with the private key from the security database into a PKCS #12 file:
> +
> +.B pki -d <security database location> -c <security database password> client-cert-show <nickname> --pkcs12 <file> --pkcs12-password <password>
> +
> +To export a client certificate with the private key from the security database into a PEM file:
> +
> +.B pki -d <security database location> -c <security database password> client-cert-show <nickname> --client-cert <file>
> +
> To delete a certificate from the security database:
>
> .B pki -d <security database location> -c <security database password> client-cert-del <nickname>
> diff --git a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
> index 066a7d580553836df62f68188929afc4de20d536..8c3805e007b7384f0b073e92bad88076e39ab2b6 100644
> --- a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
> +++ b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
> @@ -494,7 +494,9 @@ public class MainCLI extends CLI {
> String command = cmdArgs[0];
> if (!command.equals("client-init") &&
> !command.equals("client-cert-import") &&
> - !command.equals("client-cert-request")) {
> + !command.equals("client-cert-mod") &&
> + !command.equals("client-cert-request") &&
> + !command.equals("client-cert-show")) {
> init();
> }
>
> diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
> index 443d48bdfbe87253bb9f64e7eae5302c4dcce85c..c9c71521ab631a02d7c386bd4e1b38f8ecbc1e7f 100644
> --- a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
> +++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
> @@ -35,8 +35,10 @@ public class ClientCLI extends CLI {
> addModule(new ClientInitCLI(this));
> addModule(new ClientCertFindCLI(this));
> addModule(new ClientCertImportCLI(this));
> + addModule(new ClientCertModifyCLI(this));
> addModule(new ClientCertRemoveCLI(this));
> addModule(new ClientCertRequestCLI(this));
> + addModule(new ClientCertShowCLI(this));
> }
>
> public String getFullName() {
> diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java
> index 5080c55ea0d2a47dc38e5d63367b5dc00840f5e6..afa91d65935e77a5ceda09d9c70dae335e130885 100644
> --- a/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java
> +++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java
> @@ -21,6 +21,7 @@ package com.netscape.cmstools.client;
> import java.io.File;
> import java.io.FileOutputStream;
> import java.io.FileWriter;
> +import java.io.IOException;
> import java.io.PrintWriter;
> import java.net.URI;
> import java.util.Arrays;
> @@ -51,21 +52,33 @@ public class ClientCertImportCLI extends CLI {
> }
>
> public void printHelp() {
> - formatter.printHelp(getFullName() + " <nickname> [OPTIONS...]", options);
> + formatter.printHelp(getFullName() + " [nickname] [OPTIONS...]", options);
> }
>
> public void createOptions() {
> - Option option = new Option(null, "cert", true, "Import certificate file");
> + Option option = new Option(null, "cert", true, "Certificate file to import.");
> option.setArgName("path");
> options.addOption(option);
>
> - option = new Option(null, "ca-cert", true, "Import CA certificate file");
> + option = new Option(null, "ca-cert", true, "CA certificate file to import.");
> + option.setArgName("path");
> + options.addOption(option);
> +
> + option = new Option(null, "pkcs12", true, "PKCS #12 file to import.");
> + option.setArgName("path");
> + options.addOption(option);
> +
> + option = new Option(null, "pkcs12-password", true, "PKCS #12 password.");
> + option.setArgName("password");
> + options.addOption(option);
> +
> + option = new Option(null, "pkcs12-password-file", true, "PKCS #12 password file.");
> option.setArgName("path");
> options.addOption(option);
>
> options.addOption(null, "ca-server", false, "Import CA certificate from CA server");
>
> - option = new Option(null, "serial", true, "Serial number of certificate in CA");
> + option = new Option(null, "serial", true, "Serial number of certificate to import from CA server");
> option.setArgName("serial number");
> options.addOption(option);
>
> @@ -117,30 +130,72 @@ public class ClientCertImportCLI extends CLI {
> nickname = mainCLI.config.getCertNickname();
> }
>
> - if (nickname == null) {
> - System.err.println("Error: Missing certificate nickname.");
> - System.exit(-1);
> - }
> + // nickname is not required to import PKCS #12 file
>
> String certPath = cmd.getOptionValue("cert");
> String caCertPath = cmd.getOptionValue("ca-cert");
> + String pkcs12Path = cmd.getOptionValue("pkcs12");
> + String pkcs12Password = cmd.getOptionValue("pkcs12-password");
> + String pkcs12PasswordPath = cmd.getOptionValue("pkcs12-password-file");
> boolean importFromCAServer = cmd.hasOption("ca-server");
> String serialNumber = cmd.getOptionValue("serial");
> String trustAttributes = cmd.getOptionValue("trust", "u,u,u");
>
> - File certFile;
> -
> // load the certificate
> if (certPath != null) {
> - if (verbose) System.out.println("Loading certificate from " + certPath + ".");
> - certFile = new File(certPath);
> +
> + if (verbose) System.out.println("Importing certificate from " + certPath + ".");
> +
> + importCert(
> + mainCLI.certDatabase.getAbsolutePath(),
> + certPath,
> + nickname,
> + trustAttributes);
>
> } else if (caCertPath != null) {
> - if (verbose) System.out.println("Loading CA certificate from " + caCertPath + ".");
> - certFile = new File(caCertPath);
> +
> + if (verbose) System.out.println("Importing CA certificate from " + caCertPath + ".");
>
> trustAttributes = "CT,c,";
>
> + importCert(
> + mainCLI.certDatabase.getAbsolutePath(),
> + caCertPath,
> + nickname,
> + trustAttributes);
> +
> + } else if (pkcs12Path != null) {
> +
> + if (verbose) System.out.println("Importing certificates from " + pkcs12Path + ".");
> +
> + if (pkcs12Password != null && pkcs12PasswordPath != null) {
> + throw new Exception("PKCS #12 password and password file are mutually exclusive");
> +
> + } else if (pkcs12Password != null) {
> + // store password into a temporary file
> + File pkcs12PasswordFile = File.createTempFile("pki-client-cert-import-", ".pwd");
> + pkcs12PasswordFile.deleteOnExit();
> +
> + try (PrintWriter out = new PrintWriter(new FileWriter(pkcs12PasswordFile))) {
> + out.print(pkcs12Password);
> + }
> +
> + pkcs12PasswordPath = pkcs12PasswordFile.getAbsolutePath();
> +
> + } else if (pkcs12PasswordPath != null) {
> + // nothing to do
> +
> + } else {
> + throw new Exception("Missing PKCS #12 password");
> + }
> +
> + // import certificates and private key into PKCS #12 file
> + importPKCS12(
> + mainCLI.certDatabase.getAbsolutePath(),
> + mainCLI.config.getCertPassword(),
> + pkcs12Path,
> + pkcs12PasswordPath);
> +
> } else if (importFromCAServer) {
>
> // late initialization
> @@ -152,10 +207,10 @@ public class ClientCertImportCLI extends CLI {
> String caServerURI = serverURI.getScheme() + "://" +
> serverURI.getHost() + ":" + serverURI.getPort() + "/ca";
>
> - if (verbose) System.out.println("Downloading CA certificate from " + caServerURI + ".");
> + if (verbose) System.out.println("Importing CA certificate from " + caServerURI + ".");
> byte[] bytes = client.downloadCACertChain(caServerURI);
>
> - certFile = File.createTempFile("pki-client-cert-import-", ".crt", mainCLI.certDatabase);
> + File certFile = File.createTempFile("pki-client-cert-import-", ".crt");
> certFile.deleteOnExit();
>
> try (FileOutputStream out = new FileOutputStream(certFile)) {
> @@ -164,6 +219,12 @@ public class ClientCertImportCLI extends CLI {
>
> trustAttributes = "CT,c,";
>
> + importCert(
> + mainCLI.certDatabase.getAbsolutePath(),
> + certFile.getAbsolutePath(),
> + nickname,
> + trustAttributes);
> +
> } else if (serialNumber != null) {
>
> // connect to CA anonymously
> @@ -172,12 +233,15 @@ public class ClientCertImportCLI extends CLI {
> config.setCertPassword(null);
> config.setCertNickname(null);
>
> + URI serverURI = config.getServerURI();
> + if (verbose) System.out.println("Importing certificate " + serialNumber + " from " + serverURI + ".");
> +
> PKIClient client = new PKIClient(config, null);
> CertClient certClient = new CertClient(client, "ca");
>
> CertData certData = certClient.getCert(new CertId(serialNumber));
>
> - certFile = File.createTempFile("pki-client-cert-import-", ".crt", mainCLI.certDatabase);
> + File certFile = File.createTempFile("pki-client-cert-import-", ".crt");
> certFile.deleteOnExit();
>
> String encoded = certData.getEncoded();
> @@ -185,6 +249,12 @@ public class ClientCertImportCLI extends CLI {
> out.write(encoded);
> }
>
> + importCert(
> + mainCLI.certDatabase.getAbsolutePath(),
> + certFile.getAbsolutePath(),
> + nickname,
> + trustAttributes);
> +
> } else {
> System.err.println("Error: Missing certificate to import");
> printHelp();
> @@ -192,23 +262,71 @@ public class ClientCertImportCLI extends CLI {
> return;
> }
>
> - String[] commands = {
> - "/usr/bin/certutil", "-A",
> - "-d", mainCLI.certDatabase.getAbsolutePath(),
> - "-i", certFile.getAbsolutePath(),
> + if (nickname == null) {
> + MainCLI.printMessage("Imported certificates from PKCS #12 file");
> +
> + } else {
> + MainCLI.printMessage("Imported certificate \"" + nickname + "\"");
> + }
> + }
> +
> + public void importCert(
> + String dbPath,
> + String certPath,
> + String nickname,
> + String trustAttributes) throws Exception {
> +
> + if (nickname == null) {
> + System.err.println("Error: Missing certificate nickname.");
> + System.exit(-1);
> + }
> +
> + String[] command = {
> + "/bin/certutil", "-A",
> + "-d", dbPath,
> + "-i", certPath,
> "-n", nickname,
> "-t", trustAttributes
> };
>
> + try {
> + run(command);
> +
> + } catch (Exception e) {
> + throw new Exception("Unable to import certificate file", e);
> + }
> + }
> +
> + public void importPKCS12(
> + String dbPath,
> + String dbPassword,
> + String pkcs12Path,
> + String pkcs12PasswordPath) throws Exception {
> +
> + String[] command = {
> + "/bin/pk12util",
> + "-d", dbPath,
> + "-K", dbPassword,
> + "-i", pkcs12Path,
> + "-w", pkcs12PasswordPath
> + };
> +
> + try {
> + run(command);
> +
> + } catch (Exception e) {
> + throw new Exception("Unable to import PKCS #12 file", e);
> + }
> + }
> +
> + public void run(String[] command) throws IOException, InterruptedException {
> +
> Runtime rt = Runtime.getRuntime();
> - Process p = rt.exec(commands);
> -
> + Process p = rt.exec(command);
> int rc = p.waitFor();
> +
> if (rc != 0) {
> - MainCLI.printMessage("Import failed");
> - return;
> + throw new IOException("Command failed. RC: " + rc);
> }
> -
> - MainCLI.printMessage("Imported certificate \"" + nickname + "\"");
> }
> }
> diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertModifyCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertModifyCLI.java
> new file mode 100644
> index 0000000000000000000000000000000000000000..738dca07c3e5c98d89e821846d74a6cd45f64004
> --- /dev/null
> +++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertModifyCLI.java
> @@ -0,0 +1,126 @@
> +// --- BEGIN COPYRIGHT BLOCK ---
> +// This program is free software; you can redistribute it and/or modify
> +// it under the terms of the GNU General Public License as published by
> +// the Free Software Foundation; version 2 of the License.
> +//
> +// 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, write to the Free Software Foundation, Inc.,
> +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> +//
> +// (C) 2014 Red Hat, Inc.
> +// All rights reserved.
> +// --- END COPYRIGHT BLOCK ---
> +
> +package com.netscape.cmstools.client;
> +
> +import java.io.IOException;
> +
> +import org.apache.commons.cli.CommandLine;
> +import org.apache.commons.cli.Option;
> +
> +import com.netscape.cmstools.cli.CLI;
> +import com.netscape.cmstools.cli.MainCLI;
> +
> +/**
> + * @author Endi S. Dewata
> + */
> +public class ClientCertModifyCLI extends CLI {
> +
> + public ClientCLI clientCLI;
> +
> + public ClientCertModifyCLI(ClientCLI clientCLI) {
> + super("cert-mod", "Modify certificate in client security database", clientCLI);
> + this.clientCLI = clientCLI;
> +
> + createOptions();
> + }
> +
> + public void printHelp() {
> + formatter.printHelp(getFullName() + " <nickname> [OPTIONS...]", options);
> + }
> +
> + public void createOptions() {
> + Option option = new Option(null, "trust", true, "Trust attributes. Default: u,u,u.");
> + option.setArgName("trust attributes");
> + options.addOption(option);
> + }
> +
> + public void execute(String[] args) throws Exception {
> +
> + CommandLine cmd = null;
> +
> + try {
> + cmd = parser.parse(options, args);
> +
> + } catch (Exception e) {
> + System.err.println("Error: " + e.getMessage());
> + printHelp();
> + System.exit(-1);
> + }
> +
> + if (cmd.hasOption("help")) {
> + // Display usage
> + printHelp();
> + System.exit(0);
> + }
> +
> + String[] cmdArgs = cmd.getArgs();
> +
> + if (cmdArgs.length > 1) {
> + System.err.println("Error: Too many arguments specified.");
> + printHelp();
> + System.exit(-1);
> + }
> +
> + if (cmdArgs.length == 0) {
> + System.err.println("Error: Missing certificate nickname.");
> + printHelp();
> + System.exit(-1);
> + }
> +
> + MainCLI mainCLI = (MainCLI)parent.getParent();
> +
> + String nickname = cmdArgs[0];
> +
> + String trustAttributes = cmd.getOptionValue("trust", "u,u,u");
> +
> + int rc = modifyCert(
> + mainCLI.certDatabase.getAbsolutePath(),
> + nickname,
> + trustAttributes);
> +
> + if (rc != 0) {
> + MainCLI.printMessage("Modified failed");
> + return;
> + }
> +
> + MainCLI.printMessage("Modified certificate \"" + nickname + "\"");
> + }
> +
> + public int modifyCert(
> + String dbPath,
> + String nickname,
> + String trustAttributes) throws IOException, InterruptedException {
> +
> + String[] command = {
> + "/usr/bin/certutil", "-M",
> + "-d", dbPath,
> + "-n", nickname,
> + "-t", trustAttributes
> + };
> +
> + return run(command);
> + }
> +
> + public int run(String[] command) throws IOException, InterruptedException {
> +
> + Runtime rt = Runtime.getRuntime();
> + Process p = rt.exec(command);
> + return p.waitFor();
> + }
> +}
> diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertShowCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertShowCLI.java
> new file mode 100644
> index 0000000000000000000000000000000000000000..bdd9462f3097c2213b665a4dd0c57413af0d049a
> --- /dev/null
> +++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertShowCLI.java
> @@ -0,0 +1,256 @@
> +// --- BEGIN COPYRIGHT BLOCK ---
> +// This program is free software; you can redistribute it and/or modify
> +// it under the terms of the GNU General Public License as published by
> +// the Free Software Foundation; version 2 of the License.
> +//
> +// 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, write to the Free Software Foundation, Inc.,
> +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> +//
> +// (C) 2014 Red Hat, Inc.
> +// All rights reserved.
> +// --- END COPYRIGHT BLOCK ---
> +
> +package com.netscape.cmstools.client;
> +
> +import java.io.File;
> +import java.io.FileWriter;
> +import java.io.IOException;
> +import java.io.PrintWriter;
> +
> +import org.apache.commons.cli.CommandLine;
> +import org.apache.commons.cli.Option;
> +import org.apache.commons.lang.RandomStringUtils;
> +import org.apache.commons.lang.StringUtils;
> +import org.mozilla.jss.crypto.X509Certificate;
> +
> +import com.netscape.certsrv.cert.CertData;
> +import com.netscape.cmstools.cli.CLI;
> +import com.netscape.cmstools.cli.MainCLI;
> +import com.netscape.cmsutil.util.Utils;
> +
> +/**
> + * @author Endi S. Dewata
> + */
> +public class ClientCertShowCLI extends CLI {
> +
> + public ClientCLI clientCLI;
> +
> + public ClientCertShowCLI(ClientCLI clientCLI) {
> + super("cert-show", "Show certificate in client security database", clientCLI);
> + this.clientCLI = clientCLI;
> +
> + createOptions();
> + }
> +
> + public void printHelp() {
> + formatter.printHelp(getFullName() + " <nickname> [OPTIONS...]", options);
> + }
> +
> + public void createOptions() {
> + Option option = new Option(null, "cert", true, "PEM file to store the certificate.");
> + option.setArgName("file");
> + options.addOption(option);
> +
> + option = new Option(null, "client-cert", true, "PEM file to store the certificate and the private key.");
> + option.setArgName("file");
> + options.addOption(option);
> +
> + option = new Option(null, "pkcs12", true, "PKCS #12 file to store the certificate chain and the private key.");
> + option.setArgName("password");
Should be "path".
> + options.addOption(option);
> +
> + option = new Option(null, "pkcs12-password", true, "PKCS #12 file password.");
> + option.setArgName("password");
> + options.addOption(option);
> + }
> +
> + public void execute(String[] args) throws Exception {
> +
> + CommandLine cmd = null;
> +
> + try {
> + cmd = parser.parse(options, args);
> +
> + } catch (Exception e) {
> + System.err.println("Error: " + e.getMessage());
> + printHelp();
> + System.exit(-1);
> + }
> +
> + if (cmd.hasOption("help")) {
> + // Display usage
> + printHelp();
> + System.exit(0);
> + }
> +
> + String[] cmdArgs = cmd.getArgs();
> +
> + if (cmdArgs.length > 1) {
> + System.err.println("Error: Too many arguments specified.");
> + printHelp();
> + System.exit(-1);
> + }
> +
> + if (cmdArgs.length == 0) {
> + System.err.println("Error: Missing certificate nickname.");
> + printHelp();
> + System.exit(-1);
> + }
> +
> + MainCLI mainCLI = (MainCLI)parent.getParent();
> +
> + String nickname = cmdArgs[0];
> + String certPath = cmd.getOptionValue("cert");
> + String pkcs12Path = cmd.getOptionValue("pkcs12");
> + String pkcs12Password = cmd.getOptionValue("pkcs12-password");
> + String clientCertPath = cmd.getOptionValue("client-cert");
> +
> + if (certPath != null) {
> +
> + if (verbose) System.out.println("Exporting certificate to " + clientCertPath + ".");
> +
> + // late initialization
> + mainCLI.init();
> +
> + client = mainCLI.getClient();
> + X509Certificate cert = client.getCert(nickname);
> +
> + try (PrintWriter out = new PrintWriter(new FileWriter(certPath))) {
> + out.println(CertData.HEADER);
> + out.println(Utils.base64encode(cert.getEncoded()));
> + out.println(CertData.FOOTER);
> + }
> +
> + } else if (pkcs12Path != null) {
> +
> + if (verbose) System.out.println("Exporting certificate chain and private key to " + pkcs12Path + ".");
> +
> + if (pkcs12Password == null) {
> + throw new Exception("Missing PKCS #12 password");
> + }
> +
> + // store password into a temporary file
> + File pkcs12PasswordFile = File.createTempFile("pki-client-cert-show-", ".pwd");
> + pkcs12PasswordFile.deleteOnExit();
> +
> + try (PrintWriter out = new PrintWriter(new FileWriter(pkcs12PasswordFile))) {
> + out.print(pkcs12Password);
> + }
> +
> + // export certificate chain and private key into PKCS #12 file
> + exportPKCS12(
> + mainCLI.certDatabase.getAbsolutePath(),
> + mainCLI.config.getCertPassword(),
> + pkcs12Path,
> + pkcs12PasswordFile.getAbsolutePath(),
> + nickname);
> +
> + } else if (clientCertPath != null) {
> +
> + if (verbose) System.out.println("Exporting client certificate and private key to " + clientCertPath + ".");
> +
> + // generate random PKCS #12 password
> + pkcs12Password = RandomStringUtils.randomAlphanumeric(16);
> +
> + // store password into a temporary file
> + File pkcs12PasswordFile = File.createTempFile("pki-client-cert-show-", ".pwd");
> + pkcs12PasswordFile.deleteOnExit();
> +
> + try (PrintWriter out = new PrintWriter(new FileWriter(pkcs12PasswordFile))) {
> + out.print(pkcs12Password);
> + }
> +
> + // export certificate chain and private key into a temporary PKCS #12 file
> + File pkcs12File = File.createTempFile("pki-client-cert-show-", ".p12");
> + pkcs12File.deleteOnExit();
> +
> + exportPKCS12(
> + mainCLI.certDatabase.getAbsolutePath(),
> + mainCLI.config.getCertPassword(),
> + pkcs12File.getAbsolutePath(),
> + pkcs12PasswordFile.getAbsolutePath(),
> + nickname);
> +
> + // export client certificate and private key into a PEM file
> + exportClientCertificate(
> + pkcs12File.getAbsolutePath(),
> + pkcs12PasswordFile.getAbsolutePath(),
> + clientCertPath);
> +
> + } else {
> + // late initialization
> + mainCLI.init();
> +
> + client = mainCLI.getClient();
> + X509Certificate cert = client.getCert(nickname);
> +
> + ClientCLI.printCertInfo(cert);
> + }
> + }
> +
> + public void exportPKCS12(
> + String dbPath,
> + String dbPassword,
> + String pkcs12Path,
> + String pkcs12PasswordPath,
> + String nickname) throws Exception {
> +
> + String[] command = {
> + "/bin/pk12util",
> + "-d", dbPath,
> + "-K", dbPassword,
> + "-o", pkcs12Path,
> + "-w", pkcs12PasswordPath,
> + "-n", nickname
> + };
> +
> + try {
> + run(command);
> +
> + } catch (Exception e) {
> + throw new Exception("Unable to export PKCS #12 file", e);
> + }
> + }
> +
> + public void exportClientCertificate(
> + String pkcs12Path,
> + String pkcs12PasswordPath,
> + String clientCertPath) throws Exception {
> +
> + String[] command = {
> + "/bin/openssl",
> + "pkcs12",
> + "-clcerts", // client certificate only
> + "-nodes", // no encryption
> + "-in", pkcs12Path,
> + "-passin", "file:" + pkcs12PasswordPath,
> + "-out", clientCertPath
> + };
> +
> + try {
> + run(command);
> +
> + } catch (Exception e) {
> + throw new Exception("Unable to export client certificate", e);
> + }
> + }
> +
> + public void run(String[] command) throws IOException, InterruptedException {
> +
> + if (verbose) System.out.println("Command: " + StringUtils.join(command, " "));
> +
> + Runtime rt = Runtime.getRuntime();
> + Process p = rt.exec(command);
> + int rc = p.waitFor();
> +
> + if (rc != 0) {
> + throw new IOException("Command failed. RC: " + rc);
> + }
> + }
> +}
> --
> 1.8.4.2
>
> _______________________________________________
> Pki-devel mailing list
> Pki-devel at redhat.com
> https://www.redhat.com/mailman/listinfo/pki-devel
More information about the Pki-devel
mailing list