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
commit7c690d7e1238133677e49236595eb24483876ef8 (patch)
tree3bc1e80d9660d0c210eb05a74b386a4cc49e3860
parent063cd7724d77707a8070c5f416b19d966440d739 (diff)
downloadfreeipa-7c690d7e1238133677e49236595eb24483876ef8.tar.gz
freeipa-7c690d7e1238133677e49236595eb24483876ef8.tar.xz
freeipa-7c690d7e1238133677e49236595eb24483876ef8.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 393c52d0e..89dd2ad36 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -68,7 +68,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.x509 import load_certificate_from_file, load_certificate_chain_from_file
from ipalib.util import validate_domain_name
@@ -199,7 +199,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>)")
@@ -289,10 +289,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.")
@@ -913,7 +909,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:
@@ -924,7 +920,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:
@@ -936,6 +932,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()
@@ -1065,8 +1066,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,
@@ -1120,7 +1120,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 2a9f3b618..61ea52a6b 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -221,14 +221,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
@@ -632,24 +632,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)
@@ -670,7 +669,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 b6e0e68f9..7d7c742ac 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -734,8 +734,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)
@@ -746,13 +744,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()
@@ -767,21 +770,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:
@@ -789,8 +794,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 81b54211f..c1ced3dcb 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,