Skip to content

Instantly share code, notes, and snippets.

@jrmdev
Created April 5, 2020 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jrmdev/9b57cbdf3ab0b7e53765ddcee68867f9 to your computer and use it in GitHub Desktop.
Save jrmdev/9b57cbdf3ab0b7e53765ddcee68867f9 to your computer and use it in GitHub Desktop.
This is a helper script I made to assist with common OpenSSL command lines. See help for available commands.
#!/usr/bin/env python
import os
import sys
from subprocess import CalledProcessError, check_output, PIPE
class ShellCmd():
def __init__(self, cmd):
self.output = None
self.returncode = None
self.command = cmd
self.run()
def run(self):
print self.command
try:
self.output = check_output(self.command, stderr=PIPE)
self.returncode = 0
except CalledProcessError as e:
self.output = e.output
self.returncode = e.returncode
class OSSLW():
"""Main openssl-wrapper class"""
def __init__(self, file=None):
# Certificate subject parameters
self.country = 'AU'
self.state = 'Victoria'
self.location = 'Melbourne'
self.orga = 'ACME Corp, Inc.'
self.unit = 'IT Dept'
self.common_name = '*.acmecorp.com'
self.nb_days = 365
self.key_bits = 2048
# Input file parameters
self.file_path = file
self.file_content = None
self.file_format = None
self.file_type = None
self.file_desc = None
self.file_dump = None
# General parameters
self.openssl_path = 'openssl'
self.pass_in = 'password'
self.pass_out = 'password'
if self.file_path:
self.file_info()
def set_file(self, file):
self.file_path = file
self.file_info()
def set_passin(self, passwd):
self.pass_in = passwd
def set_passout(self, passwd):
self.pass_out = passwd
def file_info(self):
if not os.path.exists(self.file_path):
self.error("%s: no such file" % self.file_path)
with open(self.file_path, 'rb') as f:
self.file_content = f.read()
if '-----BEGIN' in self.file_content:
self.file_format = 'pem'
elif self.file_content.startswith('\x30\x82'):
self.file_format = 'der'
else:
self.error("%s: file is neither in PEM or DER format." % self.file_path)
commands = [
('x509', 'certificate', [self.openssl_path, 'x509', '-inform', self.file_format, '-in', self.file_path, '-text', '-noout']),
('req', 'Certificate Signing Request (CSR)', [self.openssl_path, 'req', '-inform', self.file_format, '-in', self.file_path, '-text', '-noout']),
('rsa', 'RSA Public Key', [self.openssl_path, 'rsa', '-inform', self.file_format, '-pubin', '-in', self.file_path, '-text', '-noout']),
('rsa', 'RSA Private Key', [self.openssl_path, 'rsa', '-inform', self.file_format, '-in', self.file_path, '-text', '-noout']),
('pkcs12', 'PKCS#12 Bundle', [self.openssl_path, 'pkcs12', '-info', '-in', self.file_path, '-passin', 'pass:%s' % self.pass_in, '-passout', 'pass:%s' % self.pass_out]),
]
for command in commands:
cmd = ShellCmd(command[2])
if not cmd.returncode:
self.file_type = command[0]
self.file_desc = command[1]
self.file_dump = cmd.output
break
if not self.file_type:
self.error("File '%s' is neither of a certificate, key, CSR or bundle. (wrong password?)" % self.file_path)
def error(self, msg):
sys.exit("[!] %s" % msg)
def check(self):
"""Display basic information about the file"""
print self.file_dump
print "[+] File '%s' is a %s in the %s format." % (self.file_path, self.file_desc, self.file_format.upper())
def dump(self):
"""Dump parameters of the RSA key for reuse in a script"""
print "# File '%s' is a %s." % (self.file_path, self.file_desc)
if self.file_desc == 'RSA Public Key':
command = ShellCmd([self.openssl_path, 'rsa', '-pubin', '-noout', '-text', '-in', self.file_path])
elif self.file_desc == 'RSA Private Key':
command = ShellCmd([self.openssl_path, 'rsa', '-noout', '-text', '-in', self.file_path])
else:
self.error("Only RSA keys can be dumped.")
fields = {'modulus': 'N', 'Modulus': 'N', 'Exponent': 'e', 'publicExponent': 'e', 'privateExponent': 'd', 'prime1': 'p', 'prime2': 'q', 'exponent1': 'dp', 'exponent2': 'dq', 'coefficient': 'coeff'}
output = command.output.strip()
output = output.replace(':\n ', ':').split('\n')
for i in range(1, len(output)):
line = output[i].split(':', 1)
try:
val = line[1].replace(':','')
val = int(val, 16)
except:
val = line[1].strip().split()
val = int(val[0])
print '%s = %d' % (fields[line[0]], val)
def der2pem(self):
"""Convert a DER file into PEM format"""
if self.file_format == 'pem':
self.error("File %s already in PEM format" % self.file_path)
outfile = os.path.splitext(self.file_path)[0] + '.pem'
cmd = ShellCmd([self.openssl_path, self.file_type, '-inform', 'der', '-in', self.file_path, '-outform', 'pem', '-out', outfile])
if not cmd.returncode:
print "[i] Saving PEM file as %s" % outfile
else:
self.error("[i] Format not supported for conversion.")
def pem2der(self):
"""Convert a PEM file into DER format"""
if self.file_format == 'der':
self.error("File %s already in DER format" % self.file_path)
outfile = os.path.splitext(self.file_path)[0] + '.cer'
cmd = ShellCmd([self.openssl_path, self.file_type, '-inform', 'pem', '-in', self.file_path, '-outform', 'der', '-out', outfile])
if not cmd.returncode:
print "[i] Saving DER file as %s" % outfile
else:
self.error("[i] Format not supported for conversion.")
def get_pubkey(self):
"""Derive the public key from a private key"""
outfile = os.path.splitext(self.file_path)[0] + '.pub'
command = ShellCmd([self.openssl_path, 'rsa', '-in', self.file_path, '-pubout', '-out', outfile])
if command.returncode:
self.error("An error occurred.")
else:
print "[+] Saving %s" % outfile
def key_unprotect(self):
"""Remove the password from a private key file"""
outfile = os.path.splitext(self.file_path)[0] + '_nopass.key'
command = ShellCmd([self.openssl_path, 'rsa', '-in', self.file_path, '-out', outfile, '-passin', 'pass:%s' % self.pass_in])
if command.returncode:
self.error("An error occurred.")
else:
print "[+] Saving %s" % outfile
def gen_selfsigned(self, basename):
"""Create a self-signed certificate and key"""
base = os.path.basename(basename)
subj = "/C=%s/ST=%s/L=%s/O=%s/OU=%s/CN=%s" % (self.country, self.state, self.location, self.orga, self.unit, self.common_name)
command = ShellCmd([self.openssl_path, 'req', '-x509', '-sha256', '-nodes', '-days', str(self.nb_days), '-newkey', 'rsa:%d' % self.key_bits, '-keyout', '%s.key' % base, '-outform', 'pem', '-out', '%s.pem' % base, '-subj', subj])
if command.returncode:
self.error("An error occurred.")
command = ShellCmd([self.openssl_path, 'rsa', '-in', '%s.key' % base, '-pubout', '-out', '%s.pub' % base])
if command.returncode:
self.error("An error occurred.")
print
print "Files:"
print " [+] Certificate : %s.pem" % base
print " [+] Private key : %s.key" % base
print " [+] Public key : %s.pub" % base
def ca_create(self):
"""Create a self-signed CA certificate and key"""
self.common_name = 'Certification Authority for %s' % self.common_name
self.gen_selfsigned('rootCA')
def ca_sign(self, basename, cacert, cakey, privkey=None):
"""Create a CSR from the provided key, then create a CA-signed certificate using the provided CA-cert and CA-key and the CSR generated."""
base = os.path.basename(basename)
cacert = OSSLW(cacert)
cakey = OSSLW(cakey)
if not privkey:
cmd = ShellCmd([self.openssl_path, 'genrsa', '-out', '%s.key' % base, str(self.key_bits)])
privkey = OSSLW('%s.key' % base)
else:
privkey = OSSLW(privkey)
subj = "/C=%s/ST=%s/L=%s/O=%s/OU=%s/CN=%s" % (self.country, self.state, self.location, self.orga, self.unit, self.common_name)
commands = (
[self.openssl_path, 'req', '-new', '-key', privkey.file_path, '-out', '%s.csr' % base, '-subj', subj],
[self.openssl_path, 'x509', '-req', '-in', '%s.csr' % base, '-CA', cacert.file_path, '-CAkey', cakey.file_path, '-CAcreateserial', '-out', '%s.pem' % base, '-days', str(self.nb_days), '-sha256']
)
for command in commands:
c = ShellCmd(command)
if c.returncode:
self.error("An error occurred.")
print
print "Files:"
print " [i] Using Private Key : %s" % privkey.file_path
print " [i] Using CA Certificate : %s" % cacert.file_path
print " [i] Using CA key : %s" % cakey.file_path
print " ---"
print " [+] Server Key : %s" % privkey.file_path
print " [+] Server Cert : %s.pem" % base
print " [+] Server CSR : %s.csr" % base
def pfx_unprotect(self):
outfile = os.path.splitext(self.file_path)[0] + '_nopass.pfx'
command = ShellCmd([self.openssl_path, 'pkcs12', '-in', self.file_path, '-nodes', '-out', 'temp.pem', '-passin', 'pass:%s' % self.pass_in])
if command.returncode:
self.error("An error occurred.")
command = ShellCmd([self.openssl_path, 'pkcs12', '-export', '-in', 'temp.pem', '-out', outfile, '-password', 'pass:%s' % self.pass_out])
if command.returncode:
self.error("An error occurred.")
print "[+] Saved as %s." % outfile
os.unlink('temp.pem')
def pfx_pack(self, cert, key, cacert=None):
outfile = os.path.splitext(cert)[0] + '.pfx'
cert = OSSLW(cert)
key = OSSLW(key)
if cacert:
cacert = OSSLW(cacert)
command = ShellCmd([self.openssl_path, 'pkcs12', '-export', '-out', outfile, '-certfile', cacert.file_path, '-inkey', key.file_path, '-in', cert.file_path, '-passout', 'pass:%s' % self.pass_out])
else:
command = ShellCmd([self.openssl_path, 'pkcs12', '-export', '-out', outfile, '-inkey', key.file_path, '-in', cert.file_path, '-passout', 'pass:%s' % self.pass_out])
if command.returncode:
self.error("An error occurred.")
print "[+] Saved as %s" % outfile
def pfx_unpack(self):
outfile = os.path.splitext(self.file_path)[0]
# Exract cert from pfx
command = ShellCmd([self.openssl_path, 'pkcs12', '-in', self.file_path, '-passin', 'pass:%s' % self.pass_in, '-out', '%s.pem' % outfile, '-nodes', '-nokeys'])
if command.returncode:
self.error("An error occurred.")
# Exract priv key from pfx
command = ShellCmd([self.openssl_path, 'pkcs12', '-in', self.file_path, '-passin', 'pass:%s' % self.pass_in, '-out', '%s.key' % outfile, '-nodes', '-nocerts'])
if command.returncode:
self.error("An error occurred.")
# Exract pub key from priv key
command = ShellCmd([self.openssl_path, 'rsa', '-in', '%s.key' % outfile, '-pubout', '-out', '%s.pub' % outfile])
if command.returncode:
self.error("An error occurred.")
print
print "Files:"
print " [+] Certificate : %s.pem" % outfile
print " [+] Private key : %s.key" % outfile
print " [+] Public key : %s.pub" % outfile
def main():
cmd = sys.argv[1]
osslw = OSSLW()
if len(sys.argv) > 3:
sys.argv.append("")
if cmd == 'check' and len(sys.argv) >= 3:
if len(sys.argv) > 3:
osslw.set_passin(sys.argv[3])
osslw.set_passout(sys.argv[4])
osslw.set_file(sys.argv[2])
osslw.check()
elif cmd == 'dump' and len(sys.argv) >= 3:
if len(sys.argv) > 3:
osslw.set_passin(sys.argv[3])
osslw.set_passout(sys.argv[4])
osslw.set_file(sys.argv[2])
osslw.dump()
elif cmd == 'der2pem' and len(sys.argv) == 3:
osslw.set_file(sys.argv[2])
osslw.der2pem()
elif cmd == 'pem2der' and len(sys.argv) == 3:
osslw.set_file(sys.argv[2])
osslw.pem2der()
elif cmd == 'key_extract' and len(sys.argv) == 3:
osslw.set_file(sys.argv[2])
osslw.get_pubkey()
elif cmd == 'key_unprotect' and len(sys.argv) >= 3:
if len(sys.argv) > 3:
osslw.set_passin(sys.argv[3])
osslw.set_passout(sys.argv[4])
osslw.set_file(sys.argv[2])
osslw.key_unprotect()
elif cmd == 'pfx_unprotect' and len(sys.argv) >= 3:
if len(sys.argv) > 3:
osslw.set_passin(sys.argv[3])
osslw.set_passout(sys.argv[4])
osslw.set_file(sys.argv[2])
osslw.pfx_unprotect()
elif cmd == 'pfx_pack' and len(sys.argv) >= 4:
osslw.pfx_pack(*sys.argv[2:])
elif cmd == 'pfx_unpack' and len(sys.argv) >= 3:
if len(sys.argv) > 3:
osslw.set_passin(sys.argv[3])
osslw.set_passout(sys.argv[3])
osslw.set_file(sys.argv[2])
osslw.pfx_unpack()
elif cmd == 'cert_create' and len(sys.argv) == 3:
osslw.gen_selfsigned(sys.argv[2])
elif cmd == 'ca_create' and len(sys.argv) == 2:
osslw.ca_create()
elif cmd == 'ca_sign' and len(sys.argv) >= 5:
osslw.ca_sign(*sys.argv[2:])
else:
usage()
def usage():
print "output files extensions:"
print ".der, .cer (DER-encoded certificates or keys)"
print ".pem, .crt (PEM-encoded certificates or keys)"
print ".pfx, .p12 (PKCS#12 bundles)"
print ".key (RSA private keys)"
print ".pub (RSA public keys)"
print ".csr (RSA certificate signing requests)"
print
print
print "usage: %s <cmd>" % sys.argv[0]
print ""
print " check <file> [ passwd ] -- display information about the file"
print " dump <file> [ passwd ] -- dump parameters from an RSA key"
print " der2pem <file> -- convert a cert or key to PEM format"
print " pem2der <file> -- convert a cert or key to DER format"
print " cert_create <basename> -- generate a self-signed certificate and key"
print " key_extract <file> -- derive the public key from a private key"
print " key_unprotect <file> <passwd> -- remove the password from a private key file"
print " pfx_unprotect <file> <passwd> -- remove the password from a PKCS12 bundle"
print " pfx_pack <cert> <key> [ cacert ] -- compress cert(s) and priv. key into PKCS12"
print " pfx_unpack <file> [ passwd ] -- extract PKCS12 into cert(s) and priv. key"
print " ca_create -- create a CA certificate and key"
print " ca_sign <basename> <cacert> <cakey> [ privkey ] -- generate a CA-signed certificate using an existing CA."
print " If a private key isn't provided, one will be generated."
sys.exit(1)
if __name__ == '__main__':
usage() if len(sys.argv) < 2 else main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment