From a265c45e38eb0d4470671c3d6ba9cf539c647eb0 Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Sun, 20 Apr 2014 15:46:30 +0100 Subject: [PATCH] the "autoca" tool can now use a local CA --- autoca/ca.py | 1 + autoca/ca_stub.py | 1 + autoca/ca_tool.py | 36 +++++++++++++++++++++++++++++------- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/autoca/ca.py b/autoca/ca.py index 0461ecd..33ffefb 100644 --- a/autoca/ca.py +++ b/autoca/ca.py @@ -11,6 +11,7 @@ log = logging.getLogger(__name__) class CA(object): + """A Certification Authority stored on the local filesystem.""" def __init__(self, root, subject, bits=1024, digest='sha1'): self.ca_subject = subject diff --git a/autoca/ca_stub.py b/autoca/ca_stub.py index 3a208de..d5c7f30 100644 --- a/autoca/ca_stub.py +++ b/autoca/ca_stub.py @@ -14,6 +14,7 @@ class Error(Exception): class CaStub(object): + """Client stub for a remote CA.""" def __init__(self, url, secret=None): self.url = url.rstrip('/') diff --git a/autoca/ca_tool.py b/autoca/ca_tool.py index 40c9570..546da8a 100644 --- a/autoca/ca_tool.py +++ b/autoca/ca_tool.py @@ -3,6 +3,7 @@ import os import logging import sys from OpenSSL import crypto +from autoca import ca from autoca import ca_stub from autoca import certutil @@ -21,6 +22,8 @@ def main(): parser = optparse.OptionParser() parser.add_option('--url', dest='url', help='autoca API endpoint') + parser.add_option('--ca-path', dest='ca_path', + help='local CA directory') parser.add_option('--output', dest='output', metavar='FILE', help='write output to this file') parser.add_option('--outkey', dest='outkey', metavar='FILE', @@ -31,6 +34,10 @@ def main(): parser.add_option('--subject', dest='subject', help='specify the X.509 subject as a set of ' 'comma-separated ATTR=VALUE assignments') + parser.add_option('--ca-subject', dest='ca_subject', + help='CA X.509 subject (only on initialization)') + parser.add_option('--ca-bits', dest='ca_bits', type='int', default=1024, + help='CA key size (only on initialization)') parser.add_option('--secret', dest='secret', help='shared secret for authentication') parser.add_option('--days', dest='days', type='int', default=7, @@ -38,8 +45,10 @@ def main(): opts, args = parser.parse_args() if len(args) < 1: parser.error('No command specified') - if not opts.url: - parser.error('Must specify --url') + if not opts.url and not opts.ca_path: + parser.error('Must specify one of --url or --ca-path') + if opts.url and opts.ca_path: + parser.error('Must specify at most one of --url or --ca-path') secret = opts.secret if not secret: @@ -47,26 +56,39 @@ def main(): with open(os.getenv('AUTOCA_SECRET'), 'r') as fd: secret = fd.read().strip() - ca = ca_stub.CaStub(opts.url, secret) + if opts.url: + client = ca_stub.CaStub(opts.url, secret) + else: + ca_subject = None + if opts.ca_subject: + ca_subject = certutil.parse_subject(opts.ca_subject) + client = ca.CA(opts.ca_path, ca_subject, opts.ca_bits) cmd, args = args[0], args[1:] if cmd == 'get-ca': - writeout(opts.output, ca.get_ca()) + writeout(opts.output, client.get_ca()) elif cmd == 'get-crl': fmt = 'pem' if args: fmt = args[0].lower() - writeout(opts.output, ca.get_crl(format=fmt)) + writeout(opts.output, client.get_crl(format=fmt)) elif cmd == 'sign': if not opts.subject: parser.error('Must specify --subject') subject = certutil.parse_subject(opts.subject) - pkey, cert = ca.make_certificate(subject, days=opts.days, - server=opts.server) + pkey, cert = client.make_certificate(subject, days=opts.days, + server=opts.server) writeout(opts.output, crypto.dump_certificate( crypto.FILETYPE_PEM, cert)) writeout(opts.outkey, crypto.dump_privatekey( crypto.FILETYPE_PEM, pkey)) + elif cmd == 'init': + if not opts.ca_subject: + parser.error('Must specify --ca-subject') + if not opts.ca_path: + parser.error('The "init" command is only valid with a local CA') + # Nothing to do, actually. + print 'Done.' else: parser.error('Unknown command') -- GitLab