[Pki-devel] [PATCH] 657 Refactored CA certificate generation.

Endi Sukma Dewata edewata at redhat.com
Mon Nov 9 19:59:00 UTC 2015


The CA certificate request and signing processes have been moved
from the configuration servlet into the deployment scriptlet. This
way the admin will have the option to:

* generate self-signed CA certificate
* import externally-signed CA certificate
* import existing CA certificate

before the server is started for the first time.

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

Note: This is a preliminary patch. There are some unfinished works.

-- 
Endi S. Dewata
-------------- next part --------------
From f81bea0247d11109bb30c704648d50ab3050cc20 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata at redhat.com>
Date: Sat, 7 Nov 2015 00:09:19 +0100
Subject: [PATCH] Refactored CA certificate generation.

The CA certificate request and signing processes have been moved
from the configuration servlet into the deployment scriptlet. This
way the admin will have the option to:

* generate self-signed CA certificate
* import externally-signed CA certificate
* import existing CA certificate

before the server is started for the first time.

https://fedorahosted.org/pki/ticket/456
---
 base/common/python/pki/nss.py                      | 217 +++++++++++++++++++++
 .../cms/servlet/csadmin/ConfigurationUtils.java    |  86 +++++++-
 .../dogtagpki/server/rest/SystemConfigService.java |  29 ++-
 .../python/pki/server/deployment/pkihelper.py      |  16 +-
 .../server/deployment/scriptlets/configuration.py  | 207 ++++++++++++++++----
 .../server/deployment/scriptlets/finalization.py   |  12 +-
 6 files changed, 505 insertions(+), 62 deletions(-)
 create mode 100644 base/common/python/pki/nss.py

diff --git a/base/common/python/pki/nss.py b/base/common/python/pki/nss.py
new file mode 100644
index 0000000000000000000000000000000000000000..d156418fba34ddf6a6ad7ac3949afa401f86b22b
--- /dev/null
+++ b/base/common/python/pki/nss.py
@@ -0,0 +1,217 @@
+#!/usr/bin/python
+# 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) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+
+import base64
+import os
+import shutil
+import subprocess
+import tempfile
+
+
+class NSSDatabase(object):
+
+    def __init__(self, directory, password_file=None):
+        self.directory = directory
+        self.password_file = password_file
+
+    def add_cert(self,
+        nickname, cert_file,
+        trust_attributes='u,u,u'):
+
+        subprocess.check_call([
+            'certutil',
+            '-A',
+            '-d', self.directory,
+            '-n', nickname,
+            '-i', cert_file,
+            '-t', trust_attributes,
+        ])
+
+    def modify_cert(self,
+        nickname,
+        trust_attributes='u,u,u'):
+
+        subprocess.check_call([
+            'certutil',
+            '-M',
+            '-d', self.directory,
+            '-n', nickname,
+            '-t', trust_attributes,
+        ])
+
+    def create_noise(self, noise_file, size=2048):
+
+        subprocess.check_call([
+            'openssl',
+            'rand',
+            '-out', noise_file,
+            str(size)
+        ])
+
+    def create_request(self,
+        subject_dn,
+        noise_file,
+        request_file):
+
+        tmpdir = tempfile.mkdtemp()
+
+        try:
+            binary_request_file = os.path.join(tmpdir, 'request.bin')
+            b64_request_file = os.path.join(tmpdir, 'request.b64')
+
+            # generate binary request
+            subprocess.check_call([
+                'certutil',
+                '-R',
+                '-d', self.directory,
+                '-f', self.password_file,
+                '-s', subject_dn,
+                '-z', noise_file,
+                '-o', binary_request_file
+            ])
+
+            # encode binary request in base-64
+            subprocess.check_call([
+                'BtoA', binary_request_file, b64_request_file])
+
+            # read base-64 request
+            with open(b64_request_file, 'r') as f:
+                b64_request = f.read()
+
+            # add header and footer
+            with open(request_file, 'w') as f:
+                f.write('-----BEGIN NEW CERTIFICATE REQUEST-----\n')
+                f.write(b64_request)
+                f.write('-----END NEW CERTIFICATE REQUEST-----\n')
+
+        finally:
+            shutil.rmtree(tmpdir)
+
+    def create_self_signed_ca_cert(self,
+        issuer_dn,
+        request_file,
+        cert_file,
+        serial='1',
+        validity=240):
+
+        p = subprocess.Popen([
+            'certutil',
+            '-C',
+            '-x',
+            '-d', self.directory,
+            '-f', self.password_file,
+            '-c', issuer_dn,
+            '-a',
+            '-i', request_file,
+            '-o', cert_file,
+            '-m', serial,
+            '-v', str(validity),
+            '--keyUsage', 'digitalSignature,nonRepudiation,certSigning,crlSigning,critical',
+            '-2',
+            '-3',
+            '--extSKID',
+            '--extAIA'
+        ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+        keystroke = ''
+
+        # Is this a CA certificate [y/N]?
+        keystroke += 'y\n'
+
+        # Enter the path length constraint, enter to skip [<0 for unlimited path]:
+        keystroke += '\n'
+
+        # Is this a critical extension [y/N]?
+        keystroke += 'y\n'
+
+        # Enter value for the authKeyID extension [y/N]?
+        keystroke += 'y\n'
+
+        # TODO: generate SHA1 ID (see APolicyRule.formSHA1KeyId())
+        # Enter value for the key identifier fields,enter to omit:
+        keystroke += '2d:7e:83:37:75:5a:fd:0e:8d:52:a3:70:16:93:36:b8:4a:d6:84:9f\n'
+
+        # Select one of the following general name type:
+        keystroke += '0\n'
+
+        # Enter value for the authCertSerial field, enter to omit:
+        keystroke += '\n'
+
+        # Is this a critical extension [y/N]?
+        keystroke += '\n'
+
+        # TODO: generate SHA1 ID (see APolicyRule.formSHA1KeyId())
+        # Adding Subject Key ID extension.
+        # Enter value for the key identifier fields,enter to omit:
+        keystroke += '2d:7e:83:37:75:5a:fd:0e:8d:52:a3:70:16:93:36:b8:4a:d6:84:9f\n'
+
+        # Is this a critical extension [y/N]?
+        keystroke += '\n'
+
+        # Enter access method type for Authority Information Access extension:
+        keystroke += '2\n'
+
+        # Select one of the following general name type:
+        keystroke += '7\n'
+
+        # TODO: replace with actual hostname name and port number
+        # Enter data:
+        keystroke += 'http://server.example.com:8080/ca/ocsp\n'
+
+        # Select one of the following general name type:
+        keystroke += '0\n'
+
+        # Add another location to the Authority Information Access extension [y/N]
+        keystroke += '\n'
+
+        # Is this a critical extension [y/N]?
+        keystroke += '\n'
+
+        p.communicate(keystroke)
+
+        rc = p.wait()
+
+        if rc:
+            raise Exception('Failed to generate self-signed CA certificate. RC: %d' + rc)
+
+    def get_cert(self, nickname, cert_type='pem'):
+
+        if cert_type == 'pem':
+            cert_type_option = '-a'
+
+        elif cert_type == 'der' or cert_type == 'base64':
+            cert_type_option = '-r'
+
+        else:
+            raise Exception('Invalid certificate type: %s' % cert_type)
+
+        cert = subprocess.check_output([
+            'certutil',
+            '-L',
+            '-d', self.directory,
+            '-n', nickname,
+            cert_type_option
+        ])
+
+        if cert_type == 'base64':
+            cert = base64.b64encode(cert)
+
+        return cert
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 88118adf8a7535442d8f1f678ce14f6f6ac07e51..31d18f06e863a3388c6a2a79345a1f07b1926f6d 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -126,6 +126,7 @@ import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.EPropertyNotFound;
 import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.base.MetaInfo;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.base.ResourceNotFoundException;
 import com.netscape.certsrv.ca.ICertificateAuthority;
@@ -133,6 +134,8 @@ import com.netscape.certsrv.client.ClientConfig;
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.client.PKIConnection;
 import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.certsrv.dbs.certdb.ICertRecord;
+import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
 import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord;
 import com.netscape.certsrv.key.KeyData;
 import com.netscape.certsrv.ldap.ILdapConnFactory;
@@ -2318,24 +2321,55 @@ public class ConfigurationUtils {
     public static void createRSAKeyPair(String token, int keysize, IConfigStore config, String ct)
             throws NoSuchAlgorithmException, NoSuchTokenException, TokenException,
             CryptoManager.NotInitializedException, EPropertyNotFound, EBaseException {
-        /* generate key pair */
+
         KeyPair pair = null;
         do {
+            // generate key pair
             pair = CryptoUtil.generateRSAKeyPair(token, keysize);
+
+            // get private key ID
             byte id[] = ((org.mozilla.jss.crypto.PrivateKey) pair.getPrivate()).getUniqueID();
-            String kid = CryptoUtil.byte2string(id);
-            config.putString(PCERT_PREFIX + ct + ".privkey.id", kid);
-            // try to locate the private key
+
+            // find private key
             org.mozilla.jss.crypto.PrivateKey privk =
-                    CryptoUtil.findPrivateKeyFromID(CryptoUtil.string2byte(kid));
+                    CryptoUtil.findPrivateKeyFromID(id);
+
+            // if private key not found, generate a new key pair
             if (privk == null) {
-                CMS.debug("Found bad RSA key id " + kid);
                 pair = null;
             }
+
         } while (pair == null);
 
-        byte modulus[] = ((RSAPublicKey) pair.getPublic()).getModulus().toByteArray();
-        byte exponent[] = ((RSAPublicKey) pair.getPublic()).getPublicExponent().toByteArray();
+        storeKeyPair(config, ct, pair);
+    }
+
+    public static void loadKeyPair(String nickname, IConfigStore store, String ct) throws Exception {
+
+        CryptoManager cm = CryptoManager.getInstance();
+
+        X509Certificate cert = cm.findCertByNickname(nickname);
+
+        PublicKey publicKey = cert.getPublicKey();
+        PrivateKey privateKey = cm.findPrivKeyByCert(cert);
+
+        KeyPair pair = new KeyPair(publicKey, privateKey);
+        ConfigurationUtils.storeKeyPair(store, ct, pair);
+    }
+
+    public static void storeKeyPair(IConfigStore config, String ct, KeyPair pair)
+            throws TokenException, EBaseException {
+
+        RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
+        PrivateKey privateKey = (PrivateKey) pair.getPrivate();
+
+        byte id[] = privateKey.getUniqueID();
+
+        String kid = CryptoUtil.byte2string(id);
+        config.putString(PCERT_PREFIX + ct + ".privkey.id", kid);
+
+        byte modulus[] = publicKey.getModulus().toByteArray();
+        byte exponent[] = publicKey.getPublicExponent().toByteArray();
 
         config.putString(PCERT_PREFIX + ct + ".pubkey.modulus",
                 CryptoUtil.byte2string(modulus));
@@ -2812,6 +2846,20 @@ public class ConfigurationUtils {
         }
     }
 
+    public static void loadCertRequest(IConfigStore config, String certTag, Cert cert) throws Exception {
+
+        CMS.debug("ConfigurationUtils.loadCertRequest()");
+
+        String caDN = config.getString(PCERT_PREFIX + certTag + ".dn");
+        cert.setDN(caDN);
+
+        String subsystem = config.getString(PCERT_PREFIX + certTag + ".subsystem");
+        String certReqs = config.getString(subsystem + "." + certTag + ".certreq");
+        String certReqf = CryptoUtil.reqFormat(certReqs);
+
+        cert.setRequest(certReqf);
+    }
+
     public static void handleCertRequest(IConfigStore config, String certTag, Cert cert) throws EPropertyNotFound,
             EBaseException, InvalidKeyException, NotInitializedException, TokenException, NoSuchAlgorithmException,
             NoSuchProviderException, CertificateException, SignatureException, IOException {
@@ -2953,6 +3001,28 @@ public class ConfigurationUtils {
         return pubk;
     }
 
+    public static void loadCert(Cert cert) throws Exception {
+
+        String certTag = cert.getCertTag();
+        CMS.debug("Loading certificate " + certTag);
+
+        // load certificate
+        CryptoManager cm = CryptoManager.getInstance();
+        X509Certificate x509Cert = cm.findCertByNickname(cert.getNickname());
+        X509CertImpl x509CertImpl = new X509CertImpl(x509Cert.getEncoded());
+
+        ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem(ICertificateAuthority.ID);
+        ICertificateRepository cr = ca.getCertificateRepository();
+
+        BigInteger serialNo = x509Cert.getSerialNumber();
+
+        MetaInfo meta = new MetaInfo();
+
+        // create certificate record
+        ICertRecord record = cr.createCertRecord(serialNo, x509CertImpl, meta);
+        cr.addCertificateRecord(record);
+    }
+
     public static int handleCerts(Cert cert) throws IOException, EBaseException, CertificateException,
             NotInitializedException, TokenException, InvalidKeyException {
         String certTag = cert.getCertTag();
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
index a0138681a39baeff272d75408dbee9a74d0529dc..64c9cea408909025a03b44b243d3a865576c1d58 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
@@ -420,7 +420,14 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                 }
                 cs.commit(false);
 
-                if (!request.getStepTwo()) {
+                if (csType.equals("CA") && tag.equals("signing")) { // self-signed CA cert
+                    CMS.debug("configure(): loading signing cert key pair");
+                    ConfigurationUtils.loadKeyPair(certData.getNickname(), cs, tag);
+
+                } else if (csType.equals("CA") && tag.equals("external_signing")) { // externally-signed CA cert
+                    CMS.debug("configure(): external signing cert doesn't have key pair");
+
+                } else if (!request.getStepTwo()) {
                     if (keytype.equals("ecc")) {
                         String curvename = certData.getKeyCurveName() != null ?
                                 certData.getKeyCurveName() : cs.getString("keys.ecc.curve.default");
@@ -443,7 +450,14 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                 cert.setSubsystem(cs.getString("preop.cert." + tag + ".subsystem"));
                 cert.setType(cs.getString("preop.cert." + tag + ".type"));
 
-                if (!request.getStepTwo()) {
+                if (csType.equals("CA") && (tag.equals("signing") || tag.equals("external_signing"))) {
+                    // self-signed && externally-signed CA
+                    String certStr = cs.getString("ca." + tag + ".cert" );
+                    cert.setCert(certStr);
+                    CMS.debug("ConfigurationUtils: certificate " + tag + ": " + certStr);
+                    ConfigurationUtils.updateConfig(cs, tag);
+
+                } else if (!request.getStepTwo()) {
                     ConfigurationUtils.configCert(null, null, null, cert);
 
                 } else {
@@ -465,8 +479,15 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                     CMS.debug("Step 2:  certStr for '" + tag + "' is " + certStr);
                 }
 
-                // Handle Cert Requests for everything EXCEPT Stand-alone PKI (Step 2)
-                if (request.getStandAlone()) {
+                if (csType.equals("CA") && (tag.equals("signing") || tag.equals("external_signing"))) {
+                    CMS.debug("Loading cert request for " + tag + " certificate");
+                    ConfigurationUtils.loadCertRequest(cs, tag, cert);
+
+                    CMS.debug("Loading cert " + tag);
+                    ConfigurationUtils.loadCert(cert);
+
+                } else if (request.getStandAlone()) {
+                    // Handle Cert Requests for everything EXCEPT Stand-alone PKI (Step 2)
                     if (!request.getStepTwo()) {
                         // Stand-alone PKI (Step 1)
                         ConfigurationUtils.handleCertRequest(cs, tag, cert);
diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
index 61f04d215ba3eba48b7e18733fd58b29555ced83..26c37034c2ecceac89b6f1008731a9f402dc55f5 100644
--- a/base/server/python/pki/server/deployment/pkihelper.py
+++ b/base/server/python/pki/server/deployment/pkihelper.py
@@ -3813,17 +3813,7 @@ class ConfigClient:
             if not isinstance(certs, list):
                 certs = [certs]
             for cdata in certs:
-                if (self.subsystem == "CA" and self.external and
-                        not self.external_step_two):
-                    # External CA (Step 1)
-                    if cdata['tag'].lower() == "signing":
-                        # Save 'External CA Signing Certificate' CSR (Step 1)
-                        self.save_system_csr(
-                            cdata['request'],
-                            log.PKI_CONFIG_EXTERNAL_CSR_SAVE,
-                            self.mdict['pki_external_csr_path'])
-                        return
-                elif self.standalone and not self.external_step_two:
+                if self.standalone and not self.external_step_two:
                     # Stand-alone PKI (Step 1)
                     if cdata['tag'].lower() == "audit_signing":
                         # Save Stand-alone PKI 'Audit Signing Certificate' CSR
@@ -3992,7 +3982,9 @@ class ConfigClient:
             data.tokenPassword = self.mdict['pki_token_password']
         data.subsystemName = self.mdict['pki_subsystem_name']
         data.standAlone = self.standalone
-        data.stepTwo = self.external_step_two
+
+        # step two is no longer needed in the configuration servlet
+        data.stepTwo = False
 
         # Cloning parameters
         if self.mdict['pki_instance_type'] == "Tomcat":
diff --git a/base/server/python/pki/server/deployment/scriptlets/configuration.py b/base/server/python/pki/server/deployment/scriptlets/configuration.py
index c6e89023560fc92cb9bd451d9b7f05818807da8a..fa878d591602cd248e51a5c95b35c541fe18d59e 100644
--- a/base/server/python/pki/server/deployment/scriptlets/configuration.py
+++ b/base/server/python/pki/server/deployment/scriptlets/configuration.py
@@ -21,19 +21,75 @@
 
 from __future__ import absolute_import
 import json
+import os
 
 # PKI Deployment Imports
 from .. import pkiconfig as config
 from .. import pkimessages as log
 from .. import pkiscriptlet
-import pki.system
+
+import pki.nss
 import pki.encoder
+import pki.server
+import pki.system
+import pki.util
 
 
 # PKI Deployment Configuration Scriptlet
 class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
     rv = 0
 
+    def generate_ca_csr(self, deployer, subsystem, nssdb, request_file, password_file):
+
+        deployer.password.create_password_conf(
+            password_file,
+            deployer.mdict['pki_pin'], pin_sans_token=True)
+        deployer.file.modify(password_file,
+             uid=0, gid=0)
+
+        noise_file = os.path.join(
+            deployer.mdict['pki_database_path'], 'noise.bin')
+
+        nssdb.create_noise(
+            noise_file=noise_file,
+            size=int(deployer.mdict['pki_ca_signing_key_size']))
+
+        nssdb.create_request(
+            subject_dn=deployer.mdict['pki_ca_signing_subject_dn'],
+            noise_file=noise_file,
+            request_file=request_file)
+
+        b64_request = ''
+
+        with open(request_file) as f:
+            for line in f:
+                if line.startswith('-----BEGIN NEW CERTIFICATE REQUEST-----'):
+                    continue
+                if line.startswith('-----END NEW CERTIFICATE REQUEST-----'):
+                    continue
+                else:
+                    b64_request += line.rstrip('\r\n')
+
+        subsystem.config['ca.signing.certreq'] = b64_request
+
+    def import_ca_cert(self, subsystem, nssdb, nickname, cert_file):
+
+        nssdb.add_cert(
+            nickname=nickname,
+            cert_file=cert_file,
+            trust_attributes='CTu,CTu,CTu')
+
+        b64_cert = nssdb.get_cert(
+            nickname=nickname,
+            cert_type='base64'
+        )
+
+        subsystem.config['ca.signing.nickname'] = nickname
+        subsystem.config['ca.signing.tokenname'] = 'internal'
+        subsystem.config['ca.signing.cert'] = b64_cert
+        subsystem.config['ca.signing.cacertnickname'] = nickname
+        subsystem.config['ca.signing.defaultSigningAlgorithm'] = 'SHA256withRSA'
+
     def spawn(self, deployer):
 
         # ALWAYS establish the following Tomcat instance symbolic link since
@@ -81,40 +137,121 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
             deployer.mdict['pki_client_secmod_database'],
             password_file=deployer.mdict['pki_client_password_conf'])
 
-        # Start/Restart this Tomcat PKI Process
-        # Optionally prepare to enable a java debugger
-        # (e. g. - 'eclipse'):
-        if config.str2bool(deployer.mdict['pki_enable_java_debugger']):
-            config.prepare_for_an_external_java_debugger(
-                deployer.mdict['pki_target_tomcat_conf_instance_id'])
-        tomcat_instance_subsystems = \
-            len(deployer.instance.tomcat_instance_subsystems())
-        if tomcat_instance_subsystems == 1:
-            deployer.systemd.start()
-        elif tomcat_instance_subsystems > 1:
-            deployer.systemd.restart()
-
-        # wait for startup
-        status = deployer.instance.wait_for_startup(60)
-        if status is None:
-            config.pki_log.error(
-                "server failed to restart",
-                extra=config.PKI_INDENTATION_LEVEL_2)
-            raise Exception("server failed to restart")
-
-        # Optionally wait for debugger to attach (e. g. - 'eclipse'):
-        if config.str2bool(deployer.mdict['pki_enable_java_debugger']):
-            config.wait_to_attach_an_external_java_debugger()
-
-        # Construct PKI Subsystem Configuration Data
-        data = None
-        if deployer.mdict['pki_instance_type'] == "Tomcat":
-            # CA, KRA, OCSP, TKS, or TPS
-            data = deployer.config_client.construct_pki_configuration_data()
-
-        # Configure the subsystem
-        deployer.config_client.configure_pki_data(
-            json.dumps(data, cls=pki.encoder.CustomTypeEncoder))
+        instance = pki.server.PKIInstance(deployer.mdict['pki_instance_name'])
+        instance.load()
+
+        subsystem = instance.get_subsystem(deployer.mdict['pki_subsystem'].lower())
+
+        password_file = os.path.join(
+            deployer.mdict['pki_database_path'], "password.txt")
+
+        nssdb = pki.nss.NSSDatabase(
+            directory=deployer.mdict['pki_database_path'],
+            password_file=password_file
+        )
+
+        if deployer.mdict['pki_subsystem'] == 'CA':
+
+            if not config.str2bool(deployer.mdict['pki_external']): # self-signed CA
+
+                request_file = os.path.join(deployer.mdict['pki_database_path'], 'signing.csr')
+
+                # generate CA certificate request
+                self.generate_ca_csr(deployer, subsystem, nssdb, request_file, password_file)
+
+                cert_file = os.path.join(
+                    deployer.mdict['pki_database_path'], 'signing.crt')
+
+                # self-sign CA certificate
+                nssdb.create_self_signed_ca_cert(
+                    issuer_dn=deployer.mdict['pki_ca_signing_subject_dn'],
+                    request_file=request_file,
+                    cert_file=cert_file)
+
+                nickname = deployer.mdict['pki_ca_signing_nickname']
+
+                # import self-signed CA certificate
+                self.import_ca_cert(subsystem, nssdb, nickname, cert_file)
+
+                subsystem.save()
+
+            elif not config.str2bool(deployer.mdict['pki_external_step_two']): # external CA step 1
+
+                request_file = deployer.mdict['pki_external_csr_path']
+
+                # generate CA certificate request
+                self.generate_ca_csr(deployer, subsystem, nssdb, request_file, password_file)
+
+                subsystem.save()
+
+            else: # external CA step 2
+
+                external_signing_nickname = 'caSigningCert External CA'
+                external_signing_cert_file = deployer.mdict['pki_external_ca_cert_chain_path']
+
+                # import external CA certificate
+                nssdb.add_cert(
+                    nickname=external_signing_nickname,
+                    cert_file=external_signing_cert_file,
+                    trust_attributes='CTu,CTu,CTu'
+                )
+
+                external_signing_cert = nssdb.get_cert(
+                    nickname=external_signing_nickname,
+                    cert_type='base64'
+                )
+
+                subsystem.config['ca.external_signing.nickname'] = external_signing_nickname
+                subsystem.config['ca.external_signing.tokenname'] = 'internal'
+                subsystem.config['ca.external_signing.cert'] = external_signing_cert
+
+                signing_nickname = deployer.mdict['pki_ca_signing_nickname']
+                signing_cert_file = deployer.mdict['pki_external_ca_cert_path']
+
+                # import externally-signed CA certificate
+                self.import_ca_cert(subsystem, nssdb, signing_nickname, signing_cert_file)
+
+                subsystem.save()
+
+        external = config.str2bool(deployer.mdict['pki_external'])
+        step_one = not config.str2bool(deployer.mdict['pki_external_step_two'])
+
+        if not (external and step_one):
+
+            # Start/Restart this Tomcat PKI Process
+            # Optionally prepare to enable a java debugger
+            # (e. g. - 'eclipse'):
+            if config.str2bool(deployer.mdict['pki_enable_java_debugger']):
+                config.prepare_for_an_external_java_debugger(
+                    deployer.mdict['pki_target_tomcat_conf_instance_id'])
+            tomcat_instance_subsystems = \
+                len(deployer.instance.tomcat_instance_subsystems())
+            if tomcat_instance_subsystems == 1:
+                deployer.systemd.start()
+            elif tomcat_instance_subsystems > 1:
+                deployer.systemd.restart()
+
+            # wait for startup
+            status = deployer.instance.wait_for_startup(60)
+            if status is None:
+                config.pki_log.error(
+                    "server failed to restart",
+                    extra=config.PKI_INDENTATION_LEVEL_2)
+                raise Exception("server failed to restart")
+
+            # Optionally wait for debugger to attach (e. g. - 'eclipse'):
+            if config.str2bool(deployer.mdict['pki_enable_java_debugger']):
+                config.wait_to_attach_an_external_java_debugger()
+
+            # Construct PKI Subsystem Configuration Data
+            data = None
+            if deployer.mdict['pki_instance_type'] == "Tomcat":
+                # CA, KRA, OCSP, TKS, or TPS
+                data = deployer.config_client.construct_pki_configuration_data()
+
+            # Configure the subsystem
+            deployer.config_client.configure_pki_data(
+                json.dumps(data, cls=pki.encoder.CustomTypeEncoder))
 
         return self.rv
 
diff --git a/base/server/python/pki/server/deployment/scriptlets/finalization.py b/base/server/python/pki/server/deployment/scriptlets/finalization.py
index 56ddf0219d37dc7258e95464aff9ae925456a1a8..3c4f469aced9eec7928cf2c1a27ac43ebe5e1886 100644
--- a/base/server/python/pki/server/deployment/scriptlets/finalization.py
+++ b/base/server/python/pki/server/deployment/scriptlets/finalization.py
@@ -67,9 +67,15 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         if len(deployer.instance.tomcat_instance_subsystems()) == 1:
             # Modify contents of 'serverCertNick.conf' (if necessary)
             deployer.servercertnick_conf.modify()
-        # Optionally, programmatically 'restart' the configured PKI instance
-        if config.str2bool(deployer.mdict['pki_restart_configured_instance']):
-            deployer.systemd.restart()
+
+        external = config.str2bool(deployer.mdict['pki_external'])
+        step_one = not config.str2bool(deployer.mdict['pki_external_step_two'])
+
+        if not (external and step_one):
+            # Optionally, programmatically 'restart' the configured PKI instance
+            if config.str2bool(deployer.mdict['pki_restart_configured_instance']):
+                deployer.systemd.restart()
+
         # Optionally, 'purge' the entire temporary client infrastructure
         # including the client NSS security databases and password files
         #
-- 
2.4.3



More information about the Pki-devel mailing list