summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2014-08-05 09:06:39 +0200
committerPetr Viktorin <pviktori@dhcp-31-13.brq.redhat.com>2014-09-05 13:59:04 +0200
commit6ad8c464a43260f8f58dc262f841c35be35b57b5 (patch)
treed596fb119f94b21a2c01c839a0659b74a4aacf6f
parent418ce870bfbe13cea694a7b862cafe35c703f660 (diff)
downloadfreeipa-6ad8c464a43260f8f58dc262f841c35be35b57b5.tar.gz
freeipa-6ad8c464a43260f8f58dc262f841c35be35b57b5.tar.xz
freeipa-6ad8c464a43260f8f58dc262f841c35be35b57b5.zip
Make CA-less ipa-server-install option --root-ca-file optional.
The CA cert specified by --root-ca-file option must always be the CA cert of the CA which issued the server certificates in the PKCS#12 files. As the cert is not actually user selectable, use CA cert from the PKCS#12 files by default if it is present. Document --root-ca-file in ipa-server-install man page. https://fedorahosted.org/freeipa/ticket/4457 Reviewed-By: Petr Viktorin <pviktori@redhat.com>
-rwxr-xr-xinstall/tools/ipa-server-install22
-rw-r--r--install/tools/man/ipa-server-install.13
-rw-r--r--ipaserver/install/dsinstance.py15
-rw-r--r--ipaserver/install/installutils.py46
-rw-r--r--ipaserver/install/ipa_replica_prepare.py14
-rw-r--r--ipaserver/install/ipa_server_certinstall.py3
6 files changed, 59 insertions, 44 deletions
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 6e77b434a..c81914951 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -69,7 +69,7 @@ from ipapython import sysrestore
from ipapython.ipautil import *
from ipapython import ipautil
from ipapython import dogtag
-from ipalib import api, errors, util
+from ipalib import api, errors, util, x509
from ipapython.config import IPAOptionParser
from ipalib.util import validate_domain_name
from ipalib.constants import CACERT
@@ -223,7 +223,7 @@ def parse_options():
cert_group.add_option("--pkinit_pin", dest="pkinit_pin",
help="The password of the Kerberos KDC PKCS#12 file")
cert_group.add_option("--root-ca-file", dest="root_ca_file",
- help="PEM file with root CA certificate(s) to trust")
+ help="PEM file containing the CA certificate for the PKCS#12 files")
cert_group.add_option("--subject", action="callback", callback=subject_callback,
type="string",
help="The certificate subject base (default O=<realm-name>)")
@@ -316,10 +316,6 @@ def parse_options():
if options.pkinit_pkcs12 and options.pkinit_pin is None:
parser.error("You must specify --pkinit_pin with --pkinit_pkcs12")
- if options.dirsrv_pkcs12 and not options.root_ca_file:
- parser.error(
- "--root-ca-file must be given with the PKCS#12 options.")
-
if (options.external_cert_file or options.external_ca_file) and options.dirsrv_pkcs12:
parser.error(
"PKCS#12 options cannot be used with the external CA options.")
@@ -920,7 +916,7 @@ def main():
if options.http_pin is None:
sys.exit("%s unlock password required" % options.http_pkcs12)
http_pkcs12_info = (options.http_pkcs12, options.http_pin)
- http_cert_name = installutils.check_pkcs12(
+ http_ca_cert = installutils.check_pkcs12(
http_pkcs12_info, ca_file, host_name)
if options.dirsrv_pkcs12:
@@ -931,7 +927,7 @@ def main():
if options.dirsrv_pin is None:
sys.exit("%s unlock password required" % options.dirsrv_pkcs12)
dirsrv_pkcs12_info = (options.dirsrv_pkcs12, options.dirsrv_pin)
- dirsrv_cert_name = installutils.check_pkcs12(
+ dirsrv_ca_cert = installutils.check_pkcs12(
dirsrv_pkcs12_info, ca_file, host_name)
if options.pkinit_pkcs12:
@@ -943,6 +939,11 @@ def main():
sys.exit("%s unlock password required" % options.pkinit_pkcs12)
pkinit_pkcs12_info = (options.pkinit_pkcs12, options.pkinit_pin)
+ if (options.http_pkcs12 and options.dirsrv_pkcs12 and
+ http_ca_cert != dirsrv_ca_cert):
+ sys.exit("%s and %s are not signed by the same CA certificate" %
+ (options.http_pkcs12, options.dirsrv_pkcs12))
+
if not options.dm_password:
dm_password = read_dm_password()
@@ -1073,8 +1074,7 @@ def main():
ntp.create_instance()
if options.dirsrv_pkcs12:
- ds = dsinstance.DsInstance(fstore=fstore,
- cert_nickname=dirsrv_cert_name)
+ ds = dsinstance.DsInstance(fstore=fstore)
ds.create_instance(realm_name, host_name, domain_name,
dm_password, dirsrv_pkcs12_info,
idstart=options.idstart, idmax=options.idmax,
@@ -1128,7 +1128,7 @@ def main():
ca.publish_ca_cert(CACERT)
else:
# Put the CA cert where other instances expect it
- shutil.copy(options.root_ca_file, CACERT)
+ x509.write_certificate(http_ca_cert, CACERT)
os.chmod(CACERT, 0444)
# we now need to enable ssl on the ds
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
index d713d2db4..8cc2ffa45 100644
--- a/install/tools/man/ipa-server-install.1
+++ b/install/tools/man/ipa-server-install.1
@@ -118,6 +118,9 @@ The password of the Apache Server PKCS#12 file
\fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR
The password of the Kerberos KDC PKCS#12 file
.TP
+\fB\-\-root\-ca\-file\fR=\fIFILE\fR
+PEM file containing the CA certificate of the CA which issued the Directory Server, Apache Server and Kerberos KDC SSL certificates. Use this option if the CA certificate is not present in the PKCS#12 files.
+.TP
\fB\-\-subject\fR=\fISUBJECT\fR
The certificate subject base (default O=REALM.NAME)
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 1719df46d..cc1d32709 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -223,14 +223,14 @@ info: IPA V2.0
class DsInstance(service.Service):
def __init__(self, realm_name=None, domain_name=None, dm_password=None,
- fstore=None, cert_nickname='Server-Cert'):
+ fstore=None):
service.Service.__init__(self, "dirsrv",
service_desc="directory server",
dm_password=dm_password,
ldapi=False,
autobind=service.DISABLED
)
- self.nickname = cert_nickname
+ self.nickname = 'Server-Cert'
self.dm_password = dm_password
self.realm = realm_name
self.sub_dict = None
@@ -641,24 +641,23 @@ class DsInstance(service.Service):
raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0])
# We only handle one server cert
- nickname = server_certs[0][0]
- self.dercert = dsdb.get_cert_from_db(nickname, pem=False)
+ self.nickname = server_certs[0][0]
+ self.dercert = dsdb.get_cert_from_db(self.nickname, pem=False)
else:
- nickname = self.nickname
cadb = certs.CertDB(self.realm, host_name=self.fqdn, subject_base=self.subject_base)
# FIXME, need to set this nickname in the RA plugin
cadb.export_ca_cert('ipaCert', False)
dsdb.create_from_cacert(cadb.cacert_fname, passwd=None)
self.dercert = dsdb.create_server_cert(
- nickname, self.fqdn, cadb)
+ self.nickname, self.fqdn, cadb)
dsdb.create_pin_file()
self.cacert_name = dsdb.cacert_name
if self.ca_is_configured:
dsdb.track_server_cert(
- nickname, self.principal, dsdb.passwd_fname,
+ self.nickname, self.principal, dsdb.passwd_fname,
'restart_dirsrv %s' % self.serverid)
conn = ipaldap.IPAdmin(self.fqdn)
@@ -679,7 +678,7 @@ class DsInstance(service.Service):
DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')),
objectclass=["top", "nsEncryptionModule"],
cn=["RSA"],
- nsSSLPersonalitySSL=[nickname],
+ nsSSLPersonalitySSL=[self.nickname],
nsSSLToken=["internal (software)"],
nsSSLActivation=["on"],
)
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 3b9138fef..e4cf5040f 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -800,8 +800,6 @@ def check_pkcs12(pkcs12_info, ca_file, hostname):
This is used for files given to --*_pkcs12 to ipa-server-install and
ipa-replica-prepare.
-
- Return a (server cert name, CA cert names) tuple
"""
pkcs12_filename, pkcs12_passwd = pkcs12_info
root_logger.debug('Checking PKCS#12 certificate %s', pkcs12_filename)
@@ -812,13 +810,18 @@ def check_pkcs12(pkcs12_info, ca_file, hostname):
# Import the CA cert first so it has a known nickname
# (if it's present in the PKCS#12 it won't be overwritten)
ca_cert_name = 'The Root CA'
- try:
- nssdb.import_pem_cert(ca_cert_name, "CT,C,C", ca_file)
- except (ValueError, RuntimeError) as e:
- raise ScriptError(str(e))
+ if ca_file:
+ try:
+ nssdb.import_pem_cert(ca_cert_name, "CT,C,C", ca_file)
+ except (ValueError, RuntimeError) as e:
+ raise ScriptError(str(e))
# Import everything in the PKCS#12
- nssdb.import_pkcs12(pkcs12_filename, db_pwd_file.name, pkcs12_passwd)
+ try:
+ nssdb.import_pkcs12(
+ pkcs12_filename, db_pwd_file.name, pkcs12_passwd)
+ except RuntimeError as e:
+ raise ScriptError(str(e))
# Check we have exactly one server cert (one with a private key)
server_certs = nssdb.find_server_certs()
@@ -833,21 +836,23 @@ def check_pkcs12(pkcs12_info, ca_file, hostname):
# Check we have the whole cert chain & the CA is in it
trust_chain = nssdb.get_trust_chain(server_cert_name)
- while trust_chain:
- if trust_chain[0] == ca_cert_name:
- break
- trust_chain = trust_chain[1:]
- else:
- raise ScriptError(
- '%s is not signed by %s, or the full certificate chain is not '
- 'present in the PKCS#12 file' % (pkcs12_filename, ca_file))
- if len(trust_chain) != 2:
+ if len(trust_chain) < 2:
+ if ca_file:
+ raise ScriptError(
+ '%s is not signed by %s, or the full certificate chain is '
+ 'not present in the PKCS#12 file' %
+ (pkcs12_filename, ca_file))
+ else:
+ raise ScriptError(
+ 'The full certificate chain is not present in %s' %
+ pkcs12_filename)
+ if ca_file and trust_chain[-2] != ca_cert_name:
raise ScriptError(
- 'trust chain of the server certificate in %s contains %s '
- 'certificates, expected 2' %
- (pkcs12_filename, len(trust_chain)))
+ '%s is not signed by %s' % (pkcs12_filename, ca_file))
+ ca_cert_name = trust_chain[-2]
# Check server validity
+ nssdb.trust_root_cert(ca_cert_name)
try:
nssdb.verify_server_cert_validity(server_cert_name, hostname)
except ValueError as e:
@@ -855,8 +860,7 @@ def check_pkcs12(pkcs12_info, ca_file, hostname):
'The server certificate in %s is not valid: %s' %
(pkcs12_filename, e))
- return server_cert_name
-
+ return nssdb.get_cert(ca_cert_name)
@contextmanager
def private_ccache(path=None):
diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py
index 1099046dd..c8a978dfa 100644
--- a/ipaserver/install/ipa_replica_prepare.py
+++ b/ipaserver/install/ipa_replica_prepare.py
@@ -139,7 +139,7 @@ class ReplicaPrepare(admintool.AdminTool):
"could not find directory instance: %s" % config_dir)
def check_pkcs12(self, pkcs12_file, pkcs12_pin):
- installutils.check_pkcs12(
+ return installutils.check_pkcs12(
pkcs12_info=(pkcs12_file, pkcs12_pin),
ca_file=CACERT,
hostname=self.replica_fqdn)
@@ -221,7 +221,8 @@ class ReplicaPrepare(admintool.AdminTool):
if options.http_pin is None:
raise admintool.ScriptError(
"%s unlock password required" % options.http_pkcs12)
- self.check_pkcs12(options.http_pkcs12, options.http_pin)
+ http_ca_cert = self.check_pkcs12(
+ options.http_pkcs12, options.http_pin)
if options.dirsrv_pkcs12:
if options.dirsrv_pin is None:
@@ -231,7 +232,8 @@ class ReplicaPrepare(admintool.AdminTool):
if options.dirsrv_pin is None:
raise admintool.ScriptError(
"%s unlock password required" % options.dirsrv_pkcs12)
- self.check_pkcs12(options.dirsrv_pkcs12, options.dirsrv_pin)
+ dirsrv_ca_cert = self.check_pkcs12(
+ options.dirsrv_pkcs12, options.dirsrv_pin)
if options.pkinit_pkcs12:
if options.pkinit_pin is None:
@@ -242,6 +244,12 @@ class ReplicaPrepare(admintool.AdminTool):
raise admintool.ScriptError(
"%s unlock password required" % options.pkinit_pkcs12)
+ if (options.http_pkcs12 and options.dirsrv_pkcs12 and
+ http_ca_cert != dirsrv_ca_cert):
+ raise admintool.ScriptError(
+ "%s and %s are not signed by the same CA certificate" %
+ (options.http_pkcs12, options.dirsrv_pkcs12))
+
if (not ipautil.file_exists(
dogtag.configured_constants().CS_CFG_PATH) and
options.dirsrv_pin is None):
diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py
index af5d21a2a..6300a14ae 100644
--- a/ipaserver/install/ipa_server_certinstall.py
+++ b/ipaserver/install/ipa_server_certinstall.py
@@ -154,7 +154,7 @@ class ServerCertInstall(admintool.AdminTool):
os.chown(os.path.join(dirname, 'secmod.db'), 0, pent.pw_gid)
def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command):
- server_cert = installutils.check_pkcs12(
+ installutils.check_pkcs12(
pkcs12_info=(self.pkcs12_fname, pkcs12_passwd),
ca_file=CACERT,
hostname=api.env.host)
@@ -166,6 +166,7 @@ class ServerCertInstall(admintool.AdminTool):
cdb.delete_cert(old_cert)
cdb.import_pkcs12(self.pkcs12_fname, pkcs12_passwd)
+ server_cert = cdb.find_server_certs()[0][0]
if api.env.enable_ra:
cdb.track_server_cert(server_cert, principal, cdb.passwd_fname,