I have a skeleton that -- works, but I'm kind of stuck on the following;
Any help would be greatly appreciated; code thus far -
#!/usr/bin/env python
from OpenSSL import crypto, SSL
import subprocess, os, sys
# Create 'usage' portion
# Something, blah blah, use script like this, blah blah.
# Variable
TYPE_RSA = crypto.TYPE_RSA
# Generate pkey
def generateKey(type, bits):
keyfile = 'incommon.key'
key = crypto.PKey()
key.generate_key(type, bits)
if os.path.exists(keyfile):
print "Certificate file exists, aborting."
print " ", keyfile
sys.exit(1)
else:
f = open(keyfile, "w")
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
f.close()
return key
# Generate CSR
def generateCSR(nodename):
csrfile = 'incommon.csr'
req = crypto.X509Req()
# Return an X509Name object representing the subject of the certificate.
req.get_subject().CN = nodename
#req.get_subject().countryName = 'xxx'
#req.get_subject().stateOrProvinceName = 'xxx'
#req.get_subject().localityName = 'xxx'
#req.get_subject().organizationName = 'xxx'
#req.get_subject().organizationalUnitName = 'xxx'
# Set the public key of the certificate to pkey.
req.set_pubkey(key)
# Sign the certificate, using the key pkey and the message digest algorithm identified by the string digest.
req.sign(key, "sha1")
# Dump the certificate request req into a buffer string encoded with the type type.
if os.path.exists(csrfile):
print "Certificate file exists, aborting."
print " ", csrfile
sys.exit(1)
else:
f = open('incommon.csr', "w")
f.write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req))
f.close()
#Call key & CSR functions
key = generateKey(TYPE_RSA,2048)
# Needs to take input from user.
generateCSR('test.test.edu')
EDIT:
I ended up fixing this awhile ago. Here's the code with the added extensions, or you can clone it from my Github: https://github.com/cjcotton/python-csr;
# Generate Certificate Signing Request (CSR)
def generateCSR(nodename, sans = []):
C = raw_input('Enter your country: ')
ST = raw_input("Enter your state: ")
L = raw_input("Enter your location: ")
O = raw_input("Enter your organization: ")
OU = raw_input("Enter your organizational unit: ")
# Allows you to permanently set values required for CSR
# To use, comment raw_input and uncomment this section.
# 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
To generate a CSR, you will need to create a key pair for your server. These two items are a digital certificate key pair and cannot be separated. If you lose your public/private key file or your password and generate a new one, your SSL Certificate will no longer match.
OpenSSL CSR Wizard. Our OpenSSL CSR Wizard is the fastest way to create your CSR for Apache (or any platform) using OpenSSL. Fill in the details, click Generate, then paste your customized OpenSSL CSR command in to your terminal. Note: After 2015, certificates for internal names will no longer be trusted.
For your first question about how to add a SAN to a CSR, look into using the add_extensions
method on the X509req
object (which is curiously not mentioned in the docs for the X509req
class)
It would look something like this
altnames = ', '.join(['DNS:foo.example.com',
'DNS:bar.example.com',
'IP:203.0.113.12'])
req.add_extensions([OpenSSL.crypto.X509Extension("subjectAltName",
False,
altnames)])
Update : Thanks to Peter Gallagher for catching the missing type prefixes (e.g. DNS
, IP
) in my original answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With