Add pyx509/pyasn1 based tool to create sslcert directives
[cacert-infradocs.git] / tools / sslcert.py
1 #!/usr/bin/env python2
2
3 from __future__ import print_function
4
5 from datetime import datetime
6 from hashlib import sha1
7 import argparse
8 import os.path
9
10 from pyasn1_modules import pem
11 from pyx509.pkcs7.asn1_models.X509_certificate import Certificate
12 from pyx509.pkcs7_models import X509Certificate
13 from pyx509.pkcs7.asn1_models.decoder_workarounds import decode
14
15
16 ALTNAME_MAP = (
17 ('dNSName', 'DNS'),
18 ('rfc822Name', 'EMAIL'),
19 ('iPAddress', 'IP')
20 )
21
22
23 def x509_parse(derData):
24 """Decodes certificate.
25 @param derData: DER-encoded certificate string
26 @returns: pkcs7_models.X509Certificate
27 """
28 cert = decode(derData, asn1Spec=Certificate())[0]
29 x509cert = X509Certificate(cert)
30 return x509cert
31
32
33 def get_altnames(cert):
34 altnames = cert.tbsCertificate.subjAltNameExt.value.values
35 retval = []
36 for typ, data in [(field[1], altnames[field[0]]) for field in ALTNAME_MAP]:
37 for item in sorted(data):
38 retval.append("{typ}:{item}".format(typ=typ, item=item))
39 return ", ".join(retval)
40
41
42 def get_serial(cert):
43 serial = "%X" % cert.tbsCertificate.serial_number
44 return "0" * (len(serial) % 2) + serial
45
46
47 def get_expiration(cert):
48 return datetime.strptime(
49 cert.tbsCertificate.validity.valid_to, '%Y%m%d%H%M%SZ'
50 ).strftime('%b %d %Y %H:%M:%S GMT')
51
52
53 def get_sha1fp(certdata):
54 hexhash = sha1(certdata).hexdigest().upper()
55 return ":".join([hexhash[i:i+2] for i in range(0, len(hexhash), 2)])
56
57
58 def get_issuer(cert):
59 return cert.tbsCertificate.issuer.get_attributes()['CN'][0]
60
61
62 def get_subject(cert):
63 return cert.tbsCertificate.subject.get_attributes()['CN'][0]
64
65
66 if __name__ == '__main__':
67 parser = argparse.ArgumentParser(
68 description=(
69 'Create an sslcert directive from data taken from a PEM encoded '
70 'X.509 certificate file and its corresponding PEM encoded RSA key '
71 'file.'))
72 parser.add_argument(
73 'cert', metavar='CERT', type=open,
74 help='PEM encoded X.509 certficate file')
75 parser.add_argument(
76 '--key', metavar='KEY', type=open,
77 help='PEM encoded RSA private key', default=None)
78 args = parser.parse_args()
79
80 certpem = pem.readPemFromFile(args.cert)
81 certpath = os.path.abspath(args.cert.name)
82 if args.key:
83 haskey = True
84 keypem = pem.readPemFromFile(args.key)
85 keypath = os.path.abspath(args.key.name)
86 else:
87 keypath = 'TODO: define key path'
88
89 cert = x509_parse(certpem)
90 data = {
91 'altnames': get_altnames(cert),
92 'certfile': certpath,
93 'keyfile': keypath,
94 'serial': get_serial(cert),
95 'expiration': get_expiration(cert),
96 'sha1fp': get_sha1fp(certpem),
97 'issuer': get_issuer(cert),
98 'subject': get_subject(cert),
99 }
100 print(""".. sslcert:: {subject}
101 :altnames: {altnames}
102 :certfile: {certfile}
103 :keyfile: {keyfile}
104 :serial: {serial}
105 :expiration: {expiration}
106 :sha1fp: {sha1fp}
107 :issuer: {issuer}
108 """.format(**data))