使用Python生成CSR(加密)
我有一个基本的框架,运行得还不错,但在以下几个方面遇到了一些困难:
- 我在加密库中找不到处理SAN(主题备用名称)的方法。希望我没有搞错术语。如果我有一个主要的主机名,比如 test.test.edu,然后我还想让这个主机名也能用 pushu.edu,通常这可以通过“主题备用名称”来实现。
- 有没有办法查看整个证书签名请求(CSR)?比如,它显示的主题、州等信息。我只是想把这些信息打印到屏幕上,但在加密库中找不到方法。
任何帮助都将非常感谢;到目前为止的代码如下 -
#!/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')
编辑:
我在一段时间前解决了这个问题。这里是添加了扩展的代码,或者你可以从我的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
2 个回答
3
Gene的回答差不多,但每个主题备用名称(Subject Alternative Name)前面必须加上一个类型,比如DNS、IP、电子邮件等等。如果你想用DNS,下面的代码就可以用了:
aliases = ['test1.example.com', 'test2.example.com']
if aliases:
subject_alt_names = []
for alias in aliases:
subject_alt_names.append("DNS:{}".format(alias))
req.add_extensions([crypto.X509Extension("subjectAltName", False, ",".join(subject_alt_names))])
9
关于你第一个问题,如何在证书签名请求(CSR)中添加一个SAN(主题备用名称),你可以看看在X509req
对象上使用的add_extensions
方法(有趣的是,这个方法在X509req
类的文档中并没有提到)。
它的用法大概是这样的:
altnames = ', '.join(['DNS:foo.example.com',
'DNS:bar.example.com',
'IP:203.0.113.12'])
req.add_extensions([OpenSSL.crypto.X509Extension("subjectAltName",
False,
altnames)])
更新:感谢Peter Gallagher指出我原回答中缺少的类型前缀(例如DNS
、IP
)。