在开发运维平台的时候,都有绕不过的一个需求,那就是对网站证书的管理。

我们需要对证书进行集中化管理,包括颁发证书、解析证书,甚至要定时分析是否有证书过期需要即时续费等,给管理人员一个直观的展示。

首先安装依赖模块,pyopenssl用于证书解析和python-dateutil模块用于日期解析,使用pip直接安装即可。

pip install pyopenssl python-dateutil

生成证书脚本

from OpenSSL import crypto


k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, 2048)  # generate RSA key-pair

cert = crypto.X509()
cert.get_subject().C = "CN"
cert.get_subject().O = "XWL, Inc."
cert.get_subject().OU = "XWL"
cert.get_subject().CN = "xwl.io"
cert.set_serial_number(1000)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(10*365*24*60*60)
cert.set_issuer(cert.get_subject())

cert.set_pubkey(k)
cert.sign(k, 'sha256')
open("selfsign.crt", 'wb').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open("private.key", 'wb').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))

直接使用刚刚生成的证书进行解析,具体注释下脚本输出内容中已有说明。

import OpenSSL
import time
from dateutil import parser

cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open("selfsign.crt").read())
certIssue = cert.get_issuer()

print ("证书版本:            ",cert.get_version() + 1)

print ("证书序列号:          ",hex(cert.get_serial_number()))

print ("证书中使用的签名算法: ",cert.get_signature_algorithm().decode("UTF-8"))

print ("颁发者:              ",certIssue.commonName)

datetime_struct = parser.parse(cert.get_notBefore().decode("UTF-8"))

print ("有效期从:             ",datetime_struct.strftime('%Y-%m-%d %H:%M:%S'))

datetime_struct = parser.parse(cert.get_notAfter().decode("UTF-8"))

print ("到:                   ",datetime_struct.strftime('%Y-%m-%d %H:%M:%S'))

print ("证书是否已经过期:      ",cert.has_expired())

print("公钥长度" ,cert.get_pubkey().bits())

print("公钥:\n" ,OpenSSL.crypto.dump_publickey(OpenSSL.crypto.FILETYPE_PEM, cert.get_pubkey()).decode("utf-8"))

print("主体信息:")

print("CN : 通用名称  OU : 机构单元名称")
print("O  : 机构名    L  : 地理位置")
print("S  : 州/省名   C  : 国名")

for item in certIssue.get_components():
    print(item[0].decode("utf-8"), "  ——  ",item[1].decode("utf-8"))

print(cert.get_extension_count())

subject = cert.get_subject()
print("域名:\n" ,subject.CN)

通常在接收到用户上传的证书之后,也会对其进行可用性校验,防止误传。

import OpenSSL


with open("selfsign.crt") as f:
    crt = f.read()

with open("private.key") as f:
    key = f.read()

try:
    private_key_obj = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, private_key)
except OpenSSL.crypto.Error:
    raise Exception('private key is not correct: %s' % private_key)

try:
    cert_obj = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
except OpenSSL.crypto.Error:
    raise Exception('certificate is not correct: %s' % cert)

context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
context.use_privatekey(private_key_obj)
context.use_certificate(cert_obj)
try:
    context.check_privatekey()
    print("ok")
except OpenSSL.SSL.Error:
    print("error")

以上就是我们常用的证书管理的操作,以及获取常用证书信息的方法。