On 18.8.2011 17:47, Rob Crittenden wrote:
Jan Cholasta wrote:
On 17.8.2011 10:27, Jan Cholasta wrote:
Verify that --external_cert_file and --external_ca_file are both
readable, valid PEM files and that their subject/issuer is correct.

Also fixes ipalib.x509.load_certificate_from_file.

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

Honza


Patch attached.

nack, but this is very close.

If the CA is a chain the signing check may fail if the first cert isn't
the one that signed the CSR. You need to check all CA certs in the file.

rob

Fixed.

Honza

--
Jan Cholasta
>From fe6cb906e43b51bbfb23d85f5502eb71f1ad8f3a Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Wed, 17 Aug 2011 10:19:37 +0200
Subject: [PATCH] Verify that the external CA certificate files are correct.

ticket 1572
---
 install/tools/ipa-server-install |   43 ++++++++++++++++++++++++++++++++-----
 ipalib/x509.py                   |   20 ++++++++++++++++-
 2 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 189bb20..05caad8 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -39,6 +39,7 @@ import traceback
 from ConfigParser import RawConfigParser
 import random
 import tempfile
+import nss.error
 
 from ipaserver.install import dsinstance
 from ipaserver.install import krbinstance
@@ -59,6 +60,7 @@ from ipalib import api, errors, util
 from ipalib.parameters import IA5Str
 from ipapython.config import IPAOptionParser
 from ipalib.dn import DN
+from ipalib.x509 import load_certificate_from_file, load_certificate_chain_from_file
 
 pw_name = None
 uninstalling = False
@@ -567,18 +569,47 @@ def main():
             # already having done the first stage of the CA install.
             print "CA is not installed yet. To install with an external CA is a two-stage process.\nFirst run the installer with --external-ca."
             sys.exit(1)
-        if not ipautil.file_exists(options.external_cert_file):
-            print "%s does not exist" % options.external_cert_file
-            sys.exit(1)
-        if not ipautil.file_exists(options.external_ca_file):
-            print "%s does not exist" % options.external_ca_file
-            sys.exit(1)
 
     # This will override any settings passed in on the cmdline
     if ipautil.file_exists(ANSWER_CACHE):
         dm_password = read_password("Directory Manager", confirm=False)
         options._update_loose(read_cache(dm_password))
 
+    if options.external_cert_file:
+        try:
+            extcert = load_certificate_from_file(options.external_cert_file)
+        except IOError, e:
+            print "Can't load the PKCS#10 certificate: %s." % str(e)
+            sys.exit(1)
+        except nss.error.NSPRError:
+            print "'%s' is not a valid PEM-encoded certificate." % options.external_cert_file
+            sys.exit(1)
+
+        if DN(unicode(extcert.subject)) != DN(('CN','Certificate Authority'), options.subject):
+            print "Subject of the PKCS#10 certificate is not correct."
+            sys.exit(1)
+
+        try:
+            extchain = load_certificate_chain_from_file(options.external_ca_file)
+        except IOError, e:
+            print "Can't load the external CA chain: %s." % str(e)
+            sys.exit(1)
+        except nss.error.NSPRError:
+            print "'%s' is not a valid PEM-encoded certificate chain." % options.external_ca_file
+            sys.exit(1)
+
+        certdict = dict((unicode(cert.subject), cert) for cert in extchain)
+        if unicode(extcert.issuer) not in certdict:
+            print "The PKCS#10 certificate is not signed by the external CA."
+            sys.exit(1)
+
+        cert = extcert
+        while unicode(cert.issuer) in certdict and cert.issuer != cert.subject:
+            cert = certdict[unicode(cert.issuer)]
+        if cert.issuer != cert.subject:
+            print "The external CA chain is incomplete."
+            sys.exit(1)
+
     print "=============================================================================="
     print "This program will set up the FreeIPA Server."
     print ""
diff --git a/ipalib/x509.py b/ipalib/x509.py
index 23f337e..04e1b94 100644
--- a/ipalib/x509.py
+++ b/ipalib/x509.py
@@ -34,6 +34,7 @@
 import os
 import sys
 import base64
+import re
 import nss.nss as nss
 from nss.error import NSPRError
 from ipapython import ipautil
@@ -45,6 +46,8 @@ from ipalib import errors
 PEM = 0
 DER = 1
 
+PEM_REGEX = re.compile(r'(?<=-----BEGIN CERTIFICATE-----).*?(?=-----END CERTIFICATE-----)', re.DOTALL)
+
 def valid_issuer(issuer, realm):
     return issuer in ('CN=%s Certificate Authority' % realm,
                       'CN=Certificate Authority,O=%s' % realm,)
@@ -89,6 +92,21 @@ def load_certificate(data, datatype=PEM, dbdir=None):
 
     return nss.Certificate(buffer(data))
 
+def load_certificate_chain_from_file(filename, dbdir=None):
+    """
+    Load a certificate chain from a PEM file.
+
+    Returns a list of nss.Certificate objects.
+    """
+    fd = open(filename, 'r')
+    data = fd.read()
+    fd.close()
+
+    chain = PEM_REGEX.findall(data)
+    chain = [load_certificate(cert, PEM, dbdir) for cert in chain]
+
+    return chain
+
 def load_certificate_from_file(filename, dbdir=None):
     """
     Load a certificate from a PEM file.
@@ -99,7 +117,7 @@ def load_certificate_from_file(filename, dbdir=None):
     data = fd.read()
     fd.close()
 
-    return load_certificate(file, PEM, dbdir)
+    return load_certificate(data, PEM, dbdir)
 
 def get_subject(certificate, datatype=PEM, dbdir=None):
     """
-- 
1.7.6

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to