[Freeipa-devel] [PATCH] 0091 Allow full customisability of CA subject name

Fraser Tweedale ftweedal at redhat.com
Mon Aug 22 05:00:57 UTC 2016


On Fri, Aug 19, 2016 at 08:09:33PM +1000, Fraser Tweedale wrote:
> On Mon, Aug 15, 2016 at 10:54:25PM +1000, Fraser Tweedale wrote:
> > On Mon, Aug 15, 2016 at 02:08:54PM +0200, Jan Cholasta wrote:
> > > On 19.7.2016 12:05, Jan Cholasta wrote:
> > > > On 19.7.2016 11:54, Fraser Tweedale wrote:
> > > > > On Tue, Jul 19, 2016 at 09:36:17AM +0200, Jan Cholasta wrote:
> > > > > > Hi,
> > > > > > 
> > > > > > On 15.7.2016 07:05, Fraser Tweedale wrote:
> > > > > > > On Fri, Jul 15, 2016 at 03:04:48PM +1000, Fraser Tweedale wrote:
> > > > > > > > The attached patch is a work in progress for
> > > > > > > > https://fedorahosted.org/freeipa/ticket/2614 (BZ 828866).
> > > > > > > > 
> > > > > > > > I am sharing now to make the approach clear and solicit feedback.
> > > > > > > > 
> > > > > > > > It has been tested for server install, replica install (with and
> > > > > > > > without CA) and CA-replica install (all hosts running master+patch).
> > > > > > > > 
> > > > > > > > Migration from earlier versions and server/replica/CA install on a
> > > > > > > > CA-less deployment are not yet tested; these will be tested over
> > > > > > > > coming days and patch will be tweaked as necessary.
> > > > > > > > 
> > > > > > > > Commit message has a fair bit to say so I won't repeat here but let
> > > > > > > > me know your questions and comments.
> > > > > > > > 
> > > > > > > > Thanks,
> > > > > > > > Fraser
> > > > > > > > 
> > > > > > > It does help to attach the patch, of course ^_^
> > > > > > 
> > > > > > IMO explicit is better than implicit, so instead of introducing
> > > > > > additional
> > > > > > magic around --subject, I would rather add a new separate option for
> > > > > > specifying the CA subject name (I think --ca-subject, for consistency
> > > > > > with
> > > > > > --ca-signing-algorithm).
> > > > > > 
> > > > > The current situation - the --subject argument which specifies the
> > > > > not the subject but the subject base, is confusing enough (to say
> > > > > nothing of the limitations that give rise to the RFE).
> > > > > 
> > > > > Retaining --subject for specifying the subject base and adding
> > > > > --ca-subject for specifying the *actual* subject DN gets us over the
> > > > > line in terms of the RFE, but does not make the installer less
> > > > > confusing.  This is why I made --subject accept the full subject DN,
> > > > > with provisions to retain existing behaviour.
> > > > > 
> > > > > IMO if we want to have separate arguments for subject DN and subject
> > > > > base (I am not against it), let's bite the bullet and name arguments
> > > > > accordingly.  --subject should be used to specify full Subject DN,
> > > > > --subject-base (or similar) for specifying subject base.
> > > > 
> > > > IMHO --ca-subject is better than --subject, because it is more explicit
> > > > whose subject name that is (the CA's). I agree that --subject should be
> > > > deprecated and replaced with --subject-base.
> > > > 
> > > > > 
> > > > > (I intentionally defer discussion of specific behaviour if one, none
> > > > > or both are specified; let's resolve the question or renaming /
> > > > > changing meaning of arguments first).
> > > > > 
> > > > > 
> > > > > > By specifying the option you would override the default "CN=Certificate
> > > > > > Authority,$SUBJECT_BASE" subject name. If --external-ca was not used,
> > > > > > additional validation would be done to make sure the subject name meets
> > > > > > Dogtag's expectations. Actually, it might make sense to always do the
> > > > > > additional validation, to be able to print a warning that if a
> > > > > > Dogtag-incompatible subject name is used, it won't be possible to
> > > > > > change the
> > > > > > CA cert chaining from externally signed to self-signed later.
> > > > > > 
> > > > > > Honza
> > > 
> > > Bump, any update on this?
> > > 
> > I have an updated patch that fixes some issues Sebastian encountered
> > in testing, but I've not yet tackled the main change requested by
> > Honza (in brief: adding --ca-subject for specifying that, adding
> > --subject-base for specifying that, and deprecating --subject;
> > Sebastian, see discussion above and feel free to give your
> > thoughts).  I expect I'll get back onto this work within the next
> > few days.
> > 
> Update: I've got an updated version of patch almost ready for
> review, but I'm still ironing out some wrinkles in replica
> installation.
> 
> Expect to be able to send it Monday or Tuesday for review.
>
Updated patch attached.

I expect it will take a while to review, test and get the ACK, but
in any case: IMO it should not be merged until after ipa-4-4 branch
gets created.

Thanks,
Fraser
-------------- next part --------------
From d49a6b113c45ecd0a6686a1821338f5cf91cb1f5 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 11 Jul 2016 12:57:11 +1000
Subject: [PATCH] Allow full customisability of IPA CA subject DN

Currently only the "subject base" of the IPA CA subject DN can be
customised via the installer's --subject option.  The RDN
"CN=Certificate Authority" is appended to form the subject DN, and
this composition is widely assumed, hardcoded in many places.

Some administrators need more control over the CA subject DN,
especially to satisfy expectations of external CAs when the IPA CA
is to be externally signed.

This patch adds full customisability of the CA subject DN.  In
particular:

- Deprecate the ambiguously named --subject option.

- Add the --subject-base option for explicitly specifying the
  subject base.  If not given, fall back to --subject, then to
  "O=$REALM".

- Add the --ca-subject option for explictly specifying the CA
  subject DN.  If not given, default to
  "CN=Certificate Authority, $SUBJECT_BASE".

- If creating a self-signed CA, to meet Dogtag's expectations some
  normalisation may occur. Specifically: the "most specific" CN AVA
  encountered shall be the most specific RDN (it is moved if
  necessary); if the subject DN does not contain a CN AVA, then
  "CN=Certificate Authority" is appended.

- The subject base need not be related to or contained within the CA
  subject DN.

- During ipa-server-install print a summary of the subject base and
  CA subject DN that will be used, including a note if the subject
  DN was normalised.

Fixes: https://fedorahosted.org/freeipa/ticket/2614
---
 install/share/certmap.conf.template        |  2 +-
 install/tools/ipa-ca-install               | 27 ++++++++-----
 install/tools/man/ipa-server-install.1     | 12 +++++-
 ipaserver/install/ca.py                    | 21 +++++-----
 ipaserver/install/cainstance.py            | 36 +++++++++--------
 ipaserver/install/certs.py                 | 20 +++++++---
 ipaserver/install/dsinstance.py            | 57 +++++++++++---------------
 ipaserver/install/installutils.py          | 39 ++++++++++++++++--
 ipaserver/install/ipa_cacert_manage.py     |  9 ++++-
 ipaserver/install/krainstance.py           | 22 +++++-----
 ipaserver/install/server/common.py         | 46 +++++++++++++--------
 ipaserver/install/server/install.py        | 64 ++++++++++++++++++++++++------
 ipaserver/install/server/replicainstall.py | 22 +++++++---
 13 files changed, 251 insertions(+), 126 deletions(-)

diff --git a/install/share/certmap.conf.template b/install/share/certmap.conf.template
index e76bf3c653a4f1d130ce8c264a28cac5dc63925c..d59b095faff804eae4cbd2ef984aa8ca3be52946 100644
--- a/install/share/certmap.conf.template
+++ b/install/share/certmap.conf.template
@@ -41,6 +41,6 @@ certmap default         default
 #default:InitFn         <Init function's name>
 default:DNComps
 default:FilterComps     uid
-certmap ipaca           CN=Certificate Authority,$SUBJECT_BASE
+certmap ipaca           $ISSUER_DN
 ipaca:CmapLdapAttr      seeAlso
 ipaca:verifycert        on
diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 985e7413aa06900976934c329757ce45da5ff12d..a506984924fdd56b552aaf78ba5a5f0e6b10e461 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -20,6 +20,7 @@
 
 import sys
 import os
+import six
 import shutil
 import tempfile
 from ipapython import ipautil
@@ -31,9 +32,10 @@ from ipaserver.install.installutils import check_creds, ReplicaConfig
 from ipaserver.install import bindinstance, dsinstance, ca
 from ipaserver.install import cainstance, custodiainstance, service
 from ipapython import version
-from ipalib import api
-from ipalib.constants import DOMAIN_LEVEL_0
+from ipalib import api, x509
+from ipalib.constants import DOMAIN_LEVEL_0, IPA_CA_CN
 from ipapython.dn import DN
+from ipapython.certdb import get_ca_nickname
 from ipapython.config import IPAOptionParser
 from ipapython.ipa_log_manager import root_logger, standard_logging_setup
 from ipaplatform.paths import paths
@@ -41,6 +43,10 @@ from ipaplatform.paths import paths
 log_file_name = paths.IPAREPLICA_CA_INSTALL_LOG
 REPLICA_INFO_TOP_DIR = None
 
+if six.PY3:
+    unicode = str
+
+
 def parse_options():
     usage = "%prog [options] REPLICA_FILE"
     parser = IPAOptionParser(usage=usage, version=version.VERSION)
@@ -160,9 +166,12 @@ def install_replica(safe_options, options, filename):
     conn.connect(bind_dn=DN(('cn', 'Directory Manager')),
                             bind_pw=dirman_password)
 
-    if config.subject_base is None:
-        attrs = conn.get_ipa_config()
-        config.subject_base = attrs.get('ipacertificatesubjectbase')[0]
+    # look up CA subject name (needed for DS certmap.conf)
+    ipa_ca_nickname = get_ca_nickname(config.realm_name)
+    db = certs.CertDB(config.realm_name, nssdir=paths.IPA_NSSDB_DIR)
+    cert = db.get_cert_from_db(ipa_ca_nickname)
+    options.subject_base = dsinstance.DsInstance().find_subject_base()
+    options.ca_subject = unicode(x509.load_certificate(cert).subject)
 
     if config.master_host_name is None:
         config.ca_host_name = \
@@ -175,7 +184,6 @@ def install_replica(safe_options, options, filename):
     options.domain_name = config.domain_name
     options.dm_password = config.dirman_password
     options.host_name = config.host_name
-    options.subject = config.subject_base
     if os.path.exists(cafile):
         options.ca_cert_file = cafile
     else:
@@ -193,7 +201,8 @@ def install_replica(safe_options, options, filename):
                                    host_name=config.host_name,
                                    dm_password=config.dirman_password)
         CA.configure_replica(config.ca_host_name,
-                             subject_base=config.subject_base,
+                             subject_base=options.subject_base,
+                             subject=options.ca_subject,
                              ca_cert_bundle=ca_data)
         # Install CA DNS records
         if bindinstance.dns_container_exists(api.env.host, api.env.basedn,
@@ -220,13 +229,13 @@ def install_master(safe_options, options):
                               bind_pw=dm_password)
 
     config = api.Command['config_show']()['result']
-    subject_base = config['ipacertificatesubjectbase'][0]
+    subject = api.Command.ca_show(IPA_CA_CN)['result']['ipacasubjectdn']
 
     options.realm_name = api.env.realm
     options.domain_name = api.env.domain
     options.dm_password = dm_password
     options.host_name = api.env.host
-    options.subject = subject_base
+    options.ca_subject = subject
 
     ca.install_check(True, None, options)
     ca.install(True, None, options)
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
index 55b49449e3c44aebfeefe5cb71d73e9abf07c5b2..9412eab4a345b1f25bdf91a09b4493ba3f27de34 100644
--- a/install/tools/man/ipa-server-install.1
+++ b/install/tools/man/ipa-server-install.1
@@ -129,8 +129,12 @@ Name of the Kerberos KDC SSL certificate to install
 \fB\-\-ca\-cert\-file\fR=\fIFILE\fR
 File containing the CA certificate of the CA which issued the Directory Server, Apache Server and Kerberos KDC certificates. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. Use this option if the CA certificate is not present in the certificate files.
 .TP
-\fB\-\-subject\fR=\fISUBJECT\fR
-The certificate subject base (default O=REALM.NAME)
+\fB\-\-subject\-base\fR=\fIDN\fR
+The certificate subject base (default: O=REALM.NAME).  Used in the Subject DN
+for host and service certificates issued using the default profile.
+.TP
+\fB\-\-ca\-subject\fR=\fIDN\fR
+The CA certificate subject DN (default: CN=Certificate Authority,SUBJECT_BASE).
 .TP
 \fB\-\-ca\-signing\-algorithm\fR=\fIALGORITHM\fR
 Signing algorithm of the IPA CA certificate. Possible values are SHA1withRSA, SHA256withRSA, SHA512withRSA. Default value is SHA256withRSA. Use this option with --external-ca if the external CA does not support the default signing algorithm.
@@ -200,6 +204,10 @@ An unattended uninstallation that will never prompt for user input
 .TP
 \fB\-P\fR \fIMASTER_PASSWORD\fR, \fB\-\-master\-password\fR=\fIMASTER_PASSWORD\fR
 The kerberos master password (normally autogenerated).
+.TP
+\fB\-\-subject\fR=\fIDN\fR
+The certificate subject base (default: O=REALM.NAME).  Used in the Subject DN
+for host and service certificates issued using the default profile.
 
 .SH "EXIT STATUS"
 0 if the (un)installation was successful
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index 00e0b038ca03320fd7b8268fb3eb96c5bc50a3ac..e143944d2af11dabd2e870484c7c2a1178a1f885 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -25,7 +25,7 @@ def install_check(standalone, replica_config, options):
 
     realm_name = options.realm_name
     host_name = options.host_name
-    subject_base = options.subject
+    subject_base = options.subject_base
 
     if replica_config is not None:
         if standalone and api.env.ra_plugin == 'selfsign':
@@ -68,7 +68,7 @@ def install_check(standalone, replica_config, options):
                   "--external-ca.")
 
         external_cert_file, external_ca_file = installutils.load_external_cert(
-            options.external_cert_files, options.subject)
+            options.external_cert_files, options.ca_subject)
     elif options.external_ca:
         if cainstance.is_step_one_done():
             raise ScriptError(
@@ -104,7 +104,7 @@ def install_check(standalone, replica_config, options):
                 if not cert:
                     continue
                 subject = DN(str(x509.get_subject(cert)))
-                if subject in (DN('CN=Certificate Authority', subject_base),
+                if subject in (DN(options.ca_subject),
                                DN('CN=IPA RA', subject_base),
                                DN('CN=Object Signing Cert', subject_base)):
                     raise ScriptError(
@@ -122,7 +122,6 @@ def install_step_0(standalone, replica_config, options):
     domain_name = options.domain_name
     dm_password = options.dm_password
     host_name = options.host_name
-    subject_base = options.subject
 
     if replica_config is not None:
         # Configure the CA if necessary
@@ -134,8 +133,10 @@ def install_step_0(standalone, replica_config, options):
         if standalone:
             api.Backend.ldap2.disconnect()
 
-        cainstance.install_replica_ca(replica_config, postinstall,
-                ra_p12=getattr(options, 'ra_p12', None))
+        cainstance.install_replica_ca(
+                replica_config, postinstall,
+                ra_p12=getattr(options, 'ra_p12', None),
+                subject=options.ca_subject)
 
         if standalone and not api.Backend.ldap2.isconnected():
             api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
@@ -155,19 +156,19 @@ def install_step_0(standalone, replica_config, options):
         ca.create_ra_agent_db = False
     if external == 0:
         ca.configure_instance(host_name, dm_password,
-                              dm_password, subject_base=subject_base,
+                              dm_password, subject=options.ca_subject,
                               ca_signing_algorithm=options.ca_signing_algorithm)
     elif external == 1:
         ca.configure_instance(host_name, dm_password,
                               dm_password, csr_file=paths.ROOT_IPA_CSR,
-                              subject_base=subject_base,
+                              subject=options.ca_subject,
                               ca_signing_algorithm=options.ca_signing_algorithm,
                               ca_type=options.external_ca_type)
     else:
         ca.configure_instance(host_name, dm_password, dm_password,
                               cert_file=external_cert_file.name,
                               cert_chain_file=external_ca_file.name,
-                              subject_base=subject_base,
+                              subject=options.ca_subject,
                               ca_signing_algorithm=options.ca_signing_algorithm)
 
 
@@ -176,7 +177,7 @@ def install_step_1(standalone, replica_config, options):
     domain_name = options.domain_name
     dm_password = options.dm_password
     host_name = options.host_name
-    subject_base = options.subject
+    subject_base = options.subject_base
 
     basedn = ipautil.realm_to_suffix(realm_name)
 
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 2ec02d6628ebc9e3a9bad141ec636c84eab14cef..94898afcd0aa9b3e2326089cafd9f2f9723202e9 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -345,7 +345,8 @@ class CAInstance(DogtagInstance):
                            pkcs12_info=None, master_host=None, csr_file=None,
                            cert_file=None, cert_chain_file=None,
                            master_replication_port=None,
-                           subject_base=None, ca_signing_algorithm=None,
+                           subject_base=None, subject=None,
+                           ca_signing_algorithm=None,
                            ca_type=None, ra_p12=None):
         """Create a CA instance.
 
@@ -365,10 +366,12 @@ class CAInstance(DogtagInstance):
             self.clone = True
         self.master_host = master_host
         self.master_replication_port = master_replication_port
-        if subject_base is None:
-            self.subject_base = DN(('O', self.realm))
-        else:
-            self.subject_base = subject_base
+
+        self.subject_base = \
+            subject_base or installutils.default_subject_base(self.realm)
+        self.subject = \
+            subject or installutils.default_ca_subject_dn(self.subject_base)
+
         if ca_signing_algorithm is None:
             self.ca_signing_algorithm = 'SHA256withRSA'
         else:
@@ -502,7 +505,7 @@ class CAInstance(DogtagInstance):
         config.set("CA", "pki_audit_signing_subject_dn",
             str(DN(('cn', 'CA Audit'), self.subject_base)))
         config.set("CA", "pki_ca_signing_subject_dn",
-            str(DN(('cn', 'Certificate Authority'), self.subject_base)))
+            str(self.subject))
 
         # Certificate nicknames
         config.set("CA", "pki_subsystem_nickname", "subsystemCert cert-pki-ca")
@@ -776,7 +779,7 @@ class CAInstance(DogtagInstance):
             userCertificate=[cert_data],
             description=['2;%s;%s;%s' % (
                 cert.serial_number,
-                DN(('CN', 'Certificate Authority'), self.subject_base),
+                DN(self.subject),
                 DN(('CN', 'IPA RA'), self.subject_base))])
         conn.add_entry(entry)
 
@@ -855,7 +858,7 @@ class CAInstance(DogtagInstance):
         st = 1
         en = 0
         subid = 0
-        ca_dn = DN(('CN','Certificate Authority'), self.subject_base)
+        ca_dn = DN(self.subject)
         while st > 0:
             st = certlist.find('-----BEGIN', en)
             en = certlist.find('-----END', en+1)
@@ -1306,7 +1309,7 @@ class CAInstance(DogtagInstance):
         basedn = ipautil.realm_to_suffix(self.realm)
         self.ldap_enable('CA', self.fqdn, None, basedn)
 
-    def configure_replica(self, master_host, subject_base=None,
+    def configure_replica(self, master_host, subject_base=None, subject=None,
                           ca_cert_bundle=None, ca_signing_algorithm=None,
                           ca_type=None):
         """Creates a replica CA, creating a local DS backend and using
@@ -1315,10 +1318,12 @@ class CAInstance(DogtagInstance):
         """
         self.master_host = master_host
         self.master_replication_port = 389
-        if subject_base is None:
-            self.subject_base = DN(('O', self.realm))
-        else:
-            self.subject_base = subject_base
+
+        self.subject_base = \
+            subject_base or installutils.default_subject_base(self.realm)
+        self.subject = \
+            subject or installutils.default_ca_subject_dn(self.subject_base)
+
         if ca_signing_algorithm is None:
             self.ca_signing_algorithm = 'SHA256withRSA'
         else:
@@ -1490,7 +1495,7 @@ def replica_ca_install_check(config):
         exit('IPA schema missing on master CA directory server')
 
 
-def install_replica_ca(config, postinstall=False, ra_p12=None):
+def install_replica_ca(config, postinstall=False, ra_p12=None, subject=None):
     """
     Install a CA on a replica.
 
@@ -1510,7 +1515,6 @@ def install_replica_ca(config, postinstall=False, ra_p12=None):
 
     ca = CAInstance(config.realm_name, certs.NSS_DIR)
     ca.dm_password = config.dirman_password
-    ca.subject_base = config.subject_base
 
     if not config.setup_ca:
         # We aren't configuring the CA in this step but we still need
@@ -1529,7 +1533,7 @@ def install_replica_ca(config, postinstall=False, ra_p12=None):
                           pkcs12_info=(cafile,), ra_p12=ra_p12,
                           master_host=config.master_host_name,
                           master_replication_port=config.ca_ds_port,
-                          subject_base=config.subject_base)
+                          subject=subject)
 
     # Restart httpd since we changed it's config and added ipa-pki-proxy.conf
     # Without the restart, CA service status check would fail due to missing
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 9eaec73300ebb61f2e71e72a03114c870966d95f..b154c3b9e36ea874b45225b0ba09af468c115072 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -72,9 +72,19 @@ class CertDB(object):
 
     This class knows IPA-specific details such as nssdir location, or the
     CA cert name.
+
+    ``ca_subject_dn``
+      IPA CA subject DN.  This argument is required when importing
+      CA certificates into the certificate database.
+    ``subject_base``
+      Realm subject base DN.  This argument is required when creating
+      server or object signing certs.
+
     """
     # TODO: Remove all selfsign code
-    def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_base=None):
+    def __init__(
+            self, realm, nssdir=NSS_DIR, fstore=None, host_name=None,
+            ca_subject_dn=None, subject_base=None):
         self.nssdb = NSSDatabase(nssdir)
 
         self.secdir = nssdir
@@ -93,15 +103,13 @@ class CertDB(object):
         self.certreq_fname = None
         self.certder_fname = None
         self.host_name = host_name
+        self.ca_subject_dn = ca_subject_dn
         self.subject_base = subject_base
         try:
             self.cwd = os.getcwd()
         except OSError as e:
             raise RuntimeError("Unable to determine the current directory: %s" % str(e))
 
-        if not subject_base:
-            self.subject_base = DN(('O', 'IPA'))
-
         self.cacert_name = get_ca_nickname(self.realm)
         self.valid_months = "120"
         self.keysize = "1024"
@@ -120,6 +128,7 @@ class CertDB(object):
         else:
             self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
 
+    ca_subject_dn = ipautil.dn_attribute_property('_ca_subject_dn')
     subject_base = ipautil.dn_attribute_property('_subject_base')
 
     def __del__(self):
@@ -253,13 +262,12 @@ class CertDB(object):
         certs = fd.read()
         fd.close()
 
-        ca_dn = DN(('CN','Certificate Authority'), self.subject_base)
         st = 0
         while True:
             try:
                 (cert, st) = find_cert_from_txt(certs, st)
                 (rdn, subject_dn) = get_cert_nickname(cert)
-                if subject_dn == ca_dn:
+                if subject_dn == self.ca_subject_dn:
                     nick = get_ca_nickname(self.realm)
                 else:
                     nick = str(subject_dn)
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 26cd2461a6833b7e129411b0005ba3a521bd3232..525857c3b5eef60dd1639a465fd2988646329904 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -238,6 +238,7 @@ class DsInstance(service.Service):
         self.dercert = None
         self.idstart = None
         self.idmax = None
+        self.subject = None
         self.subject_base = None
         self.open_ports = []
         self.run_init_memberof = True
@@ -255,6 +256,7 @@ class DsInstance(service.Service):
             self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
 
 
+    subject = ipautil.dn_attribute_property('_subject')
     subject_base = ipautil.dn_attribute_property('_subject_base')
 
     def __common_setup(self, enable_ssl=False):
@@ -303,7 +305,8 @@ class DsInstance(service.Service):
         self.step("configuring directory to start on boot", self.__enable)
 
     def init_info(self, realm_name, fqdn, domain_name, dm_password,
-                  subject_base, idstart, idmax, pkcs12_info, ca_file=None):
+                  subject_base, subject,
+                  idstart, idmax, pkcs12_info, ca_file=None):
         self.realm = realm_name.upper()
         self.serverid = installutils.realm_to_serverid(self.realm)
         self.suffix = ipautil.realm_to_suffix(self.realm)
@@ -312,6 +315,7 @@ class DsInstance(service.Service):
         self.domain = domain_name
         self.principal = "ldap/%s@%s" % (self.fqdn, self.realm)
         self.subject_base = subject_base
+        self.subject = subject
         self.idstart = idstart
         self.idmax = idmax
         self.pkcs12_info = pkcs12_info
@@ -323,11 +327,13 @@ class DsInstance(service.Service):
 
     def create_instance(self, realm_name, fqdn, domain_name,
                         dm_password, pkcs12_info=None,
-                        idstart=1100, idmax=999999, subject_base=None,
+                        idstart=1100, idmax=999999,
+                        subject_base=None, subject=None,
                         hbac_allow=True, ca_file=None):
         self.init_info(
             realm_name, fqdn, domain_name, dm_password,
-            subject_base, idstart, idmax, pkcs12_info, ca_file=ca_file)
+            subject_base, subject,
+            idstart, idmax, pkcs12_info, ca_file=ca_file)
 
         self.__common_setup()
         self.step("restarting directory server", self.__restart_instance)
@@ -361,8 +367,9 @@ class DsInstance(service.Service):
         self.start_creation(runtime=10)
 
     def create_replica(self, realm_name, master_fqdn, fqdn,
-                       domain_name, dm_password, subject_base, api,
-                       pkcs12_info=None, ca_file=None,
+                       domain_name, dm_password,
+                       subject_base, subject,
+                       api, pkcs12_info=None, ca_file=None,
                        ca_is_configured=None, promote=False):
         # idstart and idmax are configured so that the range is seen as
         # depleted by the DNA plugin and the replica will go and get a
@@ -377,6 +384,7 @@ class DsInstance(service.Service):
             domain_name=domain_name,
             dm_password=dm_password,
             subject_base=subject_base,
+            subject=subject,
             idstart=idstart,
             idmax=idmax,
             pkcs12_info=pkcs12_info,
@@ -760,7 +768,9 @@ class DsInstance(service.Service):
 
     def __enable_ssl(self):
         dirname = config_dirname(self.serverid)
-        dsdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base)
+        dsdb = certs.CertDB(
+                self.realm, nssdir=dirname,
+                ca_subject_dn=self.subject, subject_base=self.subject_base)
         if self.pkcs12_info:
             if self.ca_is_configured:
                 trust_flags = 'CT,C,C'
@@ -878,7 +888,7 @@ class DsInstance(service.Service):
         shutil.copyfile(ipautil.SHARE_DIR + "certmap.conf.template",
                         config_dirname(self.serverid) + "certmap.conf")
         installutils.update_file(config_dirname(self.serverid) + "certmap.conf",
-                                 '$SUBJECT_BASE', str(self.subject_base))
+                                 '$ISSUER_DN', str(self.subject))
         sysupgrade.set_upgrade_state(
             'certmap.conf',
             'subject_base',
@@ -1021,7 +1031,9 @@ class DsInstance(service.Service):
         self.stop()
 
         dirname = config_dirname(installutils.realm_to_serverid(self.realm))
-        certdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base)
+        certdb = certs.CertDB(
+                self.realm, nssdir=dirname,
+                ca_subject_dn=self.subject, subject_base=self.subject_base)
         if not cacert_name or len(cacert_name) == 0:
             cacert_name = "Imported CA"
         # we can't pass in the nickname, so we set the instance variable
@@ -1144,8 +1156,7 @@ class DsInstance(service.Service):
         Try to find the current value of certificate subject base.
         1) Look in sysupgrade first
         2) If no value is found there, look in DS (start DS if necessary)
-        3) Last resort, look in the certmap.conf itself
-        4) If all fails, log loudly and return None
+        3) If all fails, log loudly and return None
 
         Note that this method can only be executed AFTER the ipa server
         is configured, the api is initialized elsewhere and
@@ -1193,27 +1204,6 @@ class DsInstance(service.Service):
                 except Exception:
                     pass
 
-        if not subject_base:
-            root_logger.debug('Unable to find certificate subject base in DS')
-            root_logger.debug('Trying to find certificate subject base in '
-                              'certmap.conf')
-
-            certmap_dir = config_dirname(
-                installutils.realm_to_serverid(api.env.realm)
-            )
-            try:
-                with open(os.path.join(certmap_dir, 'certmap.conf')) as f:
-                    for line in f:
-                        if line.startswith('certmap ipaca'):
-                            subject_base = line.strip().split(',')[-1]
-                            root_logger.debug(
-                                'Found certificate subject base in certmap.conf: '
-                                '%s', subject_base)
-
-            except IOError as e:
-                root_logger.error('Cannot open certmap.conf to find certificate '
-                                  'subject base: %s', e.strerror)
-
         if subject_base:
             return subject_base
 
@@ -1250,9 +1240,10 @@ class DsInstance(service.Service):
         os.chown(paths.DS_KEYTAB, pent.pw_uid, pent.pw_gid)
 
     def __get_ds_cert(self):
-        subject = DN(('O', self.realm))
         nssdb_dir = config_dirname(self.serverid)
-        db = certs.CertDB(self.realm, nssdir=nssdb_dir, subject_base=subject)
+        db = certs.CertDB(
+            self.realm, nssdir=nssdb_dir,
+            ca_subject_dn=self.subject, subject_base=self.subject_base)
         db.request_service_cert(self.nickname, self.principal, self.fqdn)
         db.create_pin_file()
 
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 7578bf8f5c0ed358014e39914ce37b65a778ea48..7144231faf40e5f658bc70fb5b1b417bea479a45 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -996,7 +996,7 @@ def check_entropy():
     except ValueError as e:
         root_logger.debug("Invalid value in %s %s", paths.ENTROPY_AVAIL, e)
 
-def load_external_cert(files, subject_base):
+def load_external_cert(files, subject):
     """
     Load and verify external CA certificate chain from multiple files.
 
@@ -1004,7 +1004,7 @@ def load_external_cert(files, subject_base):
     chain formats.
 
     :param files: Names of files to import
-    :param subject_base: Subject name base for IPA certificates
+    :param subject: IPA CA subject DN
     :returns: Temporary file with the IPA CA certificate and temporary file
         with the external CA certificate chain
     """
@@ -1018,7 +1018,7 @@ def load_external_cert(files, subject_base):
         except RuntimeError as e:
             raise ScriptError(str(e))
 
-        ca_subject = DN(('CN', 'Certificate Authority'), subject_base)
+        ca_subject = DN(subject)
         ca_nickname = None
         cache = {}
         for nickname, trust_flags in nssdb.list_certs():
@@ -1377,3 +1377,36 @@ def remove_ccache(ccache_path=None, run_as=None):
     except ipautil.CalledProcessError as e:
         root_logger.warning(
             "Failed to clear Kerberos credentials cache: {}".format(e))
+
+
+def default_subject_base(realm_name):
+    return DN(('O', realm_name))
+
+
+def default_ca_subject_dn(subject_base):
+    return DN(('CN', 'Certificate Authority'), subject_base)
+
+
+def normalize_dogtag_ca_subject_dn(dn):
+    """
+    Prepare a CA subject DN to be compliant with Dogtag.
+
+    Move the most specific CN AVA encountered to be the most
+    specific RDN, if it is not already so.
+
+    If no CN AVA is encountered, add 'CN=Certificate Authority' as
+    the most specific RDN.
+
+    """
+    cn_ava = None
+    l = []
+    for rdn in DN(dn):
+        for ava in rdn:
+            if cn_ava is None and ava.attr.lower() == 'cn':
+                cn_ava = ava
+            else:
+                l.append(ava)
+    if cn_ava is None:
+        cn_ava = ('cn', 'Certificate Authority')
+    l.insert(0, cn_ava)
+    return DN(*l)
diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py
index 32ef25c7aac3e57d27955b6a2608adb6a1626019..044328464bfe9ce8fea3ffb03d6fa92eb70fa822 100644
--- a/ipaserver/install/ipa_cacert_manage.py
+++ b/ipaserver/install/ipa_cacert_manage.py
@@ -24,6 +24,7 @@ from optparse import OptionGroup
 from nss import nss
 from nss.error import NSPRError
 import gssapi
+import six
 
 from ipapython import admintool, certmonger, ipautil
 from ipapython.dn import DN
@@ -31,6 +32,9 @@ from ipaplatform.paths import paths
 from ipalib import api, errors, x509, certstore
 from ipaserver.install import certs, cainstance, installutils
 
+if six.PY3:
+    unicode = str
+
 
 class CACertManage(admintool.AdminTool):
     command_name = 'ipa-cacert-manage'
@@ -198,8 +202,6 @@ class CACertManage(admintool.AdminTool):
 
         options = self.options
         conn = api.Backend.ldap2
-        cert_file, ca_file = installutils.load_external_cert(
-            options.external_cert_files, x509.subject_base())
 
         nss_cert = None
         nss.nss_init(paths.PKI_TOMCAT_ALIAS_DIR)
@@ -211,6 +213,9 @@ class CACertManage(admintool.AdminTool):
             pkinfo = nss_cert.subject_public_key_info.format()
             #pylint: enable=E1101
 
+            cert_file, ca_file = installutils.load_external_cert(
+                options.external_cert_files, unicode(subject))
+
             nss_cert = x509.load_certificate_from_file(cert_file.name)
             cert = nss_cert.der_data
             if nss_cert.subject != subject:
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index 590a8407d76a1c54dd2323986a8981b7c4851daa..e8de01adfb50fc01159e4a7d3fe5c88ce9465911 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -80,7 +80,7 @@ class KRAInstance(DogtagInstance):
 
     def configure_instance(self, realm_name, host_name, dm_password,
                            admin_password, pkcs12_info=None, master_host=None,
-                           subject_base=None):
+                           subject_base=None, subject=None):
         """Create a KRA instance.
 
            To create a clone, pass in pkcs12_info.
@@ -92,10 +92,12 @@ class KRAInstance(DogtagInstance):
         if self.pkcs12_info is not None:
             self.clone = True
         self.master_host = master_host
-        if subject_base is None:
-            self.subject_base = DN(('O', self.realm))
-        else:
-            self.subject_base = subject_base
+
+        self.subject_base = \
+            subject_base or installutils.default_subject_base(realm_name)
+        self.subject = \
+            subject or installutils.default_ca_subject_dn(self.subject_base)
+
         self.realm = realm_name
         self.suffix = ipautil.realm_to_suffix(realm_name)
 
@@ -296,7 +298,7 @@ class KRAInstance(DogtagInstance):
             userCertificate=[cert_data],
             description=['2;%s;%s;%s' % (
                 cert.serial_number,
-                DN(('CN', 'Certificate Authority'), self.subject_base),
+                DN(self.subject),
                 DN(('CN', 'IPA RA'), self.subject_base))])
         conn.add_entry(entry)
 
@@ -364,10 +366,10 @@ class KRAInstance(DogtagInstance):
         self.fqdn = host_name
         self.dm_password = dm_password
         self.master_host = master_host
-        if subject_base is None:
-            self.subject_base = DN(('O', self.realm))
-        else:
-            self.subject_base = subject_base
+
+        self.subject_base = \
+            subject_base or installutils.default_subject_base(self.realm)
+
         self.suffix = ipautil.realm_to_suffix(self.realm)
 
         self.pkcs12_info = kra_cert_bundle
diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py
index e6093d15cd1067a83ed89945c4a9c983c66ec06f..9f00728dd40083f53ceed5a4c2bb9dc01e087b78 100644
--- a/ipaserver/install/server/common.py
+++ b/ipaserver/install/server/common.py
@@ -19,7 +19,7 @@ from ipapython.dnsutil import check_zone_overlap
 if six.PY3:
     unicode = str
 
-VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c',
+VALID_SUBJECT_ATTRS = ['cn', 'st', 'o', 'ou', 'dnqualifier', 'c',
                        'serialnumber', 'l', 'title', 'sn', 'givenname',
                        'initials', 'generationqualifier', 'dc', 'mail',
                        'uid', 'postaladdress', 'postalcode', 'postofficebox',
@@ -28,6 +28,21 @@ VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c',
                        'incorporationcountry', 'businesscategory']
 
 
+def _subject_validator(knob, value):
+    v = unicode(value, 'utf-8')
+    if any(ord(c) < 0x20 for c in v):
+        raise ValueError("must not contain control characters")
+    if '&' in v:
+        raise ValueError("must not contain an ampersand (\"&\")")
+    try:
+        dn = DN(v)
+        for rdn in dn:
+            if rdn.attr.lower() not in VALID_SUBJECT_ATTRS:
+                raise ValueError("invalid attribute: \"%s\"" % rdn.attr)
+    except ValueError as e:
+        raise ValueError("invalid subject base format: %s" % e)
+
+
 class BaseServerCA(common.Installable, core.Group, core.Composite):
     description = "certificate system"
 
@@ -130,23 +145,22 @@ class BaseServerCA(common.Installable, core.Group, core.Composite):
 
     subject = Knob(
         str, None,
+        deprecated=True,
         description="The certificate subject base (default O=<realm-name>)",
-    )
+        cli_metavar='DN',
+    ).validator(_subject_validator)
 
-    @subject.validator
-    def subject(self, value):
-        v = unicode(value, 'utf-8')
-        if any(ord(c) < 0x20 for c in v):
-            raise ValueError("must not contain control characters")
-        if '&' in v:
-            raise ValueError("must not contain an ampersand (\"&\")")
-        try:
-            dn = DN(v)
-            for rdn in dn:
-                if rdn.attr.lower() not in VALID_SUBJECT_ATTRS:
-                    raise ValueError("invalid attribute: \"%s\"" % rdn.attr)
-        except ValueError as e:
-            raise ValueError("invalid subject base format: %s" % e)
+    subject_base = Knob(
+        str, None,
+        description="The certificate subject base (default O=<realm-name>)",
+        cli_metavar='DN',
+    ).validator(_subject_validator)
+
+    ca_subject = Knob(
+        str, None,
+        description="The CA certificate subject DN (default CN=Certificate Authority,$SUBJECT_BASE)",
+        cli_metavar='DN',
+    ).validator(_subject_validator)
 
     ca_signing_algorithm = Knob(
         {'SHA1withRSA', 'SHA256withRSA', 'SHA512withRSA'}, None,
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 6644a6b31943f6a4826a531df5c50df9a562fdff..b54028437202f8ee78933a9b999e50a7478bd01a 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -239,7 +239,7 @@ def check_dirsrv(unattended):
         raise ScriptError(msg)
 
 
-def set_subject_in_config(realm_name, dm_password, suffix, subject_base):
+def set_subject_base_in_config(realm_name, dm_password, suffix, subject_base):
         ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % (
             installutils.realm_to_serverid(realm_name)
         )
@@ -335,6 +335,13 @@ def install_check(installer):
                "manually.")
         print(textwrap.fill(msg, width=79, replace_whitespace=False))
 
+    if options.subject:
+        msg = (
+            "WARNING: option '--subject' is deprecated. "
+            "It has been superseded by '--subject-base'."
+        )
+        print(textwrap.fill(msg, width=79, replace_whitespace=False))
+
     installer._installation_cleanup = True
 
     print("\nThe log file for this installation can be found in "
@@ -482,8 +489,27 @@ def install_check(installer):
     else:
         realm_name = options.realm_name.upper()
 
-    if not options.subject:
-        options.subject = DN(('O', realm_name))
+    if not options.subject_base:
+        if options.subject:
+            # deprecated option was supplied
+            options.subject_base = options.subject
+        else:
+            options.subject_base = \
+                installutils.default_subject_base(realm_name)
+
+    if not options.ca_subject:
+        options.ca_subject = \
+            installutils.default_ca_subject_dn(options.subject_base)
+
+    ca_subject_normalized = False
+    if not (options.external_ca or options.external_cert_files):
+        # CA will be self-signed by Dogtag;
+        # normalize DN to Dogtag's expectations
+        sdn_norm = installutils.normalize_dogtag_ca_subject_dn(
+            options.ca_subject)
+        if sdn_norm != options.ca_subject:
+            ca_subject_normalized = True
+            options.ca_subject = sdn_norm
 
     if options.http_cert_files:
         if options.http_pin is None:
@@ -622,6 +648,15 @@ def install_check(installer):
     print("Realm name:     %s" % realm_name)
     print()
 
+    if options.setup_ca:
+        print("The CA will be configured with:")
+        dn_msg = "CA subject DN:     %s" % options.ca_subject
+        if ca_subject_normalized:
+            dn_msg += " (normalized)"
+        print(dn_msg)
+        print("Cert subject base: %s" % options.subject_base)
+        print()
+
     if options.setup_dns:
         print("BIND DNS server will be configured to serve IPA domain with:")
         print("Forwarders:       %s" % (
@@ -735,7 +770,8 @@ def install(installer):
             ds.create_instance(realm_name, host_name, domain_name,
                                dm_password, dirsrv_pkcs12_info,
                                idstart=options.idstart, idmax=options.idmax,
-                               subject_base=options.subject,
+                               subject_base=options.subject_base,
+                               subject=options.ca_subject,
                                hbac_allow=not options.no_hbac_allow)
         else:
             ds = dsinstance.DsInstance(fstore=fstore,
@@ -745,7 +781,8 @@ def install(installer):
             ds.create_instance(realm_name, host_name, domain_name,
                                dm_password,
                                idstart=options.idstart, idmax=options.idmax,
-                               subject_base=options.subject,
+                               subject_base=options.subject_base,
+                               subject=options.ca_subject,
                                hbac_allow=not options.no_hbac_allow)
 
         ntpinstance.ntp_ldap_enable(host_name, ds.suffix, realm_name)
@@ -756,7 +793,7 @@ def install(installer):
         installer._ds = ds
         ds.init_info(
             realm_name, host_name, domain_name, dm_password,
-            options.subject, 1101, 1100, None)
+            options.subject_base, options.ca_subject, 1101, 1100, None)
 
     if setup_ca:
         if not options.external_cert_files and options.external_ca:
@@ -791,12 +828,12 @@ def install(installer):
                             dm_password, master_password,
                             setup_pkinit=not options.no_pkinit,
                             pkcs12_info=pkinit_pkcs12_info,
-                            subject_base=options.subject)
+                            subject_base=options.subject_base)
     else:
         krb.create_instance(realm_name, host_name, domain_name,
                             dm_password, master_password,
                             setup_pkinit=not options.no_pkinit,
-                            subject_base=options.subject)
+                            subject_base=options.subject_base)
 
     if setup_ca:
         ca.install_step_1(False, None, options)
@@ -821,13 +858,13 @@ def install(installer):
     if options.http_cert_files:
         http.create_instance(
             realm_name, host_name, domain_name, dm_password,
-            pkcs12_info=http_pkcs12_info, subject_base=options.subject,
+            pkcs12_info=http_pkcs12_info, subject_base=options.subject_base,
             auto_redirect=not options.no_ui_redirect,
             ca_is_configured=setup_ca)
     else:
         http.create_instance(
             realm_name, host_name, domain_name, dm_password,
-            subject_base=options.subject,
+            subject_base=options.subject_base,
             auto_redirect=not options.no_ui_redirect,
             ca_is_configured=setup_ca)
     tasks.restore_context(paths.CACHE_IPA_SESSIONS)
@@ -837,8 +874,9 @@ def install(installer):
     os.chmod(CACERT, 0o644)
     ca_db.publish_ca_cert(CACERT)
 
-    set_subject_in_config(realm_name, dm_password,
-                          ipautil.realm_to_suffix(realm_name), options.subject)
+    set_subject_base_in_config(
+        realm_name, dm_password,
+        ipautil.realm_to_suffix(realm_name), options.subject_base)
 
     # Apply any LDAP updates. Needs to be done after the configuration file
     # is created
@@ -1190,6 +1228,8 @@ class ServerCA(BaseServerCA):
     pkinit_cert_name = Knob(BaseServerCA.pkinit_cert_name)
     ca_cert_files = Knob(BaseServerCA.ca_cert_files)
     subject = Knob(BaseServerCA.subject)
+    subject_base = Knob(BaseServerCA.subject_base)
+    ca_subject = Knob(BaseServerCA.ca_subject)
     ca_signing_algorithm = Knob(BaseServerCA.ca_signing_algorithm)
     skip_schema_check = None
 
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index c73600ccad4ededd6f5b17dd5a35479af9093166..fa2ef1808ca95618464f3108bce9738ce6d899fd 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -18,6 +18,7 @@ import tempfile
 import six
 
 from ipapython import ipaldap, ipautil, sysrestore
+from ipapython.certdb import get_ca_nickname
 from ipapython.dn import DN
 from ipapython.install.common import step
 from ipapython.install.core import Knob
@@ -71,7 +72,7 @@ def make_pkcs12_info(directory, cert_name, password_name):
         return None
 
 
-def install_http_certs(config, fstore, remote_api):
+def install_http_certs(config, fstore, remote_api, subject_base):
 
     # Obtain keytab for the HTTP service
     fstore.backup_file(paths.IPA_KEYTAB)
@@ -89,8 +90,7 @@ def install_http_certs(config, fstore, remote_api):
 
     # Obtain certificate for the HTTP service
     nssdir = certs.NSS_DIR
-    subject = DN(('O', config.realm_name))
-    db = certs.CertDB(config.realm_name, nssdir=nssdir, subject_base=subject)
+    db = certs.CertDB(config.realm_name, nssdir=nssdir, subject_base=subject_base)
     db.request_service_cert('Server-Cert', principal, config.host_name, True)
     # FIXME: need Signing-Cert too ?
 
@@ -120,6 +120,7 @@ def install_replica_ds(config, options, ca_is_configured, remote_api,
         domain_name=config.domain_name,
         dm_password=config.dirman_password,
         subject_base=config.subject_base,
+        subject=options.ca_subject,
         pkcs12_info=pkcs12_info,
         ca_is_configured=ca_is_configured,
         ca_file=ca_file,
@@ -599,6 +600,9 @@ def install_check(installer):
         raise RuntimeError("CA cert file is not available. Please run "
                            "ipa-replica-prepare to create a new replica file.")
 
+    # look up CA subject name (needed for DS certmap.conf)
+    options.ca_subject = unicode(x509.load_certificate_from_file(cafile).subject)
+
     for pkcs12_name, pin_name in (('dscert.p12', 'dirsrv_pin.txt'),
                                   ('httpcert.p12', 'http_pin.txt')):
         pkcs12_info = make_pkcs12_info(config.dir, pkcs12_name, pin_name)
@@ -717,7 +721,6 @@ def install_check(installer):
         if options.setup_ca:
             options.realm_name = config.realm_name
             options.host_name = config.host_name
-            options.subject = config.subject_base
             ca.install_check(False, config, options)
 
         if config.setup_kra:
@@ -1256,6 +1259,12 @@ def promote_check(installer):
         if subject_base is not None:
             config.subject_base = DN(subject_base)
 
+        # look up CA subject name (needed for DS certmap.conf)
+        ipa_ca_nickname = get_ca_nickname(config.realm_name)
+        db = certs.CertDB(config.realm_name, nssdir=paths.IPA_NSSDB_DIR)
+        cert = db.get_cert_from_db(ipa_ca_nickname)
+        options.ca_subject = unicode(x509.load_certificate(cert).subject)
+
         # Find if any server has a CA
         ca_host = service.find_providing_server('CA', conn, api.env.server)
         if ca_host is not None:
@@ -1289,7 +1298,7 @@ def promote_check(installer):
 
             options.realm_name = config.realm_name
             options.host_name = config.host_name
-            options.subject = config.subject_base
+
             ca.install_check(False, None, options)
 
         if config.setup_kra:
@@ -1418,7 +1427,7 @@ def promote(installer):
 
         # Must install http certs before changing ipa configuration file
         # or certmonger will fail to contact the peer master
-        install_http_certs(config, fstore, remote_api)
+        install_http_certs(config, fstore, remote_api, config.subject_base)
 
         ntpinstance.ntp_ldap_enable(config.host_name, ds.suffix,
                                     remote_api.env.realm)
@@ -1507,6 +1516,7 @@ def promote(installer):
                                    dm_password=config.dirman_password)
         ca.configure_replica(config.ca_host_name,
                              subject_base=config.subject_base,
+                             subject=options.ca_subject,
                              ca_cert_bundle=ca_data)
 
     if options.setup_kra:
-- 
2.5.5



More information about the Freeipa-devel mailing list