2014-03-13 04:28:27 -05:00
|
|
|
# Authors: Jan Cholasta <jcholast@redhat.com>
|
|
|
|
#
|
|
|
|
# Copyright (C) 2014 Red Hat
|
|
|
|
# see file 'COPYING' for use and warranty information
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
2018-04-05 02:21:16 -05:00
|
|
|
from __future__ import print_function, absolute_import
|
2015-08-12 06:44:11 -05:00
|
|
|
|
2017-05-23 11:35:57 -05:00
|
|
|
import logging
|
2014-03-13 04:28:27 -05:00
|
|
|
import os
|
2016-11-23 03:04:43 -06:00
|
|
|
from optparse import OptionGroup # pylint: disable=deprecated-module
|
2015-07-20 09:04:07 -05:00
|
|
|
import gssapi
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2018-01-29 01:34:51 -06:00
|
|
|
from ipalib.constants import RENEWAL_CA_NAME, RENEWAL_REUSE_CA_NAME, IPA_CA_CN
|
2016-11-23 08:40:21 -06:00
|
|
|
from ipalib.install import certmonger, certstore
|
2016-11-23 08:04:40 -06:00
|
|
|
from ipapython import admintool, ipautil
|
2017-04-27 02:37:38 -05:00
|
|
|
from ipapython.certdb import (EMPTY_TRUST_FLAGS,
|
|
|
|
EXTERNAL_CA_TRUST_FLAGS,
|
2017-05-03 01:17:32 -05:00
|
|
|
TrustFlags,
|
2017-04-27 02:37:38 -05:00
|
|
|
parse_trust_flags)
|
2014-03-13 04:28:27 -05:00
|
|
|
from ipapython.dn import DN
|
|
|
|
from ipaplatform.paths import paths
|
2016-11-23 08:40:21 -06:00
|
|
|
from ipalib import api, errors, x509
|
2014-03-13 04:28:27 -05:00
|
|
|
from ipaserver.install import certs, cainstance, installutils
|
|
|
|
|
2017-05-23 11:35:57 -05:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
class CACertManage(admintool.AdminTool):
|
|
|
|
command_name = 'ipa-cacert-manage'
|
|
|
|
|
2016-07-15 07:04:59 -05:00
|
|
|
usage = "%prog renew [options]\n%prog install [options] CERTFILE"
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
description = "Manage CA certificates."
|
|
|
|
|
|
|
|
cert_nickname = 'caSigningCert cert-pki-ca'
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def add_options(cls, parser):
|
|
|
|
super(CACertManage, cls).add_options(parser)
|
|
|
|
|
|
|
|
parser.add_option(
|
|
|
|
"-p", "--password", dest='password',
|
|
|
|
help="Directory Manager password")
|
|
|
|
|
|
|
|
renew_group = OptionGroup(parser, "Renew options")
|
2014-06-13 07:45:29 -05:00
|
|
|
renew_group.add_option(
|
|
|
|
"--self-signed", dest='self_signed',
|
|
|
|
action='store_true',
|
|
|
|
help="Sign the renewed certificate by itself")
|
2017-08-22 00:40:00 -05:00
|
|
|
renew_group.add_option(
|
|
|
|
"--external-ca", dest='self_signed',
|
|
|
|
action='store_false',
|
|
|
|
help="Sign the renewed certificate by external CA")
|
2017-05-17 19:18:20 -05:00
|
|
|
ext_cas = tuple(x.value for x in cainstance.ExternalCAType)
|
2017-04-24 02:10:41 -05:00
|
|
|
renew_group.add_option(
|
|
|
|
"--external-ca-type", dest="external_ca_type",
|
|
|
|
type="choice", choices=ext_cas,
|
|
|
|
metavar="{{{0}}}".format(",".join(ext_cas)),
|
|
|
|
help="Type of the external CA. Default: generic")
|
2014-06-13 07:45:29 -05:00
|
|
|
renew_group.add_option(
|
2017-08-22 00:40:00 -05:00
|
|
|
"--external-ca-profile", dest="external_ca_profile",
|
|
|
|
type='constructor', constructor=cainstance.ExternalCAProfile,
|
|
|
|
default=None, metavar="PROFILE-SPEC",
|
|
|
|
help="Specify the certificate profile/template to use "
|
|
|
|
"at the external CA")
|
2014-03-13 04:28:27 -05:00
|
|
|
renew_group.add_option(
|
2014-09-24 09:31:39 -05:00
|
|
|
"--external-cert-file", dest="external_cert_files",
|
|
|
|
action="append", metavar="FILE",
|
|
|
|
help="File containing the IPA CA certificate and the external CA "
|
|
|
|
"certificate chain")
|
2014-03-13 04:28:27 -05:00
|
|
|
parser.add_option_group(renew_group)
|
|
|
|
|
2014-06-13 07:49:29 -05:00
|
|
|
install_group = OptionGroup(parser, "Install options")
|
|
|
|
install_group.add_option(
|
|
|
|
"-n", "--nickname", dest='nickname',
|
|
|
|
help="Nickname for the certificate")
|
|
|
|
install_group.add_option(
|
|
|
|
"-t", "--trust-flags", dest='trust_flags', default='C,,',
|
|
|
|
help="Trust flags for the certificate in certutil format")
|
|
|
|
parser.add_option_group(install_group)
|
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
def validate_options(self):
|
|
|
|
super(CACertManage, self).validate_options(needs_root=True)
|
|
|
|
|
|
|
|
installutils.check_server_configuration()
|
|
|
|
|
|
|
|
parser = self.option_parser
|
|
|
|
|
|
|
|
if not self.args:
|
|
|
|
parser.error("command not provided")
|
|
|
|
|
|
|
|
command = self.command = self.args[0]
|
|
|
|
|
|
|
|
if command == 'renew':
|
2014-09-24 09:31:39 -05:00
|
|
|
pass
|
2014-06-13 07:49:29 -05:00
|
|
|
elif command == 'install':
|
|
|
|
if len(self.args) < 2:
|
|
|
|
parser.error("certificate file name not provided")
|
2014-03-13 04:28:27 -05:00
|
|
|
else:
|
|
|
|
parser.error("unknown command \"%s\"" % command)
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
command = self.command
|
|
|
|
|
2016-12-02 02:10:41 -06:00
|
|
|
api.bootstrap(in_server=True, confdir=paths.ETC_IPA)
|
2014-03-13 04:28:27 -05:00
|
|
|
api.finalize()
|
|
|
|
|
2016-10-27 03:31:45 -05:00
|
|
|
self.ldap_connect()
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
try:
|
|
|
|
if command == 'renew':
|
2018-01-03 04:09:41 -06:00
|
|
|
return self.renew()
|
2014-06-13 07:49:29 -05:00
|
|
|
elif command == 'install':
|
2018-01-03 04:09:41 -06:00
|
|
|
return self.install()
|
2018-07-10 15:14:04 -05:00
|
|
|
else:
|
|
|
|
raise NotImplementedError
|
2014-03-13 04:28:27 -05:00
|
|
|
finally:
|
2016-10-27 03:31:45 -05:00
|
|
|
api.Backend.ldap2.disconnect()
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
def ldap_connect(self):
|
|
|
|
password = self.options.password
|
|
|
|
if not password:
|
|
|
|
try:
|
2015-11-23 00:38:17 -06:00
|
|
|
api.Backend.ldap2.connect(ccache=os.environ.get('KRB5CCNAME'))
|
2015-07-20 09:04:07 -05:00
|
|
|
except (gssapi.exceptions.GSSError, errors.ACIError):
|
2014-03-13 04:28:27 -05:00
|
|
|
pass
|
|
|
|
else:
|
2015-11-23 00:38:17 -06:00
|
|
|
return
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
password = installutils.read_password(
|
|
|
|
"Directory Manager", confirm=False, validate=False)
|
|
|
|
if password is None:
|
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Directory Manager password required")
|
|
|
|
|
2016-10-27 03:31:45 -05:00
|
|
|
api.Backend.ldap2.connect(bind_pw=password)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2017-09-25 02:11:46 -05:00
|
|
|
def _get_ca_request_id(self, ca_name):
|
|
|
|
"""Lookup tracking request for IPA CA, using given ca-name."""
|
|
|
|
criteria = {
|
|
|
|
'cert-database': paths.PKI_TOMCAT_ALIAS_DIR,
|
|
|
|
'cert-nickname': self.cert_nickname,
|
|
|
|
'ca-name': ca_name,
|
|
|
|
}
|
|
|
|
return certmonger.get_request_id(criteria)
|
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
def renew(self):
|
2016-12-13 09:32:32 -06:00
|
|
|
ca = cainstance.CAInstance(api.env.realm)
|
2014-03-13 04:28:27 -05:00
|
|
|
if not ca.is_configured():
|
|
|
|
raise admintool.ScriptError("CA is not configured on this system")
|
|
|
|
|
2017-09-25 02:30:06 -05:00
|
|
|
self.request_id = self._get_ca_request_id(RENEWAL_CA_NAME)
|
2014-03-13 04:28:27 -05:00
|
|
|
if self.request_id is None:
|
2017-09-25 02:11:46 -05:00
|
|
|
# if external CA renewal was interrupted, the request may have
|
|
|
|
# been left with the "dogtag-ipa-ca-renew-agent-reuse" CA;
|
|
|
|
# look for it too
|
2017-09-25 02:30:06 -05:00
|
|
|
self.request_id = self._get_ca_request_id(RENEWAL_REUSE_CA_NAME)
|
2017-09-25 02:11:46 -05:00
|
|
|
if self.request_id is None:
|
|
|
|
raise admintool.ScriptError(
|
|
|
|
"CA certificate is not tracked by certmonger")
|
2017-05-23 11:35:57 -05:00
|
|
|
logger.debug(
|
2014-03-13 04:28:27 -05:00
|
|
|
"Found certmonger request id %r", self.request_id)
|
|
|
|
|
2015-11-09 11:28:47 -06:00
|
|
|
db = certs.CertDB(api.env.realm, nssdir=paths.PKI_TOMCAT_ALIAS_DIR)
|
2017-06-16 03:18:07 -05:00
|
|
|
cert = db.get_cert_from_db(self.cert_nickname)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
options = self.options
|
2014-09-24 09:31:39 -05:00
|
|
|
if options.external_cert_files:
|
2014-03-13 04:28:27 -05:00
|
|
|
return self.renew_external_step_2(ca, cert)
|
|
|
|
|
2014-06-13 07:45:29 -05:00
|
|
|
if options.self_signed is not None:
|
|
|
|
self_signed = options.self_signed
|
|
|
|
else:
|
2017-06-16 03:18:07 -05:00
|
|
|
self_signed = cert.is_self_signed()
|
2014-06-13 07:45:29 -05:00
|
|
|
|
|
|
|
if self_signed:
|
2014-03-13 04:28:27 -05:00
|
|
|
return self.renew_self_signed(ca)
|
|
|
|
else:
|
|
|
|
return self.renew_external_step_1(ca)
|
|
|
|
|
|
|
|
def renew_self_signed(self, ca):
|
2015-08-12 06:44:11 -05:00
|
|
|
print("Renewing CA certificate, please wait")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2017-08-22 00:40:00 -05:00
|
|
|
msg = "You cannot specify {} when renewing a self-signed CA"
|
|
|
|
if self.options.external_ca_type:
|
|
|
|
raise admintool.ScriptError(msg.format("--external-ca-type"))
|
|
|
|
if self.options.external_ca_profile:
|
|
|
|
raise admintool.ScriptError(msg.format("--external-ca-profile"))
|
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
try:
|
|
|
|
ca.set_renewal_master()
|
|
|
|
except errors.NotFound:
|
|
|
|
raise admintool.ScriptError("CA renewal master not found")
|
|
|
|
|
2017-04-24 01:40:11 -05:00
|
|
|
self.resubmit_request()
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2018-01-29 01:34:51 -06:00
|
|
|
db = certs.CertDB(api.env.realm, nssdir=paths.PKI_TOMCAT_ALIAS_DIR)
|
|
|
|
cert = db.get_cert_from_db(self.cert_nickname)
|
|
|
|
update_ipa_ca_entry(api, cert)
|
|
|
|
|
2015-08-12 06:44:11 -05:00
|
|
|
print("CA certificate successfully renewed")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
def renew_external_step_1(self, ca):
|
2015-08-12 06:44:11 -05:00
|
|
|
print("Exporting CA certificate signing request, please wait")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2017-08-22 00:40:00 -05:00
|
|
|
options = self.options
|
|
|
|
|
|
|
|
if not options.external_ca_type:
|
|
|
|
options.external_ca_type = cainstance.ExternalCAType.GENERIC.value
|
|
|
|
|
|
|
|
if options.external_ca_type == cainstance.ExternalCAType.MS_CS.value \
|
|
|
|
and options.external_ca_profile is None:
|
|
|
|
options.external_ca_profile = cainstance.MSCSTemplateV1(u"SubCA")
|
2017-04-24 02:10:41 -05:00
|
|
|
|
2017-08-22 00:40:00 -05:00
|
|
|
if options.external_ca_profile is not None:
|
|
|
|
# check that profile is valid for the external ca type
|
|
|
|
if options.external_ca_type \
|
|
|
|
not in options.external_ca_profile.valid_for:
|
|
|
|
raise admintool.ScriptError(
|
|
|
|
"External CA profile specification '{}' "
|
|
|
|
"cannot be used with external CA type '{}'."
|
|
|
|
.format(
|
|
|
|
options.external_ca_profile.unparsed_input,
|
|
|
|
options.external_ca_type)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.resubmit_request(
|
2017-09-25 02:30:06 -05:00
|
|
|
RENEWAL_REUSE_CA_NAME,
|
2017-08-22 00:40:00 -05:00
|
|
|
profile=options.external_ca_profile)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2015-08-12 06:44:11 -05:00
|
|
|
print(("The next step is to get %s signed by your CA and re-run "
|
|
|
|
"ipa-cacert-manage as:" % paths.IPA_CA_CSR))
|
2014-03-13 04:28:27 -05:00
|
|
|
print("ipa-cacert-manage renew "
|
|
|
|
"--external-cert-file=/path/to/signed_certificate "
|
2014-09-24 09:31:39 -05:00
|
|
|
"--external-cert-file=/path/to/external_ca_certificate")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2017-06-16 03:18:07 -05:00
|
|
|
def renew_external_step_2(self, ca, old_cert):
|
2015-08-12 06:44:11 -05:00
|
|
|
print("Importing the renewed CA certificate, please wait")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
options = self.options
|
2015-11-23 00:38:17 -06:00
|
|
|
conn = api.Backend.ldap2
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2017-06-16 03:18:07 -05:00
|
|
|
old_spki = old_cert.public_key_info_bytes
|
2016-10-13 02:12:31 -05:00
|
|
|
|
2016-11-16 03:31:19 -06:00
|
|
|
cert_file, ca_file = installutils.load_external_cert(
|
2017-06-16 03:18:07 -05:00
|
|
|
options.external_cert_files, DN(old_cert.subject))
|
2016-11-16 03:31:19 -06:00
|
|
|
|
2017-08-18 11:02:57 -05:00
|
|
|
with open(cert_file.name, 'rb') as f:
|
2016-10-13 02:12:31 -05:00
|
|
|
new_cert_data = f.read()
|
2017-06-16 03:18:07 -05:00
|
|
|
new_cert = x509.load_pem_x509_certificate(new_cert_data)
|
|
|
|
new_spki = new_cert.public_key_info_bytes
|
|
|
|
|
|
|
|
if new_cert.subject != old_cert.subject:
|
2016-10-13 02:12:31 -05:00
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Subject name mismatch (visit "
|
|
|
|
"http://www.freeipa.org/page/Troubleshooting for "
|
|
|
|
"troubleshooting guide)")
|
2017-06-16 03:18:07 -05:00
|
|
|
if new_cert.subject_bytes != old_cert.subject_bytes:
|
2016-10-13 02:12:31 -05:00
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Subject name encoding mismatch (visit "
|
|
|
|
"http://www.freeipa.org/page/Troubleshooting for "
|
|
|
|
"troubleshooting guide)")
|
|
|
|
if new_spki != old_spki:
|
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Subject public key info mismatch (visit "
|
|
|
|
"http://www.freeipa.org/page/Troubleshooting for "
|
|
|
|
"troubleshooting guide)")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
with certs.NSSDatabase() as tmpdb:
|
2016-12-06 02:14:54 -06:00
|
|
|
tmpdb.create_db()
|
2017-06-16 03:18:07 -05:00
|
|
|
tmpdb.add_cert(old_cert, 'IPA CA', EXTERNAL_CA_TRUST_FLAGS)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
try:
|
2017-06-16 03:18:07 -05:00
|
|
|
tmpdb.add_cert(new_cert, 'IPA CA', EXTERNAL_CA_TRUST_FLAGS)
|
2015-07-30 09:49:29 -05:00
|
|
|
except ipautil.CalledProcessError as e:
|
2014-03-13 04:28:27 -05:00
|
|
|
raise admintool.ScriptError(
|
2014-12-04 02:15:46 -06:00
|
|
|
"Not compatible with the current CA certificate: %s" % e)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2014-09-24 09:31:39 -05:00
|
|
|
ca_certs = x509.load_certificate_list_from_file(ca_file.name)
|
2014-03-13 04:28:27 -05:00
|
|
|
for ca_cert in ca_certs:
|
2017-04-27 02:33:25 -05:00
|
|
|
tmpdb.add_cert(
|
2017-06-16 03:18:07 -05:00
|
|
|
ca_cert, str(DN(ca_cert.subject)), EXTERNAL_CA_TRUST_FLAGS)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
|
|
|
try:
|
|
|
|
tmpdb.verify_ca_cert_validity('IPA CA')
|
2015-07-30 09:49:29 -05:00
|
|
|
except ValueError as e:
|
2014-03-13 04:28:27 -05:00
|
|
|
raise admintool.ScriptError(
|
2014-12-09 06:47:58 -06:00
|
|
|
"Not a valid CA certificate: %s (visit "
|
|
|
|
"http://www.freeipa.org/page/Troubleshooting for "
|
|
|
|
"troubleshooting guide)" % e)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2014-06-13 07:45:29 -05:00
|
|
|
trust_chain = tmpdb.get_trust_chain('IPA CA')[:-1]
|
|
|
|
for nickname in trust_chain:
|
|
|
|
try:
|
|
|
|
ca_cert = tmpdb.get_cert(nickname)
|
|
|
|
except RuntimeError:
|
|
|
|
break
|
|
|
|
certstore.put_ca_cert_nss(
|
2017-04-27 02:33:25 -05:00
|
|
|
conn,
|
|
|
|
api.env.basedn,
|
|
|
|
ca_cert,
|
|
|
|
nickname,
|
|
|
|
EMPTY_TRUST_FLAGS)
|
2014-06-13 07:45:29 -05:00
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
dn = DN(('cn', self.cert_nickname), ('cn', 'ca_renewal'),
|
|
|
|
('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
|
2017-06-16 03:18:07 -05:00
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
try:
|
2015-11-23 00:38:17 -06:00
|
|
|
entry = conn.get_entry(dn, ['usercertificate'])
|
2017-08-23 08:23:43 -05:00
|
|
|
entry['usercertificate'] = [new_cert]
|
2015-11-23 00:38:17 -06:00
|
|
|
conn.update_entry(entry)
|
2014-03-13 04:28:27 -05:00
|
|
|
except errors.NotFound:
|
2015-11-23 00:38:17 -06:00
|
|
|
entry = conn.make_entry(
|
2014-03-13 04:28:27 -05:00
|
|
|
dn,
|
|
|
|
objectclass=['top', 'pkiuser', 'nscontainer'],
|
|
|
|
cn=[self.cert_nickname],
|
2017-08-23 08:23:43 -05:00
|
|
|
usercertificate=[new_cert])
|
2015-11-23 00:38:17 -06:00
|
|
|
conn.add_entry(entry)
|
2014-03-13 04:28:27 -05:00
|
|
|
except errors.EmptyModlist:
|
|
|
|
pass
|
|
|
|
|
2018-01-29 01:34:51 -06:00
|
|
|
update_ipa_ca_entry(api, new_cert)
|
|
|
|
|
2014-03-13 04:28:27 -05:00
|
|
|
try:
|
|
|
|
ca.set_renewal_master()
|
|
|
|
except errors.NotFound:
|
|
|
|
raise admintool.ScriptError("CA renewal master not found")
|
|
|
|
|
2017-09-25 02:30:06 -05:00
|
|
|
self.resubmit_request(RENEWAL_REUSE_CA_NAME)
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2015-08-12 06:44:11 -05:00
|
|
|
print("CA certificate successfully renewed")
|
2014-03-13 04:28:27 -05:00
|
|
|
|
2017-09-25 02:30:06 -05:00
|
|
|
def resubmit_request(self, ca=RENEWAL_CA_NAME, profile=None):
|
2014-03-13 04:28:27 -05:00
|
|
|
timeout = api.env.startup_timeout + 60
|
|
|
|
|
2017-08-22 00:40:00 -05:00
|
|
|
cm_profile = None
|
|
|
|
if isinstance(profile, cainstance.MSCSTemplateV1):
|
|
|
|
cm_profile = profile.unparsed_input
|
|
|
|
|
|
|
|
cm_template = None
|
|
|
|
if isinstance(profile, cainstance.MSCSTemplateV2):
|
|
|
|
cm_template = profile.unparsed_input
|
|
|
|
|
2017-05-23 11:35:57 -05:00
|
|
|
logger.debug("resubmitting certmonger request '%s'", self.request_id)
|
2017-08-22 00:40:00 -05:00
|
|
|
certmonger.resubmit_request(self.request_id, ca=ca, profile=cm_profile,
|
|
|
|
template_v2=cm_template, is_ca=True)
|
2014-03-13 04:28:27 -05:00
|
|
|
try:
|
|
|
|
state = certmonger.wait_for_request(self.request_id, timeout)
|
|
|
|
except RuntimeError:
|
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Resubmitting certmonger request '%s' timed out, "
|
|
|
|
"please check the request manually" % self.request_id)
|
2014-10-14 04:26:15 -05:00
|
|
|
ca_error = certmonger.get_request_value(self.request_id, 'ca-error')
|
|
|
|
if state != 'MONITORING' or ca_error:
|
2014-03-13 04:28:27 -05:00
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Error resubmitting certmonger request '%s', "
|
|
|
|
"please check the request manually" % self.request_id)
|
|
|
|
|
2017-05-23 11:35:57 -05:00
|
|
|
logger.debug("modifying certmonger request '%s'", self.request_id)
|
2017-04-24 02:10:41 -05:00
|
|
|
certmonger.modify(self.request_id,
|
2017-09-25 02:30:06 -05:00
|
|
|
ca=RENEWAL_CA_NAME,
|
2017-08-22 00:40:00 -05:00
|
|
|
profile='', template_v2='')
|
2014-06-13 07:49:29 -05:00
|
|
|
|
|
|
|
def install(self):
|
2015-08-12 06:44:11 -05:00
|
|
|
print("Installing CA certificate, please wait")
|
2014-06-13 07:49:29 -05:00
|
|
|
|
|
|
|
options = self.options
|
|
|
|
cert_filename = self.args[1]
|
|
|
|
|
|
|
|
try:
|
2017-06-16 03:18:07 -05:00
|
|
|
cert = x509.load_certificate_from_file(cert_filename)
|
2016-10-13 02:12:31 -05:00
|
|
|
except IOError as e:
|
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Can't open \"%s\": %s" % (cert_filename, e))
|
|
|
|
except (TypeError, ValueError) as e:
|
|
|
|
raise admintool.ScriptError("Not a valid certificate: %s" % e)
|
2014-06-13 07:49:29 -05:00
|
|
|
|
2017-06-16 03:18:07 -05:00
|
|
|
nickname = options.nickname or str(DN(cert.subject))
|
2014-06-13 07:49:29 -05:00
|
|
|
|
2016-02-22 11:14:46 -06:00
|
|
|
ca_certs = certstore.get_ca_certs_nss(api.Backend.ldap2,
|
|
|
|
api.env.basedn,
|
|
|
|
api.env.realm,
|
|
|
|
False)
|
|
|
|
|
2014-09-29 09:22:30 -05:00
|
|
|
with certs.NSSDatabase() as tmpdb:
|
2016-12-06 02:14:54 -06:00
|
|
|
tmpdb.create_db()
|
2017-04-27 02:33:25 -05:00
|
|
|
tmpdb.add_cert(cert, nickname, EXTERNAL_CA_TRUST_FLAGS)
|
2016-02-22 11:14:46 -06:00
|
|
|
for ca_cert, ca_nickname, ca_trust_flags in ca_certs:
|
|
|
|
tmpdb.add_cert(ca_cert, ca_nickname, ca_trust_flags)
|
2014-09-29 09:22:30 -05:00
|
|
|
|
|
|
|
try:
|
|
|
|
tmpdb.verify_ca_cert_validity(nickname)
|
2015-07-30 09:49:29 -05:00
|
|
|
except ValueError as e:
|
2014-09-29 09:22:30 -05:00
|
|
|
raise admintool.ScriptError(
|
2014-12-09 06:47:58 -06:00
|
|
|
"Not a valid CA certificate: %s (visit "
|
|
|
|
"http://www.freeipa.org/page/Troubleshooting for "
|
|
|
|
"troubleshooting guide)" % e)
|
2014-09-29 09:22:30 -05:00
|
|
|
|
2017-05-03 01:17:32 -05:00
|
|
|
trust_flags = options.trust_flags.split(',')
|
|
|
|
if (set(options.trust_flags) - set(',CPTcgpuw') or
|
|
|
|
len(trust_flags) not in [3, 4]):
|
2014-06-13 07:49:29 -05:00
|
|
|
raise admintool.ScriptError("Invalid trust flags")
|
|
|
|
|
2017-05-03 01:17:32 -05:00
|
|
|
extra_flags = trust_flags[3:]
|
|
|
|
extra_usages = set()
|
|
|
|
if extra_flags:
|
|
|
|
if 'C' in extra_flags[0]:
|
|
|
|
extra_usages.add(x509.EKU_PKINIT_KDC)
|
|
|
|
if 'T' in extra_flags[0]:
|
|
|
|
extra_usages.add(x509.EKU_PKINIT_CLIENT_AUTH)
|
|
|
|
|
|
|
|
trust_flags = parse_trust_flags(','.join(trust_flags[:3]))
|
|
|
|
trust_flags = TrustFlags(trust_flags.has_key,
|
|
|
|
trust_flags.trusted,
|
|
|
|
trust_flags.ca,
|
|
|
|
trust_flags.usages | extra_usages)
|
2017-04-27 02:37:38 -05:00
|
|
|
|
2014-06-13 07:49:29 -05:00
|
|
|
try:
|
|
|
|
certstore.put_ca_cert_nss(
|
2015-11-23 00:38:17 -06:00
|
|
|
api.Backend.ldap2, api.env.basedn, cert, nickname, trust_flags)
|
2015-07-30 09:49:29 -05:00
|
|
|
except ValueError as e:
|
2014-06-13 07:49:29 -05:00
|
|
|
raise admintool.ScriptError(
|
|
|
|
"Failed to install the certificate: %s" % e)
|
|
|
|
|
2015-08-12 06:44:11 -05:00
|
|
|
print("CA certificate successfully installed")
|
2018-01-29 01:34:51 -06:00
|
|
|
|
|
|
|
|
|
|
|
def update_ipa_ca_entry(api, cert):
|
|
|
|
"""
|
|
|
|
The Issuer DN of the IPA CA may have changed. Update the IPA CA entry.
|
|
|
|
|
|
|
|
:param api: finalised API object, with *connected* LDAP backend
|
|
|
|
:param cert: a python-cryptography Certificate object
|
|
|
|
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
entry = api.Backend.ldap2.get_entry(
|
|
|
|
DN(('cn', IPA_CA_CN), api.env.container_ca, api.env.basedn),
|
|
|
|
['ipacaissuerdn'])
|
|
|
|
entry['ipacaissuerdn'] = [DN(cert.issuer)]
|
|
|
|
api.Backend.ldap2.update_entry(entry)
|
|
|
|
except errors.EmptyModlist:
|
|
|
|
pass
|