Python Cryptography – renewing certs

Photo by Markus Spiske on Unsplash
   python3 -m venv ~/.venv/cryptography
   source ~/.venv/cryptography/bin/activate
   pip install cryptography

I am taking a look at https://pypi.org/project/cryptography/ a comprehensive library for OpenSSL and more.

So this is a program which you point at a URL and it provides an ssl key and Certificate Request Form to speed up the certifcate renewal. I’ve since put this into an API so it can deliver the CSR’s and Key to whoever wants them. The spirit of this blog really is about showing how a Sys Admin can use Python to help with chores.

#!/usr/bin/env python
import sys
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import dsa, rsa
from cryptography.hazmat.primitives.serialization import load_pem_private_key


primary_name = 'test.example.com'
alias_list= [ 'www.example.com', 'f5-example.com' ]

#passphrase="None"
passphrase=b"secret"
Country="GB"
County="Hertfordshire"
Locality="Hemel Hempstead"
Organisation="Muppets Inc"

key = rsa.generate_private_key(public_exponent=65537, key_size=2048,)

snippet="["
for n in alias_list:
  snippet=snippet + " x509.DNSName(u\"{0}\"),".format(n)
snippet=snippet + "]"

csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name(
[  x509.NameAttribute(NameOID.COUNTRY_NAME, Country),
   x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, County),
   x509.NameAttribute(NameOID.LOCALITY_NAME, Locality),
   x509.NameAttribute(NameOID.ORGANIZATION_NAME, Organisation),
   x509.NameAttribute(NameOID.COMMON_NAME, primary_name),
])).add_extension(x509.SubjectAlternativeName(eval(snippet)),
    critical=False,).sign(key, hashes.SHA256())

with open(primary_name + ".csr", "wb") as f:
  f.write(csr.public_bytes(serialization.Encoding.PEM))

with open(primary_name + ".key", "wb") as f:
  if passphrase == "None":
    f.write(key.private_bytes(
      encoding=serialization.Encoding.PEM, 
      format=serialization.PrivateFormat.TraditionalOpenSSL, 
      encryption_algorithm=serialization.NoEncryption() ,))
  else:
    f.write(key.private_bytes(
      encoding=serialization.Encoding.PEM,
      format=serialization.PrivateFormat.TraditionalOpenSSL,
      encryption_algorithm=serialization.BestAvailableEncryption(passphrase),))

Ideally we should be using more automated tools for maintaining our certificates. There are some sites around that help with creating the certificate requests( https://www.digicert.com/easy-csr/openssl.htm) but really with the implicit security it’s not a great idea to be using them. Would be nice if we had each certificate registered and could be updated in a devops fashion.