diff options
author | Fraser Tweedale <ftweedal@redhat.com> | 2016-08-08 14:27:20 +1000 |
---|---|---|
committer | Jan Cholasta <jcholast@redhat.com> | 2016-12-12 13:03:15 +0100 |
commit | 32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d (patch) | |
tree | 484f57785d6f872f22e118aed13df38d74a2591e /ipaserver/plugins | |
parent | cc5b88e5d4ac1171374be9ae8e6e60730243dd3d (diff) | |
download | freeipa-32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d.tar.gz freeipa-32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d.tar.xz freeipa-32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d.zip |
Add options to write lightweight CA cert or chain to file
Administrators need a way to retrieve the certificate or certificate
chain of an IPA-managed lightweight CA. Add params to the `ca'
object for carrying the CA certificate and chain (as multiple DER
values). Add the `--chain' flag for including the chain in the
result (chain is also included with `--all'). Add the
`--certificate-out' option for writing the certificate to a file (or
the chain, if `--chain' was given).
Fixes: https://fedorahosted.org/freeipa/ticket/6178
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Reviewed-By: Tomas Krizek <tkrizek@redhat.com>
Diffstat (limited to 'ipaserver/plugins')
-rw-r--r-- | ipaserver/plugins/ca.py | 65 | ||||
-rw-r--r-- | ipaserver/plugins/dogtag.py | 12 |
2 files changed, 72 insertions, 5 deletions
diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py index d9ae8c81f..ef1d68c3a 100644 --- a/ipaserver/plugins/ca.py +++ b/ipaserver/plugins/ca.py @@ -2,14 +2,18 @@ # Copyright (C) 2016 FreeIPA Contributors see COPYING for license # -from ipalib import api, errors, output, DNParam, Str +import base64 + +import six + +from ipalib import api, errors, output, Bytes, DNParam, Flag, Str from ipalib.constants import IPA_CA_CN from ipalib.plugable import Registry from ipaserver.plugins.baseldap import ( LDAPObject, LDAPSearch, LDAPCreate, LDAPDelete, LDAPUpdate, LDAPRetrieve, LDAPQuery, pkey_to_value) from ipaserver.plugins.cert import ca_enabled_check -from ipalib import _, ngettext +from ipalib import _, ngettext, x509 __doc__ = _(""" @@ -100,6 +104,18 @@ class ca(LDAPObject): doc=_('Issuer Distinguished Name'), flags=['no_create', 'no_update'], ), + Bytes( + 'certificate', + label=_("Certificate"), + doc=_("Base-64 encoded certificate."), + flags={'no_create', 'no_update', 'no_search'}, + ), + Bytes( + 'certificate_chain*', + label=_("Certificate chain"), + doc=_("X.509 certificate chain"), + flags={'no_create', 'no_update', 'no_search'}, + ), ) permission_filter_objectclasses = ['ipaca'] @@ -145,6 +161,21 @@ class ca(LDAPObject): } +def set_certificate_attrs(entry, options, always_include_cert=True): + ca_id = entry['ipacaid'][0] + full = options.get('all', False) + with api.Backend.ra_lightweight_ca as ca_api: + if always_include_cert or full: + der = ca_api.read_ca_cert(ca_id) + entry['certificate'] = six.text_type(base64.b64encode(der)) + + if options.get('chain', False) or full: + pkcs7_der = ca_api.read_ca_chain(ca_id) + pems = x509.pkcs7_to_pems(pkcs7_der, x509.DER) + ders = [x509.normalize_certificate(pem) for pem in pems] + entry['certificate_chain'] = ders + + @register() class ca_find(LDAPSearch): __doc__ = _("Search for CAs.") @@ -154,16 +185,32 @@ class ca_find(LDAPSearch): def execute(self, *keys, **options): ca_enabled_check() - return super(ca_find, self).execute(*keys, **options) + result = super(ca_find, self).execute(*keys, **options) + for entry in result['result']: + set_certificate_attrs(entry, options, always_include_cert=False) + return result + + +_chain_flag = Flag( + 'chain', + default=False, + doc=_('Include certificate chain in output'), +) @register() class ca_show(LDAPRetrieve): __doc__ = _("Display the properties of a CA.") - def execute(self, *args, **kwargs): + takes_options = LDAPRetrieve.takes_options + ( + _chain_flag, + ) + + def execute(self, *keys, **options): ca_enabled_check() - return super(ca_show, self).execute(*args, **kwargs) + result = super(ca_show, self).execute(*keys, **options) + set_certificate_attrs(result['result'], options) + return result @register() @@ -171,6 +218,10 @@ class ca_add(LDAPCreate): __doc__ = _("Create a CA.") msg_summary = _('Created CA "%(value)s"') + takes_options = LDAPCreate.takes_options + ( + _chain_flag, + ) + def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options): ca_enabled_check() if not ldap.can_add(dn[1:]): @@ -203,6 +254,10 @@ class ca_add(LDAPCreate): entry['ipacasubjectdn'] = [resp['dn']] return dn + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + set_certificate_attrs(entry_attrs, options) + return dn + @register() class ca_del(LDAPDelete): diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py index 0bdb4daf2..b77b21aa2 100644 --- a/ipaserver/plugins/dogtag.py +++ b/ipaserver/plugins/dogtag.py @@ -2125,6 +2125,18 @@ class ra_lightweight_ca(RestClient): except: raise errors.RemoteRetrieveError(reason=_("Response from CA was not valid JSON")) + def read_ca_cert(self, ca_id): + _status, _resp_headers, resp_body = self._ssldo( + 'GET', '{}/cert'.format(ca_id), + headers={'Accept': 'application/pkix-cert'}) + return resp_body + + def read_ca_chain(self, ca_id): + _status, _resp_headers, resp_body = self._ssldo( + 'GET', '{}/chain'.format(ca_id), + headers={'Accept': 'application/pkcs7-mime'}) + return resp_body + def disable_ca(self, ca_id): self._ssldo( 'POST', ca_id + '/disable', |