Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. #
# Apache needs access to this database so we need to create it # where apache can reach
""" Determine if the current IPA CA is self-signed or using another CA
We do this based on the CA plugin that is currently in use. """ if api.env.ra_plugin == 'selfsign': return True else: return False
""" The selfsign backend is enabled only one a single master.
Return True/False whether this is that master.
Returns None if not a self-signed server. """ if ipa_self_signed(): return api.env.enable_ra else: return None
""" Given a cert blob (str) which may or may not contian leading and trailing text, pull out just the certificate part. This will return the FIRST cert in a stream of data.
Returns a tuple (certificate, last position in cert) """ s = cert.find('-----BEGIN CERTIFICATE-----', start) e = cert.find('-----END CERTIFICATE-----', s) if e > 0: e = e + 25
if s < 0 or e < 0: raise RuntimeError("Unable to find certificate")
cert = cert[s:e] return (cert, e)
""" 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_dn) when rdn is the string representation of the first RDN in the subject and subject_dn is a DN object. """ nsscert = x509.load_certificate(cert) subject = str(nsscert.subject) dn = DN(subject)
return (str(dn[0]), dn)
""" Get the next serial number if we're using an NSS-based self-signed CA.
The file is an ini-like file with following properties: lastvalue = the last serial number handed out nextreplica = the serial number the next replica should start with replicainterval = the number to add to nextreplica the next time a replica is created
File locking is attempted so we have unique serial numbers. """ fp = None parser = RawConfigParser() if ipautil.file_exists(serial_file): try: fp = open(serial_file, "r+") fcntl.flock(fp.fileno(), fcntl.LOCK_EX) parser.readfp(fp) serial = parser.getint('selfsign', 'lastvalue') cur_serial = serial + 1 except IOError, e: raise RuntimeError("Unable to determine serial number: %s" % str(e)) except MissingSectionHeaderError: fcntl.flock(fp.fileno(), fcntl.LOCK_UN) fp.close() f=open(serial_file,"r") r = f.readline() f.close() cur_serial = int(r) + 1 fp = open(serial_file, "w") fcntl.flock(fp.fileno(), fcntl.LOCK_EX) parser.add_section('selfsign') parser.set('selfsign', 'nextreplica', 500000) parser.set('selfsign', 'replicainterval', 500000) else: fp = open(serial_file, "w") fcntl.flock(fp.fileno(), fcntl.LOCK_EX) parser.add_section('selfsign') parser.set('selfsign', 'nextreplica', 500000) parser.set('selfsign', 'replicainterval', 500000) cur_serial = 1000
try: fp.seek(0) parser.set('selfsign', 'lastvalue', cur_serial) parser.write(fp) fp.flush() fcntl.flock(fp.fileno(), fcntl.LOCK_UN) fp.close() except IOError, e: raise RuntimeError("Unable to increment serial number: %s" % str(e))
return str(cur_serial)
""" Return the starting serial number for a new self-signed replica """ fp = None parser = RawConfigParser() if ipautil.file_exists(serial_file): try: fp = open(serial_file, "r+") fcntl.flock(fp.fileno(), fcntl.LOCK_EX) parser.readfp(fp) serial = parser.getint('selfsign', 'nextreplica') nextreplica = serial + parser.getint('selfsign', 'replicainterval') except IOError, e: raise RuntimeError("Unable to determine serial number: %s" % str(e)) else: raise RuntimeError("%s does not exist, cannot create replica" % serial_file) try: fp.seek(0) parser.set('selfsign', 'nextreplica', nextreplica) parser.write(fp) fp.flush() fcntl.flock(fp.fileno(), fcntl.LOCK_UN) fp.close() except IOError, e: raise RuntimeError("Unable to increment serial number: %s" % str(e))
return str(serial)
self.secdir = nssdir self.realm = realm
self.noise_fname = self.secdir + "/noise.txt" self.passwd_fname = self.secdir + "/pwdfile.txt" self.certdb_fname = self.secdir + "/cert8.db" self.keydb_fname = self.secdir + "/key3.db" self.secmod_fname = self.secdir + "/secmod.db" self.cacert_fname = self.secdir + "/cacert.asc" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" self.pwd_conf = "/etc/httpd/conf/password.conf" self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.subject_base = subject_base try: self.cwd = os.getcwd() except OSError, e: raise RuntimeError("Unable to determine the current directory: %s" % str(e))
self.self_signed_ca = ipa_self_signed()
if not subject_base: self.subject_base = "O=IPA" self.subject_format = "CN=%%s,%s" % self.subject_base
self.cacert_name = get_ca_nickname(self.realm) self.valid_months = "120" self.keysize = "1024"
# We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID]
if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
if self.reqdir is not None: shutil.rmtree(self.reqdir, ignore_errors=True) try: os.chdir(self.cwd) except: pass
""" Create a temporary directory to store certificate requests and certificates. This should be called before requesting certificates.
This is set outside of __init__ to avoid creating a temporary directory every time we open a cert DB. """ if self.reqdir is not None: return
self.reqdir = tempfile.mkdtemp('', 'ipa-', '/var/lib/ipa') self.certreq_fname = self.reqdir + "/tmpcertreq" self.certder_fname = self.reqdir + "/tmpcert.der"
# When certutil makes a request it creates a file in the cwd, make # sure we are in a unique place when this happens os.chdir(self.reqdir)
"""A CA cert was loaded from a PKCS#12 file. Set up our serial file"""
cur_serial = self.find_cacert_serial() try: fp = open(CA_SERIALNO, "w") parser = RawConfigParser() parser.add_section('selfsign') parser.set('selfsign', 'lastvalue', cur_serial) parser.set('selfsign', 'nextreplica', 500000) parser.set('selfsign', 'replicainterval', 500000) parser.write(fp) fp.close() except IOError, e: raise RuntimeError("Unable to increment serial number: %s" % str(e))
if uid: pent = pwd.getpwnam(uid) os.chown(fname, pent.pw_uid, pent.pw_gid) else: os.chown(fname, self.uid, self.gid) perms = stat.S_IRUSR if write: perms |= stat.S_IWUSR os.chmod(fname, perms)
return sha1(ipautil.ipa_generate_password()).hexdigest()
new_args = ["/usr/bin/certutil", "-d", self.secdir] new_args = new_args + args return ipautil.run(new_args, stdin)
if not self.self_signed_ca: f = open(self.passwd_fname, "r") password = f.readline() f.close() new_args = ["/usr/bin/signtool", "-d", self.secdir, "-p", password] else: new_args = ["/usr/bin/signtool", "-d", self.secdir] new_args = new_args + args ipautil.run(new_args, stdin)
if ipautil.file_exists(self.noise_fname): os.remove(self.noise_fname) f = open(self.noise_fname, "w") f.write(self.gen_password()) self.set_perms(self.noise_fname)
ipautil.backup_file(self.passwd_fname) f = open(self.passwd_fname, "w") if passwd is not None: f.write("%s\n" % passwd) else: f.write(self.gen_password()) f.close() self.set_perms(self.passwd_fname)
ipautil.backup_file(self.certdb_fname) ipautil.backup_file(self.keydb_fname) ipautil.backup_file(self.secmod_fname) self.run_certutil(["-N", "-f", self.passwd_fname]) self.set_perms(self.passwd_fname, write=True)
""" Return a tuple of tuples containing (nickname, trust) """ p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-L"], stdout=subprocess.PIPE)
certs = p.stdout.read() certs = certs.split("\n")
# FIXME, this relies on NSS never changing the formatting of certutil certlist = [] for cert in certs: nickname = cert[0:61] trust = cert[61:] if re.match(r'\w+,\w+,\w+', trust): certlist.append((nickname.strip(), trust))
return tuple(certlist)
""" Returns True if nickname exists in the certdb, False otherwise.
This could also be done directly with: certutil -L -d -n <nickname> ... """
certs = self.list_certs()
for cert in certs: if nickname == cert[0]: return True
return False
os.chdir(self.secdir) subject = "cn=%s Certificate Authority" % self.realm p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-S", "-n", self.cacert_name, "-s", subject, "-x", "-t", "CT,,C", "-1", "-2", "-5", "-m", next_serial(), "-v", self.valid_months, "-z", self.noise_fname, "-f", self.passwd_fname], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Create key usage extension # 0 - Digital Signature # 1 - Non-repudiation # 5 - Cert signing key # Is this a critical extension [y/N]? y p.stdin.write("0\n1\n5\n9\ny\n") # Create basic constraint extension # Is this a CA certificate [y/N]? y # Enter the path length constraint, enter to skip [<0 for unlimited pat # Is this a critical extension [y/N]? y # 5 6 7 9 n -> SSL, S/MIME, Object signing CA p.stdin.write("y\n\ny\n") p.stdin.write("5\n6\n7\n9\nn\n") p.wait() os.chdir(self.cwd)
"""create_pkcs12 tells us whether we should create a PKCS#12 file of the CA or not. If we are running on a replica then we won't have the private key to make a PKCS#12 file so we don't need to do that step.""" # export the CA cert for use with other apps ipautil.backup_file(self.cacert_fname) root_nicknames = self.find_root_cert(nickname) fd = open(self.cacert_fname, "w") for root in root_nicknames: (cert, stderr, returncode) = self.run_certutil(["-L", "-n", root, "-a"]) fd.write(cert) fd.close() os.chmod(self.cacert_fname, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) if create_pkcs12: ipautil.backup_file(self.pk12_fname) ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, "-o", self.pk12_fname, "-n", self.cacert_name, "-w", self.passwd_fname, "-k", self.passwd_fname]) self.set_perms(self.pk12_fname)
""" Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ fd = open(cacert_fname) certs = fd.read() fd.close()
ca_dn = DN(('CN','Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) (rdn, subject_dn) = get_cert_nickname(cert) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.run_certutil(["-A", "-n", nick, "-t", "CT,,C", "-a"], stdin=cert) except RuntimeError: break
""" Retrieve a certificate from the current NSS database for nickname.
pem controls whether the value returned PEM or DER-encoded. The default is the data straight from certutil -a. """ try: args = ["-L", "-n", nickname, "-a"] (cert, err, returncode) = self.run_certutil(args) if pem: return cert else: (cert, start) = find_cert_from_txt(cert, start=0) cert = x509.strip_header(cert) dercert = base64.b64decode(cert) return dercert except ipautil.CalledProcessError: return ''
(out, err, returncode) = self.run_certutil(["-L", "-n", self.cacert_name]) data = out.split('\n') for line in data: x = re.match(r'\s+Serial Number: (\d+) .*', line) if x is not None: return x.group(1)
raise RuntimeError("Unable to find serial number")
""" Tell certmonger to track the given certificate nickname.
If command is not a full path then it is prefixed with /usr/lib[64]/ipa/certmonger. """ if command is not None and not os.path.isabs(command): if sys.maxsize > 2**32: libpath = 'lib64' else: libpath = 'lib' command = '/usr/%s/ipa/certmonger/%s' % (libpath, command) cmonger = ipaservices.knownservices.certmonger cmonger.enable() ipaservices.knownservices.messagebus.start() cmonger.start() try: (stdout, stderr, rc) = certmonger.start_tracking(nickname, self.secdir, password_file, command) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error("certmonger failed starting to track certificate: %s" % str(e)) return
cmonger.stop() cert = self.get_cert_from_db(nickname) nsscert = x509.load_certificate(cert, dbdir=self.secdir) subject = str(nsscert.subject) m = re.match('New tracking request "(\d+)" added', stdout) if not m: root_logger.error('Didn\'t get new %s request, got %s' % (cmonger.service_name, stdout)) raise RuntimeError('%s did not issue new tracking request for \'%s\' in \'%s\'. Use \'ipa-getcert list\' to list existing certificates.' % (cmonger.service_name, nickname, self.secdir)) request_id = m.group(1)
certmonger.add_principal(request_id, principal) certmonger.add_subject(request_id, subject)
cmonger.start()
""" Tell certmonger to stop tracking the given certificate nickname. """
# Always start certmonger. We can't untrack something if it isn't # running cmonger = ipaservices.knownservices.certmonger ipaservices.knownservices.messagebus.start() cmonger.start() try: certmonger.stop_tracking(self.secdir, nickname=nickname) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error("certmonger failed to stop tracking certificate: %s" % str(e)) cmonger.stop()
""" other_certdb can mean one of two things, depending on the context.
If we are using a self-signed CA then other_certdb contains the CA that will be signing our CSR.
If we are using a dogtag CA then it contains the RA agent key that will issue our cert.
You can override the certificate Subject by specifying a subject.
Returns a certificate in DER format. """ cdb = other_certdb if not cdb: cdb = self if subject is None: subject=self.subject_format % hostname self.request_cert(subject) cdb.issue_server_cert(self.certreq_fname, self.certder_fname) self.add_cert(self.certder_fname, nickname) fd = open(self.certder_fname, "r") dercert = fd.read() fd.close()
os.unlink(self.certreq_fname) os.unlink(self.certder_fname)
return dercert
cdb = other_certdb if not cdb: cdb = self if subject is None: subject=self.subject_format % hostname self.request_cert(subject) cdb.issue_signing_cert(self.certreq_fname, self.certder_fname) self.add_cert(self.certder_fname, nickname) os.unlink(self.certreq_fname) os.unlink(self.certder_fname)
self.create_noise_file() self.setup_cert_request() args = ["-R", "-s", subject, "-o", self.certreq_fname, "-k", certtype, "-g", keysize, "-z", self.noise_fname, "-f", self.passwd_fname] if not self.self_signed_ca: args.append("-a") (stdout, stderr, returncode) = self.run_certutil(args) os.remove(self.noise_fname) return (stdout, stderr)
self.setup_cert_request() if self.self_signed_ca: p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-C", "-c", self.cacert_name, "-i", certreq_fname, "-o", cert_fname, "-m", next_serial(), "-v", self.valid_months, "-f", self.passwd_fname, "-1", "-5"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# Bah - this sucks, but I guess it isn't possible to fully # control this with command line arguments. # # What this is requesting is: # -1 (Create key usage extension) # 2 - Key encipherment # 9 - done # n - not critical # # -5 (Create netscape cert type extension) # 1 - SSL Server # 9 - done # n - not critical p.stdin.write("2\n9\nn\n1\n9\nn\n") p.wait() else: if self.host_name is None: raise RuntimeError("CA Host is not set.")
f = open(certreq_fname, "r") csr = f.readlines() f.close() csr = "".join(csr)
# We just want the CSR bits, make sure there is nothing else csr = pkcs10.strip_header(csr)
params = {'profileId': 'caIPAserviceCert', 'cert_request_type': 'pkcs10', 'requestor_name': 'IPA Installer', 'cert_request': csr, 'xmlOutput': 'true'}
# Send the request to the CA f = open(self.passwd_fname, "r") password = f.readline() f.close() http_status, http_reason_phrase, http_headers, http_body = \ dogtag.https_request(self.host_name, api.env.ca_ee_install_port, "/ca/ee/ca/profileSubmitSSLClient", self.secdir, password, "ipaCert", **params)
if http_status != 200: raise CertificateOperationError(error='Unable to communicate with CMS (%s)' % \ http_reason_phrase)
# The result is an XML blob. Pull the certificate out of that doc = xml.dom.minidom.parseString(http_body) item_node = doc.getElementsByTagName("b64") try: try: cert = item_node[0].childNodes[0].data except IndexError: raise RuntimeError("Certificate issuance failed") finally: doc.unlink()
# base64-decode the result for uniformity cert = base64.b64decode(cert)
# Write the certificate to a file. It will be imported in a later # step. This file will be read later to be imported. f = open(cert_fname, "w") f.write(cert) f.close()
return
self.setup_cert_request() if self.self_signed_ca: p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-C", "-c", self.cacert_name, "-i", certreq_fname, "-o", cert_fname, "-m", next_serial(), "-v", self.valid_months, "-f", self.passwd_fname, "-1", "-5"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# Bah - this sucks, but I guess it isn't possible to fully # control this with command line arguments. # # What this is requesting is: # -1 (Create key usage extension) # 0 - Digital Signature # 5 - Cert signing key # 9 - done # n - not critical # # -5 (Create netscape cert type extension) # 3 - Object Signing # 9 - done # n - not critical p.stdin.write("0\n5\n9\nn\n3\n9\nn\n") p.wait() else: if self.host_name is None: raise RuntimeError("CA Host is not set.")
f = open(certreq_fname, "r") csr = f.readlines() f.close() csr = "".join(csr)
# We just want the CSR bits, make sure there is no thing else csr = pkcs10.strip_header(csr)
params = {'profileId': 'caJarSigningCert', 'cert_request_type': 'pkcs10', 'requestor_name': 'IPA Installer', 'cert_request': csr, 'xmlOutput': 'true'}
# Send the request to the CA f = open(self.passwd_fname, "r") password = f.readline() f.close() http_status, http_reason_phrase, http_headers, http_body = \ dogtag.https_request(self.host_name, api.env.ca_ee_install_port, "/ca/ee/ca/profileSubmitSSLClient", self.secdir, password, "ipaCert", **params) if http_status != 200: raise RuntimeError("Unable to submit cert request")
# The result is an XML blob. Pull the certificate out of that doc = xml.dom.minidom.parseString(http_body) item_node = doc.getElementsByTagName("b64") cert = item_node[0].childNodes[0].data doc.unlink()
# base64-decode the cert for uniformity cert = base64.b64decode(cert)
# Write the certificate to a file. It will be imported in a later # step. This file will be read later to be imported. f = open(cert_fname, "w") f.write(cert) f.close()
return
""" Load a certificate from a PEM file and add minimal trust. """ args = ["-A", "-n", nickname, "-t", "u,u,u", "-i", cert_fname, "-f", self.passwd_fname] self.run_certutil(args)
""" This is the format of Directory Server pin files. """ ipautil.backup_file(self.pin_fname) f = open(self.pin_fname, "w") f.write("Internal (Software) Token:") pwdfile = open(self.passwd_fname) f.write(pwdfile.read()) f.close() pwdfile.close() self.set_perms(self.pin_fname)
""" This is the format of mod_nss pin files. """ ipautil.backup_file(self.pwd_conf) f = open(self.pwd_conf, "w") f.write("internal:") pwdfile = open(self.passwd_fname) f.write(pwdfile.read()) f.close() pwdfile.close() # TODO: replace explicit uid by a platform-specific one self.set_perms(self.pwd_conf, uid="apache")
""" Given a nickname, return a list of the certificates that make up the trust chain. """ root_nicknames = [] p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-O", "-n", nickname], stdout=subprocess.PIPE)
chain = p.stdout.read() chain = chain.split("\n")
for c in chain: m = re.match('\s*"(.*)" \[.*', c) if m: root_nicknames.append(m.groups()[0])
if len(root_nicknames) > 1: # If you pass in the name of a CA to get the chain it may only # return 1 (self-signed). Return that. try: root_nicknames.remove(nickname) except ValueError: # The nickname wasn't in the list pass
# Try to work around a change in the F-11 certutil where untrusted # CA's are not shown in the chain. This will make a default IPA # server installable. if len(root_nicknames) == 0 and self.self_signed_ca: return [self.cacert_name]
return root_nicknames
"""Given a PKCS#12 file, try to find any certificates that do not have a key. The assumption is that these are the root CAs. """ args = ["/usr/bin/pk12util", "-d", self.secdir, "-l", pkcs12_fname, "-k", passwd_fname] if passwd_fname: args = args + ["-w", passwd_fname] try: (stdout, stderr, returncode) = ipautil.run(args) except ipautil.CalledProcessError, e: if e.returncode == 17: raise RuntimeError("incorrect password") else: raise RuntimeError("unknown error using pkcs#12 file")
lines = stdout.split('\n')
# A simple state machine. # 1 = looking for "Certificate:" # 2 = looking for the Friendly name (nickname) nicknames = [] state = 1 for line in lines: if state == 2: m = re.match("\W+Friendly Name: (.*)", line) if m: nicknames.append( m.groups(0)[0]) state = 1 if line == "Certificate:": state = 2
return nicknames
if root_nickname is None: root_logger.debug("Unable to identify root certificate to trust. Continueing but things are likely to fail.") return
if root_nickname[:7] == "Builtin": root_logger.debug("No need to add trust for built-in root CA's, skipping %s" % root_nickname) else: try: self.run_certutil(["-M", "-n", root_nickname, "-t", "CT,CT,"]) except ipautil.CalledProcessError, e: root_logger.error("Setting trust on %s failed" % root_nickname)
p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, "-L"], stdout=subprocess.PIPE)
certs = p.stdout.read()
certs = certs.split("\n")
server_certs = []
for cert in certs: fields = cert.split() if not len(fields): continue flags = fields[-1] if 'u' in flags: name = " ".join(fields[0:-1]) # NSS 3.12 added a header to the certutil output if name == "Certificate Nickname Trust": continue server_certs.append((name, flags))
return server_certs
args = ["/usr/bin/pk12util", "-d", self.secdir, "-i", pkcs12_fname, "-k", self.passwd_fname] if passwd_fname: args = args + ["-w", passwd_fname] try: ipautil.run(args) except ipautil.CalledProcessError, e: if e.returncode == 17: raise RuntimeError("incorrect password") else: raise RuntimeError("unknown error import pkcs#12 file")
if nickname is None: nickname = get_ca_nickname(api.env.realm)
ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname])
nickname, pem_fname): ipautil.run(["/usr/bin/openssl", "pkcs12", "-export", "-name", nickname, "-in", pem_fname, "-out", pkcs12_fname, "-passout", "file:" + pkcs12_pwd_fname])
self.create_noise_file() self.create_passwd_file(passwd) self.create_certdbs() self.create_ca_cert() self.export_ca_cert(self.cacert_name, True) self.create_pin_file()
if ipautil.file_exists(self.certdb_fname): # We already have a cert db, see if it is for the same CA. # If it is we leave things as they are. f = open(cacert_fname, "r") newca = f.readlines() f.close() newca = "".join(newca) (newca, st) = find_cert_from_txt(newca)
cacert = self.get_cert_from_db(self.cacert_name) if cacert != '': (cacert, st) = find_cert_from_txt(cacert)
if newca == cacert: return
# The CA certificates are different or something went wrong. Start with # a new certificate database. self.create_passwd_file(passwd) self.create_certdbs() self.load_cacert(cacert_fname)
"""Create a new NSS database using the certificates in a PKCS#12 file.
pkcs12_fname: the filename of the PKCS#12 file pkcs12_pwd_fname: the file containing the pin for the PKCS#12 file nickname: the nickname/friendly-name of the cert we are loading passwd: The password to use for the new NSS database we are creating
The global CA may be added as well in case it wasn't included in the PKCS#12 file. Extra certs won't hurt in any case. """ self.create_noise_file() self.create_passwd_file(passwd) self.create_certdbs() self.import_pkcs12(pkcs12_fname, pkcs12_pwd_fname) server_certs = self.find_server_certs() if len(server_certs) == 0: raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_fname)
# We only handle one server cert nickname = server_certs[0][0]
ca_names = self.find_root_cert_from_pkcs12(pkcs12_fname, pkcs12_pwd_fname) if len(ca_names) == 0: raise RuntimeError("Could not find a CA cert in %s" % pkcs12_fname)
self.cacert_name = ca_names[0] for ca in ca_names: self.trust_root_cert(ca)
self.create_pin_file() self.export_ca_cert(nickname, False) self.self_signed_ca=False
# This file implies that we have our own self-signed CA. Ensure # that it no longer exists (from previous installs, for example). try: os.remove(CA_SERIALNO) except: pass
"""Create a new certificate with the spcial othername encoding needed by a KDC certificate.
nickname: the CN name set in the certificate destdir: the location where cert and key are to be installed
destdir will contain kdc.pem if the operation is successful """
reqcfg = "kdc_req.conf" extcfg = ipautil.SHARE_DIR + "kdc_extensions.template" key_fname = destdir + "/kdckey.pem" cert_fname = destdir + "/kdccert.pem" key_cert_fname = destdir + "/kdc.pem"
# Setup the temp dir self.setup_cert_request()
# Copy the CA password file because openssl apparently can't use # the same file twice within the same command and throws an error ca_pwd_file = self.reqdir + "pwdfile.txt" shutil.copyfile(self.passwd_fname, ca_pwd_file)
# Extract the cacert.pem file used by openssl to sign the certs ipautil.run(["/usr/bin/openssl", "pkcs12", "-in", self.pk12_fname, "-passin", "file:" + self.passwd_fname, "-passout", "file:" + ca_pwd_file, "-out", "cacert.pem"])
# Create the kdc key ipautil.run(["/usr/bin/openssl", "genrsa", "-out", key_fname, "2048"])
# Prepare a simple cert request req_dict = dict(PASSWORD=self.gen_password(), SUBJBASE=self.subject_base, CERTNAME="CN="+nickname) req_template = ipautil.SHARE_DIR + reqcfg + ".template" conf = ipautil.template_file(req_template, req_dict) fd = open(reqcfg, "w+") fd.write(conf) fd.close()
base = self.subject_base.replace(",", "/") esc_subject = "CN=%s/%s" % (nickname, base)
ipautil.run(["/usr/bin/openssl", "req", "-new", "-config", reqcfg, "-subj", esc_subject, "-key", key_fname, "-out", "kdc.req"])
# Finally, sign the cert using the extensions file to set the # special name ipautil.run(["/usr/bin/openssl", "x509", "-req", "-CA", "cacert.pem", "-extfile", extcfg, "-extensions", "kdc_cert", "-passin", "file:" + ca_pwd_file, "-set_serial", next_serial(), "-in", "kdc.req", "-out", cert_fname], env = { 'REALM':self.realm, 'HOST_FQDN':hostname })
# Merge key and cert in a single file fd = open(key_fname, "r") key = fd.read() fd.close() fd = open(cert_fname, "r") cert = fd.read() fd.close() fd = open(key_cert_fname, "w") fd.write(key) fd.write(cert) fd.close() os.unlink(key_fname) os.unlink(cert_fname)
ipautil.run(["/usr/bin/openssl", "pkcs12", "-nodes", "-in", p12_fname, "-out", pem_fname, "-passin", "file:" + p12_pwd_fname])
self.fstore.backup_file(self.noise_fname) self.fstore.backup_file(self.passwd_fname) self.fstore.backup_file(self.certdb_fname) self.fstore.backup_file(self.keydb_fname) self.fstore.backup_file(self.secmod_fname) self.fstore.backup_file(self.cacert_fname) self.fstore.backup_file(self.pk12_fname) self.fstore.backup_file(self.pin_fname) self.fstore.backup_file(self.certreq_fname) self.fstore.backup_file(self.certder_fname)
shutil.copy(self.cacert_fname, location) os.chmod(location, 0444) |