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