[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