Commit a265c45e authored by ale's avatar ale
Browse files

the "autoca" tool can now use a local CA

parent a0f28b37
......@@ -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
......@@ -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('/')
......@@ -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 =
ca = ca_stub.CaStub(opts.url, secret)
if opts.url:
client = ca_stub.CaStub(opts.url, secret)
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,
pkey, cert = client.make_certificate(subject, days=opts.days,
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.'
parser.error('Unknown command')
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment