[Freeipa-devel] [PATCH] 0059..0064 Lightweight sub-CAs

Fraser Tweedale ftweedal at redhat.com
Wed Jun 8 03:15:41 UTC 2016


On Tue, Jun 07, 2016 at 03:42:22PM +1000, Fraser Tweedale wrote:
> On Wed, Jun 01, 2016 at 02:51:04PM +1000, Fraser Tweedale wrote:
> > Hi team,
> > 
> > This patchset implements the 'ca' plugin for creating and managing
> > lightweight sub-CAs, and updates the 'caacl' plugin and
> > 'cert-request' command to support multiple CAs.
> > 
> > A brief overview of the patches:
> > 
> > 0059
> >   'ca' plugin, associated schema changes and container objects,
> >   Dogtag REST API wrapper
> > 0060
> >   Add CA entry for the IPA CA on install/upgrade
> > 0061
> >   Update 'caacl' plugin with CA support (including enforcement)
> > 0062
> >   Update ra.request_certificate() to support specifying target CA
> > 0063
> >   Add '--ca' option to 'cert-request' command
> > 0064
> >   Add '--issuer' option to 'cert-find' command
> > 
> > These patches depend on other pending patches:
> > 
> >     0051, 0052, 0053, 0054, 0055, 0056
> > 
> > Signing key replication depends on unmerged Dogtag patches.  Builds
> > of Dogtag with the required patches, and of FreeIPA with all
> > completed sub-CAs work, should be available from my COPR soon:
> > https://copr.fedorainfracloud.org/coprs/ftweedal/freeipa/
> > 
> > Some parts of the design are not implemented in the current
> > patchset, including:
> > 
> > - local parent CA (ipaca object) references
> > - sub-CA certificate renewal
> > - 'cert-show' command '--ca=NAME' option
> > - certmonger support for specifying CA
> > - revocation of deleted CAs
> > 
> > I look forward to your reviews!
> > 
> > Thanks,
> > Fraser
> >
> Rebased and updated patches attached.
> 
> Substantive changes:
> 
> - add required attributes for issuer DN and subject DN
> - prevent rename of IPA CA
> - when adding IPA CA entry, contact Dogtag to learn authority id,
>   issuer DN and subject DN
> - add 'read_ca' method to Dogtag interface
> - tighten ACIs to prevent modification of ipacaid attribute
> 
Updated patch 0064-3; adds --issuer option to cert-show and --ca
option to cert-show and cert-find.
-------------- next part --------------
From 7367f8efb5e8d8f1edeaaa74b3f35b79fc5a9a46 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 10 May 2016 13:56:40 +1000
Subject: [PATCH] Add issuer options to 'cert-show' and 'cert-find'

Add options to cert-show and cert-find for specifying the issuer as
a DN, or a CA name.

Also add the issuer DN to the output of cert-find.

Part of: https://fedorahosted.org/freeipa/ticket/4559
---
 API.txt                     |   8 +++-
 VERSION                     |   4 +-
 ipaserver/plugins/cert.py   | 106 +++++++++++++++++++++++++++++++-------------
 ipaserver/plugins/dogtag.py |   9 ++++
 4 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/API.txt b/API.txt
index 571c646c7b973b3107e9abf9f60caa4ded297c2f..f6853991659bfcaaae12d68fe8b4b8edefd6855f 100644
--- a/API.txt
+++ b/API.txt
@@ -730,11 +730,13 @@ output: Entry('result')
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: PrimaryKey('value')
 command: cert_find
-args: 0,17,4
+args: 0,19,4
 option: Flag('all', autofill=True, cli_name='all', default=False)
+option: Str('ca?', autofill=False)
 option: Flag('exactly?', autofill=True, default=False)
 option: Str('issuedon_from?', autofill=False)
 option: Str('issuedon_to?', autofill=False)
+option: Str('issuer?', autofill=False)
 option: Int('max_serial_number?', autofill=False)
 option: Int('min_serial_number?', autofill=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -774,8 +776,10 @@ option: Int('revocation_reason', autofill=True, default=0)
 option: Str('version?')
 output: Output('result')
 command: cert_show
-args: 1,2,1
+args: 1,4,1
 arg: Str('serial_number')
+option: Str('ca?', autofill=False)
+option: Str('issuer?', autofill=False)
 option: Str('out?')
 option: Str('version?')
 output: Output('result')
diff --git a/VERSION b/VERSION
index 6577c80904f99ab6b30217ddc82625ccda928df0..600ab8182332de68bc356100ae0e232c68e30d90 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=179
-# Last change: ftweedal - add --ca option to cert-request
+IPA_API_VERSION_MINOR=180
+# Last change: ftweedal - add issuer options to cert-show and cert-find
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index f09947337efc3d5b5872937df4a82663dfb6eff9..ce7d042d4f872c9f8176e887fd2bbfe07c1fe1a9 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -583,37 +583,17 @@ class cert_show(VirtualCommand):
 
     takes_args = _serial_number
 
-    has_output_params = (
-        Str('certificate',
-            label=_('Certificate'),
-        ),
-        Str('subject',
-            label=_('Subject'),
-        ),
-        Str('issuer',
-            label=_('Issuer'),
-        ),
-        Str('valid_not_before',
-            label=_('Not Before'),
-        ),
-        Str('valid_not_after',
-            label=_('Not After'),
-        ),
-        Str('md5_fingerprint',
-            label=_('Fingerprint (MD5)'),
-        ),
-        Str('sha1_fingerprint',
-            label=_('Fingerprint (SHA1)'),
-        ),
-        Str('revocation_reason',
-            label=_('Revocation reason'),
-        ),
-        Str('serial_number_hex',
-            label=_('Serial number (hex)'),
-        ),
-    )
-
     takes_options = (
+        Str('ca?',
+            label=_('Issuing CA'),
+            doc=_('Name of issing CA'),
+            autofill=False,
+        ),
+        Str('issuer?',
+            label=_('Issuer'),
+            doc=_('Issuer DN'),
+            autofill=False,
+        ),
         Str('out?',
             label=_('Output filename'),
             doc=_('File to store the certificate in.'),
@@ -621,6 +601,33 @@ class cert_show(VirtualCommand):
         ),
     )
 
+    has_output_params = (
+        Str('certificate',
+            label=_('Certificate'),
+        ),
+        Str('subject',
+            label=_('Subject'),
+        ),
+        Str('valid_not_before',
+            label=_('Not Before'),
+        ),
+        Str('valid_not_after',
+            label=_('Not After'),
+        ),
+        Str('md5_fingerprint',
+            label=_('Fingerprint (MD5)'),
+        ),
+        Str('sha1_fingerprint',
+            label=_('Fingerprint (SHA1)'),
+        ),
+        Str('revocation_reason',
+            label=_('Revocation reason'),
+        ),
+        Str('serial_number_hex',
+            label=_('Serial number (hex)'),
+        ),
+    )
+
     operation="retrieve certificate"
 
     def execute(self, serial_number, **options):
@@ -635,8 +642,29 @@ class cert_show(VirtualCommand):
                 raise acierr
             hostname = get_host_from_principal(bind_principal)
 
+        issuer_dn = None
+        if 'ca' in options and 'issuer' in options:
+            raise errors.MutuallyExclusiveError(
+                reason=_('CA and Issuer DN cannot both be set'))
+        if 'ca' in options:
+            ca_obj = api.Command.ca_show(options['ca'])['result']
+            issuer_dn = ca_obj['ipacasubjectdn'][0]
+        elif 'issuer' in options:
+            issuer_dn = options['issuer']
+
+        # Dogtag lightweight CAs have shared serial number domain, so
+        # we don't tell Dogtag the issuer (but we check the cert after).
+        #
         result=self.Backend.ra.get_certificate(serial_number)
         cert = x509.load_certificate(result['certificate'])
+
+        if issuer_dn is not None and DN(unicode(cert.issuer)) != DN(issuer_dn):
+            # DN of cert differs from what we requested
+            raise errors.NotFound(
+                reason=_("Certificate with serial number %(serial)d and "
+                    "issuer '%(issuer)s' not found")
+                    % dict(serial=serial_number, issuer=issuer_dn))
+
         result['subject'] = unicode(cert.subject)
         result['issuer'] = unicode(cert.issuer)
         result['valid_not_before'] = unicode(cert.valid_not_before_str)
@@ -738,6 +766,16 @@ class cert_find(Command):
             doc=_('Subject'),
             autofill=False,
         ),
+        Str('ca?',
+            label=_('Issuing CA'),
+            doc=_('Name of issing CA'),
+            autofill=False,
+        ),
+        Str('issuer?',
+            label=_('Issuer'),
+            doc=_('Issuer DN'),
+            autofill=False,
+        ),
         Int('revocation_reason?',
             label=_('Reason'),
             doc=_('Reason for revoking the certificate (0-10). Type '
@@ -822,6 +860,14 @@ class cert_find(Command):
 
     def execute(self, **options):
         ca_enabled_check()
+
+        if 'ca' in options and 'issuer' in options:
+            raise errors.MutuallyExclusiveError(
+                reason=_('CA and Issuer DN cannot both be set'))
+        if 'ca' in options:
+            ca_obj = api.Command.ca_show(options['ca'])['result']
+            options['issuer'] = unicode(ca_obj['ipacasubjectdn'][0])
+
         ret = dict(
             result=self.Backend.ra.find(options)
         )
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index 43aab92ffe6bba42d21135eb4f87cbde635f86e0..919ecfeaca6c3ca41040152157e5d275f230704a 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -1809,6 +1809,10 @@ class ra(rabase.rabase):
             node.text = options['subject']
             booloptions['subjectInUse'] = True
 
+        if 'issuer' in options:
+            node = etree.SubElement(page, 'issuerDN')
+            node.text = options['issuer']
+
         if 'revocation_reason' in options:
             node = etree.SubElement(page, 'revocationReason')
             node.text = unicode(options['revocation_reason'])
@@ -1897,6 +1901,11 @@ class ra(rabase.rabase):
             dn = cert.xpath('SubjectDN')
             if len(dn) == 1:
                 response_request['subject'] = unicode(dn[0].text)
+
+            issuer_dn = cert.xpath('IssuerDN')
+            if len(dn) == 1:
+                response_request['issuer'] = unicode(issuer_dn[0].text)
+
             status = cert.xpath('Status')
             if len(status) == 1:
                 response_request['status'] = unicode(status[0].text)
-- 
2.5.5



More information about the Freeipa-devel mailing list