如何使用 Python 的 pyOpenSSL 创建和签署证书?
How do I create and sign certificates with Python's pyOpenSSL?
我想使用 python 创建一个 CA 证书,以及我用它签署的客户端证书。我将在 OpenVPN 中使用这些。经过几天的研究和反复试验,这就是我想出的:
#!/usr/bin/env python
import os
import sys
import random
from OpenSSL import crypto
###########
# CA Cert #
###########
ca_key = crypto.PKey()
ca_key.generate_key(crypto.TYPE_RSA, 2048)
ca_cert = crypto.X509()
ca_cert.set_version(2)
ca_cert.set_serial_number(random.randint(50000000,100000000))
ca_subj = ca_cert.get_subject()
ca_subj.commonName = "My CA"
ca_cert.add_extensions([
crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=ca_cert),
])
ca_cert.add_extensions([
crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=ca_cert),
])
ca_cert.add_extensions([
crypto.X509Extension("basicConstraints", False, "CA:TRUE"),
crypto.X509Extension("keyUsage", False, "keyCertSign, cRLSign"),
])
ca_cert.set_issuer(ca_subj)
ca_cert.set_pubkey(ca_key)
ca_cert.sign(ca_key, 'sha256')
ca_cert.gmtime_adj_notBefore(0)
ca_cert.gmtime_adj_notAfter(10*365*24*60*60)
# Save certificate
with open("ca.crt", "wt") as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert))
# Save private key
with open("ca.key", "wt") as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, ca_key))
###############
# Client Cert #
###############
client_key = crypto.PKey()
client_key.generate_key(crypto.TYPE_RSA, 2048)
client_cert = crypto.X509()
client_cert.set_version(2)
client_cert.set_serial_number(random.randint(50000000,100000000))
client_subj = client_cert.get_subject()
client_subj.commonName = "Client"
client_cert.add_extensions([
crypto.X509Extension("basicConstraints", False, "CA:FALSE"),
crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=client_cert),
])
client_cert.add_extensions([
crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=ca_cert),
crypto.X509Extension("extendedKeyUsage", False, "clientAuth"),
crypto.X509Extension("keyUsage", False, "digitalSignature"),
])
client_cert.set_issuer(ca_subj)
client_cert.set_pubkey(client_key)
client_cert.sign(ca_key, 'sha256')
client_cert.gmtime_adj_notBefore(0)
client_cert.gmtime_adj_notAfter(10*365*24*60*60)
# Save certificate
with open("client.crt", "wt") as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, client_cert))
# Save private key
with open("client.key", "wt") as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, client_key))
这会生成证书和私钥,但不幸的是,我一定是做错了什么,因为它们没有验证:
$ openssl verify -verbose -CAfile ca.crt client.crt
client.crt: CN = Client
error 7 at 0 depth lookup:certificate signature failure
139823049836448:error:04091068:rsa routines:INT_RSA_VERIFY:bad signature:rsa_sign.c:293:
139823049836448:error:0D0C5006:asn1 encoding routines:ASN1_item_verify:EVP lib:a_verify.c:241:
我做错了什么?
您在签署证书后设置 notBefore 和 notAfter,从而更改已签署的证书 - 这使得签名不再与证书匹配:
client_cert.sign(ca_key, 'sha256')
client_cert.gmtime_adj_notBefore(0)
client_cert.gmtime_adj_notAfter(10*365*24*60*60)
# Save certificate
...
如果将签名部分移到最后一步,即直接在写入文件之前,则验证成功:
client_cert.gmtime_adj_notBefore(0)
client_cert.gmtime_adj_notAfter(10*365*24*60*60)
client_cert.sign(ca_key, 'sha256')
# Save certificate
...
我想使用 python 创建一个 CA 证书,以及我用它签署的客户端证书。我将在 OpenVPN 中使用这些。经过几天的研究和反复试验,这就是我想出的:
#!/usr/bin/env python
import os
import sys
import random
from OpenSSL import crypto
###########
# CA Cert #
###########
ca_key = crypto.PKey()
ca_key.generate_key(crypto.TYPE_RSA, 2048)
ca_cert = crypto.X509()
ca_cert.set_version(2)
ca_cert.set_serial_number(random.randint(50000000,100000000))
ca_subj = ca_cert.get_subject()
ca_subj.commonName = "My CA"
ca_cert.add_extensions([
crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=ca_cert),
])
ca_cert.add_extensions([
crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=ca_cert),
])
ca_cert.add_extensions([
crypto.X509Extension("basicConstraints", False, "CA:TRUE"),
crypto.X509Extension("keyUsage", False, "keyCertSign, cRLSign"),
])
ca_cert.set_issuer(ca_subj)
ca_cert.set_pubkey(ca_key)
ca_cert.sign(ca_key, 'sha256')
ca_cert.gmtime_adj_notBefore(0)
ca_cert.gmtime_adj_notAfter(10*365*24*60*60)
# Save certificate
with open("ca.crt", "wt") as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert))
# Save private key
with open("ca.key", "wt") as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, ca_key))
###############
# Client Cert #
###############
client_key = crypto.PKey()
client_key.generate_key(crypto.TYPE_RSA, 2048)
client_cert = crypto.X509()
client_cert.set_version(2)
client_cert.set_serial_number(random.randint(50000000,100000000))
client_subj = client_cert.get_subject()
client_subj.commonName = "Client"
client_cert.add_extensions([
crypto.X509Extension("basicConstraints", False, "CA:FALSE"),
crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=client_cert),
])
client_cert.add_extensions([
crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=ca_cert),
crypto.X509Extension("extendedKeyUsage", False, "clientAuth"),
crypto.X509Extension("keyUsage", False, "digitalSignature"),
])
client_cert.set_issuer(ca_subj)
client_cert.set_pubkey(client_key)
client_cert.sign(ca_key, 'sha256')
client_cert.gmtime_adj_notBefore(0)
client_cert.gmtime_adj_notAfter(10*365*24*60*60)
# Save certificate
with open("client.crt", "wt") as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, client_cert))
# Save private key
with open("client.key", "wt") as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, client_key))
这会生成证书和私钥,但不幸的是,我一定是做错了什么,因为它们没有验证:
$ openssl verify -verbose -CAfile ca.crt client.crt
client.crt: CN = Client
error 7 at 0 depth lookup:certificate signature failure
139823049836448:error:04091068:rsa routines:INT_RSA_VERIFY:bad signature:rsa_sign.c:293:
139823049836448:error:0D0C5006:asn1 encoding routines:ASN1_item_verify:EVP lib:a_verify.c:241:
我做错了什么?
您在签署证书后设置 notBefore 和 notAfter,从而更改已签署的证书 - 这使得签名不再与证书匹配:
client_cert.sign(ca_key, 'sha256')
client_cert.gmtime_adj_notBefore(0)
client_cert.gmtime_adj_notAfter(10*365*24*60*60)
# Save certificate
...
如果将签名部分移到最后一步,即直接在写入文件之前,则验证成功:
client_cert.gmtime_adj_notBefore(0)
client_cert.gmtime_adj_notAfter(10*365*24*60*60)
client_cert.sign(ca_key, 'sha256')
# Save certificate
...