summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-07-29 11:27:11 -0400
committerRob Crittenden <rcritten@redhat.com>2009-07-30 13:55:29 -0400
commit8ab2977eeb79571ed6f976a12a51ed2b75cdc12b (patch)
tree7474f87987ae53a5b197114870b2d5ccad61d500
parentd2e1de019b13ba2b322fb7668b6c6ff664ae3b1a (diff)
downloadfreeipa-8ab2977eeb79571ed6f976a12a51ed2b75cdc12b.tar.gz
freeipa-8ab2977eeb79571ed6f976a12a51ed2b75cdc12b.tar.xz
freeipa-8ab2977eeb79571ed6f976a12a51ed2b75cdc12b.zip
Backport certs.py patches from master.
Fix deprecation warning for the sha library on Python 2.6 sha has been replaced by hashlib. We need to support Python 2.4 - 2.6 so this will use hashlib if available but fall back onto sha if not. Fortunately they use the same API for the function we need. 509042 Identify CAs to trust from an imported PKCS#12 file We used to use certutil -O to determine the cert chain to trust. This behavior changed in F-11 such that untrusted CAs are not displayed. This is only used when we import PKCS#12 files so use pk12util -l to display the list of certs and keys in the file to determine the nickname(s) of the CAs to trust. 509111 No need to trust NSS built-in CA's, more specific regex for finding CA nickname - Add some logging so we have a better idea of what happened if things fail - Default to self-signed CA to trust if one is not found. This will fix the self-signed CA case where certutil doesn't return untrusted CA's in -O output. - Remove unused httplib import
-rw-r--r--ipa-server/ipaserver/certs.py73
1 files changed, 63 insertions, 10 deletions
diff --git a/ipa-server/ipaserver/certs.py b/ipa-server/ipaserver/certs.py
index 8cb1d088..cc4211c2 100644
--- a/ipa-server/ipaserver/certs.py
+++ b/ipa-server/ipaserver/certs.py
@@ -18,14 +18,21 @@
#
import os, stat, subprocess, re
-import sha
import errno
import tempfile
import shutil
+import logging
from ipa import sysrestore
from ipa import ipautil
+# The sha module is deprecated in Python 2.6, replaced by hashlib. Try
+# that first and fall back to sha.sha if it isn't available.
+try:
+ from hashlib import sha256 as sha
+except ImportError:
+ from sha import sha
+
CA_SERIALNO="/var/lib/ipa/ca_serialno"
class CertDB(object):
@@ -118,7 +125,7 @@ class CertDB(object):
os.chmod(fname, perms)
def gen_password(self):
- return sha.sha(ipautil.ipa_generate_password()).hexdigest()
+ return sha(ipautil.ipa_generate_password()).hexdigest()
def run_certutil(self, args, stdin=None):
new_args = ["/usr/bin/certutil", "-d", self.secdir]
@@ -311,15 +318,55 @@ class CertDB(object):
chain = p.stdout.read()
chain = chain.split("\n")
- root_nickname = re.match('\ *"(.*)".*', chain[0]).groups()[0]
+ root_nickname = re.match('\ *"(.*)" \[.*', chain[0]).groups()[0]
return root_nickname
- def trust_root_cert(self, nickname):
- root_nickname = self.find_root_cert(nickname)
-
- self.run_certutil(["-M", "-n", root_nickname,
- "-t", "CT,CT,"])
+ def find_root_cert_from_pkcs12(self, pkcs12_fname, passwd_fname=None):
+ """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) = 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
+
+ def trust_root_cert(self, root_nickname):
+ if root_nickname is None:
+ logging.debug("Unable to identify root certificate to trust. Continuing but things are likely to fail.")
+ return
+
+ if root_nickname[:7] == "Builtin":
+ logging.debug("No need to add trust for built-in root CA's, skipping %s" % root_nickname)
+ else:
+ self.run_certutil(["-M", "-n", root_nickname,
+ "-t", "CT,CT,"])
def find_server_certs(self):
p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir,
@@ -399,8 +446,14 @@ class CertDB(object):
# We only handle one server cert
nickname = server_certs[0][0]
- self.cacert_name = self.find_root_cert(nickname)
- self.trust_root_cert(nickname)
+ 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 nickname in ca_names:
+ self.trust_root_cert(nickname)
+
self.create_pin_file()
self.export_ca_cert(self.cacert_name, False)