[Pki-devel] [PATCH] 689 Added pki-server commands to export system certificates.

Endi Sukma Dewata edewata at redhat.com
Tue Feb 23 05:38:07 UTC 2016


Some pki-server commands have been added to simplify exporting
the required certificates for subsystem installations. These
commands will invoke the pki pkcs12 utility to export the
certificates from the instance NSS database.

The pki-server ca-cert-chain-export command will export the
the certificate chain needed for installing additional
subsystems running on a separate instance.

The pki-server <subsystem>-clone-prepare commands will export
the certificates required for cloning a subsystem.

https://fedorahosted.org/pki/ticket/1742

-- 
Endi S. Dewata
-------------- next part --------------
From 25d302f2a4799946636edcfe97a428303021d689 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata at redhat.com>
Date: Fri, 19 Feb 2016 15:09:49 +0100
Subject: [PATCH] Added pki-server commands to export system certificates.

Some pki-server commands have been added to simplify exporting
the required certificates for subsystem installations. These
commands will invoke the pki pkcs12 utility to export the
certificates from the instance NSS database.

The pki-server ca-cert-chain-export command will export the
the certificate chain needed for installing additional
subsystems running on a separate instance.

The pki-server <subsystem>-clone-prepare commands will export
the certificates required for cloning a subsystem.

https://fedorahosted.org/pki/ticket/1742
---
 base/common/python/pki/nssdb.py                |  22 ++-
 base/server/python/pki/server/__init__.py      | 121 ++++++++++++++-
 base/server/python/pki/server/cli/ca.py        | 202 ++++++++++++++++++++++++-
 base/server/python/pki/server/cli/instance.py  |  94 ++++++++++++
 base/server/python/pki/server/cli/kra.py       | 139 +++++++++++++++++
 base/server/python/pki/server/cli/ocsp.py      | 138 +++++++++++++++++
 base/server/python/pki/server/cli/subsystem.py |  74 +++++----
 base/server/python/pki/server/cli/tks.py       | 138 +++++++++++++++++
 base/server/python/pki/server/cli/tps.py       | 138 +++++++++++++++++
 base/server/sbin/pki-server                    |   9 ++
 10 files changed, 1036 insertions(+), 39 deletions(-)
 create mode 100644 base/server/python/pki/server/cli/kra.py
 create mode 100644 base/server/python/pki/server/cli/ocsp.py
 create mode 100644 base/server/python/pki/server/cli/tks.py
 create mode 100644 base/server/python/pki/server/cli/tps.py

diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py
index c6beab317fd0f3ea67dc02c356528ae50f8d6e1a..a418cdc00aaadec6f7635dd2d2eefdf8fb8d7888 100644
--- a/base/common/python/pki/nssdb.py
+++ b/base/common/python/pki/nssdb.py
@@ -484,7 +484,7 @@ class NSSDatabase(object):
         finally:
             shutil.rmtree(tmpdir)
 
-    def export_pkcs12(self, pkcs12_file, nickname, pkcs12_password=None,
+    def export_pkcs12(self, pkcs12_file, nicknames=None, pkcs12_password=None,
                       pkcs12_password_file=None):
 
         tmpdir = tempfile.mkdtemp()
@@ -502,14 +502,24 @@ class NSSDatabase(object):
                 raise Exception('Missing PKCS #12 password')
 
             cmd = [
-                'pk12util',
+                'pki',
                 '-d', self.directory,
-                '-k', self.password_file,
-                '-o', pkcs12_file,
-                '-w', password_file,
-                '-n', nickname
+                '-C', self.password_file
             ]
 
+            if self.token and self.token != 'internal':
+                cmd.extend(['--token', self.token])
+
+            cmd.extend(['pkcs12-export'])
+
+            cmd.extend([
+                '--pkcs12', pkcs12_file,
+                '--pkcs12-password-file', password_file
+            ])
+
+            if nicknames:
+                cmd.extend(nicknames)
+
             subprocess.check_call(cmd)
 
         finally:
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index cb246aaa1a162c1c8971ef50bb8312a5b2e2737b..04635f85641b91b6093482884924e39cdc7ecf9b 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -64,10 +64,9 @@ class PKISubsystem(object):
     def __init__(self, instance, subsystem_name):
 
         self.instance = instance
-        self.name = subsystem_name
-        self.type = instance.type
+        self.name = subsystem_name  # e.g. ca, kra
 
-        if self.type >= 10:
+        if instance.type >= 10:
             self.base_dir = os.path.join(self.instance.base_dir, self.name)
         else:
             self.base_dir = instance.base_dir
@@ -87,8 +86,8 @@ class PKISubsystem(object):
             instance.conf_dir, 'Catalina', 'localhost', self.name + '.xml')
 
         self.config = {}
-        self.type = None
-        self.prefix = None
+        self.type = None    # e.g. CA, KRA
+        self.prefix = None  # e.g. ca, kra
 
         # custom subsystem location
         self.doc_base = os.path.join(self.base_dir, 'webapps', self.name)
@@ -107,7 +106,7 @@ class PKISubsystem(object):
         self.type = self.config['cs.type']
         self.prefix = self.type.lower()
 
-    def find_subsystem_certs(self):
+    def find_system_certs(self):
         certs = []
 
         cert_ids = self.config['%s.cert.list' % self.name].split(',')
@@ -144,6 +143,116 @@ class PKISubsystem(object):
         self.config['%s.%s.certreq' % (self.name, cert_id)] = (
             cert.get('request', None))
 
+    def export_system_cert(
+            self,
+            cert_id,
+            pkcs12_file,
+            pkcs12_password_file,
+            new_file=False):
+
+        cert = self.get_subsystem_cert(cert_id)
+        nickname = cert['nickname']
+        token = cert['token']
+        if token == 'Internal Key Storage Token':
+            token = 'internal'
+        nssdb_password = self.instance.get_password(token)
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            nssdb_password_file = os.path.join(tmpdir, 'password.txt')
+            with open(nssdb_password_file, 'w') as f:
+                f.write(nssdb_password)
+
+            # add the certificate, key, and chain
+            cmd = [
+                'pki',
+                '-d', self.instance.nssdb_dir,
+                '-C', nssdb_password_file
+            ]
+
+            if token and token != 'internal':
+                cmd.extend(['--token', token])
+
+            cmd.extend([
+                'pkcs12-cert-add',
+                '--pkcs12', pkcs12_file,
+                '--pkcs12-password-file', pkcs12_password_file,
+            ])
+
+            if new_file:
+                cmd.extend(['--new-file'])
+
+            cmd.extend([
+                nickname
+            ])
+
+            subprocess.check_call(cmd)
+
+        finally:
+            shutil.rmtree(tmpdir)
+
+    def export_cert_chain(
+            self,
+            pkcs12_file,
+            pkcs12_password_file):
+
+        # use subsystem certificate to get certificate chain
+        cert = self.get_subsystem_cert('subsystem')
+        nickname = cert['nickname']
+        token = cert['token']
+        if token == 'Internal Key Storage Token':
+            token = 'internal'
+        nssdb_password = self.instance.get_password(token)
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            nssdb_password_file = os.path.join(tmpdir, 'password.txt')
+            with open(nssdb_password_file, 'w') as f:
+                f.write(nssdb_password)
+
+            # export the certificate, key, and chain
+            cmd = [
+                'pki',
+                '-d', self.instance.nssdb_dir,
+                '-C', nssdb_password_file
+            ]
+
+            if token and token != 'internal':
+                cmd.extend(['--token', token])
+
+            cmd.extend([
+                'pkcs12-export',
+                '--pkcs12', pkcs12_file,
+                '--pkcs12-password-file', pkcs12_password_file,
+                nickname
+            ])
+
+            subprocess.check_call(cmd)
+
+            # remove the certificate and key, but keep the chain
+            cmd = [
+                'pki',
+                '-d', self.instance.nssdb_dir,
+                '-C', nssdb_password_file
+            ]
+
+            if token and token != 'internal':
+                cmd.extend(['--token', token])
+
+            cmd.extend([
+                'pkcs12-cert-del',
+                '--pkcs12', pkcs12_file,
+                '--pkcs12-password-file', pkcs12_password_file,
+                nickname
+            ])
+
+            subprocess.check_call(cmd)
+
+        finally:
+            shutil.rmtree(tmpdir)
+
     def save(self):
         sorted_config = sorted(self.config.items(), key=operator.itemgetter(0))
         with io.open(self.cs_conf, 'wb') as f:
diff --git a/base/server/python/pki/server/cli/ca.py b/base/server/python/pki/server/cli/ca.py
index e35e741c55102e03276b81868a4997d1d05f4f7a..a47a293cffc3313f76e28c63934ea7ef526a6c25 100644
--- a/base/server/python/pki/server/cli/ca.py
+++ b/base/server/python/pki/server/cli/ca.py
@@ -22,10 +22,12 @@ from __future__ import absolute_import
 from __future__ import print_function
 import getopt
 import io
+import os
+import shutil
 import sys
+import tempfile
 
 import pki.cli
-import pki.server.ca
 
 
 class CACLI(pki.cli.CLI):
@@ -35,6 +37,7 @@ class CACLI(pki.cli.CLI):
             'ca', 'CA management commands')
 
         self.add_module(CACertCLI())
+        self.add_module(CACloneCLI())
 
 
 class CACertCLI(pki.cli.CLI):
@@ -43,9 +46,106 @@ class CACertCLI(pki.cli.CLI):
         super(CACertCLI, self).__init__(
             'cert', 'CA certificates management commands')
 
+        self.add_module(CACertChainCLI())
         self.add_module(CACertRequestCLI())
 
 
+class CACertChainCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(CACertChainCLI, self).__init__(
+            'chain', 'CA certificate chain management commands')
+
+        self.add_module(CACertChainExportCLI())
+
+
+class CACertChainExportCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(CACertChainExportCLI, self).__init__(
+            'export', 'Export certificate chain')
+
+    def print_help(self):
+        print('Usage: pki-server ca-cert-chain-export [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file               PKCS #12 file to store certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'i:v', [
+                'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12-file':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                with io.open(a, 'rb') as f:
+                    pkcs12_password = f.read()
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        subsystem = instance.get_subsystem('ca')
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt')
+            with open(pkcs12_password_file, 'w') as f:
+                f.write(pkcs12_password)
+
+            subsystem.export_cert_chain(pkcs12_file, pkcs12_password_file)
+
+        finally:
+            shutil.rmtree(tmpdir)
+
+
 class CACertRequestCLI(pki.cli.CLI):
 
     def __init__(self):
@@ -203,3 +303,103 @@ class CACertRequestShowCLI(pki.cli.CLI):
 
         else:
             CACertRequestCLI.print_request(request, details=True)
+
+
+class CACloneCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(CACloneCLI, self).__init__(
+            'clone', 'CA clone management commands')
+
+        self.add_module(CAClonePrepareCLI())
+
+
+class CAClonePrepareCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(CAClonePrepareCLI, self).__init__(
+            'prepare', 'Prepare CA clone')
+
+    def print_help(self):
+        print('Usage: pki-server ca-clone-prepare [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file               PKCS #12 file to store certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'i:v', [
+                'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12-file':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                with io.open(a, 'rb') as f:
+                    pkcs12_password = f.read()
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        subsystem = instance.get_subsystem('ca')
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt')
+            with open(pkcs12_password_file, 'w') as f:
+                f.write(pkcs12_password)
+
+            subsystem.export_system_cert(
+                'subsystem', pkcs12_file, pkcs12_password_file, new_file=True)
+            subsystem.export_system_cert('signing', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('ocsp_signing', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('audit_signing', pkcs12_file, pkcs12_password_file)
+
+        finally:
+            shutil.rmtree(tmpdir)
diff --git a/base/server/python/pki/server/cli/instance.py b/base/server/python/pki/server/cli/instance.py
index 5e70e5f28c566ed7db7f7b35fa08327661bacdbe..b5e6a5e4105b455337d33eefc61c631d57f3c6bd 100644
--- a/base/server/python/pki/server/cli/instance.py
+++ b/base/server/python/pki/server/cli/instance.py
@@ -21,6 +21,7 @@
 from __future__ import absolute_import
 from __future__ import print_function
 import getopt
+import getpass
 import os
 import sys
 
@@ -35,6 +36,7 @@ class InstanceCLI(pki.cli.CLI):
         super(InstanceCLI, self).__init__('instance',
                                           'Instance management commands')
 
+        self.add_module(InstanceCertCLI())
         self.add_module(InstanceFindCLI())
         self.add_module(InstanceShowCLI())
         self.add_module(InstanceStartCLI())
@@ -49,6 +51,98 @@ class InstanceCLI(pki.cli.CLI):
         print('  Active: %s' % instance.is_active())
 
 
+class InstanceCertCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(InstanceCertCLI, self).__init__(
+            'cert', 'Instance certificate management commands')
+
+        self.add_module(InstanceCertExportCLI())
+
+
+class InstanceCertExportCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(InstanceCertExportCLI, self).__init__(
+            'export', 'Export subsystem certificate')
+
+    def print_help(self):  # flake8: noqa
+        print('Usage: pki-server instance-cert-export [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>       Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file <path>           Output file to store the exported certificate and key in PKCS #12 format.')
+        print('      --pkcs12-password <password>   Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file <path>  Input file containing the password for the PKCS #12 file.')
+        print('  -v, --verbose                      Run in verbose mode.')
+        print('      --help                         Show help message.')
+        print()
+
+    def execute(self, argv):
+
+        try:
+            opts, _ = getopt.gnu_getopt(argv, 'i:v', [
+                'instance=',
+                'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+        pkcs12_password_file = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12-file':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                pkcs12_password_file = a
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: missing output file')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        if not pkcs12_password and not pkcs12_password_file:
+            pkcs12_password = getpass.getpass(prompt='Enter password for PKCS #12 file: ')
+
+        nssdb = instance.open_nssdb()
+        try:
+            nssdb.export_pkcs12(
+                pkcs12_file=pkcs12_file,
+                pkcs12_password=pkcs12_password,
+                pkcs12_password_file=pkcs12_password_file)
+        finally:
+            nssdb.close()
+
+        self.print_message('Exported certificates')
+
+
 class InstanceFindCLI(pki.cli.CLI):
 
     def __init__(self):
diff --git a/base/server/python/pki/server/cli/kra.py b/base/server/python/pki/server/cli/kra.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1b27dbc13167af483ced1c1118f55ea44492419
--- /dev/null
+++ b/base/server/python/pki/server/cli/kra.py
@@ -0,0 +1,139 @@
+# Authors:
+#     Endi S. Dewata <edewata at redhat.com>
+#
+# 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.
+#
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+import getopt
+import io
+import os
+import shutil
+import sys
+import tempfile
+
+import pki.cli
+
+
+class KRACLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(KRACLI, self).__init__(
+            'kra', 'KRA management commands')
+
+        self.add_module(KRACloneCLI())
+
+
+class KRACloneCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(KRACloneCLI, self).__init__(
+            'clone', 'KRA clone management commands')
+
+        self.add_module(KRAClonePrepareCLI())
+
+
+class KRAClonePrepareCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(KRAClonePrepareCLI, self).__init__(
+            'prepare', 'Prepare KRA clone')
+
+    def print_help(self):
+        print('Usage: pki-server kra-clone-prepare [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file               PKCS #12 file to store certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'i:v', [
+                'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12-file':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                with io.open(a, 'rb') as f:
+                    pkcs12_password = f.read()
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        subsystem = instance.get_subsystem('kra')
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt')
+            with open(pkcs12_password_file, 'w') as f:
+                f.write(pkcs12_password)
+
+            subsystem.export_system_cert(
+                'subsystem', pkcs12_file, pkcs12_password_file, new_file=True)
+            subsystem.export_system_cert('transport', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('storage', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('audit_signing', pkcs12_file, pkcs12_password_file)
+
+        finally:
+            shutil.rmtree(tmpdir)
diff --git a/base/server/python/pki/server/cli/ocsp.py b/base/server/python/pki/server/cli/ocsp.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b1b43487aac97e86962edfd5ba1bb687e28a69e
--- /dev/null
+++ b/base/server/python/pki/server/cli/ocsp.py
@@ -0,0 +1,138 @@
+# Authors:
+#     Endi S. Dewata <edewata at redhat.com>
+#
+# 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.
+#
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+import getopt
+import io
+import os
+import shutil
+import sys
+import tempfile
+
+import pki.cli
+
+
+class OCSPCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(OCSPCLI, self).__init__(
+            'ocsp', 'OCSP management commands')
+
+        self.add_module(OCSPCloneCLI())
+
+
+class OCSPCloneCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(OCSPCloneCLI, self).__init__(
+            'clone', 'OCSP clone management commands')
+
+        self.add_module(OCSPClonePrepareCLI())
+
+
+class OCSPClonePrepareCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(OCSPClonePrepareCLI, self).__init__(
+            'prepare', 'Prepare OCSP clone')
+
+    def print_help(self):
+        print('Usage: pki-server ocsp-clone-prepare [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file               PKCS #12 file to store certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'i:v', [
+                'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                with io.open(a, 'rb') as f:
+                    pkcs12_password = f.read()
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        subsystem = instance.get_subsystem('ocsp')
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt')
+            with open(pkcs12_password_file, 'w') as f:
+                f.write(pkcs12_password)
+
+            subsystem.export_system_cert(
+                'subsystem', pkcs12_file, pkcs12_password_file, new_file=True)
+            subsystem.export_system_cert('signing', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('audit_signing', pkcs12_file, pkcs12_password_file)
+
+        finally:
+            shutil.rmtree(tmpdir)
diff --git a/base/server/python/pki/server/cli/subsystem.py b/base/server/python/pki/server/cli/subsystem.py
index f0e38b65e3eec743773325e6f52debf6d665e891..8450f7b61d8191b737de8c3e47a80b4b2cca1691 100644
--- a/base/server/python/pki/server/cli/subsystem.py
+++ b/base/server/python/pki/server/cli/subsystem.py
@@ -301,12 +301,14 @@ class SubsystemCertCLI(pki.cli.CLI):
         self.add_module(SubsystemCertUpdateCLI())
 
     @staticmethod
-    def print_subsystem_cert(cert):
+    def print_subsystem_cert(cert, show_all=False):
         print('  Cert ID: %s' % cert['id'])
         print('  Nickname: %s' % cert['nickname'])
         print('  Token: %s' % cert['token'])
-        print('  Certificate: %s' % cert['data'])
-        print('  Request: %s' % cert['request'])
+
+        if show_all:
+            print('  Certificate: %s' % cert['data'])
+            print('  Request: %s' % cert['request'])
 
 
 class SubsystemCertFindCLI(pki.cli.CLI):
@@ -315,10 +317,11 @@ class SubsystemCertFindCLI(pki.cli.CLI):
         super(SubsystemCertFindCLI, self).__init__(
             'find', 'Find subsystem certificates')
 
-    def usage(self):
+    def print_help(self):
         print('Usage: pki-server subsystem-cert-find [OPTIONS] <subsystem ID>')
         print()
         print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --show-all                  Show all attributes.')
         print('  -v, --verbose                   Run in verbose mode.')
         print('      --help                      Show help message.')
         print()
@@ -327,26 +330,30 @@ class SubsystemCertFindCLI(pki.cli.CLI):
 
         try:
             opts, args = getopt.gnu_getopt(argv, 'i:v', [
-                'instance=',
+                'instance=', 'show-all',
                 'verbose', 'help'])
 
         except getopt.GetoptError as e:
             print('ERROR: ' + str(e))
-            self.usage()
+            self.print_help()
             sys.exit(1)
 
         if len(args) != 1:
             print('ERROR: missing subsystem ID')
-            self.usage()
+            self.print_help()
             sys.exit(1)
 
         subsystem_name = args[0]
         instance_name = 'pki-tomcat'
+        show_all = False
 
         for o, a in opts:
             if o in ('-i', '--instance'):
                 instance_name = a
 
+            elif o == '--show-all':
+                show_all = True
+
             elif o in ('-v', '--verbose'):
                 self.set_verbose(True)
 
@@ -356,14 +363,14 @@ class SubsystemCertFindCLI(pki.cli.CLI):
 
             else:
                 print('ERROR: unknown option ' + o)
-                self.usage()
+                self.print_help()
                 sys.exit(1)
 
         instance = pki.server.PKIInstance(instance_name)
         instance.load()
 
         subsystem = instance.get_subsystem(subsystem_name)
-        results = subsystem.find_subsystem_certs()
+        results = subsystem.find_system_certs()
 
         self.print_message('%s entries matched' % len(results))
 
@@ -374,7 +381,7 @@ class SubsystemCertFindCLI(pki.cli.CLI):
             else:
                 print()
 
-            SubsystemCertCLI.print_subsystem_cert(cert)
+            SubsystemCertCLI.print_subsystem_cert(cert, show_all)
 
 
 class SubsystemCertShowCLI(pki.cli.CLI):
@@ -448,8 +455,8 @@ class SubsystemCertExportCLI(pki.cli.CLI):
         super(SubsystemCertExportCLI, self).__init__(
             'export', 'Export subsystem certificate')
 
-    def usage(self):  # flake8: noqa
-        print('Usage: pki-server subsystem-cert-export [OPTIONS] <subsystem ID> <cert ID>')
+    def print_help(self):  # flake8: noqa
+        print('Usage: pki-server subsystem-cert-export [OPTIONS] <subsystem ID> [cert ID]')
         print()
         print('  -i, --instance <instance ID>       Instance ID (default: pki-tomcat).')
         print('      --cert-file <path>             Output file to store the exported certificate in PEM format.')
@@ -471,21 +478,16 @@ class SubsystemCertExportCLI(pki.cli.CLI):
 
         except getopt.GetoptError as e:
             print('ERROR: ' + str(e))
-            self.usage()
+            self.print_help()
             sys.exit(1)
 
         if len(args) < 1:
             print('ERROR: missing subsystem ID')
-            self.usage()
-            sys.exit(1)
-
-        if len(args) < 2:
-            print('ERROR: missing cert ID')
-            self.usage()
+            self.print_help()
             sys.exit(1)
 
         subsystem_name = args[0]
-        cert_id = args[1]
+
         instance_name = 'pki-tomcat'
         cert_file = None
         csr_file = None
@@ -521,19 +523,28 @@ class SubsystemCertExportCLI(pki.cli.CLI):
 
             else:
                 print('ERROR: unknown option ' + o)
-                self.usage()
+                self.print_help()
                 sys.exit(1)
 
-        if not cert_file and not csr_file and not pkcs12_file:
+        if not pkcs12_file:
             print('ERROR: missing output file')
-            self.usage()
+            self.print_help()
             sys.exit(1)
 
         instance = pki.server.PKIInstance(instance_name)
         instance.load()
 
         subsystem = instance.get_subsystem(subsystem_name)
-        subsystem_cert = subsystem.get_subsystem_cert(cert_id)
+        subsystem_cert = None
+
+        if len(args) >= 2:
+            cert_id = args[1]
+            subsystem_cert = subsystem.get_subsystem_cert(cert_id)
+
+        if (cert_file or csr_file) and not subsystem_cert:
+            print('ERROR: missing cert ID')
+            self.print_help()
+            sys.exit(1)
 
         if cert_file:
 
@@ -552,17 +563,28 @@ class SubsystemCertExportCLI(pki.cli.CLI):
             if not pkcs12_password and not pkcs12_password_file:
                 pkcs12_password = getpass.getpass(prompt='Enter password for PKCS #12 file: ')
 
+            nicknames = []
+
+            if subsystem_cert:
+                nicknames.append(subsystem_cert['nickname'])
+
+            else:
+                subsystem_certs = subsystem.find_system_certs()
+                for subsystem_cert in subsystem_certs:
+                    nicknames.append(subsystem_cert['nickname'])
+
             nssdb = instance.open_nssdb()
             try:
                 nssdb.export_pkcs12(
                     pkcs12_file=pkcs12_file,
-                    nickname=subsystem_cert['nickname'],
+                    nicknames=nicknames,
                     pkcs12_password=pkcs12_password,
                     pkcs12_password_file=pkcs12_password_file)
+
             finally:
                 nssdb.close()
 
-        self.print_message('Exported %s certificate' % cert_id)
+        self.print_message('Export complete')
 
 
 class SubsystemCertUpdateCLI(pki.cli.CLI):
diff --git a/base/server/python/pki/server/cli/tks.py b/base/server/python/pki/server/cli/tks.py
new file mode 100644
index 0000000000000000000000000000000000000000..39343db98e937e23aaa08d5556f03b4ff8724917
--- /dev/null
+++ b/base/server/python/pki/server/cli/tks.py
@@ -0,0 +1,138 @@
+# Authors:
+#     Endi S. Dewata <edewata at redhat.com>
+#
+# 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.
+#
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+import getopt
+import io
+import os
+import shutil
+import sys
+import tempfile
+
+import pki.cli
+
+
+class TKSCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(TKSCLI, self).__init__(
+            'tks', 'TKS management commands')
+
+        self.add_module(TKSCloneCLI())
+
+
+class TKSCloneCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(TKSCloneCLI, self).__init__(
+            'clone', 'TKS clone management commands')
+
+        self.add_module(TKSClonePrepareCLI())
+
+
+class TKSClonePrepareCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(TKSClonePrepareCLI, self).__init__(
+            'prepare', 'Prepare TKS clone')
+
+    def print_help(self):
+        print('Usage: pki-server tks-clone-prepare [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file               PKCS #12 file to store certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'i:v', [
+                'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12-file':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                with io.open(a, 'rb') as f:
+                    pkcs12_password = f.read()
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        subsystem = instance.get_subsystem('tks')
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt')
+            with open(pkcs12_password_file, 'w') as f:
+                f.write(pkcs12_password)
+
+            subsystem.export_system_cert(
+                'subsystem', pkcs12_file, pkcs12_password_file, new_file=True)
+            subsystem.export_system_cert('signing', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('audit_signing', pkcs12_file, pkcs12_password_file)
+
+        finally:
+            shutil.rmtree(tmpdir)
diff --git a/base/server/python/pki/server/cli/tps.py b/base/server/python/pki/server/cli/tps.py
new file mode 100644
index 0000000000000000000000000000000000000000..05045cb0d7c4bd19956f8b98afe5b370bc587d07
--- /dev/null
+++ b/base/server/python/pki/server/cli/tps.py
@@ -0,0 +1,138 @@
+# Authors:
+#     Endi S. Dewata <edewata at redhat.com>
+#
+# 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.
+#
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+import getopt
+import io
+import os
+import shutil
+import sys
+import tempfile
+
+import pki.cli
+
+
+class TPSCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(TPSCLI, self).__init__(
+            'tps', 'TPS management commands')
+
+        self.add_module(TPSCloneCLI())
+
+
+class TPSCloneCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(TPSCloneCLI, self).__init__(
+            'clone', 'TPS clone management commands')
+
+        self.add_module(TPSClonePrepareCLI())
+
+
+class TPSClonePrepareCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(TPSClonePrepareCLI, self).__init__(
+            'prepare', 'Prepare TPS clone')
+
+    def print_help(self):
+        print('Usage: pki-server tps-clone-prepare [OPTIONS]')
+        print()
+        print('  -i, --instance <instance ID>    Instance ID (default: pki-tomcat).')
+        print('      --pkcs12-file               PKCS #12 file to store certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'i:v', [
+                'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'verbose', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        instance_name = 'pki-tomcat'
+        pkcs12_file = None
+        pkcs12_password = None
+
+        for o, a in opts:
+            if o in ('-i', '--instance'):
+                instance_name = a
+
+            elif o == '--pkcs12-file':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                with io.open(a, 'rb') as f:
+                    pkcs12_password = f.read()
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        instance = pki.server.PKIInstance(instance_name)
+        instance.load()
+
+        subsystem = instance.get_subsystem('tps')
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt')
+            with open(pkcs12_password_file, 'w') as f:
+                f.write(pkcs12_password)
+
+            subsystem.export_system_cert(
+                'subsystem', pkcs12_file, pkcs12_password_file, new_file=True)
+            subsystem.export_system_cert('signing', pkcs12_file, pkcs12_password_file)
+            subsystem.export_system_cert('audit_signing', pkcs12_file, pkcs12_password_file)
+
+        finally:
+            shutil.rmtree(tmpdir)
diff --git a/base/server/sbin/pki-server b/base/server/sbin/pki-server
index f3e784a1539a4cff82cdc765da53f2cb01b27a3c..5e81ed6b9cc36c2358a7b25e162b1c79d53f2967 100644
--- a/base/server/sbin/pki-server
+++ b/base/server/sbin/pki-server
@@ -26,6 +26,10 @@ import sys
 
 import pki.cli
 import pki.server.cli.ca
+import pki.server.cli.kra
+import pki.server.cli.ocsp
+import pki.server.cli.tks
+import pki.server.cli.tps
 import pki.server.cli.instance
 import pki.server.cli.subsystem
 import pki.server.cli.migrate
@@ -40,6 +44,11 @@ class PKIServerCLI(pki.cli.CLI):
             'PKI server command-line interface')
 
         self.add_module(pki.server.cli.ca.CACLI())
+        self.add_module(pki.server.cli.kra.KRACLI())
+        self.add_module(pki.server.cli.ocsp.OCSPCLI())
+        self.add_module(pki.server.cli.tks.TKSCLI())
+        self.add_module(pki.server.cli.tps.TPSCLI())
+
         self.add_module(pki.server.cli.instance.InstanceCLI())
         self.add_module(pki.server.cli.subsystem.SubsystemCLI())
         self.add_module(pki.server.cli.migrate.MigrateCLI())
-- 
2.4.3



More information about the Pki-devel mailing list