diff --git a/csrgen.py b/csrgen.py new file mode 100644 index 0000000..b588d30 --- /dev/null +++ b/csrgen.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# +# Generate a key, self-signed certificate, and certificate request. +# Usage: csrgen +# +# When more than one hostname is provided, a SAN (Subject Alternate Name) +# certificate and request are generated. This can be acheived by adding -s. +# Usage: csrgen -s +# +# Author: Courtney Cotton 06-25-2014 + +# Libraries/Modules +from OpenSSL import crypto, SSL +import subprocess, os, sys, shutil +import argparse + +# Generate Certificate Signing Request (CSR) +def generateCSR(nodename, sans = []): + + C = 'US' + ST = 'New York' + L = 'Location' + O = 'Organization' + OU = 'Organizational Unit' + + csrfile = 'host.csr' + keyfile = 'host.key' + TYPE_RSA = crypto.TYPE_RSA + # Appends SAN to have 'DNS:' + ss = [] + for i in sans: + ss.append("DNS: %s" % i) + ss = ", ".join(ss) + + req = crypto.X509Req() + req.get_subject().CN = nodename + req.get_subject().countryName = C + req.get_subject().stateOrProvinceName = ST + req.get_subject().localityName = L + req.get_subject().organizationName = O + req.get_subject().organizationalUnitName = OU + # Add in extensions + base_constraints = ([ + crypto.X509Extension("keyUsage", False, "Digital Signature, Non Repudiation, Key Encipherment"), + crypto.X509Extension("basicConstraints", False, "CA:FALSE"), + ]) + x509_extensions = base_constraints + # If there are SAN entries, append the base_constraints to include them. + if ss: + san_constraint = crypto.X509Extension("subjectAltName", False, ss) + x509_extensions.append(san_constraint) + req.add_extensions(x509_extensions) + # Utilizes generateKey function to kick off key generation. + key = generateKey(TYPE_RSA, 2048) + req.set_pubkey(key) + req.sign(key, "sha1") + generateFiles(csrfile, req) + generateFiles(keyfile, key) + return req + +# Generate Private Key +def generateKey(type, bits): + + key = crypto.PKey() + key.generate_key(type, bits) + return key + +# Generate .csr/key files. +def generateFiles(mkFile, request): + + if mkFile == 'host.csr': + f = open(mkFile, "w") + f.write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, request)) + f.close() + print crypto.dump_certificate_request(crypto.FILETYPE_PEM, request) + elif mkFile == 'host.key': + f = open(mkFile, "w") + f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, request)) + f.close() + else: + print "Failed." + exit() + + +# Run Portion +parser = argparse.ArgumentParser() +parser.add_argument("name", help="Provide the FQDN", action="store") +parser.add_argument("-s", "--san", help="SANS", action="store", nargs='*', default="") +args = parser.parse_args() + +hostname = args.name +sans = args.san + +generateCSR(hostname, sans)