CA-less installer options usability fixes

The --*_pkcs12 options of ipa-server-install and ipa-replica-prepare have
been replaced by --*-cert-file options which accept multiple files.
ipa-server-certinstall now accepts multiple files as well. The files are
accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and
raw private key and PKCS#12 formats.

The --root-ca-file option of ipa-server-install has been replaced by
--ca-cert-file option which accepts multiple files. The files are
accepted in PEM and DER certificate and PKCS#7 certificate chain formats.

The --*_pin options of ipa-server-install and ipa-replica-prepare have been
renamed to --*-pin.

https://fedorahosted.org/freeipa/ticket/4489

Reviewed-By: Petr Viktorin <pviktori@redhat.com>
This commit is contained in:
Jan Cholasta 2014-09-24 16:41:47 +02:00 committed by Martin Kosek
parent 3aa0731fc6
commit 88083887c9
8 changed files with 322 additions and 228 deletions

View File

@ -215,20 +215,45 @@ def parse_options():
help=SUPPRESS_HELP)
cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false",
default=True, help="disables pkinit setup steps")
cert_group.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12",
help="PKCS#12 file containing the Directory Server SSL certificate")
cert_group.add_option("--http_pkcs12", dest="http_pkcs12",
help="PKCS#12 file containing the Apache Server SSL certificate")
cert_group.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12",
help="PKCS#12 file containing the Kerberos KDC SSL certificate")
cert_group.add_option("--dirsrv-cert-file", dest="dirsrv_cert_files",
action="append", metavar="FILE",
help="File containing the Directory Server SSL certificate and private key")
cert_group.add_option("--dirsrv_pkcs12", dest="dirsrv_cert_files",
action="append",
help=SUPPRESS_HELP)
cert_group.add_option("--http-cert-file", dest="http_cert_files",
action="append", metavar="FILE",
help="File containing the Apache Server SSL certificate and private key")
cert_group.add_option("--http_pkcs12", dest="http_cert_files",
action="append",
help=SUPPRESS_HELP)
cert_group.add_option("--pkinit-cert-file", dest="pkinit_cert_files",
action="append", metavar="FILE",
help="File containing the Kerberos KDC SSL certificate and private key")
cert_group.add_option("--pkinit_pkcs12", dest="pkinit_cert_files",
action="append",
help=SUPPRESS_HELP)
cert_group.add_option("--dirsrv-pin", dest="dirsrv_pin", sensitive=True,
metavar="PIN",
help="The password to unlock the Directory Server private key")
cert_group.add_option("--dirsrv_pin", dest="dirsrv_pin", sensitive=True,
help="The password of the Directory Server PKCS#12 file")
help=SUPPRESS_HELP)
cert_group.add_option("--http-pin", dest="http_pin", sensitive=True,
metavar="PIN",
help="The password to unlock the Apache Server private key")
cert_group.add_option("--http_pin", dest="http_pin", sensitive=True,
help="The password of the Apache Server PKCS#12 file")
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 containing the CA certificate for the PKCS#12 files")
help=SUPPRESS_HELP)
cert_group.add_option("--pkinit-pin", dest="pkinit_pin", sensitive=True,
metavar="PIN",
help="The password to unlock the Kerberos KDC private key")
cert_group.add_option("--pkinit_pin", dest="pkinit_pin", sensitive=True,
help=SUPPRESS_HELP)
cert_group.add_option("--ca-cert-file", dest="ca_cert_files",
action="append", metavar="FILE",
help="File containing CA certificates for the service certificate files")
cert_group.add_option("--root-ca-file", dest="ca_cert_files",
action="append",
help=SUPPRESS_HELP)
cert_group.add_option("--subject", action="callback", callback=subject_callback,
type="string",
help="The certificate subject base (default O=<realm-name>)")
@ -311,22 +336,25 @@ def parse_options():
if not options.forwarders and not options.no_forwarders:
parser.error("You must specify at least one --forwarder option or --no-forwarders option")
# If any of the PKCS#12 options are selected, all are required.
pkcs12_req = (options.dirsrv_pkcs12, options.http_pkcs12)
pkcs12_opt = (options.pkinit_pkcs12,)
if any(pkcs12_req + pkcs12_opt) and not all(pkcs12_req):
parser.error("--dirsrv_pkcs12 and --http_pkcs12 are required if any "
"PKCS#12 options are used.")
# If any of the key file options are selected, all are required.
cert_file_req = (options.dirsrv_cert_files, options.http_cert_files)
cert_file_opt = (options.pkinit_cert_files,)
if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
parser.error("--dirsrv-cert-file and --http-cert-file are required if "
"any key file options are used.")
if options.unattended:
if options.dirsrv_pkcs12 and options.dirsrv_pin is None:
parser.error("You must specify --dirsrv_pin with --dirsrv_pkcs12")
if options.http_pkcs12 and options.http_pin is None:
parser.error("You must specify --http_pin with --http_pkcs12")
if options.pkinit_pkcs12 and options.pkinit_pin is None:
parser.error("You must specify --pkinit_pin with --pkinit_pkcs12")
if options.dirsrv_cert_files and options.dirsrv_pin is None:
parser.error(
"You must specify --dirsrv-pin with --dirsrv-cert-file")
if options.http_cert_files and options.http_pin is None:
parser.error(
"You must specify --http-pin with --http-cert-file")
if options.pkinit_cert_files and options.pkinit_pin is None:
parser.error(
"You must specify --pkinit-pin with --pkinit-cert-file")
if options.external_cert_files and options.dirsrv_pkcs12:
if options.external_cert_files and options.dirsrv_cert_files:
parser.error("Service certificate file options cannot be used with "
"the external CA options.")
@ -334,8 +362,9 @@ def parse_options():
if options.external_cert_files:
parser.error("You cannot specify --external-cert-file "
"together with --external-ca")
if options.dirsrv_pkcs12:
parser.error("You cannot specify PKCS#12 options together with --external-ca")
if options.dirsrv_cert_files:
parser.error("You cannot specify service certificate file options "
"together with --external-ca")
if (options.external_cert_files and
any(not os.path.isabs(path) for path in options.external_cert_files)):
@ -761,7 +790,7 @@ def main():
options.external_cert_files, options.subject)
# We only set up the CA if the PKCS#12 options are not given.
if options.dirsrv_pkcs12:
if options.dirsrv_cert_files:
setup_ca = False
setup_kra = False
else:
@ -903,43 +932,58 @@ def main():
if not options.subject:
options.subject = DN(('O', realm_name))
ca_file = options.root_ca_file
if options.http_pkcs12:
if options.http_cert_files:
if options.http_pin is None:
options.http_pin = installutils.read_password(
"Enter %s unlock" % options.http_pkcs12,
"Enter Apache Server private key unlock",
confirm=False, validate=False)
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_ca_cert = installutils.check_pkcs12(
http_pkcs12_info, ca_file, host_name)
sys.exit(
"Apache Server private key unlock password required")
http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12(
cert_files=options.http_cert_files,
key_password=options.http_pin,
key_nickname=None,
ca_cert_files=options.ca_cert_files,
host_name=host_name)
http_pkcs12_info = (http_pkcs12_file.name, http_pin)
if options.dirsrv_pkcs12:
if options.dirsrv_cert_files:
if options.dirsrv_pin is None:
options.dirsrv_pin = installutils.read_password(
"Enter %s unlock" % options.dirsrv_pkcs12,
options.dirsrv_pin = read_password(
"Enter Directory Server private key unlock",
confirm=False, validate=False)
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_ca_cert = installutils.check_pkcs12(
dirsrv_pkcs12_info, ca_file, host_name)
sys.exit(
"Directory Server private key unlock password required")
dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12(
cert_files=options.dirsrv_cert_files,
key_password=options.dirsrv_pin,
key_nickname=None,
ca_cert_files=options.ca_cert_files,
host_name=host_name)
dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)
if options.pkinit_pkcs12:
if options.pkinit_cert_files:
if options.pkinit_pin is None:
options.pkinit_pin = installutils.read_password(
"Enter %s unlock" % options.pkinit_pkcs12,
options.pkinit_pin = read_password(
"Enter Kerberos KDC private key unlock",
confirm=False, validate=False)
if options.pkinit_pin is None:
sys.exit("%s unlock password required" % options.pkinit_pkcs12)
pkinit_pkcs12_info = (options.pkinit_pkcs12, options.pkinit_pin)
sys.exit(
"Kerberos KDC private key unlock password required")
pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12(
cert_files=options.pkinit_cert_files,
key_password=options.pkinit_pin,
key_nickname=None,
ca_cert_files=options.ca_cert_files,
host_name=host_name)
pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin)
if (options.http_pkcs12 and options.dirsrv_pkcs12 and
if (options.http_cert_files and options.dirsrv_cert_files 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))
sys.exit("Apache Server SSL certificate and Directory Server SSL "
"certificate are not signed by the same CA certificate")
if not options.dm_password:
dm_password = read_dm_password()
@ -1064,14 +1108,13 @@ def main():
if not ntp.is_configured():
ntp.create_instance()
if options.dirsrv_pkcs12:
if options.dirsrv_cert_files:
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,
subject_base=options.subject,
hbac_allow=not options.hbac_allow,
ca_file=ca_file)
hbac_allow=not options.hbac_allow)
else:
ds = dsinstance.DsInstance(fstore=fstore)
ds.create_instance(realm_name, host_name, domain_name,
@ -1137,7 +1180,7 @@ def main():
ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH)
krb = krbinstance.KrbInstance(fstore)
if options.pkinit_pkcs12:
if options.pkinit_cert_files:
krb.create_instance(realm_name, host_name, domain_name,
dm_password, master_password,
setup_pkinit=options.setup_pkinit,
@ -1163,11 +1206,11 @@ def main():
# Create a HTTP instance
http = httpinstance.HTTPInstance(fstore)
if options.http_pkcs12:
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,
auto_redirect=options.ui_redirect, ca_file=ca_file)
auto_redirect=options.ui_redirect)
else:
http.create_instance(
realm_name, host_name, domain_name, dm_password,

View File

@ -35,23 +35,23 @@ Once the file has been created it will be named replica\-hostname. This file can
A replica should only be installed on the same or higher version of IPA on the remote system.
.SH "OPTIONS"
.TP
\fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR
PKCS#12 file containing the Directory Server SSL Certificate and Private Key
\fB\-\-dirsrv\-cert\-file\fR=\fIFILE\fR
File containing the Directory Server SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times.
.TP
\fB\-\-http_pkcs12\fR=\fIFILE\fR
PKCS#12 file containing the Apache Server SSL Certificate and Private Key
\fB\-\-http\-cert\-file\fR=\fIFILE\fR
File containing the Apache Server SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times.
.TP
\fB\-\-pkinit_pkcs12\fR=\fIFILE\fR
PKCS#12 file containing the Kerberos KDC Certificate and Private Key
\fB\-\-pkinit\-cert\-file\fR=\fIFILE\fR
File containing the Kerberos KDC SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times.
.TP
\fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR
The password of the Directory Server PKCS#12 file
\fB\-\-dirsrv\-pin\fR=\fIPIN\fR
The password to unlock the Directory Server private key
.TP
\fB\-\-http_pin\fR=\fIHTTP_PIN\fR
The password of the Apache Server PKCS#12 file
\fB\-\-http\-pin\fR=\fIPIN\fR
The password to unlock the Apache Server private key
.TP
\fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR
The password of the Kerberos KDC PKCS#12 file
\fB\-\-pkinit\-pin\fR=\fIPIN\fR
The password to unlock the Kerberos KDC private key
.TP
\fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR
Directory Manager (existing master) password

View File

@ -20,9 +20,9 @@
.SH "NAME"
ipa\-server\-certinstall \- Install new SSL server certificates
.SH "SYNOPSIS"
ipa\-server\-certinstall [\fIOPTION\fR]... PKCS12_FILE
ipa\-server\-certinstall [\fIOPTION\fR]... FILE...
.SH "DESCRIPTION"
Replace the current SSL Directory and/or Apache server certificate(s) with the certificate in the PKCS#12 file.
Replace the current SSL Directory and/or Apache server certificate(s) with the certificate in the specified files. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats.
PKCS#12 is a file format used to safely transport SSL certificates and public/private keypairs.
@ -38,7 +38,7 @@ Install the certificate on the Directory Server
Install the certificate in the Apache Web Server
.TP
\fB\-\-pin\fR=\fIPIN\fR
The password of the PKCS#12 file
The password to unlock the private key
.TP
\fB\-\-dirman\-password\fR=\fIDIRMAN_PASSWORD\fR
Directory Manager password

View File

@ -93,26 +93,26 @@ File containing the IPA CA certificate and the external CA certificate chain. Th
\fB\-\-no\-pkinit\fR
Disables pkinit setup steps
.TP
\fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR
PKCS#12 file containing the Directory Server SSL Certificate
\fB\-\-dirsrv\-cert\-file\fR=\fIFILE\fR
File containing the Directory Server SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times.
.TP
\fB\-\-http_pkcs12\fR=\fIFILE\fR
PKCS#12 file containing the Apache Server SSL Certificate
\fB\-\-http\-cert\-file\fR=\fIFILE\fR
File containing the Apache Server SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times.
.TP
\fB\-\-pkinit_pkcs12\fR=\fIFILE\fR
PKCS#12 file containing the Kerberos KDC SSL certificate
\fB\-\-pkinit\-cert\-file\fR=\fIFILE\fR
File containing the Kerberos KDC SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times.
.TP
\fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR
The password of the Directory Server PKCS#12 file
\fB\-\-dirsrv\-pin\fR=\fIPIN\fR
The password to unlock the Directory Server private key
.TP
\fB\-\-http_pin\fR=\fIHTTP_PIN\fR
The password of the Apache Server PKCS#12 file
\fB\-\-http\-pin\fR=\fIPIN\fR
The password to unlock the Apache Server private key
.TP
\fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR
The password of the Kerberos KDC PKCS#12 file
\fB\-\-pkinit\-pin\fR=\fIPIN\fR
The password to unlock the Kerberos KDC private key
.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.
\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)

View File

@ -801,72 +801,98 @@ def handle_error(error, log_file_name=None):
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.
def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files,
host_name):
"""
Load and verify server certificate and private key from multiple files
The files are accepted in PEM and DER certificate, PKCS#7 certificate
chain, PKCS#8 and raw private key and PKCS#12 formats.
:param cert_files: Names of server certificate and private key files to
import
:param key_password: Password to decrypt private keys
:param key_nickname: Nickname of the private key to import from PKCS#12
files
:param ca_cert_files: Names of CA certificate files to import
:param host_name: Host name of the server
:returns: Temporary PKCS#12 file with the server certificate, private key
and CA certificate chain, password to unlock the PKCS#12 file and
the CA certificate of the CA that issued the server certificate
"""
pkcs12_filename, pkcs12_passwd = 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)
db_password = ipautil.ipa_generate_password()
db_pwdfile = ipautil.write_tmp_file(db_password)
nssdb.create_db(db_pwdfile.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'
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
try:
nssdb.import_pkcs12(
pkcs12_filename, db_pwd_file.name, pkcs12_passwd)
nssdb.import_files(cert_files, db_pwdfile.name,
True, key_password, key_nickname)
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()
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
if ca_cert_files:
try:
nssdb.import_files(ca_cert_files, db_pwdfile.name)
except RuntimeError as e:
raise ScriptError(str(e))
for nickname, trust_flags in nssdb.list_certs():
if 'u' in trust_flags:
key_nickname = nickname
continue
nssdb.trust_root_cert(nickname)
# Check we have the whole cert chain & the CA is in it
trust_chain = nssdb.get_trust_chain(server_cert_name)
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:
trust_chain = list(reversed(nssdb.get_trust_chain(key_nickname)))
ca_cert = None
for nickname in trust_chain[1:]:
cert = nssdb.get_cert(nickname)
if ca_cert is None:
ca_cert = cert
nss_cert = x509.load_certificate(cert, x509.DER)
subject = DN(str(nss_cert.subject))
issuer = DN(str(nss_cert.issuer))
del nss_cert
if subject == issuer:
break
else:
raise ScriptError(
'%s is not signed by %s' % (pkcs12_filename, ca_file))
ca_cert_name = trust_chain[-2]
"The full certificate chain is not present in %s" %
(", ".join(cert_files)))
for nickname in trust_chain[1:]:
try:
nssdb.verify_ca_cert_validity(nickname)
except ValueError, e:
raise ScriptError(
"CA certificate %s in %s is not valid: %s" %
(subject, ", ".join(cert_files), e))
# Check server validity
nssdb.trust_root_cert(ca_cert_name)
try:
nssdb.verify_server_cert_validity(server_cert_name, hostname)
nssdb.verify_server_cert_validity(key_nickname, host_name)
except ValueError as e:
raise ScriptError(
'The server certificate in %s is not valid: %s' %
(pkcs12_filename, e))
"The server certificate in %s is not valid: %s" %
(", ".join(cert_files), e))
return nssdb.get_cert(ca_cert_name)
out_file = tempfile.NamedTemporaryFile()
out_password = ipautil.ipa_generate_password()
out_pwdfile = ipautil.write_tmp_file(out_password)
args = [
paths.PK12UTIL,
'-o', out_file.name,
'-n', key_nickname,
'-d', nssdb.secdir,
'-k', db_pwdfile.name,
'-w', out_pwdfile.name,
]
ipautil.run(args)
return out_file, out_password, ca_cert
@contextmanager
def private_ccache(path=None):

View File

@ -22,7 +22,7 @@ import os
import shutil
import tempfile
import time
from optparse import OptionGroup
from optparse import OptionGroup, SUPPRESS_HELP
from ConfigParser import SafeConfigParser
import dns.resolver
@ -75,21 +75,39 @@ class ReplicaPrepare(admintool.AdminTool):
group = OptionGroup(parser, "SSL certificate options",
"Only used if the server was installed using custom SSL certificates")
group.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12",
metavar="FILE",
help="install certificate for the directory server")
group.add_option("--http_pkcs12", dest="http_pkcs12",
metavar="FILE",
help="install certificate for the http server")
group.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12",
metavar="FILE",
help="install certificate for the KDC")
group.add_option("--dirsrv_pin", dest="dirsrv_pin", metavar="PIN",
help="PIN for the Directory Server PKCS#12 file")
group.add_option("--http_pin", dest="http_pin", metavar="PIN",
help="PIN for the Apache Server PKCS#12 file")
group.add_option("--pkinit_pin", dest="pkinit_pin", metavar="PIN",
help="PIN for the KDC pkinit PKCS#12 file")
group.add_option("--dirsrv-cert-file", dest="dirsrv_cert_files",
action="append", metavar="FILE",
help="File containing the Directory Server SSL certificate and private key")
group.add_option("--dirsrv_pkcs12", dest="dirsrv_cert_files",
action="append",
help=SUPPRESS_HELP)
group.add_option("--http-cert-file", dest="http_cert_files",
action="append", metavar="FILE",
help="File containing the Apache Server SSL certificate and private key")
group.add_option("--http_pkcs12", dest="http_cert_files",
action="append",
help=SUPPRESS_HELP)
group.add_option("--pkinit-cert-file", dest="pkinit_cert_files",
action="append", metavar="FILE",
help="File containing the Kerberos KDC SSL certificate and private key")
group.add_option("--pkinit_pkcs12", dest="pkinit_cert_files",
action="append",
help=SUPPRESS_HELP)
group.add_option("--dirsrv-pin", dest="dirsrv_pin", sensitive=True,
metavar="PIN",
help="The password to unlock the Directory Server private key")
group.add_option("--dirsrv_pin", dest="dirsrv_pin", sensitive=True,
help=SUPPRESS_HELP)
group.add_option("--http-pin", dest="http_pin", sensitive=True,
metavar="PIN",
help="The password to unlock the Apache Server private key")
group.add_option("--http_pin", dest="http_pin", sensitive=True,
help=SUPPRESS_HELP)
group.add_option("--pkinit-pin", dest="pkinit_pin", sensitive=True,
metavar="PIN",
help="The password to unlock the Kerberos KDC private key")
group.add_option("--pkinit_pin", dest="pkinit_pin", sensitive=True,
help=SUPPRESS_HELP)
parser.add_option_group(group)
def validate_options(self):
@ -112,11 +130,11 @@ class ReplicaPrepare(admintool.AdminTool):
options.setup_pkinit = False
# If any of the PKCS#12 options are selected, all are required.
pkcs12_req = (options.dirsrv_pkcs12, options.http_pkcs12)
pkcs12_opt = (options.pkinit_pkcs12,)
if any(pkcs12_req + pkcs12_opt) and not all(pkcs12_req):
cert_file_req = (options.dirsrv_cert_files, options.http_cert_files)
cert_file_opt = (options.pkinit_cert_files,)
if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
self.option_parser.error(
"--dirsrv_pkcs12 and --http_pkcs12 are required if any "
"--dirsrv-cert-file and --http-cert-file are required if any "
"PKCS#12 options are used.")
if len(self.args) < 1:
@ -134,11 +152,11 @@ class ReplicaPrepare(admintool.AdminTool):
if api.env.host == self.replica_fqdn:
raise admintool.ScriptError("You can't create a replica on itself")
if not api.env.enable_ra and not options.http_pkcs12:
if not api.env.enable_ra and not options.http_cert_files:
raise admintool.ScriptError(
"Cannot issue certificates: a CA is not installed. Use the "
"--http_pkcs12, --dirsrv_pkcs12 options to provide custom "
"certificates.")
"--http-cert-file, --dirsrv-cert-file options to provide "
"custom certificates.")
config_dir = dsinstance.config_dirname(
dsinstance.realm_to_serverid(api.env.realm))
@ -146,11 +164,13 @@ class ReplicaPrepare(admintool.AdminTool):
raise admintool.ScriptError(
"could not find directory instance: %s" % config_dir)
def check_pkcs12(self, pkcs12_file, pkcs12_pin):
return installutils.check_pkcs12(
pkcs12_info=(pkcs12_file, pkcs12_pin),
ca_file=CACERT,
hostname=self.replica_fqdn)
def load_pkcs12(self, cert_files, key_password, key_nickname):
return installutils.load_pkcs12(
cert_files=cert_files,
key_password=key_password,
key_nickname=key_nickname,
ca_cert_files=[CACERT],
host_name=self.replica_fqdn)
def ask_for_options(self):
options = self.options
@ -231,42 +251,52 @@ class ReplicaPrepare(admintool.AdminTool):
if disconnect:
api.Backend.ldap2.disconnect()
if options.http_pkcs12:
self.http_pin = self.dirsrv_pin = self.pkinit_pin = None
if options.http_cert_files:
if options.http_pin is None:
options.http_pin = installutils.read_password(
"Enter %s unlock" % options.http_pkcs12,
"Enter Apache Server private key unlock",
confirm=False, validate=False)
if options.http_pin is None:
raise admintool.ScriptError(
"%s unlock password required" % options.http_pkcs12)
http_ca_cert = self.check_pkcs12(
options.http_pkcs12, options.http_pin)
"Apache Server private key unlock password required")
http_pkcs12_file, http_pin, http_ca_cert = self.load_pkcs12(
options.http_cert_files, options.http_pin, None)
self.http_pkcs12_file = http_pkcs12_file
self.http_pin = http_pin
if options.dirsrv_pkcs12:
if options.dirsrv_cert_files:
if options.dirsrv_pin is None:
options.dirsrv_pin = installutils.read_password(
"Enter %s unlock" % options.dirsrv_pkcs12,
"Enter Directory Server private key unlock",
confirm=False, validate=False)
if options.dirsrv_pin is None:
raise admintool.ScriptError(
"%s unlock password required" % options.dirsrv_pkcs12)
dirsrv_ca_cert = self.check_pkcs12(
options.dirsrv_pkcs12, options.dirsrv_pin)
"Directory Server private key unlock password required")
dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = self.load_pkcs12(
options.dirsrv_cert_files, options.dirsrv_pin, None)
self.dirsrv_pkcs12_file = dirsrv_pkcs12_file
self.dirsrv_pin = dirsrv_pin
if options.pkinit_pkcs12:
if options.pkinit_cert_files:
if options.pkinit_pin is None:
options.pkinit_pin = installutils.read_password(
"Enter %s unlock" % options.pkinit_pkcs12,
"Enter Kerberos KDC private key unlock",
confirm=False, validate=False)
if options.pkinit_pin is None:
raise admintool.ScriptError(
"%s unlock password required" % options.pkinit_pkcs12)
"Kerberos KDC private key unlock password required")
pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = self.load_pkcs12(
options.pkinit_cert_files, options.pkinit_pin, None)
self.pkinit_pkcs12_file = pkinit_pkcs12_file
self.pkinit_pin = pkinit_pin
if (options.http_pkcs12 and options.dirsrv_pkcs12 and
if (options.http_cert_files and options.dirsrv_cert_files 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))
"Apache Server SSL certificate and Directory Server SSL "
"certificate are not signed by the same CA certificate")
if (not ipautil.file_exists(
dogtag.configured_constants().CS_CFG_PATH) and
@ -316,13 +346,11 @@ class ReplicaPrepare(admintool.AdminTool):
passwd_fname = os.path.join(self.dir, "dirsrv_pin.txt")
with open(passwd_fname, "w") as fd:
fd.write("%s\n" % (options.dirsrv_pin or ''))
fd.write("%s\n" % (self.dirsrv_pin or ''))
if options.dirsrv_pkcs12:
self.log.info(
"Copying SSL certificate for the Directory Server from %s",
options.dirsrv_pkcs12)
self.copy_info_file(options.dirsrv_pkcs12, "dscert.p12")
if options.dirsrv_cert_files:
self.log.info("Copying SSL certificate for the Directory Server")
self.copy_info_file(self.dirsrv_pkcs12_file.name, "dscert.p12")
else:
if ipautil.file_exists(options.ca_file):
# Since it is possible that the Directory Manager password
@ -339,7 +367,7 @@ class ReplicaPrepare(admintool.AdminTool):
"Creating SSL certificate for the Directory Server")
self.export_certdb("dscert", passwd_fname)
if not options.dirsrv_pkcs12:
if not options.dirsrv_cert_files:
self.log.info(
"Creating SSL certificate for the dogtag Directory Server")
self.export_certdb("dogtagcert", passwd_fname)
@ -354,13 +382,11 @@ class ReplicaPrepare(admintool.AdminTool):
passwd_fname = os.path.join(self.dir, "http_pin.txt")
with open(passwd_fname, "w") as fd:
fd.write("%s\n" % (options.http_pin or ''))
fd.write("%s\n" % (self.http_pin or ''))
if options.http_pkcs12:
self.log.info(
"Copying SSL certificate for the Web Server from %s",
options.http_pkcs12)
self.copy_info_file(options.http_pkcs12, "httpcert.p12")
if options.http_cert_files:
self.log.info("Copying SSL certificate for the Web Server")
self.copy_info_file(self.http_pkcs12_file.name, "httpcert.p12")
else:
self.log.info("Creating SSL certificate for the Web Server")
self.export_certdb("httpcert", passwd_fname)
@ -373,13 +399,11 @@ class ReplicaPrepare(admintool.AdminTool):
passwd_fname = os.path.join(self.dir, "pkinit_pin.txt")
with open(passwd_fname, "w") as fd:
fd.write("%s\n" % (options.pkinit_pin or ''))
fd.write("%s\n" % (self.pkinit_pin or ''))
if options.pkinit_pkcs12:
self.log.info(
"Copying SSL certificate for the KDC from %s",
options.pkinit_pkcs12)
self.copy_info_file(options.pkinit_pkcs12, "pkinitcert.p12")
if options.pkinit_cert_files:
self.log.info("Copying SSL certificate for the KDC")
self.copy_info_file(self.pkinit_pkcs12_file.name, "pkinitcert.p12")
else:
self.log.info("Creating SSL certificate for the KDC")
self.export_certdb("pkinitcert", passwd_fname, is_kdc=True)

View File

@ -36,7 +36,7 @@ from ipaserver.plugins.ldap2 import ldap2
class ServerCertInstall(admintool.AdminTool):
command_name = 'ipa-server-certinstall'
usage = "%prog <-d|-w> [options] <PKCS#12 file>"
usage = "%prog <-d|-w> [options] <file> ..."
description = "Install new SSL server certificates."
@ -54,7 +54,7 @@ class ServerCertInstall(admintool.AdminTool):
help="install certificate for the http server")
parser.add_option(
"--pin",
dest="pin",
dest="pin", metavar="PIN", sensitive=True,
help="The password of the PKCS#12 file")
parser.add_option(
"--dirsrv_pin", "--http_pin",
@ -73,8 +73,8 @@ class ServerCertInstall(admintool.AdminTool):
if not self.options.dirsrv and not self.options.http:
self.option_parser.error("you must specify dirsrv and/or http")
if len(self.args) != 1:
self.option_parser.error("you must provide a pkcs12 filename")
if not self.args:
self.option_parser.error("you must provide certificate filename")
def ask_for_options(self):
super(ServerCertInstall, self).ask_for_options()
@ -88,17 +88,15 @@ class ServerCertInstall(admintool.AdminTool):
if self.options.pin is None:
self.options.pin = installutils.read_password(
"Enter %s unlock" % self.args[0], confirm=False, validate=False)
"Enter private key unlock", confirm=False, validate=False)
if self.options.pin is None:
raise admintool.ScriptError(
"%s unlock password required" % self.args[0])
"Private key unlock password required")
def run(self):
api.bootstrap(in_server=True)
api.finalize()
self.pkcs12_fname = self.args[0]
if self.options.dirsrv:
self.install_dirsrv_cert()
@ -154,10 +152,12 @@ 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):
installutils.check_pkcs12(
pkcs12_info=(self.pkcs12_fname, pkcs12_passwd),
ca_file=CACERT,
hostname=api.env.host)
pkcs12_file, pin, ca_cert = installutils.load_pkcs12(
cert_files=self.args,
key_password=pkcs12_passwd,
key_nickname=None,
ca_cert_files=[CACERT],
host_name=api.env.host)
cdb = certs.CertDB(api.env.realm, nssdir=dirname)
try:
@ -165,7 +165,7 @@ class ServerCertInstall(admintool.AdminTool):
cdb.untrack_server_cert(old_cert)
cdb.delete_cert(old_cert)
cdb.import_pkcs12(self.pkcs12_fname, pkcs12_passwd)
cdb.import_pkcs12(pkcs12_file.name, pin)
server_cert = cdb.find_server_certs()[0][0]
if api.env.enable_ra:

View File

@ -154,9 +154,9 @@ class CALessBase(IntegrationTest):
args = [
'ipa-server-install',
'--http_pkcs12', http_pkcs12,
'--dirsrv_pkcs12', dirsrv_pkcs12,
'--root-ca-file', root_ca_file,
'--http-cert-file', http_pkcs12,
'--dirsrv-cert-file', dirsrv_pkcs12,
'--ca-cert-file', root_ca_file,
'--ip-address', host.ip,
'-r', host.domain.name,
'-p', host.config.dirman_password,
@ -166,9 +166,9 @@ class CALessBase(IntegrationTest):
]
if http_pin is not None:
args.extend(['--http_pin', http_pin])
args.extend(['--http-pin', http_pin])
if dirsrv_pin is not None:
args.extend(['--dirsrv_pin', dirsrv_pin])
args.extend(['--dirsrv-pin', dirsrv_pin])
if unattended:
args.extend(['-U'])
@ -230,13 +230,13 @@ class CALessBase(IntegrationTest):
]
if http_pkcs12:
args.extend(['--http_pkcs12', http_pkcs12])
args.extend(['--http-cert-file', http_pkcs12])
if dirsrv_pkcs12:
args.extend(['--dirsrv_pkcs12', dirsrv_pkcs12])
args.extend(['--dirsrv-cert-file', dirsrv_pkcs12])
if http_pin is not None:
args.extend(['--http_pin', http_pin])
args.extend(['--http-pin', http_pin])
if dirsrv_pin is not None:
args.extend(['--dirsrv_pin', dirsrv_pin])
args.extend(['--dirsrv-pin', dirsrv_pin])
args.extend([replica.hostname])
@ -428,8 +428,8 @@ class TestServerInstall(CALessBase):
result = self.install_server(http_pin=None)
assert_error(result,
'ipa-server-install: error: You must specify --http_pin '
'with --http_pkcs12')
'ipa-server-install: error: You must specify --http-pin '
'with --http-cert-file')
def test_missing_ds_password(self):
"IPA server install with missing DS PKCS#12 password (unattended)"
@ -441,7 +441,7 @@ class TestServerInstall(CALessBase):
result = self.install_server(dirsrv_pin=None)
assert_error(result,
'ipa-server-install: error: You must specify '
'--dirsrv_pin with --dirsrv_pkcs12')
'--dirsrv-pin with --dirsrv-cert-file')
def test_incorect_http_pin(self):
"IPA server install with incorrect HTTP PKCS#12 password"
@ -784,8 +784,9 @@ class TestReplicaInstall(CALessBase):
raiseonerr=False)
assert result.returncode > 0
assert ('Cannot issue certificates: a CA is not installed. Use the '
'--http_pkcs12, --dirsrv_pkcs12 options to provide custom '
'certificates.' in result.stderr_text), result.stderr_text
'--http-cert-file, --dirsrv-cert-file options to provide '
'custom certificates.' in result.stderr_text), \
result.stderr_text
def test_nonexistent_http_pkcs12_file(self):
"IPA replica install with non-existent HTTP PKCS#12 file"
@ -1479,7 +1480,7 @@ class TestCertinstall(CALessBase):
args = ['ipa-server-certinstall',
'-w', 'server.p12',
'--http_pin', self.cert_password]
'--http-pin', self.cert_password]
result = self.certinstall('w', 'ca1/server', args=args)
assert result.returncode == 0
@ -1490,7 +1491,7 @@ class TestCertinstall(CALessBase):
args = ['ipa-server-certinstall',
'-d', 'server.p12',
'--dirsrv_pin', self.cert_password]
'--dirsrv-pin', self.cert_password]
stdin_text = self.master.config.dirman_password + '\n'
result = self.certinstall('d', 'ca1/server',