22b97588c628ca9b9e13afd866f5e6087bdbc3d2
[stack/cam.git] / cam / main.py
1 #!/usr/bin/python
2
3 import logging
4 import optparse
5 import os
6 import sys
7 import time
8 from cam import config
9
10
11 USAGE = '''cam [<OPTIONS>] <COMMAND> [<ARG>...]
12 CAM v%(version)s - (c)2012-2014 by <ale@incal.net> 
13 Minimal X509 Certification Authority management tool.
14
15 Known commands:
16
17   init [<RSA_CRT>]
18     Initialize the environment and create a new CA certificate
19     (you can also import an existing certificate)
20
21   gen <TAG>...
22     Create (or re-create) the certificates corresponding
23     to TAG
24
25   gencrl
26     Update the CRL
27
28   list
29     List all known certificates
30
31   fp [<TAG>...]
32     Print SHA1/MD5 fingerprints of certificates
33
34   files <TAG>...
35     Dump all the certificate-related files of this TAG
36
37   check 
38     Should be run weekly from a cron job to warn you if some
39     certificates are about to expire (controlled by the 'warning_days'
40     parameter in the 'global' section of the configuration)
41
42 The configuration file consists of a ini-style file, with a 'ca'
43 section that specifies global CA parameters, and more sections for
44 each tag with certificate-specific information. See the documentation
45 for more details on how to write your own configuration.
46
47 Run `cam --help' to get a list of available command-line options.
48
49 ''' % {'version': '2.1'}
50
51
52 def find_cert(certs, name):
53     for c in certs:
54         if c.name == name:
55             return c
56     raise Exception('Certificate "%s" not found' % name)
57
58
59 def cmd_init(global_config, ca, certs, args):
60     ca.create()
61
62
63 def cmd_gen(global_config, ca, certs, args):
64     if len(args) < 1:
65         print 'Nothing to do.'
66     for tag in args:
67         ca.generate(find_cert(certs, tag))
68
69
70 def cmd_gencrl(global_config, ca, certs, args):
71     ca.gencrl()
72
73
74 def cmd_files(global_config, ca, certs, args):
75     if len(args) < 1:
76         print 'Nothing to do.'
77     for tag in args:
78         c = find_cert(certs, tag)
79         print c.public_key_file
80         print c.private_key_file
81
82
83 def cmd_list(global_config, ca, certs, args):
84     now = time.time()
85     for cert in sorted(certs, key=lambda x: x.name):
86         expiry = cert.get_expiration_date()
87         state = 'OK'
88         expiry_str = ''
89         if not expiry:
90             state = 'MISSING'
91         else:
92             if expiry < now:
93                 state = 'EXPIRED'
94             expiry_str = time.strftime('%Y/%m/%d', time.gmtime(expiry))
95         print cert.name, cert.cn, state, expiry_str
96
97
98 def cmd_fingerprint(global_config, ca, certs, args):
99     if len(args) > 0:
100         certs = [find_cert(certs, x) for x in args]
101     for cert in certs:
102         print cert.name, cert.cn
103         print '  SHA1:', cert.get_fingerprint('sha1')
104         print '  MD5:', cert.get_fingerprint('md5')
105
106
107 def cmd_check(global_config, ca, certs, args):
108     now = time.time()
109     warning_time = 86400 * int(global_config.get('warning_days', 15))
110     retval = 0
111     for cert in certs:
112         exp = cert.get_expiration_date()
113         if exp and (exp - now) < warning_time:
114             print '%s (%s) is about to expire.' % (cert.name, cert.cn)
115             retval = 1
116     return retval
117
118
119 cmd_table = {
120     'init': cmd_init,
121     'gen': cmd_gen,
122     'gencrl': cmd_gencrl,
123     'files': cmd_files,
124     'list': cmd_list,
125     'fp': cmd_fingerprint,
126     'fingerprint': cmd_fingerprint,
127     'check': cmd_check,
128 }
129
130
131 def main():
132     parser = optparse.OptionParser(usage=USAGE)
133     parser.add_option('-d', '--debug', dest='debug', help='Be verbose',
134                       action='store_true')
135     parser.add_option('-c', '--config', dest='config', help='Config file')
136     opts, args = parser.parse_args()
137
138     if len(args) > 0 and args[0] == 'help':
139         parser.print_help()
140         return 0
141     if not opts.config:
142         parser.error('Must specify --config')
143     if len(args) < 1:
144         parser.error('Must specify a command')
145
146     logging.basicConfig(
147         format='cam: %(levelname)s: %(message)s',
148         level=logging.DEBUG if opts.debug else logging.INFO)
149
150     try:
151         global_config, ca, certs = config.read_config(opts.config)
152         try:
153             cmd, args = args[0], args[1:]
154             if cmd not in cmd_table:
155                 parser.error('unknown command "%s"' % cmd)
156             cmdfn = cmd_table[cmd]
157             return cmdfn(global_config, ca, certs, args)
158         finally:
159             ca.close()
160     except Exception as e:
161         if opts.debug:
162             logging.exception(e)
163         else:
164             logging.error(e)
165         return 1
166
167
168 def main_wrapper():
169     try:
170         return main()
171     except Exception, e:
172         logging.exception('uncaught exception')
173         return 1
174
175
176 if __name__ == '__main__':
177     sys.exit(main_wrapper())