From 8d5eb937f99fd18398401f3f744eb85775293e23 Mon Sep 17 00:00:00 2001 From: Matthew Harmsen Date: Thu, 6 Dec 2012 14:23:21 -0800 Subject: Implemented ability to utilize an external CA * TRAC Ticket #231 - Dogtag 10: Update PKI Deployment to handle external CA --- .../cms/servlet/csadmin/SystemConfigService.java | 26 ++++--- base/deploy/src/scriptlets/configuration.jy | 17 +---- base/deploy/src/scriptlets/finalization.py | 8 +- base/deploy/src/scriptlets/initialization.py | 22 ++++-- base/deploy/src/scriptlets/pkihelper.py | 14 +++- base/deploy/src/scriptlets/pkijython.py | 87 ++++++++++++++++++---- base/deploy/src/scriptlets/pkimessages.py | 5 ++ base/deploy/src/scriptlets/pkiparser.py | 33 +++++--- 8 files changed, 148 insertions(+), 64 deletions(-) diff --git a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java index e4f9445d3..7013d1c8a 100644 --- a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java +++ b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java @@ -373,21 +373,22 @@ public class SystemConfigService extends PKIService implements SystemConfigResou psStore.putString("replicationdb", replicationpwd); psStore.commit(false); - ConfigurationUtils.populateDB(); + if (data.getStepTwo() == null) { + ConfigurationUtils.populateDB(); - cs.putString("preop.internaldb.replicationpwd", replicationpwd); - cs.putString("preop.database.removeData", "false"); - cs.commit(false); - - if (data.getIsClone().equals("true")) { - CMS.debug("Start setting up replication."); - ConfigurationUtils.setupReplication(); - } + cs.putString("preop.internaldb.replicationpwd", replicationpwd); + cs.putString("preop.database.removeData", "false"); + cs.commit(false); - ConfigurationUtils.reInitSubsystem(csType); - ConfigurationUtils.populateDBManager(); - ConfigurationUtils.populateVLVIndexes(); + if (data.getIsClone().equals("true")) { + CMS.debug("Start setting up replication."); + ConfigurationUtils.setupReplication(); + } + ConfigurationUtils.reInitSubsystem(csType); + ConfigurationUtils.populateDBManager(); + ConfigurationUtils.populateVLVIndexes(); + } } catch (Exception e) { throw new PKIException("Error in populating database" + e); } @@ -560,6 +561,7 @@ public class SystemConfigService extends PKIService implements SystemConfigResou // submitting to external ca if ((data.getIssuingCA()!= null) && data.getIssuingCA().equals("External CA") && (!hasSigningCert)) { response.setSystemCerts(SystemCertDataFactory.create(certs)); + response.setStatus(SUCCESS); return response; } diff --git a/base/deploy/src/scriptlets/configuration.jy b/base/deploy/src/scriptlets/configuration.jy index 80543b856..5af3becf5 100644 --- a/base/deploy/src/scriptlets/configuration.jy +++ b/base/deploy/src/scriptlets/configuration.jy @@ -100,21 +100,8 @@ def main(argv): log.PKI_JYTHON_NOT_YET_IMPLEMENTED) return rv elif master['pki_instance_type'] == "Tomcat": - if master['pki_subsystem'] == "CA": - if config.str2bool(master['pki_external']): - print "%s '%s %s' %s" %\ - (log.PKI_JYTHON_INDENTATION_2, - config.PKI_DEPLOYMENT_EXTERNAL_CA, - master['pki_subsystem'], - log.PKI_JYTHON_NOT_YET_IMPLEMENTED) - return rv - else: - # PKI, Subordinate, or Cloned CA - data = jyutil.rest_client.construct_pki_configuration_data( - token) - else: - # PKI or Cloned KRA, OCSP, or TKS - data = jyutil.rest_client.construct_pki_configuration_data(token) + # PKI or Cloned CA, KRA, OCSP, or TKS, Subordinate CA, or External CA + data = jyutil.rest_client.construct_pki_configuration_data(token) # Formulate PKI Subsystem Configuration Data Response jyutil.rest_client.configure_pki_data(data) diff --git a/base/deploy/src/scriptlets/finalization.py b/base/deploy/src/scriptlets/finalization.py index ec8fa6eff..1a6e731ae 100644 --- a/base/deploy/src/scriptlets/finalization.py +++ b/base/deploy/src/scriptlets/finalization.py @@ -33,7 +33,13 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): rv = 0 def spawn(self): - if config.str2bool(master['pki_skip_installation']): + if master['pki_subsystem'] == "CA" and\ + config.str2bool(master['pki_external_step_two']): + # must check for 'External CA Step 2' installation PRIOR to + # 'pki_skip_installation' since this value has been set to true + # by the initialization scriptlet + pass + elif config.str2bool(master['pki_skip_installation']): config.pki_log.info(log.SKIP_FINALIZATION_SPAWN_1, __name__, extra=config.PKI_INDENTATION_LEVEL_1) return self.rv diff --git a/base/deploy/src/scriptlets/initialization.py b/base/deploy/src/scriptlets/initialization.py index a0298f740..ba678cc27 100644 --- a/base/deploy/src/scriptlets/initialization.py +++ b/base/deploy/src/scriptlets/initialization.py @@ -41,13 +41,21 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet): config.pki_log.info(log.SKIP_INITIALIZATION_SPAWN_1, __name__, extra=config.PKI_INDENTATION_LEVEL_1) return self.rv - config.pki_log.info(log.INITIALIZATION_SPAWN_1, __name__, - extra=config.PKI_INDENTATION_LEVEL_1) - # verify that this type of "subsystem" does NOT yet - # exist for this "instance" - util.instance.verify_subsystem_does_not_exist() - # detect and avoid any namespace collisions - util.namespace.collision_detection() + else: + config.pki_log.info(log.INITIALIZATION_SPAWN_1, __name__, + extra=config.PKI_INDENTATION_LEVEL_1) + if master['pki_subsystem'] == "CA" and\ + config.str2bool(master['pki_external_step_two']): + # verify that this type of "subsystem" currently EXISTS + # for this "instance" (External CA Step 2) + util.instance.verify_subsystem_exists() + master['pki_skip_installation'] = "True"; + else: + # verify that this type of "subsystem" does NOT yet + # exist for this "instance" + util.instance.verify_subsystem_does_not_exist() + # detect and avoid any namespace collisions + util.namespace.collision_detection() # initialize 'uid' and 'gid' util.identity.add_uid_and_gid(master['pki_user'], master['pki_group']) # establish 'uid' and 'gid' diff --git a/base/deploy/src/scriptlets/pkihelper.py b/base/deploy/src/scriptlets/pkihelper.py index 2d7b75938..5d89a1201 100644 --- a/base/deploy/src/scriptlets/pkihelper.py +++ b/base/deploy/src/scriptlets/pkihelper.py @@ -685,7 +685,8 @@ class configuration_file: master['pki_user_deployment_cfg'], extra=config.PKI_INDENTATION_LEVEL_2) sys.exit(1) - if not config.str2bool(master['pki_step_two']): + if not config.str2bool(master['pki_external_step_two']): + # External CA (Step 1) if not master.has_key('pki_external_csr_path') or\ not len(master['pki_external_csr_path']): config.pki_log.error( @@ -694,13 +695,15 @@ class configuration_file: master['pki_user_deployment_cfg'], extra=config.PKI_INDENTATION_LEVEL_2) sys.exit(1) - elif not os.path.isfile(master['pki_external_csr_path']): + elif os.path.exists(master['pki_external_csr_path']) and\ + not os.path.isfile(master['pki_external_csr_path']): config.pki_log.error( log.PKI_FILE_ALREADY_EXISTS_NOT_A_FILE_1, master['pki_external_csr_path'], extra=config.PKI_INDENTATION_LEVEL_2) sys.exit(1) else: + # External CA (Step 2) if not master.has_key('pki_external_ca_cert_chain_path') or\ not len(master['pki_external_ca_cert_chain_path']): config.pki_log.error( @@ -709,7 +712,9 @@ class configuration_file: master['pki_user_deployment_cfg'], extra=config.PKI_INDENTATION_LEVEL_2) sys.exit(1) - elif not os.path.isfile( + elif os.path.exists( + master['pki_external_ca_cert_chain_path']) and\ + not os.path.isfile( master['pki_external_ca_cert_chain_path']): config.pki_log.error( log.PKI_FILE_ALREADY_EXISTS_NOT_A_FILE_1, @@ -724,7 +729,8 @@ class configuration_file: master['pki_user_deployment_cfg'], extra=config.PKI_INDENTATION_LEVEL_2) sys.exit(1) - elif not os.path.isfile( + elif os.path.exists(master['pki_external_ca_cert_path']) and\ + not os.path.isfile( master['pki_external_ca_cert_path']): config.pki_log.error( log.PKI_FILE_ALREADY_EXISTS_NOT_A_FILE_1, diff --git a/base/deploy/src/scriptlets/pkijython.py b/base/deploy/src/scriptlets/pkijython.py index c1bec9327..b832abac8 100644 --- a/base/deploy/src/scriptlets/pkijython.py +++ b/base/deploy/src/scriptlets/pkijython.py @@ -20,6 +20,7 @@ import jarray # System Python Imports import ConfigParser +import errno import os import re import sys @@ -389,6 +390,26 @@ class rest_client: cert.setToken(self.master["pki_%s_token" % tag]) return cert + def mkdirs(self, path): + try: + os.makedirs(path) + except OSError, e: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + + def write_data_to_file(self, filename, data): + FILE = open(filename, "w") + FILE.write(data) + FILE.close() + + def read_data_from_file(self, filename): + FILE = open(filename, "r") + data = FILE.read() + FILE.close() + return data + def retrieve_existing_server_cert(self, cfg_file): cs_cfg = read_simple_configuration_file(cfg_file) cstype = cs_cfg.get('cs.type').lower() @@ -439,7 +460,6 @@ class rest_client: if master['pki_subsystem'] == "CA": if config.str2bool(master['pki_clone']): # Cloned CA - # alee - is this correct? data.setHierarchy("root") elif config.str2bool(master['pki_external']): # External CA @@ -466,8 +486,8 @@ class rest_client: # CA Clone, KRA Clone, OCSP Clone, TKS Clone, or # Subordinate CA self.set_existing_security_domain(data) - elif not config.str2bool(master['pki_external']): - # PKI CA + else: + # PKI CA or External CA self.set_new_security_domain(data) if master['pki_subsystem'] != "RA": @@ -488,6 +508,10 @@ class rest_client: # CA Clone, KRA Clone, OCSP Clone, TKS Clone, # Subordinate CA, or External CA data.setIssuingCA(master['pki_issuing_ca']) + if master['pki_subsystem'] == "CA" and\ + config.str2bool(master['pki_external_step_two']): + # External CA Step 2 + data.setStepTwo("true"); # Create system certs systemCerts = ArrayList() @@ -495,10 +519,26 @@ class rest_client: # Create 'CA Signing Certificate' if master['pki_subsystem'] == "CA": if not config.str2bool(master['pki_clone']): - cert = self.create_system_cert("ca_signing") - cert.setSigningAlgorithm( + cert1 = self.create_system_cert("ca_signing") + cert1.setSigningAlgorithm( master['pki_ca_signing_signing_algorithm']) - systemCerts.add(cert) + if config.str2bool(master['pki_external_step_two']): + # Load the 'External CA Signing Certificate' (Step 2) + javasystem.out.println( + log.PKI_JYTHON_EXTERNAL_CA_LOAD + " " +\ + "'" + master['pki_external_ca_cert_path'] + "'") + external_cert = self.read_data_from_file( + master['pki_external_ca_cert_path']) + cert1.setCert(external_cert); + # Load the 'External CA Signing Certificate Chain' (Step 2) + javasystem.out.println( + log.PKI_JYTHON_EXTERNAL_CA_CHAIN_LOAD + " " +\ + "'" + master['pki_external_ca_cert_chain_path'] +\ + "'") + external_cert_chain = self.read_data_from_file( + master['pki_external_ca_cert_chain_path']) + cert1.setCertChain(external_cert_chain); + systemCerts.add(cert1) # Create 'OCSP Signing Certificate' if not config.str2bool(master['pki_clone']): @@ -570,13 +610,30 @@ class rest_client: iterator = certs.iterator() while iterator.hasNext(): cdata = iterator.next() - javasystem.out.println(log.PKI_JYTHON_CDATA_TAG + " " +\ - cdata.getTag()) - javasystem.out.println(log.PKI_JYTHON_CDATA_CERT + " " +\ - cdata.getCert()) - javasystem.out.println(log.PKI_JYTHON_CDATA_REQUEST + " " +\ - cdata.getRequest()) - + if master['pki_subsystem'] == "CA" and\ + config.str2bool(master['pki_external']) and\ + not config.str2bool(master['pki_external_step_two']): + # External CA Step 1 + if cdata.getTag().lower() == "signing": + javasystem.out.println(log.PKI_JYTHON_CDATA_REQUEST +\ + " " + cdata.getRequest()) + # Save 'External CA Signing Certificate' CSR (Step 1) + javasystem.out.println(log.PKI_JYTHON_EXTERNAL_CSR_SAVE\ + + " " + "'" +\ + master['pki_external_csr_path']\ + + "'") + self.mkdirs( + os.path.dirname(master['pki_external_csr_path'])) + self.write_data_to_file(master['pki_external_csr_path'], + cdata.getRequest()) + return + else: + javasystem.out.println(log.PKI_JYTHON_CDATA_TAG +\ + " " + cdata.getTag()) + javasystem.out.println(log.PKI_JYTHON_CDATA_CERT +\ + " " + cdata.getCert()) + javasystem.out.println(log.PKI_JYTHON_CDATA_REQUEST +\ + " " + cdata.getRequest()) # Cloned PKI subsystems do not return an Admin Certificate if not config.str2bool(master['pki_clone']) and \ not config.str2bool(master['pki_import_admin_cert']): @@ -590,9 +647,7 @@ class rest_client: admin_cert_bin_file = admin_cert_file + ".der" javasystem.out.println(log.PKI_JYTHON_ADMIN_CERT_SAVE +\ " " + "'" + admin_cert_file + "'") - FILE = open(admin_cert_file, "w") - FILE.write(admin_cert) - FILE.close() + self.write_data_to_file(admin_cert_file, admin_cert) # convert the cert file to binary command = "AtoB "+ admin_cert_file + " " + admin_cert_bin_file javasystem.out.println(log.PKI_JYTHON_ADMIN_CERT_ATOB +\ diff --git a/base/deploy/src/scriptlets/pkimessages.py b/base/deploy/src/scriptlets/pkimessages.py index 8d7ba1b6e..7b0d02c78 100644 --- a/base/deploy/src/scriptlets/pkimessages.py +++ b/base/deploy/src/scriptlets/pkimessages.py @@ -290,6 +290,11 @@ PKI_JYTHON_CRMF_SUPPORT_ONLY = "only the 'crmf' certificate request type "\ "is currently supported" PKI_JYTHON_IS_DUALKEY = "dualkey = true" PKI_JYTHON_EXCEPTION_PARSER = "Problem parsing" +PKI_JYTHON_EXTERNAL_CA_LOAD = "loading external CA signing certificate "\ + "from file:" +PKI_JYTHON_EXTERNAL_CA_CHAIN_LOAD = "loading external CA signing certificate "\ + "chain from file:" +PKI_JYTHON_EXTERNAL_CSR_SAVE = "saving CA Signing CSR to file:" PKI_JYTHON_INDENTATION_0 = "pkispawn : JYTHON " PKI_JYTHON_INDENTATION_1 = "pkispawn : JYTHON ..." PKI_JYTHON_INDENTATION_2 = "pkispawn : JYTHON ......." diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py index 80bdcb216..0a77a4985 100644 --- a/base/deploy/src/scriptlets/pkiparser.py +++ b/base/deploy/src/scriptlets/pkiparser.py @@ -263,12 +263,6 @@ class PKIConfigParser: random.randint(pin_low, pin_high) config.pki_master_dict['pki_client_pin'] =\ random.randint(pin_low, pin_high) - # Generate a one-time pin to be used prior to configuration - # and add this to the "sensitive" key value pairs read in from - # the configuration file - config.pki_master_dict['pki_one_time_pin'] =\ - ''.join(random.choice(string.ascii_letters + string.digits)\ - for x in range(20)) # Configuration file name/value pairs # NEVER add "sensitive" key value pairs to the master dictionary!!! config.pki_master_dict.update(config.pki_default_dict) @@ -944,6 +938,29 @@ class PKIConfigParser: config.pki_master_dict['pki_target_registry'] =\ os.path.join(config.pki_master_dict['pki_instance_registry_path'], config.pki_master_dict['pki_instance_id']) + if config.pki_master_dict['pki_subsystem'] == "CA" and\ + config.str2bool(config.pki_master_dict['pki_external_step_two']): + # Use the 'pki_one_time_pin' established during the setup of + # External CA Step 1 + if os.path.exists(config.pki_master_dict['pki_target_cs_cfg'])\ + and\ + os.path.isfile(config.pki_master_dict['pki_target_cs_cfg']): + cs_cfg = self.read_simple_configuration_file( + config.pki_master_dict['pki_target_cs_cfg']) + config.pki_master_dict['pki_one_time_pin'] =\ + cs_cfg.get('preop.pin') + else: + config.pki_log.error(log.PKI_FILE_MISSING_OR_NOT_A_FILE_1, + config.pki_master_dict['pki_target_cs_cfg'], + extra=config.PKI_INDENTATION_LEVEL_2) + sys.exit(1) + else: + # Generate a one-time pin to be used prior to configuration + # and add this to the "sensitive" key value pairs read in from + # the configuration file + config.pki_master_dict['pki_one_time_pin'] =\ + ''.join(random.choice(string.ascii_letters + string.digits)\ + for x in range(20)) if config.pki_master_dict['pki_subsystem'] in\ config.PKI_TOMCAT_SUBSYSTEMS: config.pki_master_dict['pki_target_catalina_properties'] =\ @@ -1472,9 +1489,7 @@ class PKIConfigParser: config.pki_master_dict['pki_security_domain_uri'] elif config.str2bool(config.pki_master_dict['pki_external']): # External CA - # - # NOTE: External CA's DO NOT require a security domain - # + config.pki_master_dict['pki_security_domain_type'] = "new" if not len(config.pki_master_dict['pki_issuing_ca']): config.pki_master_dict['pki_issuing_ca'] = "External CA" else: -- cgit