From 2f650b60a4ce9c9b19a64b21ebe3051668efb4af Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 11 Jul 2011 17:39:30 -0400 Subject: 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 ca0d139b6..316fc67f7 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -94,7 +94,7 @@ def subject_callback(option, opt_str, value, parser): raise ValueError('invalid attribute: %s' % dn[x][0].attr.lower()) 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 77d6aabf4..e757e1d1f 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 fbc566a28..121b651bc 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 ebe654dd3..522d3f576 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"], -- cgit