mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Support installing with custom SSL certs, without a CA
Design: http://freeipa.org/page/V3/CA-less_install https://fedorahosted.org/freeipa/ticket/3363
This commit is contained in:
committed by
Martin Kosek
parent
a03aba5704
commit
03a2c66eda
@@ -536,6 +536,9 @@ def main():
|
|||||||
fd.write("ra_plugin=dogtag\n")
|
fd.write("ra_plugin=dogtag\n")
|
||||||
fd.write("dogtag_version=%s\n" %
|
fd.write("dogtag_version=%s\n" %
|
||||||
dogtag.install_constants.DOGTAG_VERSION)
|
dogtag.install_constants.DOGTAG_VERSION)
|
||||||
|
else:
|
||||||
|
fd.write("enable_ra=False\n")
|
||||||
|
fd.write("ra_plugin=none\n")
|
||||||
fd.write("mode=production\n")
|
fd.write("mode=production\n")
|
||||||
fd.close()
|
fd.close()
|
||||||
finally:
|
finally:
|
||||||
@@ -560,9 +563,7 @@ def main():
|
|||||||
sstore.backup_state("install", "group_exists", group_exists)
|
sstore.backup_state("install", "group_exists", group_exists)
|
||||||
|
|
||||||
#Automatically disable pkinit w/ dogtag until that is supported
|
#Automatically disable pkinit w/ dogtag until that is supported
|
||||||
#[certs.ipa_self_signed() must be called only after api.finalize()]
|
options.setup_pkinit = False
|
||||||
if not ipautil.file_exists(config.dir + "/pkinitcert.p12") and not certs.ipa_self_signed():
|
|
||||||
options.setup_pkinit = False
|
|
||||||
|
|
||||||
# Install CA cert so that we can do SSL connections with ldap
|
# Install CA cert so that we can do SSL connections with ldap
|
||||||
install_ca_cert(config)
|
install_ca_cert(config)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import pickle
|
|||||||
import random
|
import random
|
||||||
import tempfile
|
import tempfile
|
||||||
import nss.error
|
import nss.error
|
||||||
|
import base64
|
||||||
from optparse import OptionGroup, OptionValueError, SUPPRESS_HELP
|
from optparse import OptionGroup, OptionValueError, SUPPRESS_HELP
|
||||||
|
|
||||||
from ipaserver.install import dsinstance
|
from ipaserver.install import dsinstance
|
||||||
@@ -60,7 +61,7 @@ from ipapython import sysrestore
|
|||||||
from ipapython.ipautil import *
|
from ipapython.ipautil import *
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
from ipapython import dogtag
|
from ipapython import dogtag
|
||||||
from ipalib import api, errors, util
|
from ipalib import api, errors, util, x509
|
||||||
from ipapython.config import IPAOptionParser
|
from ipapython.config import IPAOptionParser
|
||||||
from ipalib.x509 import load_certificate_from_file, load_certificate_chain_from_file
|
from ipalib.x509 import load_certificate_from_file, load_certificate_chain_from_file
|
||||||
from ipalib.util import validate_domain_name
|
from ipalib.util import validate_domain_name
|
||||||
@@ -185,6 +186,8 @@ def parse_options():
|
|||||||
help="The password of the Apache Server PKCS#12 file")
|
help="The password of the Apache Server PKCS#12 file")
|
||||||
cert_group.add_option("--pkinit_pin", dest="pkinit_pin",
|
cert_group.add_option("--pkinit_pin", dest="pkinit_pin",
|
||||||
help="The password of the Kerberos KDC PKCS#12 file")
|
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")
|
||||||
cert_group.add_option("--subject", action="callback", callback=subject_callback,
|
cert_group.add_option("--subject", action="callback", callback=subject_callback,
|
||||||
type="string",
|
type="string",
|
||||||
help="The certificate subject base (default O=<realm-name>)")
|
help="The certificate subject base (default O=<realm-name>)")
|
||||||
@@ -280,7 +283,14 @@ def parse_options():
|
|||||||
if cnt > 0 and cnt < 4:
|
if cnt > 0 and cnt < 4:
|
||||||
parser.error("All PKCS#12 options are required if any are used.")
|
parser.error("All PKCS#12 options are required if any are used.")
|
||||||
|
|
||||||
if (options.external_cert_file or options.external_ca_file) and cnt:
|
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.dirsrv_pkcs12 and not options.root_ca_file:
|
||||||
|
parser.error(
|
||||||
|
"The PKCS#12 options must be given with --root-ca-file.")
|
||||||
|
|
||||||
|
if (options.external_cert_file or options.external_ca_file) and options.dirsrv_pkcs12:
|
||||||
parser.error(
|
parser.error(
|
||||||
"PKCS#12 options cannot be used with the external CA options.")
|
"PKCS#12 options cannot be used with the external CA options.")
|
||||||
|
|
||||||
@@ -289,6 +299,8 @@ def parse_options():
|
|||||||
parser.error("You cannot specify --external_cert_file together with --external-ca")
|
parser.error("You cannot specify --external_cert_file together with --external-ca")
|
||||||
if options.external_ca_file:
|
if options.external_ca_file:
|
||||||
parser.error("You cannot specify --external_ca_file together with --external-ca")
|
parser.error("You cannot specify --external_ca_file together with --external-ca")
|
||||||
|
if options.dirsrv_pkcs12:
|
||||||
|
parser.error("You cannot specify PKCS#12 options together with --external-ca")
|
||||||
|
|
||||||
if ((options.external_cert_file and not options.external_ca_file) or
|
if ((options.external_cert_file and not options.external_ca_file) or
|
||||||
(not options.external_cert_file and options.external_ca_file)):
|
(not options.external_cert_file and options.external_ca_file)):
|
||||||
@@ -561,6 +573,7 @@ def set_subject_in_config(realm_name, dm_password, suffix, subject_base):
|
|||||||
conn.update_entry(dn, mod)
|
conn.update_entry(dn, mod)
|
||||||
conn.disconnect()
|
conn.disconnect()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global ds
|
global ds
|
||||||
global uninstalling
|
global uninstalling
|
||||||
@@ -821,6 +834,13 @@ def main():
|
|||||||
else:
|
else:
|
||||||
domain_name = options.domain_name
|
domain_name = options.domain_name
|
||||||
|
|
||||||
|
if options.http_pkcs12:
|
||||||
|
# Check the given PKCS#12 files
|
||||||
|
ca_file = options.root_ca_file
|
||||||
|
check_pkcs12 = installutils.check_pkcs12
|
||||||
|
http_cert_name = check_pkcs12(http_pkcs12_info, ca_file, host_name)
|
||||||
|
dirsrv_cert_name = check_pkcs12(dirsrv_pkcs12_info, ca_file, host_name)
|
||||||
|
|
||||||
domain_name = domain_name.lower()
|
domain_name = domain_name.lower()
|
||||||
|
|
||||||
ip = get_server_ip_address(host_name, fstore, options.unattended, options)
|
ip = get_server_ip_address(host_name, fstore, options.unattended, options)
|
||||||
@@ -921,6 +941,7 @@ def main():
|
|||||||
dogtag.install_constants.DOGTAG_VERSION)
|
dogtag.install_constants.DOGTAG_VERSION)
|
||||||
else:
|
else:
|
||||||
fd.write("enable_ra=False\n")
|
fd.write("enable_ra=False\n")
|
||||||
|
fd.write("ra_plugin=none\n")
|
||||||
fd.write("mode=production\n")
|
fd.write("mode=production\n")
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
@@ -955,8 +976,6 @@ def main():
|
|||||||
root_logger.critical("failed to add DS group: %s" % e)
|
root_logger.critical("failed to add DS group: %s" % e)
|
||||||
|
|
||||||
# Create a directory server instance
|
# Create a directory server instance
|
||||||
ds = dsinstance.DsInstance(fstore=fstore)
|
|
||||||
|
|
||||||
if external != 2:
|
if external != 2:
|
||||||
# Configure ntpd
|
# Configure ntpd
|
||||||
if options.conf_ntp:
|
if options.conf_ntp:
|
||||||
@@ -966,17 +985,22 @@ def main():
|
|||||||
ntp.create_instance()
|
ntp.create_instance()
|
||||||
|
|
||||||
if options.dirsrv_pkcs12:
|
if options.dirsrv_pkcs12:
|
||||||
|
ds = dsinstance.DsInstance(fstore=fstore,
|
||||||
|
cert_nickname=dirsrv_cert_name)
|
||||||
ds.create_instance(realm_name, host_name, domain_name,
|
ds.create_instance(realm_name, host_name, domain_name,
|
||||||
dm_password, dirsrv_pkcs12_info,
|
dm_password, dirsrv_pkcs12_info,
|
||||||
|
idstart=options.idstart, idmax=options.idmax,
|
||||||
subject_base=options.subject,
|
subject_base=options.subject,
|
||||||
hbac_allow=not options.hbac_allow)
|
hbac_allow=not options.hbac_allow)
|
||||||
else:
|
else:
|
||||||
|
ds = dsinstance.DsInstance(fstore=fstore)
|
||||||
ds.create_instance(realm_name, host_name, domain_name,
|
ds.create_instance(realm_name, host_name, domain_name,
|
||||||
dm_password,
|
dm_password,
|
||||||
idstart=options.idstart, idmax=options.idmax,
|
idstart=options.idstart, idmax=options.idmax,
|
||||||
subject_base=options.subject,
|
subject_base=options.subject,
|
||||||
hbac_allow=not options.hbac_allow)
|
hbac_allow=not options.hbac_allow)
|
||||||
else:
|
else:
|
||||||
|
ds = dsinstance.DsInstance(fstore=fstore)
|
||||||
ds.init_info(
|
ds.init_info(
|
||||||
realm_name, host_name, domain_name, dm_password,
|
realm_name, host_name, domain_name, dm_password,
|
||||||
False, options.subject, 1101, 1100, None)
|
False, options.subject, 1101, 1100, None)
|
||||||
@@ -1031,8 +1055,8 @@ def main():
|
|||||||
ds.enable_ssl()
|
ds.enable_ssl()
|
||||||
ds.restart()
|
ds.restart()
|
||||||
|
|
||||||
# We need to ldap_enable the CA now that DS is up and running
|
|
||||||
if setup_ca:
|
if setup_ca:
|
||||||
|
# We need to ldap_enable the CA now that DS is up and running
|
||||||
ca.ldap_enable('CA', host_name, dm_password,
|
ca.ldap_enable('CA', host_name, dm_password,
|
||||||
ipautil.realm_to_suffix(realm_name))
|
ipautil.realm_to_suffix(realm_name))
|
||||||
if not dogtag.install_constants.SHARED_DB:
|
if not dogtag.install_constants.SHARED_DB:
|
||||||
@@ -1047,8 +1071,29 @@ def main():
|
|||||||
ca.enable_client_auth_to_db()
|
ca.enable_client_auth_to_db()
|
||||||
ca.restart()
|
ca.restart()
|
||||||
|
|
||||||
# Upload the CA cert to the directory
|
# Upload the CA cert to the directory
|
||||||
ds.upload_ca_cert()
|
ds.upload_ca_cert()
|
||||||
|
else:
|
||||||
|
with open(options.root_ca_file) as f:
|
||||||
|
pem_cert = f.read()
|
||||||
|
|
||||||
|
# Trust the CA cert
|
||||||
|
root_logger.info(
|
||||||
|
'Trusting certificate authority from %s' % options.root_ca_file)
|
||||||
|
|
||||||
|
certs.NSSDatabase('/etc/pki/nssdb').import_pem_cert(
|
||||||
|
'External CA cert', 'CT,,', options.root_ca_file)
|
||||||
|
|
||||||
|
# Put a CA cert where other instances expect it
|
||||||
|
with open('/etc/ipa/ca.crt', 'wb') as f:
|
||||||
|
f.write(pem_cert)
|
||||||
|
|
||||||
|
# Install the CA cert for the HTTP server
|
||||||
|
with open('/usr/share/ipa/html/ca.crt', 'wb') as f:
|
||||||
|
f.write(pem_cert)
|
||||||
|
|
||||||
|
# Upload the CA cert to the directory
|
||||||
|
ds.upload_ca_dercert(base64.b64decode(x509.strip_header(pem_cert)))
|
||||||
|
|
||||||
krb = krbinstance.KrbInstance(fstore)
|
krb = krbinstance.KrbInstance(fstore)
|
||||||
if options.pkinit_pkcs12:
|
if options.pkinit_pkcs12:
|
||||||
@@ -1178,8 +1223,6 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print "In order for Firefox autoconfiguration to work you will need to"
|
print "In order for Firefox autoconfiguration to work you will need to"
|
||||||
print "use a SSL signing certificate. See the IPA documentation for more details."
|
print "use a SSL signing certificate. See the IPA documentation for more details."
|
||||||
print "You also need to install a PEM copy of the CA certificate into"
|
|
||||||
print "/usr/share/ipa/html/ca.crt"
|
|
||||||
|
|
||||||
if ipautil.file_exists(ANSWER_CACHE):
|
if ipautil.file_exists(ANSWER_CACHE):
|
||||||
os.remove(ANSWER_CACHE)
|
os.remove(ANSWER_CACHE)
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import base64
|
|||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from ConfigParser import RawConfigParser, MissingSectionHeaderError
|
from ConfigParser import RawConfigParser, MissingSectionHeaderError
|
||||||
|
|
||||||
|
from nss import nss
|
||||||
|
|
||||||
from ipapython import dogtag
|
from ipapython import dogtag
|
||||||
from ipapython import sysrestore
|
from ipapython import sysrestore
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
@@ -293,9 +295,11 @@ class NSSDatabase(object):
|
|||||||
ipautil.run(args)
|
ipautil.run(args)
|
||||||
except ipautil.CalledProcessError, e:
|
except ipautil.CalledProcessError, e:
|
||||||
if e.returncode == 17:
|
if e.returncode == 17:
|
||||||
raise RuntimeError("incorrect password for pkcs#12 file")
|
raise RuntimeError("incorrect password for pkcs#12 file %s" %
|
||||||
|
pkcs12_filename)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("unknown error import pkcs#12 file")
|
raise RuntimeError("unknown error import pkcs#12 file %s" %
|
||||||
|
pkcs12_filename)
|
||||||
|
|
||||||
def find_root_cert_from_pkcs12(self, pkcs12_fname, passwd_fname=None):
|
def find_root_cert_from_pkcs12(self, pkcs12_fname, passwd_fname=None):
|
||||||
"""Given a PKCS#12 file, try to find any certificates that do
|
"""Given a PKCS#12 file, try to find any certificates that do
|
||||||
@@ -355,6 +359,53 @@ class NSSDatabase(object):
|
|||||||
fd.write(cert)
|
fd.write(cert)
|
||||||
os.chmod(location, 0444)
|
os.chmod(location, 0444)
|
||||||
|
|
||||||
|
def import_pem_cert(self, nickname, flags, location):
|
||||||
|
"""Import a cert form the given PEM file.
|
||||||
|
|
||||||
|
The file must contain exactly one certificate.
|
||||||
|
"""
|
||||||
|
with open(location) as fd:
|
||||||
|
certs = fd.read()
|
||||||
|
|
||||||
|
cert, st = find_cert_from_txt(certs)
|
||||||
|
self.add_single_pem_cert(nickname, flags, cert)
|
||||||
|
|
||||||
|
try:
|
||||||
|
find_cert_from_txt(certs, st)
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise ValueError('%s contains more than one certificate')
|
||||||
|
|
||||||
|
def add_single_pem_cert(self, nick, flags, cert):
|
||||||
|
"""Import a cert in PEM format"""
|
||||||
|
self.run_certutil(["-A", "-n", nick,
|
||||||
|
"-t", flags,
|
||||||
|
"-a"],
|
||||||
|
stdin=cert)
|
||||||
|
|
||||||
|
def verify_server_cert_validity(self, nickname, hostname):
|
||||||
|
"""Verify a certificate is valid for a SSL server with given hostname
|
||||||
|
|
||||||
|
Raises a ValueError if the certificate is invalid.
|
||||||
|
"""
|
||||||
|
certdb = cert = None
|
||||||
|
nss.nss_init(self.secdir)
|
||||||
|
try:
|
||||||
|
certdb = nss.get_default_certdb()
|
||||||
|
cert = nss.find_cert_from_nickname(nickname)
|
||||||
|
intended_usage = nss.certificateUsageSSLServer
|
||||||
|
approved_usage = cert.verify_now(certdb, True, intended_usage)
|
||||||
|
if not approved_usage & intended_usage:
|
||||||
|
raise ValueError('invalid for a SSL server')
|
||||||
|
if not cert.verify_hostname(hostname):
|
||||||
|
raise ValueError('invalid for server %s' % hostname)
|
||||||
|
finally:
|
||||||
|
del certdb, cert
|
||||||
|
nss.nss_shutdown()
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class CertDB(object):
|
class CertDB(object):
|
||||||
"""An IPA-server-specific wrapper around NSS
|
"""An IPA-server-specific wrapper around NSS
|
||||||
@@ -610,10 +661,7 @@ class CertDB(object):
|
|||||||
nick = get_ca_nickname(self.realm)
|
nick = get_ca_nickname(self.realm)
|
||||||
else:
|
else:
|
||||||
nick = str(subject_dn)
|
nick = str(subject_dn)
|
||||||
self.run_certutil(["-A", "-n", nick,
|
self.nssdb.add_single_pem_cert(nick, "CT,,C", cert)
|
||||||
"-t", "CT,,C",
|
|
||||||
"-a"],
|
|
||||||
stdin=cert)
|
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import certs
|
|||||||
import ldap
|
import ldap
|
||||||
from ipaserver.install import ldapupdate
|
from ipaserver.install import ldapupdate
|
||||||
from ipaserver.install import replication
|
from ipaserver.install import replication
|
||||||
from ipalib import errors
|
from ipalib import errors, api
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
|
|
||||||
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
|
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
|
||||||
@@ -541,7 +541,10 @@ class DsInstance(service.Service):
|
|||||||
# We only handle one server cert
|
# We only handle one server cert
|
||||||
nickname = server_certs[0][0]
|
nickname = server_certs[0][0]
|
||||||
self.dercert = dsdb.get_cert_from_db(nickname, pem=False)
|
self.dercert = dsdb.get_cert_from_db(nickname, pem=False)
|
||||||
dsdb.track_server_cert(nickname, self.principal, dsdb.passwd_fname, 'restart_dirsrv %s' % self.serverid )
|
if api.env.enable_ra:
|
||||||
|
dsdb.track_server_cert(
|
||||||
|
nickname, self.principal, dsdb.passwd_fname,
|
||||||
|
'restart_dirsrv %s' % self.serverid)
|
||||||
else:
|
else:
|
||||||
nickname = self.nickname
|
nickname = self.nickname
|
||||||
cadb = certs.CertDB(self.realm_name, host_name=self.fqdn, subject_base=self.subject_base)
|
cadb = certs.CertDB(self.realm_name, host_name=self.fqdn, subject_base=self.subject_base)
|
||||||
@@ -592,15 +595,30 @@ class DsInstance(service.Service):
|
|||||||
# check for open secure port 636 from now on
|
# check for open secure port 636 from now on
|
||||||
self.open_ports.append(636)
|
self.open_ports.append(636)
|
||||||
|
|
||||||
def upload_ca_cert(self):
|
def export_ca_cert(self, nickname, location):
|
||||||
|
dirname = config_dirname(self.serverid)
|
||||||
|
dsdb = certs.NSSDatabase(nssdir=dirname)
|
||||||
|
dsdb.export_pem_cert(nickname, location)
|
||||||
|
|
||||||
|
def upload_ca_cert(self, cacert_name=None):
|
||||||
"""
|
"""
|
||||||
Upload the CA certificate in DER form in the LDAP directory.
|
Upload the CA certificate from the NSS database to the LDAP directory.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dirname = config_dirname(self.serverid)
|
dirname = config_dirname(self.serverid)
|
||||||
certdb = certs.CertDB(self.realm_name, nssdir=dirname, subject_base=self.subject_base)
|
certdb = certs.CertDB(self.realm_name, nssdir=dirname, subject_base=self.subject_base)
|
||||||
|
|
||||||
dercert = certdb.get_cert_from_db(certdb.cacert_name, pem=False)
|
if cacert_name is None:
|
||||||
|
cacert_name = certdb.cacert_name
|
||||||
|
dercert = certdb.get_cert_from_db(cacert_name, pem=False)
|
||||||
|
self.upload_ca_dercert(dercert)
|
||||||
|
|
||||||
|
def upload_ca_dercert(self, dercert):
|
||||||
|
"""Upload the CA DER certificate to the LDAP directory
|
||||||
|
"""
|
||||||
|
# Note: Don't try to optimize if base64 data is already available.
|
||||||
|
# We want to re-encode using Python's b64encode to ensure the
|
||||||
|
# data is normalized (no extra newlines in the ldif)
|
||||||
self.sub_dict['CADERCERT'] = base64.b64encode(dercert)
|
self.sub_dict['CADERCERT'] = base64.b64encode(dercert)
|
||||||
|
|
||||||
self._ldap_mod('upload-cacert.ldif', self.sub_dict)
|
self._ldap_mod('upload-cacert.ldif', self.sub_dict)
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ class HTTPInstance(service.Service):
|
|||||||
|
|
||||||
subject_base = ipautil.dn_attribute_property('_subject_base')
|
subject_base = ipautil.dn_attribute_property('_subject_base')
|
||||||
|
|
||||||
def create_instance(self, realm, fqdn, domain_name, dm_password=None, autoconfig=True, pkcs12_info=None, self_signed_ca=False, subject_base=None, auto_redirect=True):
|
def create_instance(self, realm, fqdn, domain_name, dm_password=None,
|
||||||
|
autoconfig=True, pkcs12_info=None,
|
||||||
|
self_signed_ca=False, subject_base=None,
|
||||||
|
auto_redirect=True):
|
||||||
self.fqdn = fqdn
|
self.fqdn = fqdn
|
||||||
self.realm = realm
|
self.realm = realm
|
||||||
self.domain = domain_name
|
self.domain = domain_name
|
||||||
@@ -247,10 +250,13 @@ class HTTPInstance(service.Service):
|
|||||||
raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0])
|
raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0])
|
||||||
|
|
||||||
db.create_password_conf()
|
db.create_password_conf()
|
||||||
|
|
||||||
# We only handle one server cert
|
# We only handle one server cert
|
||||||
nickname = server_certs[0][0]
|
nickname = server_certs[0][0]
|
||||||
self.dercert = db.get_cert_from_db(nickname, pem=False)
|
self.dercert = db.get_cert_from_db(nickname, pem=False)
|
||||||
db.track_server_cert(nickname, self.principal, db.passwd_fname, 'restart_httpd')
|
|
||||||
|
if api.env.enable_ra:
|
||||||
|
db.track_server_cert(nickname, self.principal, db.passwd_fname, 'restart_httpd')
|
||||||
|
|
||||||
self.__set_mod_nss_nickname(nickname)
|
self.__set_mod_nss_nickname(nickname)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ from ipalib.util import validate_hostname
|
|||||||
from ipapython import config
|
from ipapython import config
|
||||||
from ipalib import errors
|
from ipalib import errors
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
|
from ipaserver.install import certs
|
||||||
|
|
||||||
# Used to determine install status
|
# Used to determine install status
|
||||||
IPA_MODULES = [
|
IPA_MODULES = [
|
||||||
@@ -699,3 +700,56 @@ def handle_error(error, log_file_name=None):
|
|||||||
message = "Unexpected error"
|
message = "Unexpected error"
|
||||||
message += '\n%s: %s' % (type(error).__name__, error)
|
message += '\n%s: %s' % (type(error).__name__, error)
|
||||||
return message, 1
|
return message, 1
|
||||||
|
|
||||||
|
|
||||||
|
def check_pkcs12(pkcs12_info, ca_file, hostname):
|
||||||
|
"""Check the given PKCS#12 with server cert and return the cert nickname
|
||||||
|
|
||||||
|
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, pin_filename = pkcs12_info
|
||||||
|
root_logger.debug('Checking PKCS#12 certificate %s', pkcs12_filename)
|
||||||
|
db_pwd_file = ipautil.write_tmp_file(ipautil.ipa_generate_password())
|
||||||
|
with certs.NSSDatabase() as nssdb:
|
||||||
|
nssdb.create_db(db_pwd_file.name)
|
||||||
|
|
||||||
|
# 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'
|
||||||
|
nssdb.import_pem_cert(ca_cert_name, "CT,C,C", ca_file)
|
||||||
|
|
||||||
|
# Import everything in the PKCS#12
|
||||||
|
nssdb.import_pkcs12(pkcs12_filename, db_pwd_file.name, pin_filename)
|
||||||
|
|
||||||
|
# Check we have exactly one server cert (one with a private key)
|
||||||
|
server_certs = nssdb.find_server_certs()
|
||||||
|
if not server_certs:
|
||||||
|
raise ScriptError(
|
||||||
|
'no server certificate found in %s' % pkcs12_filename)
|
||||||
|
if len(server_certs) > 1:
|
||||||
|
raise ScriptError(
|
||||||
|
'%s server certificates found in %s, expecting only one' %
|
||||||
|
(len(server_certs), pkcs12_filename))
|
||||||
|
[(server_cert_name, server_cert_trust)] = server_certs
|
||||||
|
|
||||||
|
# Check we have the whole cert chain & the CA is in it
|
||||||
|
for cert_name in nssdb.get_trust_chain(server_cert_name):
|
||||||
|
if cert_name == ca_cert_name:
|
||||||
|
break
|
||||||
|
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))
|
||||||
|
|
||||||
|
# Check server validity
|
||||||
|
try:
|
||||||
|
nssdb.verify_server_cert_validity(server_cert_name, hostname)
|
||||||
|
except ValueError as e:
|
||||||
|
raise ScriptError(
|
||||||
|
'The server certificate in %s is not valid: %s' %
|
||||||
|
(pkcs12_filename, e))
|
||||||
|
|
||||||
|
return server_cert_name
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
self.option_parser.error("You cannot specify a --reverse-zone "
|
self.option_parser.error("You cannot specify a --reverse-zone "
|
||||||
"option together with --no-reverse")
|
"option together with --no-reverse")
|
||||||
|
|
||||||
|
#Automatically disable pkinit w/ dogtag until that is supported
|
||||||
|
options.setup_pkinit = False
|
||||||
|
|
||||||
# If any of the PKCS#12 options are selected, all are required.
|
# If any of the PKCS#12 options are selected, all are required.
|
||||||
pkcs12_opts = [options.dirsrv_pkcs12, options.dirsrv_pin,
|
pkcs12_opts = [options.dirsrv_pkcs12, options.dirsrv_pin,
|
||||||
options.http_pkcs12, options.http_pin]
|
options.http_pkcs12, options.http_pin]
|
||||||
@@ -127,11 +130,6 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
if api.env.host == self.replica_fqdn:
|
if api.env.host == self.replica_fqdn:
|
||||||
raise admintool.ScriptError("You can't create a replica on itself")
|
raise admintool.ScriptError("You can't create a replica on itself")
|
||||||
|
|
||||||
#Automatically disable pkinit w/ dogtag until that is supported
|
|
||||||
#[certs.ipa_self_signed() must be called only after api.finalize()]
|
|
||||||
if not options.pkinit_pkcs12 and not certs.ipa_self_signed():
|
|
||||||
options.setup_pkinit = False
|
|
||||||
|
|
||||||
# FIXME: certs.ipa_self_signed_master return value can be
|
# FIXME: certs.ipa_self_signed_master return value can be
|
||||||
# True, False, None, with different meanings.
|
# True, False, None, with different meanings.
|
||||||
# So, we need to explicitly compare to False
|
# So, we need to explicitly compare to False
|
||||||
@@ -139,12 +137,30 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
raise admintool.ScriptError("A selfsign CA backend can only "
|
raise admintool.ScriptError("A selfsign CA backend can only "
|
||||||
"prepare on the original master")
|
"prepare on the original master")
|
||||||
|
|
||||||
|
if not api.env.enable_ra and not options.http_pkcs12:
|
||||||
|
raise admintool.ScriptError(
|
||||||
|
"Cannot issue certificates: a CA is not installed. Use the "
|
||||||
|
"--http_pkcs12, --dirsrv_pkcs12 options to provide custom "
|
||||||
|
"certificates.")
|
||||||
|
|
||||||
|
if options.http_pkcs12:
|
||||||
|
# Check the given PKCS#12 files
|
||||||
|
self.check_pkcs12(options.http_pkcs12, options.http_pin)
|
||||||
|
self.check_pkcs12(options.dirsrv_pkcs12, options.dirsrv_pin)
|
||||||
|
|
||||||
config_dir = dsinstance.config_dirname(
|
config_dir = dsinstance.config_dirname(
|
||||||
dsinstance.realm_to_serverid(api.env.realm))
|
dsinstance.realm_to_serverid(api.env.realm))
|
||||||
if not ipautil.dir_exists(config_dir):
|
if not ipautil.dir_exists(config_dir):
|
||||||
raise admintool.ScriptError(
|
raise admintool.ScriptError(
|
||||||
"could not find directory instance: %s" % config_dir)
|
"could not find directory instance: %s" % config_dir)
|
||||||
|
|
||||||
|
def check_pkcs12(self, pkcs12_file, pkcs12_pin):
|
||||||
|
pin_file = ipautil.write_tmp_file(pkcs12_pin)
|
||||||
|
installutils.check_pkcs12(
|
||||||
|
pkcs12_info=(pkcs12_file, pin_file.name),
|
||||||
|
ca_file='/etc/ipa/ca.crt',
|
||||||
|
hostname=self.replica_fqdn)
|
||||||
|
|
||||||
def ask_for_options(self):
|
def ask_for_options(self):
|
||||||
options = self.options
|
options = self.options
|
||||||
super(ReplicaPrepare, self).ask_for_options()
|
super(ReplicaPrepare, self).ask_for_options()
|
||||||
@@ -275,7 +291,7 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
"Creating SSL certificate for the Directory Server")
|
"Creating SSL certificate for the Directory Server")
|
||||||
self.export_certdb("dscert", passwd_fname)
|
self.export_certdb("dscert", passwd_fname)
|
||||||
|
|
||||||
if not certs.ipa_self_signed():
|
if not options.dirsrv_pkcs12 and not certs.ipa_self_signed():
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Creating SSL certificate for the dogtag Directory Server")
|
"Creating SSL certificate for the dogtag Directory Server")
|
||||||
self.export_certdb("dogtagcert", passwd_fname)
|
self.export_certdb("dogtagcert", passwd_fname)
|
||||||
|
|||||||
Reference in New Issue
Block a user