>From d672eb0778c3c337fb30e104da821f5ed3305fad Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Tue, 9 Sep 2014 15:06:31 -0400
Subject: [PATCH] Fix sub-CA installation with own security domain

Installation code failed to anticipate installation of a subordinate
CA that would host its own security domain.  This patch includes changes
to python installation code, java configuration servlet and
changes to man pages.

Ticket 1132
---
 .../certsrv/system/ConfigurationRequest.java       |  31 +++
 .../dogtagpki/server/rest/SystemConfigService.java | 227 +++++++++++++--------
 base/server/etc/default.cfg                        |   2 +
 base/server/man/man5/pki_default.cfg.5             |  11 +-
 base/server/man/man8/pkispawn.8                    |  26 +++
 .../python/pki/server/deployment/pkihelper.py      |  23 ++-
 .../python/pki/server/deployment/pkiparser.py      |  11 +-
 base/server/sbin/pkispawn                          |   9 +-
 8 files changed, 235 insertions(+), 105 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
index 8a7556496e96eb8b06fa05212e06bab1018867e3..c6e58d59473dee89b8ee801ee80a75ff9b4564b7 100644
--- a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+++ b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
@@ -82,6 +82,8 @@ public class ConfigurationRequest {
     private static final String STANDALONE = "standAlone";
     private static final String STEP_TWO = "stepTwo";
     private static final String GENERATE_SERVER_CERT = "generateServerCert";
+    private static final String SUBORDINATE_CREATE_NEW_SECURITY_DOMAIN = "subordinateCreateNewSecurityDomain";
+    private static final String SUBORDINATE_SECURITY_DOMAIN_NAME = "subordinateSecurityDomainName";
 
     // TPS specific parameters
     private static final String AUTHDB_BASEDN = "authdbBaseDN";
@@ -280,6 +282,12 @@ public class ConfigurationRequest {
     @XmlElement(defaultValue="false")
     protected String sharedDB;
 
+    @XmlElement(defaultValue="false")
+    protected String subordinateCreateNewSecurityDomain;
+
+    @XmlElement
+    protected String subordinateSecurityDomainName;
+
     @XmlElement
     protected String sharedDBUserDN;
 
@@ -337,6 +345,8 @@ public class ConfigurationRequest {
         authdbHost = form.getFirst(AUTHDB_HOST);
         authdbPort = form.getFirst(AUTHDB_PORT);
         authdbSecureConn = form.getFirst(AUTHDB_SECURE_CONN);
+        subordinateSecurityDomainName = form.getFirst(SUBORDINATE_SECURITY_DOMAIN_NAME);
+        subordinateCreateNewSecurityDomain = form.getFirst(SUBORDINATE_CREATE_NEW_SECURITY_DOMAIN);
 
         String value = form.getFirst(CA_URI);
         if (!StringUtils.isEmpty(value)) setCaUri(new URI(value));
@@ -997,6 +1007,25 @@ public class ConfigurationRequest {
         this.createNewDB = createNewDB;
     }
 
+    public boolean getSubordinateCreateNewSecurityDomain() {
+        if (subordinateCreateNewSecurityDomain == null) {
+            return false;
+        }
+        return subordinateCreateNewSecurityDomain.equalsIgnoreCase("true");
+    }
+
+    public void setSubordinateCreateNewSecurityDomain(String subordinateCreateNewSecurityDomain) {
+        this.subordinateCreateNewSecurityDomain = subordinateCreateNewSecurityDomain;
+    }
+
+    public String getSubordinateSecurityDomainName() {
+        return subordinateSecurityDomainName;
+    }
+
+    public void setSubordinateSecurityDomainName(String subordinateSecurityDomainName) {
+        this.subordinateSecurityDomainName = subordinateSecurityDomainName;
+    }
+
     @Override
     public String toString() {
         return "ConfigurationRequest [pin=XXXX" +
@@ -1056,6 +1085,8 @@ public class ConfigurationRequest {
                ", sharedDBUserDN=" + sharedDBUserDN +
                ", createNewDB=" + createNewDB +
                ", setupReplication=" + setupReplication +
+               ", subordinateCreateNewSecurityDomain=" + subordinateCreateNewSecurityDomain +
+               ", subordinateSecurityDomainName" + subordinateSecurityDomainName +
                "]";
     }
 
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 fa762774af30c75d8929d854982f3d144a479821..3d7f3a741812d9589cba905d40ec146179ca85a8 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
@@ -222,28 +222,8 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
         // Done Panel
         // Create or update security domain
         CMS.debug("=== Done Panel ===");
-        try {
-            String securityDomainType = data.getSecurityDomainType();
-            if (securityDomainType.equals(ConfigurationRequest.NEW_DOMAIN)) {
-                ConfigurationUtils.createSecurityDomain();
-            } else {
-                ConfigurationUtils.updateSecurityDomain();
-            }
-            cs.putString("service.securityDomainPort", CMS.getAgentPort());
-            cs.putString("securitydomain.store", "ldap");
-            cs.commit(false);
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw new PKIException("Error while updating security domain: " + e);
-        }
-
-        try {
-            if (!data.getSharedDB()) ConfigurationUtils.setupDBUser();
-        } catch (Exception e) {
-            CMS.debug(e);
-            throw new PKIException("Errors in creating or updating dbuser: " + e);
-        }
-
+        setupSecurityDomain(data);
+        setupDBUser(data);
         finalizeConfiguration(data);
 
         cs.putInteger("cs.state", 1);
@@ -268,6 +248,46 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
         response.setStatus(SUCCESS);
     }
 
+    private void setupDBUser(ConfigurationRequest data) {
+        try {
+            if (!data.getSharedDB()) ConfigurationUtils.setupDBUser();
+        } catch (Exception e) {
+            CMS.debug(e);
+            throw new PKIException("Errors in creating or updating dbuser: " + e);
+        }
+    }
+
+    private void setupSecurityDomain(ConfigurationRequest data) {
+        try {
+            String securityDomainType = data.getSecurityDomainType();
+            if (securityDomainType.equals(ConfigurationRequest.NEW_DOMAIN)) {
+                CMS.debug("Creating new security domain");
+                ConfigurationUtils.createSecurityDomain();
+            } else if (data.getSubordinateCreateNewSecurityDomain()) {
+                CMS.debug("Creating subordinate CA security domain");
+
+                // switch out security domain parameters from issuing CA security domain
+                // to subordinate CA hosted security domain
+                cs.putString("securitydomain.name", data.getSubordinateSecurityDomainName());
+                cs.putString("securitydomain.host", CMS.getEENonSSLHost());
+                cs.putString("securitydomain.httpport", CMS.getEENonSSLPort());
+                cs.putString("securitydomain.httpsagentport", CMS.getAgentPort());
+                cs.putString("securitydomain.httpseeport", CMS.getEESSLPort());
+                cs.putString("securitydomain.httpsadminport", CMS.getAdminPort());
+                ConfigurationUtils.createSecurityDomain();
+            } else {
+                CMS.debug("Updating existing security domain");
+                ConfigurationUtils.updateSecurityDomain();
+            }
+            cs.putString("service.securityDomainPort", CMS.getAgentPort());
+            cs.putString("securitydomain.store", "ldap");
+            cs.commit(false);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException("Error while updating security domain: " + e);
+        }
+    }
+
     public Collection<String> getCertList(ConfigurationRequest request) {
 
         Collection<String> certList = new ArrayList<String>();
@@ -737,10 +757,10 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
                     CMS.debug("local CA selected");
                     url = url.substring(url.indexOf("https"));
                     cs.putString("preop.ca.url", url);
-
                     URL urlx = new URL(url);
                     String host = urlx.getHost();
                     int port = urlx.getPort();
+
                     int admin_port = ConfigurationUtils.getPortFromSecurityDomain(domainXML,
                             host, port, "CA", "SecurePort", "SecureAdminPort");
 
@@ -841,81 +861,113 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
 
         String securityDomainType = data.getSecurityDomainType();
         String securityDomainName = data.getSecurityDomainName();
-        String securityDomainURL = data.getSecurityDomainUri();
 
         if (securityDomainType.equals(ConfigurationRequest.NEW_DOMAIN)) {
-            CMS.debug("Creating new security domain");
-            cs.putString("preop.securitydomain.select", "new");
-            cs.putString("securitydomain.select", "new");
-            cs.putString("preop.securitydomain.name", securityDomainName);
-            cs.putString("securitydomain.name", securityDomainName);
-            cs.putString("securitydomain.host", CMS.getEENonSSLHost());
-            cs.putString("securitydomain.httpport", CMS.getEENonSSLPort());
-            cs.putString("securitydomain.httpsagentport", CMS.getAgentPort());
-            cs.putString("securitydomain.httpseeport", CMS.getEESSLPort());
-            cs.putString("securitydomain.httpsadminport", CMS.getAdminPort());
-            // Stand-alone PKI (Step 1)
-            if (data.getStandAlone()) {
+            configureNewSecurityDomain(data, securityDomainName);
+        } else {
+            if (data.getSubordinateCreateNewSecurityDomain()) {
+                CMS.debug("Configuring new subordinate root CA");
+                configureNewSecurityDomain(data, data.getSubordinateSecurityDomainName());
+            } else {
+                CMS.debug("Joining existing security domain");
+                cs.putString("preop.securitydomain.select", "existing");
+                cs.putString("securitydomain.select", "existing");
                 cs.putString("preop.cert.subsystem.type", "remote");
-            } else {
-                cs.putString("preop.cert.subsystem.type", "local");
+                cs.putString("preop.cert.subsystem.profile", "caInternalAuthSubsystemCert");
             }
-            cs.putString("preop.cert.subsystem.profile", "subsystemCert.profile");
 
-        } else {
-            CMS.debug("Joining existing security domain");
-            cs.putString("preop.securitydomain.select", "existing");
-            cs.putString("securitydomain.select", "existing");
+            String securityDomainURL = data.getSecurityDomainUri();
+            domainXML = logIntoSecurityDomain(data, securityDomainURL);
+        }
+
+        return domainXML;
+    }
+
+    private void configureNewSecurityDomain(ConfigurationRequest data, String securityDomainName) {
+        CMS.debug("Creating new security domain");
+        cs.putString("preop.securitydomain.select", "new");
+        cs.putString("securitydomain.select", "new");
+        cs.putString("preop.securitydomain.name", securityDomainName);
+        cs.putString("securitydomain.name", securityDomainName);
+        cs.putString("securitydomain.host", CMS.getEENonSSLHost());
+        cs.putString("securitydomain.httpport", CMS.getEENonSSLPort());
+        cs.putString("securitydomain.httpsagentport", CMS.getAgentPort());
+        cs.putString("securitydomain.httpseeport", CMS.getEESSLPort());
+        cs.putString("securitydomain.httpsadminport", CMS.getAdminPort());
+        // Stand-alone PKI (Step 1)
+        if (data.getStandAlone()) {
             cs.putString("preop.cert.subsystem.type", "remote");
-            cs.putString("preop.cert.subsystem.profile", "caInternalAuthSubsystemCert");
+        } else {
+            cs.putString("preop.cert.subsystem.type", "local");
+        }
+        cs.putString("preop.cert.subsystem.profile", "subsystemCert.profile");
+    }
 
-            CMS.debug("Getting certificate chain");
-            // contact and log onto security domain
-            URL secdomainURL;
-            String host;
-            int port;
-            try {
-                secdomainURL = new URL(securityDomainURL);
-                host = secdomainURL.getHost();
-                port = secdomainURL.getPort();
-                cs.putString("securitydomain.host", host);
-                cs.putInteger("securitydomain.httpsadminport",port);
-                ConfigurationUtils.importCertChain(host, port, "/ca/admin/ca/getCertChain", "securitydomain");
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new PKIException("Failed to import certificate chain from security domain master: " + e);
-            }
+    private String logIntoSecurityDomain(ConfigurationRequest data, String securityDomainURL) {
+        URL secdomainURL;
+        String host;
+        int port;
+        try {
+            CMS.debug("Resolving security domain URL" + securityDomainURL);
+            secdomainURL = new URL(securityDomainURL);
+            host = secdomainURL.getHost();
+            port = secdomainURL.getPort();
+            cs.putString("securitydomain.host", host);
+            cs.putInteger("securitydomain.httpsadminport",port);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException("Failed to resolve security domain URL");
+        }
 
-            CMS.debug("Getting install token");
-            // log onto security domain and get token
-            String user = data.getSecurityDomainUser();
-            String pass = data.getSecurityDomainPassword();
-            String installToken;
-            try {
-                installToken = ConfigurationUtils.getInstallToken(host, port, user, pass);
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new PKIException("Failed to obtain installation token from security domain: " + e);
-            }
+        getCertChainFromSecurityDomain(host, port);
+        getInstallToken(data, host, port);
 
-            if (installToken == null) {
-                CMS.debug("Install token is null");
-                throw new PKIException("Failed to obtain installation token from security domain");
-            }
-            CMS.setConfigSDSessionId(installToken);
+        return getDomainXML(host, port);
+    }
 
-            CMS.debug("Getting domain XML");
-            try {
-                domainXML = ConfigurationUtils.getDomainXML(host, port, true);
-                ConfigurationUtils.getSecurityDomainPorts(domainXML, host, port);
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new PKIException("Failed to obtain security domain decriptor from security domain master: " + e);
-            }
+    private String getDomainXML(String host, int port) {
+        CMS.debug("Getting domain XML");
+        String domainXML = null;
+        try {
+            domainXML = ConfigurationUtils.getDomainXML(host, port, true);
+            ConfigurationUtils.getSecurityDomainPorts(domainXML, host, port);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException("Failed to obtain security domain decriptor from security domain master: " + e);
         }
         return domainXML;
     }
 
+    private void getCertChainFromSecurityDomain(String host, int port) {
+        CMS.debug("Getting security domain cert chain");
+        try {
+            ConfigurationUtils.importCertChain(host, port, "/ca/admin/ca/getCertChain", "securitydomain");
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException("Failed to import certificate chain from security domain master: " + e);
+        }
+    }
+
+    private void getInstallToken(ConfigurationRequest data, String host, int port) {
+        CMS.debug("Getting install token");
+        // log onto security domain and get token
+        String user = data.getSecurityDomainUser();
+        String pass = data.getSecurityDomainPassword();
+        String installToken;
+        try {
+            installToken = ConfigurationUtils.getInstallToken(host, port, user, pass);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException("Failed to obtain installation token from security domain: " + e);
+        }
+
+        if (installToken == null) {
+            CMS.debug("Install token is null");
+            throw new PKIException("Failed to obtain installation token from security domain");
+        }
+        CMS.setConfigSDSessionId(installToken);
+    }
+
     public void configureSubsystem(ConfigurationRequest request,
             Collection<String> certList, String token, String domainXML) {
 
@@ -1026,6 +1078,13 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
             throw new BadRequestException("Invalid security domain URI provided");
         }
 
+        // validate subordinate CA security domain settings
+        if (data.getSubordinateCreateNewSecurityDomain()) {
+            if (StringUtils.isEmpty(data.getSubordinateSecurityDomainName())) {
+                throw new BadRequestException("Subordinate CA security domain name not provided");
+            }
+        }
+
         if ((data.getSubsystemName() == null) || (data.getSubsystemName().length() ==0)) {
             throw new BadRequestException("Invalid or no subsystem name provided");
         }
diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg
index 686cc59f9eeb4b1d29b9b57073d7d233729009c7..ecf436d9f15729ed27e09975ab1f1151e504fe94 100644
--- a/base/server/etc/default.cfg
+++ b/base/server/etc/default.cfg
@@ -366,6 +366,8 @@ pki_ocsp_signing_subject_dn=cn=CA OCSP Signing Certificate,o=%(pki_security_doma
 pki_ocsp_signing_token=Internal Key Storage Token
 pki_random_serial_numbers_enable=False
 pki_subordinate=False
+pki_subordinate_create_new_security_domain=False
+pki_subordinate_security_domain_name=%(pki_dns_domainname)s Subordinate Security Domain
 pki_admin_email=%(pki_admin_name)s@%(pki_dns_domainname)s
 pki_admin_name=%(pki_admin_uid)s
 pki_admin_nickname=PKI Administrator for %(pki_dns_domainname)s
diff --git a/base/server/man/man5/pki_default.cfg.5 b/base/server/man/man5/pki_default.cfg.5
index 1522cc6f3c1e97fd566f9421b6e9532134468903..a7706656b18bc1e2fe3be80c3c7d0d841c29a377 100644
--- a/base/server/man/man5/pki_default.cfg.5
+++ b/base/server/man/man5/pki_default.cfg.5
@@ -184,7 +184,7 @@ Name of the back-end database.  It is advised that the Certificate Server have i
 \x'-1'\fBpki_issuing_ca_hostname, pki_issuing_ca_https_port, pki_issuing_ca_uri\fR
 .IP
 Hostname and port, or URI of the issuing CA.  Required for installations of subordinate CA and non-CA subsystems.  This should point to the CA that will issue the relevant system certificates for the subsystem.  In a default install, this defaults to the CA subsystem within the same instance.  The URI has the format https://<ca_hostname>:<ca_https_port>.
-
+.PP
 .SS MISCELLANEOUS PARAMETERS
 \x'-1'\fBpki_restart_configured_instance\fR
 .IP
@@ -263,6 +263,15 @@ Required for the second step of the external CA signing process.  This is the lo
 \x'-1'\fBpki_subordinate\fR
 .IP
 Specifies whether the new CA which will be a subordinate of another CA.  The master CA is specified by \fBpki_issuing_ca\fP.  Defaults to False.
+.TP
+.B pki_subordinate_create_new_security_domain
+.IP
+Set to \fBTrue\fP if the subordinate CA will host its own security domain.  Defaults to \fBFalse\fP.
+.TP
+.B pki_subordinate_security_domain_name
+.IP
+Used when \fBpki_subordinate_create_security_domain\fP is set to \fBTrue\fP.  Specifies the name of the security domain to be hosted on the subordinate CA.
+
 .SS STANDALONE PKI PARAMETERS
 A stand-alone PKI subsystem is defined as a non-CA PKI subsystem that does not contain a CA as a part of its deployment, and functions as its own security domain.  Currently, only stand-alone DRMs are supported.
 .TP
diff --git a/base/server/man/man8/pkispawn.8 b/base/server/man/man8/pkispawn.8
index 1b8f49e4b020d5279c9dce73edbcfc39f742200c..fea21d9d8619a80c095b679688a9f703b41605e6 100644
--- a/base/server/man/man8/pkispawn.8
+++ b/base/server/man/man8/pkispawn.8
@@ -310,6 +310,32 @@ pki_ca_signing_subject_dn=cn=CA Subordinate Signing ,o=example.com
 A sub-CA derives its certificate configuration -- such as allowed extensions and validity periods -- from a superior or root CA. Otherwise, the configuration of the CA is independent of the root CA, so it is its own instance rather than a clone. A sub-CA is configured using the pki_subordinate parameter and a pointer to the CA which issues the sub-CA's certificates.
 .PP
 \fBNote:\fP The value of \fBpki_ca_signing_subject_dn\fP of a subordinate CA should be different from the root CA's signing subject DN.
+.SS Installing a subordinate CA which hosts its own security domain
+\x'-1'\fBpkispawn \-s CA \-f myconfig.txt\fR
+.PP
+where \fImyconfig.txt\fP contains the following text:
+.IP
+.nf
+[DEFAULT]
+pki_admin_password=\fIpassword123\fP
+pki_client_pkcs12_password=\fIpassword123\fP
+pki_ds_password=\fIpassword123\fP
+pki_security_domain_password=\fIpassword123\fP
+pki_security_domain_hostname=<security_domain_ca_hostname>
+pki_security_domain_https_port=<security_domain_ca_https_port>
+pki_security_domain_user=caadmin
+pki_security_domain_name=Subordinate CA Security Domain
+
+[CA]
+pki_subordinate=True
+pki_issuing_ca=https://<master_ca_hostname>:<master_ca_https_port>
+pki_ca_signing_subject_dn=cn=CA Subordinate Signing ,o=example.com
+pki_subordinate_create_new_security_domain=True
+.fi
+.PP
+In this section, the subordinate CA logs onto and registers with the security domain CA (using parameters \fBpki_security_domain_hostname\fP, \fBpki_security_domain_https_port\fP, \fBpki_security_domain_user\fP and \fBpki_security_domain_password\fP) as in the previous section, but also creates and hosts a new security domain.  To do this, \fBpki_subordinate_create_new_security_domain\fP must be set to \fBTrue\fP.  The subordinate CA security domain name can also be specified by specifying a value for \fBpki_subordinate_security_domain_name\fP.
+.PP
+\fBNote:\fP The value of \fBpki_ca_signing_subject_dn\fP of a subordinate CA should be different from the root CA's signing subject DN.
 .SS Installing an externally signed CA
 \x'-1'\fBpkispawn \-s CA \-f myconfig.txt\fR
 .PP
diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
index b4c728a87999224f526e2f6bb3a12488ea6adf41..f8d6bcb13f21e321063c17339fe5af121fd39cda 100644
--- a/base/server/python/pki/server/deployment/pkihelper.py
+++ b/base/server/python/pki/server/deployment/pkihelper.py
@@ -52,7 +52,6 @@ from .pkiconfig import pki_selinux_config_ports as ports
 from . import pkimanifest as manifest
 from . import pkimessages as log
 from .pkiparser import PKIConfigParser
-import pki.account
 import pki.client
 import pki.system
 
@@ -503,6 +502,9 @@ class ConfigurationFile:
                                      extra=config.PKI_INDENTATION_LEVEL_2)
                 raise Exception(log.PKI_SUBORDINATE_UNSUPPORTED_1,
                                 self.subsystem)
+            if config.str2bool(
+                    self.mdict['pki_subordinate_create_new_security_domain']):
+                self.confirm_data_exists('pki_subordinate_security_domain_name')
 
     def confirm_external_step_two(self):
         # ALWAYS defined via 'pkiparser.py'
@@ -3414,6 +3416,7 @@ class ConfigClient:
         # generic extension support in CSR - for external CA
         self.add_req_ext = config.str2bool(
             self.mdict['pki_req_ext_add'])
+        self.security_domain_type = self.mdict['pki_security_domain_type']
 
     def configure_pki_data(self, data):
         config.pki_log.info(
@@ -3626,16 +3629,15 @@ class ConfigClient:
         self.set_hierarchy_parameters(data)
 
         # Security Domain
-        if ((self.subsystem != "CA" or self.clone or self.subordinate) and
-                not self.standalone):
-            # PKI KRA, PKI OCSP, PKI RA, PKI TKS, PKI TPS,
-            # CA Clone, KRA Clone, OCSP Clone, TKS Clone, TPS Clone, or
-            # Subordinate CA
+        if self.security_domain_type != "new":
             self.set_existing_security_domain(data)
         else:
             # PKI CA, External CA, or Stand-alone PKI
             self.set_new_security_domain(data)
 
+        if self.subordinate:
+            self.set_subca_security_domain(data)
+
         # database
         if self.subsystem != "RA":
             self.set_database_parameters(data)
@@ -3943,6 +3945,15 @@ class ConfigClient:
         data.securityDomainType = "newdomain"
         data.securityDomainName = self.mdict['pki_security_domain_name']
 
+    def set_subca_security_domain(self, data):
+        if config.str2bool(
+                self.mdict['pki_subordinate_create_new_security_domain']):
+            data.subordinateCreateNewSecurityDomain = "true"
+            data.subordinateSecurityDomainName = (
+                self.mdict['pki_subordinate_security_domain_name'])
+        else:
+            data.subordinateCreateNewSecurityDomain = "false"
+
     def set_database_parameters(self, data):
         data.dsHost = self.mdict['pki_ds_hostname']
         data.dsPort = self.mdict['pki_ds_ldap_port']
diff --git a/base/server/python/pki/server/deployment/pkiparser.py b/base/server/python/pki/server/deployment/pkiparser.py
index de224eb9a67181d6adccf39d6e59c28702cc0837..ea6bbffab1cf91a4a9b56c16c08fccb13863734d 100644
--- a/base/server/python/pki/server/deployment/pkiparser.py
+++ b/base/server/python/pki/server/deployment/pkiparser.py
@@ -1078,24 +1078,23 @@ class PKIConfigParser:
                 # Stand-alone PKI
                 self.mdict['pki_security_domain_type'] = "new"
                 self.mdict['pki_issuing_ca'] = "External CA"
-            elif config.pki_subsystem != "CA" or\
-                    config.str2bool(self.mdict['pki_clone']) or\
-                    config.str2bool(self.mdict['pki_subordinate']):
+            elif (config.pki_subsystem != "CA" or
+                    config.str2bool(self.mdict['pki_clone']) or
+                    config.str2bool(self.mdict['pki_subordinate'])):
                 # PKI KRA, PKI OCSP, PKI RA, PKI TKS, PKI TPS,
-                # CA Clone, KRA Clone, OCSP Clone, TKS Clone, TPS Clone, or
+                # CA Clone, KRA Clone, OCSP Clone, TKS Clone, TPS Clone
                 # Subordinate CA
                 self.mdict['pki_security_domain_type'] = "existing"
                 self.mdict['pki_security_domain_uri'] = \
                     "https" + "://" + \
                     self.mdict['pki_security_domain_hostname'] + ":" + \
                     self.mdict['pki_security_domain_https_port']
-
             elif config.str2bool(self.mdict['pki_external']):
                 # External CA
                 self.mdict['pki_security_domain_type'] = "new"
                 self.mdict['pki_issuing_ca'] = "External CA"
             else:
-                # PKI CA
+                # PKI CA (master)
                 self.mdict['pki_security_domain_type'] = "new"
 
             # 'External CA' Configuration name/value pairs
diff --git a/base/server/sbin/pkispawn b/base/server/sbin/pkispawn
index 4b939743a8e321244fa6efa019cb528fcf9d6306..04eec6ab99231de4f38d9c44432577bd2d8a9a9d 100755
--- a/base/server/sbin/pkispawn
+++ b/base/server/sbin/pkispawn
@@ -464,14 +464,7 @@ def main(argv):
                   e.message['desc']
             sys.exit(1)
 
-        if ((config.pki_subsystem == "KRA" or
-             config.pki_subsystem == "OCSP") and
-            not config.str2bool(parser.mdict['pki_standalone'])) or\
-           config.pki_subsystem == "TKS" or\
-           config.pki_subsystem == "TPS" or\
-           config.str2bool(parser.mdict['pki_clone']) or\
-           (config.pki_subsystem == "CA" and
-            config.str2bool(parser.mdict['pki_subordinate'])):
+        if parser.mdict['pki_security_domain_type'] != "new":
             try:
                 # Verify existence of Security Domain Password
                 if not 'pki_security_domain_password' in parser.mdict or\
-- 
1.9.3

