summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xfunc/certmaster.py70
-rwxr-xr-xscripts/certmaster-ca70
2 files changed, 129 insertions, 11 deletions
diff --git a/func/certmaster.py b/func/certmaster.py
index 89b68a0..be10814 100755
--- a/func/certmaster.py
+++ b/func/certmaster.py
@@ -1,5 +1,9 @@
#!/usr/bin/python
+# FIXME: Perms checked and okayed on all csr, certs and keys, everywhere
+# FIXME: picky about bogus CN names ../ ../ ./ etc, etc to avoid stupid attacks
+# FIXME: more intelligent fault raises
+
"""
cert master listener
@@ -24,6 +28,7 @@ import os.path
import traceback
from OpenSSL import crypto
import sha
+import glob
#from func.server import codes
import func
@@ -95,8 +100,7 @@ class CertMaster(object):
if method in self.handlers.keys():
return self.handlers[method](*params)
else:
- pass
- #raise codes.InvalidMethodException
+ raise func.codes.InvalidMethodException
def wait_for_cert(self, csrbuf):
@@ -113,7 +117,7 @@ class CertMaster(object):
return False, '', ''
requesting_host = csrreq.get_subject().CN
- certfile = '%s/%s.pem' % (self.cfg.certroot, requesting_host)
+ certfile = '%s/%s.cert' % (self.cfg.certroot, requesting_host)
csrfile = '%s/%s.csr' % (self.cfg.csrroot, requesting_host)
# check for old csr on disk
@@ -145,14 +149,8 @@ class CertMaster(object):
# else write out the csr
if self.cfg.autosign:
- slavecert = func.certs.create_slave_certificate(csrreq,
- self.cakey, self.cacert, self.cfg.cadir)
-
- destfo = open(certfile, 'w')
- destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, slavecert))
- destfo.close()
- del destfo
- cert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, slavecert)
+ cert_fn = self.sign_this_csr(csrreq)
+ cert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, cert_fn)
cacert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cacert)
return True, cert_buf, cacert_buf
@@ -166,6 +164,56 @@ class CertMaster(object):
return False, '', ''
+ def get_csrs_waiting(self):
+ hosts = []
+ csrglob = '%s/*.csr' % self.cfg.csrroot
+ csr_list = glob.glob(csrglob)
+ for f in csr_list:
+ hn = os.path.basename(f)
+ hn = hn[:-4]
+ hosts.append(hn)
+ return hosts
+
+
+ def sign_this_csr(self, csr):
+ """returns the path to the signed cert file"""
+ csr_unlink_file = None
+
+ if type(csr) is type(''):
+ if csr.startswith('/') and os.path.exists(csr): # we have a full path to the file
+ csrfo = open(csr)
+ csr_buf = csrfo.read()
+ csr_unlink_file = csr
+
+ elif os.path.exists('%s/%s' % (self.cfg.csrroot, csr)): # we have a partial path?
+ csrfo = open('%s/%s' % (self.cfg.csrroot, csr))
+ csr_buf = csrfo.read()
+ csr_unlink_file = '%s/%s' % (self.cfg.csrroot, csr)
+
+ # we have a string of some kind
+ else:
+ csr_buf = csr
+
+ try:
+ csrreq = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr_buf)
+ except crypto.Error, e:
+ print 'Bad CSR: %s' % csr
+
+ else: # assume we got a bare csr req
+ csrreq = csr
+ requesting_host = csrreq.get_subject().CN
+ certfile = '%s/%s.cert' % (self.cfg.certroot, requesting_host)
+ thiscert = func.certs.create_slave_certificate(csrreq, self.cakey, self.cacert, self.cfg.cadir)
+ destfo = open(certfile, 'w')
+ destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, thiscert))
+ destfo.close()
+ del destfo
+ if csr_unlink_file and os.path.exists(csr_unlink_file):
+ os.unlink(csr_unlink_file)
+
+ return certfile
+
+
class CertmasterXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
def __init__(self, args):
self.allow_reuse_address = True
diff --git a/scripts/certmaster-ca b/scripts/certmaster-ca
new file mode 100755
index 0000000..14f7c2f
--- /dev/null
+++ b/scripts/certmaster-ca
@@ -0,0 +1,70 @@
+#!/usr/bin/python -tt
+# sign/list keys
+# --sign hostname hostname hostname
+# --list # lists all csrs needing to be signed
+# --list-all ?
+# --clean? not sure what it will do
+
+import sys
+
+import func
+import func.certs
+import func.certmaster
+
+
+
+from optparse import OptionParser
+defaults = { 'listen_addr': 'localhost',
+ 'listen_port': '51235',
+ 'cadir': '/etc/pki/func/ca',
+ 'certroot': '/var/lib/func/certmaster/certs',
+ 'csrroot': '/var/lib/func/certmaster/csrs',
+ 'autosign': 'false'
+ }
+
+def errorprint(stuff):
+ print >> sys.stderr, stuff
+
+
+def parseargs(args):
+ usage = 'certmaster-ca [options]'
+ parser = OptionParser(usage=usage)
+
+ parser.add_option('-l', '--list', default=False, action="store_true",
+ help='list signing requests remaining')
+ parser.add_option('-s', '--sign', default=False, action="store_true",
+ help='sign requests of hosts specified')
+
+ (opts, args) = parser.parse_args()
+ # XXX FIXME check for obviously impossible things and exit, etc
+
+ return (opts, args)
+
+def main(args):
+ cm = func.certmaster.CertMaster('/etc/func/certmaster.conf', defaults)
+
+ (opts, args) = parseargs(args)
+ if opts.list:
+ hns = cm.get_csrs_waiting()
+ if hns:
+ for hn in cm.get_csrs_waiting():
+ print hn
+ else:
+ print 'No certificates to sign'
+
+ return 0
+
+ if opts.sign:
+ if not args:
+ errorprint('Need hostnames to sign')
+ return 1
+
+ for hn in args:
+ csrfile = '%s/%s.csr' % (cm.cfg.csrroot, hn)
+ certfile = cm.sign_this_csr(csrfile)
+ print '%s signed - cert located at %s' % (hn, certfile)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))