Skip to content

Instantly share code, notes, and snippets.

@cdgriffith
Last active February 22, 2017 19:38
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 cdgriffith/9dfcc211919a370e81441d7eb0a9a8d4 to your computer and use it in GitHub Desktop.
Save cdgriffith/9dfcc211919a370e81441d7eb0a9a8d4 to your computer and use it in GitHub Desktop.
OpenSSL certificate creation
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import logging
from OpenSSL import crypto
log = logging.getLogger("x509_cert")
class GenError(Exception):
"""Error in cert generator"""
class X509Cert:
def __init__(self, key_file="x509.key", existing_serials=(), key=None):
"""
Class to help easily create and manage x509 certificates
:param key_file: path to existing or new key file
:param existing_serials: to make sure ones provided are unique
:param key: existing key
"""
self.existing_serials = list(existing_serials)
self.key_file = key_file
self.key = key
if os.path.exists(self.key_file):
log.info("Loading existing key")
with open(self.key_file, 'rb') as kf:
self.key = crypto.load_privatekey(crypto.FILETYPE_PEM,
kf.read())
@staticmethod
def generate_key(key_type=crypto.TYPE_RSA, strength=2048):
"""
Generate a new key
:param key_type: either crypto.TYPE_RSA or TYPE_DSA
:param strength: suggested 2048 or 4096
:return: key
"""
key = crypto.PKey()
key.generate_key(key_type, strength)
return key
def generate_cert(self, common_name, key, serial_number,
country="US", state="Texas",
locality="San Antonio", company="None",
organization="None", digest='sha1',
start_time_from_now=0, end_time_from_now=365*24*60*60):
"""
Create a new certificate
:param common_name: url of certificate hosting location
:param key: key to generate cert off of
:param serial_number: unique number for the cert
:param country: Country of hosting location
:param state: State of hosting location
:param locality: City
:param company: Company cert is registered too
:param organization: Org cert is registered too
:param digest: string of type of hash to use
:param start_time_from_now: default is now, or 0
:param end_time_from_now: default is one year
:return: certificate
"""
if serial_number in self.existing_serials:
raise GenError("Serial number is not unique")
cert = crypto.X509()
cert.get_subject().C = country
cert.get_subject().ST = state
cert.get_subject().L = locality
cert.get_subject().O = company
cert.get_subject().OU = organization
cert.get_subject().CN = common_name
cert.set_serial_number(serial_number)
cert.gmtime_adj_notBefore(start_time_from_now)
cert.gmtime_adj_notAfter(end_time_from_now)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(key)
cert.sign(key, digest)
return cert
@staticmethod
def dump_cert(cert, cert_file="x509.cert", file_type=crypto.FILETYPE_PEM,
overwrite=False):
"""
Write the certificate to a file
:param cert: PyOpenSSL cert
:param cert_file: path to write certificate too
:param file_type: defaults to PEM
:param overwrite: overwrite file if it exists
"""
if os.path.exists(cert_file) and not overwrite:
raise GenError("Cert file already exists")
with open(cert_file, 'wb') as cf:
cf.write(crypto.dump_certificate(file_type, cert))
def dump_key(self, key, file_type=crypto.FILETYPE_PEM, overwrite=False):
"""
Write the key to a file
:param key: PyOpenSSL key
:param file_type: defaults to PEM
:param overwrite: overwrite file if it exists
"""
if os.path.exists(self.key_file) and not overwrite:
raise GenError("Key file already exists")
with open(self.key_file, 'wb') as kf:
kf.write(crypto.dump_privatekey(file_type, key))
def create(self, common_name, serial_number, cert_file="x509.cert",
key=None, **kwargs):
"""
Create a new certificate and dump them to a file
:param common_name: host of where certificate is used
:param serial_number: unique number for the certificate
:param cert_file: path to write cert file too
:param key: PyOpenSSL key
:param kwargs: arguments to pass too generate_cert
"""
key = key or self.key
if not key:
log.warning("Generating self-signed key as none was provided")
key = self.generate_key()
self.dump_key(key)
cert = self.generate_cert(common_name=common_name, key=key,
serial_number=serial_number, **kwargs)
self.dump_cert(cert, cert_file)
@staticmethod
def cert_details(cert):
"""
View certificate details
:param cert: PyOpenSSL cert
:return: cert subject
"""
return cert.get_subject()
if __name__ == '__main__':
x = X509Cert()
x.create("localhost", 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment