summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAde Lee <alee@redhat.com>2016-04-20 17:26:23 -0400
committerAde Lee <alee@redhat.com>2016-05-02 14:45:38 -0400
commit5546024b33054181a60d91c6ec6f635c567c2ea8 (patch)
treea366e0d8af34d2764d85b7fb4aff2fd9705dec36
parent6d37d95354b46846a055fcc8cdcf7f5f88ab729e (diff)
downloadpki-5546024b33054181a60d91c6ec6f635c567c2ea8.zip
pki-5546024b33054181a60d91c6ec6f635c567c2ea8.tar.gz
pki-5546024b33054181a60d91c6ec6f635c567c2ea8.tar.xz
Add CLI to check system certificate status
We add two different calls: 1. pki client-cert-validate - which checks a certificate in the client certdb and calls the System cert verification call performed by JSS in the system self test. This does some basic extensions and trust tests, and also validates cert validity and cert trust chain. 2. pki-server subsystem-cert-validate <subsystem> This calls pki client-cert-validate using the nssdb for the subsystem on all of the system certificates by default (or just one if the nickname is defined). This is a great thing to call when healthchecking an instance, and also will be used by pkispawn to verify the signing cert in the externally signed CA case. Trac Ticket 2043
-rw-r--r--base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java1
-rw-r--r--base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java194
-rw-r--r--base/server/python/pki/server/__init__.py2
-rw-r--r--base/server/python/pki/server/cli/subsystem.py118
4 files changed, 315 insertions, 0 deletions
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 f09ea74..8bafd84 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
@@ -39,6 +39,7 @@ public class ClientCLI extends CLI {
addModule(new ClientCertRemoveCLI(this));
addModule(new ClientCertRequestCLI(this));
addModule(new ClientCertShowCLI(this));
+ addModule(new ClientCertValidateCLI(this));
}
public String getFullName() {
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java
new file mode 100644
index 0000000..3988c71
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java
@@ -0,0 +1,194 @@
+// --- 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) 2016 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.client;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.lang.StringUtils;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.CertificateUsage;
+
+import com.netscape.cmstools.cli.CLI;
+
+/**
+ * @author Ade Lee
+ */
+public class ClientCertValidateCLI extends CLI {
+
+ public ClientCLI clientCLI;
+
+ public ClientCertValidateCLI(ClientCLI clientCLI) {
+ super("cert-validate", "Validate certificate", clientCLI);
+ this.clientCLI = clientCLI;
+
+ createOptions();
+ }
+
+ public void createOptions() {
+ Option option = new Option(null, "certusage", true, "Certificate usage.");
+ option.setArgName("certusage");
+ options.addOption(option);
+ }
+
+ public void printHelp() {
+ formatter.printHelp(getFullName() + " nickname", options);
+ }
+
+ public void execute(String[] args) throws Exception {
+ // Always check for "--help" prior to parsing
+ if (Arrays.asList(args).contains("--help")) {
+ // Display usage
+ printHelp();
+ System.exit(0);
+ }
+
+ CommandLine cmd = null;
+
+ try {
+ cmd = parser.parse(options, args);
+
+ } catch (Exception e) {
+ System.err.println("Error: " + e.getMessage());
+ printHelp();
+ System.exit(-1);
+ }
+
+ String[] cmdArgs = cmd.getArgs();
+
+ if (cmdArgs.length != 1) {
+ System.err.println("Error: Invalid number of arguments.");
+ printHelp();
+ System.exit(-1);
+ }
+
+ // Get nickname from command argument.
+ String nickname = cmdArgs[0];
+
+ // get usages from options
+ String certusage = cmd.getOptionValue("certusage");
+ boolean isValid = false;
+
+ try {
+ isValid = verifySystemCertByNickname(nickname, certusage);
+ } catch (Exception e) {
+ System.err.println("Certificate verification failed: " + e);
+ isValid = false;
+ }
+
+ if (isValid) {
+ System.exit(0);
+ } else {
+ System.exit(1);
+ }
+ }
+
+ public boolean verifySystemCertByNickname(String nickname, String certusage) throws Exception {
+ CertificateUsage cu = getCertificateUsage(certusage);
+ int ccu = 0;
+
+ if (cu == null) {
+ throw new Exception("Unsupported certificate usage " + certusage +
+ " in certificate " + nickname);
+ }
+
+ CryptoManager cm = CryptoManager.getInstance();
+ if (cu.getUsage() != CryptoManager.CertificateUsage.CheckAllUsages.getUsage()) {
+ if (cm.isCertValid(nickname, true, cu)) {
+ System.out.println("Valid certificate: " + nickname);
+ return true;
+ } else {
+ System.out.println("Invalid certificate: " + nickname);
+ return false;
+ }
+
+ } else {
+ // check all possible usages
+ ccu = cm.isCertValid(nickname, true);
+ if (ccu == CertificateUsage.basicCertificateUsages) {
+ /* cert is good for nothing */
+ System.out.println("Cert is good for nothing: " + nickname);
+ return false;
+ } else {
+ List<String> usages = new ArrayList<String>();
+ if ((ccu & CryptoManager.CertificateUsage.SSLServer.getUsage()) != 0)
+ usages.add("SSLServer");
+ if ((ccu & CryptoManager.CertificateUsage.SSLClient.getUsage()) != 0)
+ usages.add("SSLClient");
+ if ((ccu & CryptoManager.CertificateUsage.SSLServerWithStepUp.getUsage()) != 0)
+ usages.add("SSLServerWithStepUp");
+ if ((ccu & CryptoManager.CertificateUsage.SSLCA.getUsage()) != 0)
+ usages.add("SSLCA");
+ if ((ccu & CryptoManager.CertificateUsage.EmailSigner.getUsage()) != 0)
+ usages.add("EmailSigner");
+ if ((ccu & CryptoManager.CertificateUsage.EmailRecipient.getUsage()) != 0)
+ usages.add("EmailRecipient");
+ if ((ccu & CryptoManager.CertificateUsage.ObjectSigner.getUsage()) != 0)
+ usages.add("ObjectSigner");
+ if ((ccu & CryptoManager.CertificateUsage.UserCertImport.getUsage()) != 0)
+ usages.add("UserCertImport");
+ if ((ccu & CryptoManager.CertificateUsage.VerifyCA.getUsage()) != 0)
+ usages.add("VerifyCA");
+ if ((ccu & CryptoManager.CertificateUsage.ProtectedObjectSigner.getUsage()) != 0)
+ usages.add("ProtectedObjectSigner");
+ if ((ccu & CryptoManager.CertificateUsage.StatusResponder.getUsage()) != 0)
+ usages.add("StatusResponder");
+ if ((ccu & CryptoManager.CertificateUsage.AnyCA.getUsage()) != 0)
+ usages.add("AnyCA");
+ System.out.println("Cert has the following usages: " + StringUtils.join(usages, ','));
+ return true;
+ }
+ }
+ }
+
+ public CertificateUsage getCertificateUsage(String certusage) {
+ CertificateUsage cu = null;
+ if ((certusage == null) || certusage.equals(""))
+ cu = CryptoManager.CertificateUsage.CheckAllUsages;
+ else if (certusage.equalsIgnoreCase("CheckAllUsages"))
+ cu = CryptoManager.CertificateUsage.CheckAllUsages;
+ else if (certusage.equalsIgnoreCase("SSLServer"))
+ cu = CryptoManager.CertificateUsage.SSLServer;
+ else if (certusage.equalsIgnoreCase("SSLServerWithStepUp"))
+ cu = CryptoManager.CertificateUsage.SSLServerWithStepUp;
+ else if (certusage.equalsIgnoreCase("SSLClient"))
+ cu = CryptoManager.CertificateUsage.SSLClient;
+ else if (certusage.equalsIgnoreCase("SSLCA"))
+ cu = CryptoManager.CertificateUsage.SSLCA;
+ else if (certusage.equalsIgnoreCase("AnyCA"))
+ cu = CryptoManager.CertificateUsage.AnyCA;
+ else if (certusage.equalsIgnoreCase("StatusResponder"))
+ cu = CryptoManager.CertificateUsage.StatusResponder;
+ else if (certusage.equalsIgnoreCase("ObjectSigner"))
+ cu = CryptoManager.CertificateUsage.ObjectSigner;
+ else if (certusage.equalsIgnoreCase("UserCertImport"))
+ cu = CryptoManager.CertificateUsage.UserCertImport;
+ else if (certusage.equalsIgnoreCase("ProtectedObjectSigner"))
+ cu = CryptoManager.CertificateUsage.ProtectedObjectSigner;
+ else if (certusage.equalsIgnoreCase("VerifyCA"))
+ cu = CryptoManager.CertificateUsage.VerifyCA;
+ else if (certusage.equalsIgnoreCase("EmailSigner"))
+ cu = CryptoManager.CertificateUsage.EmailSigner;
+
+ return cu;
+ }
+}
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index 64688b3..1c590c3 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -156,6 +156,8 @@ class PKISubsystem(object):
'%s.%s.cert' % (self.name, cert_id), None)
cert['request'] = self.config.get(
'%s.%s.certreq' % (self.name, cert_id), None)
+ cert['certusage'] = self.config.get(
+ '%s.cert.%s.certusage' % (self.name, cert_id), None)
return cert
def update_subsystem_cert(self, cert):
diff --git a/base/server/python/pki/server/cli/subsystem.py b/base/server/python/pki/server/cli/subsystem.py
index 03d48f9..6d60468 100644
--- a/base/server/python/pki/server/cli/subsystem.py
+++ b/base/server/python/pki/server/cli/subsystem.py
@@ -24,8 +24,11 @@ import base64
import getopt
import getpass
import nss.nss as nss
+import os
import string
+import subprocess
import sys
+from tempfile import mkstemp
import pki.cli
import pki.nssdb
@@ -299,6 +302,7 @@ class SubsystemCertCLI(pki.cli.CLI):
self.add_module(SubsystemCertShowCLI())
self.add_module(SubsystemCertExportCLI())
self.add_module(SubsystemCertUpdateCLI())
+ self.add_module(SubsystemCertValidateCLI())
@staticmethod
def print_subsystem_cert(cert, show_all=False):
@@ -713,3 +717,117 @@ class SubsystemCertUpdateCLI(pki.cli.CLI):
self.print_message('Updated "%s" subsystem certificate' % cert_id)
SubsystemCertCLI.print_subsystem_cert(subsystem_cert)
+
+
+class SubsystemCertValidateCLI(pki.cli.CLI):
+
+ def __init__(self):
+ super(SubsystemCertValidateCLI, self).__init__(
+ 'validate', 'Validate subsystem certificates')
+
+ def usage(self):
+ print('Usage: pki-server subsystem-cert-validate [OPTIONS] <subsystem ID> [<cert_id>]')
+ print()
+ print(' -i, --instance <instance ID> Instance ID (default: pki-tomcat).')
+ print(' -v, --verbose Run in verbose mode.')
+ print(' --help Show help message.')
+ print()
+
+ def execute(self, argv):
+
+ try:
+ opts, args = getopt.gnu_getopt(argv, 'i:v', [
+ 'instance=',
+ 'verbose', 'help'])
+
+ except getopt.GetoptError as e:
+ print('ERROR: ' + str(e))
+ self.usage()
+ sys.exit(1)
+
+ if len(args) < 1:
+ print('ERROR: missing subsystem ID')
+ self.usage()
+ sys.exit(1)
+
+ subsystem_name = args[0]
+
+ if len(args) >=2:
+ cert_id = args[1]
+ else:
+ cert_id = None
+
+ instance_name = 'pki-tomcat'
+
+ for o, a in opts:
+ if o in ('-i', '--instance'):
+ instance_name = a
+
+ elif o in ('-v', '--verbose'):
+ self.set_verbose(True)
+
+ elif o == '--help':
+ self.print_help()
+ sys.exit()
+
+ else:
+ self.print_message('ERROR: unknown option ' + o)
+ self.usage()
+ sys.exit(1)
+
+ instance = pki.server.PKIInstance(instance_name)
+ instance.load()
+
+ subsystem = instance.get_subsystem(subsystem_name)
+
+ if cert_id is not None:
+ certs = [subsystem.get_subsystem_cert(cert_id)]
+ else:
+ certs = subsystem.find_system_certs()
+
+ certs_valid = True
+ for cert in certs:
+ token = cert['token']
+
+ # get token password and store in temporary file
+ if token == 'Internal Key Storage Token':
+ passwd = instance.get_password('internal')
+ else:
+ passwd = instance.get_password("hardware-%s" % token)
+
+ pwfile_handle, pwfile_path = mkstemp()
+ os.write(pwfile_handle, passwd)
+ os.close(pwfile_handle)
+
+ cmd = ['pki', '-d', instance.nssdb_dir,
+ '-W', pwfile_path ]
+
+ if token != 'Internal Key Storage Token':
+ cmd.extend(['--token', token])
+
+ cmd.extend(
+ ['client-cert-validate',
+ cert['nickname'],
+ '--certusage', cert['certusage']]
+ )
+
+ try:
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+ self.print_message("Valid certificate : %s" %cert['nickname'])
+ except subprocess.CalledProcessError as e:
+ certs_valid = False
+ if e.returncode == 1:
+ self.print_message("Invalid certificate: %s"
+ % cert['nickname'])
+ else:
+ self.print_message("Error in validating certificate: %s"
+ % cert['nickname'])
+ self.print_message(e.output)
+ finally:
+ os.unlink(pwfile_path)
+
+ if certs_valid:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+