Updated license file, added ssl cert tool

This commit is contained in:
aewens 2018-12-31 14:48:02 -06:00
parent 5a34bacaf5
commit 0b05ab06e5
2 changed files with 288 additions and 1 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner> . All rights reserved.
Copyright (c) 2018-2019 Austin Ewens. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

287
bin/sslca Normal file
View File

@ -0,0 +1,287 @@
#!/usr/bin/env python
from os import system, popen, makedirs
from os.path import exists, dirname, isfile, realpath
from sys import exit
from errno import EEXIST
from string import digits, ascii_uppercase as upper
from random import SystemRandom
from argparse import ArgumentParser
from ConfigParser import ConfigParser
from getpass import getpass
class SSLCA:
_path = "%s/etc" % dirname(dirname(realpath(__file__)))
ver = "0.1.0"
def __init__(self):
self.config = ConfigParser()
if not exists(self._path):
try:
makedirs(self._path)
except OSError as e:
if e.errno != EEXIST:
raise
config_file = "%s/sslca.conf" % self._path
if not exists(config_file):
print("Config file missing, answer prompts to generate:\n")
country = raw_input("Country Name (2 letter code): ")
state = raw_input("State or Province Name (full name): ")
city = raw_input("Locality Name (eg, city): ")
org_name = raw_input("Organization Name (eg, company): ")
org_unit = raw_input("Organization Unit Name (eg, section): ")
common_name = raw_input(
"Common Name (eg, your name of your server's hostname): ")
email = raw_input("Email Address: ")
path = self._is_path(raw_input("Absolute path for certificates: "))
bits = self._is_number(raw_input("Bits used by certificates: "))
days = self._is_number(raw_input(
"Days certifcates will be valid: "))
self.config.add_section("ssl")
self.config.add_section("defaults")
self.config.set("ssl", "country", country)
self.config.set("ssl", "state", state)
self.config.set("ssl", "city", city)
self.config.set("ssl", "org_name", org_name)
self.config.set("ssl", "org_unit", org_unit)
self.config.set("ssl", "common_name", common_name)
self.config.set("ssl", "email", email)
self.config.set("defaults", "path", path)
self.config.set("defaults", "bits", bits)
self.config.set("defaults", "days", days)
with open(config_file, "w+b") as cfgfile:
self.config.write(cfgfile)
print("\nConfig file generated at: %s" % config_file)
self.config.read(config_file)
country = self.config.get("ssl", "country")
state = self.config.get("ssl", "state")
city = self.config.get("ssl", "city")
org_name = self.config.get("ssl", "org_name")
org_unit = self.config.get("ssl", "org_unit")
common_name = self.config.get("ssl", "common_name")
email = self.config.get("ssl", "email")
self.subj = "/C=%s/ST=%s/L=%s/O=%s/OU=%s/emailAddress=%s" % (
country, state, city, org_name, org_unit, email)
self.subj_ca = "%s/CN=%s" % (self.subj, common_name)
self.bits = self.config.get("defaults", "bits")
self.path = self.config.get("defaults", "path")
self.days = self.config.get("defaults", "days")
def _is_number(self, value):
if not value.isdigit() or "." in value:
return None
return int(value)
def _is_path(self, value):
if not exists(value):
return None
return value
def _exec_cmd(self, command):
system(command)
def _exec_cmd_get(self, command):
return popen(command).read()
def _offer_randpass(self, n=13):
chars = (SystemRandom().choice(upper + digits) for _ in range(n))
return "".join(chars)
def _make_cert(self, *args, **kwargs):
name = kwargs.get("name", None)
path = kwargs.get("path", self.path)
bits = kwargs.get("bits", self.bits)
subj = kwargs.get("subj", self.subj)
aesb = kwargs.get("aesb", "")
pswd = kwargs.get("pswd", False)
path = path[:-1] if path[-1] == "/" else path
if name is None:
print("Error: You must specify the name of the certificate")
print("For help with commands, use --help")
sys.exit(1)
loc = "%s/%s" % (path, name)
pout = "-passout pass:%s" % pswd if pswd else ""
pin = "-passin pass:%s" % pswd if pswd else ""
cmd1 = "openssl genrsa %s %s -out %s.key %s" % (aesb, pout, loc, bits)
cmd2 = ("openssl req -new -key %s.key -out %s.csr -subj '%s' %s" %
(loc, loc, subj, pin))
self._exec_cmd(cmd1)
self._exec_cmd(cmd2)
def usage(self):
description = "Automates CA certificate generation and signing"
parser = ArgumentParser(prog="sslca", description=description)
parser.add_argument("-v", "--version", dest="version",
action="version", version="%(prog)s " + self.ver)
subparsers = parser.add_subparsers(title="sub-commands", dest="subs")
subparsers.required = False
self.usage_ca(subparsers)
self.usage_cert(subparsers)
self.usage_sign(subparsers)
return parser
def usage_ca(self, subparsers):
ca_parser = subparsers.add_parser("ca", help="create CA certificates")
ca_parser.add_argument("-n", "--name", dest="ca_name", required=True,
help="specify name of CA files")
ca_parser.add_argument("-p", "--path", dest="ca_path",
default=self.path, help="specify path for CA files")
ca_parser.add_argument("-b", "--bits", dest="ca_bits",
default=self.bits, help="specify the number of bits used")
ca_parser.add_argument("-d", "--days", dest="ca_days",
default=self.days, help="specify the number of days valid")
ca_parser.add_argument("-P", "--pswd", dest="ca_pswd", default=None,
help="non-interactively specify passphrase for signing key")
ca_parser.add_argument("-a", "--auto", dest="ca_auto",
action="store_true",
help="automate key passphrase using random password")
def usage_cert(self, subparsers):
cert_parser = subparsers.add_parser("cert",
help="generate normal SSL certificates")
cert_parser.add_argument("-n", "--name", dest="name", required=True,
help="specify name of certificate files")
cert_parser.add_argument("-p", "--path", dest="path",
default=self.path, help="specify name of certicicate files")
cert_parser.add_argument("-b", "--bits", dest="bits",
default=self.bits, help="specify the number of bits used")
cert_parser.add_argument("-H", "--host", dest="host", required=True,
help="specify the host for certificate files")
def usage_sign(self, subparsers):
sign_parser = subparsers.add_parser("sign",
help="sign certificate with CA")
sign_parser.add_argument("-a", "--ca", dest="ca", required=True,
help="specify name of CA used for signing")
sign_parser.add_argument("-c", "--cert", dest="cert", required=True,
help="specify name of certificate to be signed")
sign_parser.add_argument("-p", "--path", dest="path", default=self.path,
help="specify path for signed certificate files")
sign_parser.add_argument("-b", "--bits", dest="bits", default=self.bits,
help="specify the number of bits used")
sign_parser.add_argument("-d", "--days", dest="days", default=self.days,
help="specify the number of days valid")
sign_parser.add_argument("-P", "--pswd", dest="pswd", default=None,
help="non-interactively specify passphrase for signing key")
def get_arguments(self, parser):
return parser.parse_args()
def get_help(self, parser):
return parser.print_help
def inject(self, arguments, helper):
command = arguments.subs
if command == "ca":
return self.gen_ca_cert(arguments)
elif command == "cert":
return self.gen_cert(arguments)
elif command == "sign":
return self.sign_cert(arguments)
helper()
def gen_cert(self, arguments):
name = arguments.name
host = arguments.host
bits = arguments.bits
path = arguments.path
path = path[:-1] if path[-1] == "/" else path
loc = "%s/%s" % (path, name)
subj = "%s/CN=%s" % (self.subj, host)
kwargs = dict()
kwargs["name"] = name
kwargs["path"] = path
kwargs["bits"] = bits
kwargs["subj"] = subj
self._make_cert(**kwargs)
print("\n\nCreated certificate pair: %s.key, %s.csr" % (loc, loc))
def gen_ca_cert(self, arguments):
name = arguments.ca_name
path = arguments.ca_path
days = arguments.ca_days
bits = arguments.ca_bits
auto = arguments.ca_auto
pswd = arguments.ca_pswd
subj = self.subj_ca
path = path[:-1] if path[-1] == "/" else path
rand = self._offer_randpass()
pswd = None
kwargs = dict()
if not (auto or pswd):
print("Suggested Random Password: %s\n" % rand)
def request_passphrase():
passphrase1 = getpass("Enter passphrase: ")
passphrase2 = getpass("Repeat passphrase: ")
if passphrase1 == passphrase2:
return passphrase1
else:
return request_passphrase()
pswd = request_passphrase()
else:
pswd = pswd if pswd else rand
kwargs["name"] = name
kwargs["path"] = path
kwargs["bits"] = bits
kwargs["subj"] = subj
kwargs["pswd"] = pswd
kwargs["aesb"] = "-aes256"
self._make_cert(**kwargs)
loc = "%s/%s" % (path, name)
pin = "-passin pass:%s" % pswd if auto or pswd else ""
cmd = "openssl x509 -req -days %s -in %s.csr" % (days, loc)
cmd = "%s -signkey %s.key -out %s.crt %s" % (cmd, loc, loc, pin)
self._exec_cmd(cmd)
print("\n\nCreated CA certificate: %s.crt" % loc)
if auto:
print("Random Pasword Used (SAVE THIS!!!): %s" % pswd)
def sign_cert(self, arguments):
ca = arguments.ca
cert = arguments.cert
path = arguments.path
bits = arguments.bits
days = arguments.days
pswd = arguments.pswd
path = path[:-1] if path[-1] == "/" else path
loc = "%s/%s" % (path, cert)
ca_loc = "%s/%s" % (path, ca)
pin = "-passin pass:%s" % pswd if pswd else ""
cmd = "openssl x509 -req -days %s -in %s.csr" % (days, loc)
cmd = "%s -CA %s.crt -CAkey %s.key" % (cmd, ca_loc, ca_loc)
cmd = "%s -CAcreateserial -out %s.crt %s" % (cmd, loc, pin)
self._exec_cmd(cmd)
if isfile("%s/%s.crt" % (path, cert)):
print("\n\nSigned certificate: %s.crt" % loc)
else:
print("Error: Something went wrong, check that files exist")
exit(1)
## Entry point
def main():
sslca = SSLCA()
parser = sslca.usage()
arguments = sslca.get_arguments(parser)
helper = sslca.get_help(parser)
sslca.inject(arguments, helper)
if __name__ == "__main__":
main()