Commit a265c45e authored by ale's avatar ale

the "autoca" tool can now use a local CA

parent a0f28b37
...@@ -11,6 +11,7 @@ log = logging.getLogger(__name__) ...@@ -11,6 +11,7 @@ log = logging.getLogger(__name__)
class CA(object): class CA(object):
"""A Certification Authority stored on the local filesystem."""
def __init__(self, root, subject, bits=1024, digest='sha1'): def __init__(self, root, subject, bits=1024, digest='sha1'):
self.ca_subject = subject self.ca_subject = subject
...@@ -14,6 +14,7 @@ class Error(Exception): ...@@ -14,6 +14,7 @@ class Error(Exception):
class CaStub(object): class CaStub(object):
"""Client stub for a remote CA."""
def __init__(self, url, secret=None): def __init__(self, url, secret=None):
self.url = url.rstrip('/') self.url = url.rstrip('/')
...@@ -3,6 +3,7 @@ import os ...@@ -3,6 +3,7 @@ import os
import logging import logging
import sys import sys
from OpenSSL import crypto from OpenSSL import crypto
from autoca import ca
from autoca import ca_stub from autoca import ca_stub
from autoca import certutil from autoca import certutil
...@@ -21,6 +22,8 @@ def main(): ...@@ -21,6 +22,8 @@ def main():
parser = optparse.OptionParser() parser = optparse.OptionParser()
parser.add_option('--url', dest='url', parser.add_option('--url', dest='url',
help='autoca API endpoint') help='autoca API endpoint')
parser.add_option('--ca-path', dest='ca_path',
help='local CA directory')
parser.add_option('--output', dest='output', metavar='FILE', parser.add_option('--output', dest='output', metavar='FILE',
help='write output to this file') help='write output to this file')
parser.add_option('--outkey', dest='outkey', metavar='FILE', parser.add_option('--outkey', dest='outkey', metavar='FILE',
...@@ -31,6 +34,10 @@ def main(): ...@@ -31,6 +34,10 @@ def main():
parser.add_option('--subject', dest='subject', parser.add_option('--subject', dest='subject',
help='specify the X.509 subject as a set of ' help='specify the X.509 subject as a set of '
'comma-separated ATTR=VALUE assignments') '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', parser.add_option('--secret', dest='secret',
help='shared secret for authentication') help='shared secret for authentication')
parser.add_option('--days', dest='days', type='int', default=7, parser.add_option('--days', dest='days', type='int', default=7,
...@@ -38,8 +45,10 @@ def main(): ...@@ -38,8 +45,10 @@ def main():
opts, args = parser.parse_args() opts, args = parser.parse_args()
if len(args) < 1: if len(args) < 1:
parser.error('No command specified') parser.error('No command specified')
if not opts.url: if not opts.url and not opts.ca_path:
parser.error('Must specify --url') 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 secret = opts.secret
if not secret: if not secret:
...@@ -47,26 +56,39 @@ def main(): ...@@ -47,26 +56,39 @@ def main():
with open(os.getenv('AUTOCA_SECRET'), 'r') as fd: with open(os.getenv('AUTOCA_SECRET'), 'r') as fd:
secret = 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:] cmd, args = args[0], args[1:]
if cmd == 'get-ca': if cmd == 'get-ca':
writeout(opts.output, ca.get_ca()) writeout(opts.output, client.get_ca())
elif cmd == 'get-crl': elif cmd == 'get-crl':
fmt = 'pem' fmt = 'pem'
if args: if args:
fmt = args[0].lower() fmt = args[0].lower()
writeout(opts.output, ca.get_crl(format=fmt)) writeout(opts.output, client.get_crl(format=fmt))
elif cmd == 'sign': elif cmd == 'sign':
if not opts.subject: if not opts.subject:
parser.error('Must specify --subject') parser.error('Must specify --subject')
subject = certutil.parse_subject(opts.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,
server=opts.server) server=opts.server)
writeout(opts.output, crypto.dump_certificate( writeout(opts.output, crypto.dump_certificate(
crypto.FILETYPE_PEM, cert)) crypto.FILETYPE_PEM, cert))
writeout(opts.outkey, crypto.dump_privatekey( writeout(opts.outkey, crypto.dump_privatekey(
crypto.FILETYPE_PEM, pkey)) 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: else:
parser.error('Unknown command') 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