When loading a chained CA from a PKCS#7 or PEM file we used to use very generic nicknames, sometimes as bad as "Imported CA" in the case of winsync. This will use the subject of the cert to get the nickname instead.

I also extended the API of some of the x509 functions to optionally take in the NSS database dir. I had originally used this in the patch but did it another way but still thought the changes useful.

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

Word of warning, this is going to require a fair bit of testing. The way to test it is to install with an external CA, then install a replica with a CA to be sure that works as well. Testing basic installs would be handy as well.

rob
>From 9bca41c5de3761e5f5d70c4ffa16de120197bf06 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Mon, 11 Jul 2011 17:39:30 -0400
Subject: [PATCH] Use information from the certificate subject when setting the NSS nickname.

There were a few places in the code where certs were loaded from a
PKCS#7 file or a chain in a PEM file. The certificates got very
generic nicknames.

We can instead pull the subject from the certificate and use that as
the nickname.

https://fedorahosted.org/freeipa/ticket/1141
---
 install/tools/ipa-server-install |    2 +-
 ipalib/x509.py                   |   34 ++++++++++++++++++++++++++--------
 ipaserver/install/cainstance.py  |   17 ++++++++++-------
 ipaserver/install/certs.py       |   25 ++++++++++++++++++++-----
 4 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 8a6634d5a18eb22de6eb5464d69b2e81a6dd2bdf..5ac97f43f0054e87b20d08d49470cc4cab6d3f97 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -83,7 +83,7 @@ def subject_callback(option, opt_str, value, parser):
         dn = DN(v)
     except ValueError, e:
         raise ValueError('Invalid subject base format: %s' % str(e))
-    parser.values.subject = value
+    parser.values.subject = str(dn) # may as well normalize it
 
 def parse_options():
     # Guaranteed to give a random 200k range below the 2G mark (uint32_t limit)
diff --git a/ipalib/x509.py b/ipalib/x509.py
index 77d6aabf4e100ce4cff4c463fcda54a027f2bc88..e757e1d1fab8dc4d38bf8f2207daed7fe441f117 100644
--- a/ipalib/x509.py
+++ b/ipalib/x509.py
@@ -71,27 +71,45 @@ def load_certificate(data, datatype=PEM, dbdir=None):
         data = base64.b64decode(data)
 
     if dbdir is None:
-        if api.env.in_tree:
-            dbdir = api.env.dot_ipa + os.sep + 'alias'
+        if 'in_tree' in api.env:
+            if api.env.in_tree:
+                dbdir = api.env.dot_ipa + os.sep + 'alias'
+            else:
+                dbdir = "/etc/httpd/alias"
+            nss.nss_init(dbdir)
         else:
-            dbdir = "/etc/httpd/alias"
+            nss.nss_init_nodb()
+    else:
+        nss.nss_init(dbdir)
+
 
-    nss.nss_init(dbdir)
     return nss.Certificate(buffer(data))
 
-def get_subject(certificate, datatype=PEM):
+def load_certificate_from_file(filename, dbdir=None):
+    """
+    Load a certificate from a PEM file.
+
+    Returns a nss.Certificate type
+    """
+    fd = open(filename, 'r')
+    data = fd.read()
+    fd.close()
+
+    return load_certificate(file, PEM, dbdir)
+
+def get_subject(certificate, datatype=PEM, dbdir=None):
     """
     Load an X509.3 certificate and get the subject.
     """
 
-    nsscert = load_certificate(certificate, datatype)
+    nsscert = load_certificate(certificate, datatype, dbdir)
     return nsscert.subject
 
-def get_serial_number(certificate, datatype=PEM):
+def get_serial_number(certificate, datatype=PEM, dbdir=None):
     """
     Return the decimal value of the serial number.
     """
-    nsscert = load_certificate(certificate, datatype)
+    nsscert = load_certificate(certificate, datatype, dbdir)
     return nsscert.serial_number
 
 def make_pem(data):
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 4ace26db5a99afda26cfd023887eb71f48c69d55..4f0fd37d1ec8f2a6ff92888b14908e35bd140efd 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -39,6 +39,7 @@ import socket
 from ipapython import dogtag
 from ipapython.certdb import get_ca_nickname
 from ipalib import pkcs10, x509
+from ipalib.dn import DN
 import subprocess
 
 from nss.error import NSPRError
@@ -919,7 +920,7 @@ class CAInstance(service.Service):
         # makes openssl throw up.
         data = base64.b64decode(chain)
 
-        (certs, stderr, returncode) = ipautil.run(["/usr/bin/openssl",
+        (certlist, stderr, returncode) = ipautil.run(["/usr/bin/openssl",
              "pkcs7",
              "-inform",
              "DER",
@@ -932,18 +933,20 @@ class CAInstance(service.Service):
         st = 1
         en = 0
         subid = 0
+        normalized_base = str(DN(self.subject_base))
         while st > 0:
-            st = certs.find('-----BEGIN', en)
-            en = certs.find('-----END', en+1)
+            st = certlist.find('-----BEGIN', en)
+            en = certlist.find('-----END', en+1)
             if st > 0:
                 try:
                     (chain_fd, chain_name) = tempfile.mkstemp()
-                    os.write(chain_fd, certs[st:en+25])
+                    os.write(chain_fd, certlist[st:en+25])
                     os.close(chain_fd)
-                    if subid == 0:
-                        nick = self.canickname
+                    (rdn, subject) = certs.get_cert_nickname(certlist[st:en+25])
+                    if subject.lower() == ('CN=Certificate Authority,%s' % normalized_base).lower():
+                        nick = get_ca_nickname(self.realm)
                     else:
-                        nick = "%s sub %d" % (self.canickname, subid)
+                        nick = subject
                     self.__run_certutil(
                         ['-A', '-t', 'CT,C,C', '-n', nick, '-a',
                          '-i', chain_name]
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index ebe654dd30379ff709c69574deae438f84b6e27c..522d3f5760e7f6698a21784e76cf1074bb1ea034 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -38,6 +38,7 @@ from ipalib import pkcs10
 from ConfigParser import RawConfigParser, MissingSectionHeaderError
 import service
 from ipalib import x509
+from ipalib.dn import DN
 from ipalib.errors import CertificateOperationError
 
 from nss.error import NSPRError
@@ -82,6 +83,20 @@ def find_cert_from_txt(cert, start=0):
     cert = cert[s:e]
     return (cert, e)
 
+def get_cert_nickname(cert):
+    """
+    Using the subject from cert come up with a nickname suitable
+    for NSS. The caller can decide whether to use just the RDN
+    or the whole subject.
+
+    Returns a tuple of (rdn, subject)
+    """
+    nsscert = x509.load_certificate(cert)
+    subject = str(nsscert.subject)
+    dn = DN(subject)
+
+    return (str(dn[0]), str(dn))
+
 def next_serial(serial_file=CA_SERIALNO):
     """
     Get the next serial number if we're using an NSS-based self-signed CA.
@@ -415,16 +430,16 @@ class CertDB(object):
         certs = fd.read()
         fd.close()
 
+        normalized_base = str(DN(self.subject_base))
         st = 0
-        subid=0
         while True:
             try:
                 (cert, st) = find_cert_from_txt(certs, st)
-                if subid == 0:
-                    nick = self.cacert_name
+                (nick, subject) = get_cert_nickname(cert)
+                if subject.lower() == ('CN=Certificate Authority,%s' % normalized_base).lower():
+                    nick = get_ca_nickname(self.realm)
                 else:
-                    nick = "%s sub %d" % (self.cacert_name, subid)
-                subid = subid + 1
+                    nick = subject
                 self.run_certutil(["-A", "-n", nick,
                                    "-t", "CT,,C",
                                    "-a"],
-- 
1.7.4

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

Reply via email to