如何在Python中验证SSL证书?

13 投票
4 回答
23340 浏览
提问于 2025-04-16 08:18

我需要确认一个证书是由我自定义的证书颁发机构(CA)签发的。使用OpenSSL的命令行工具,这个操作很简单:

# Custom CA file: ca-cert.pem
# Cert signed by above CA: bob.cert
$ openssl verify -CAfile test-ca-cert.pem bob.cert
bob.cert: OK

但是我想在Python中做同样的事情,而且我真的不想调用命令行工具。根据我的了解,M2Crypto是最完整的OpenSSL的Python封装,但我就是搞不清楚怎么实现命令行工具的功能!

参考这个问题,我已经能做到一半了。我选择的变量名和openssl验证命令行工具的源代码中的一样,见openssl-xxx/apps/verify.c

import M2Crypto as m2
# Load the certificates
cacert = m2.X509.load_cert('test-ca-cert.pem')   # Create cert object from CA cert file
bobcert = m2.X509.load_cert('bob.cert')     # Create cert object from Bob's cert file
cert_ctx = m2.X509.X509_Store()             # Step 1 from referenced C code steps
csc = m2.X509.X509_Store_Context(cert_ctx)  # Step 2 & 5
cert_ctx.add_cert(cacert)                   # Step 3
cert_ctx.add_cert(bobcert)                  # ditto
# Skip step 4 (no CRLs to add)
# Step 5 is combined with step 2...I think. (X509_STORE_CTX_init: Python creates and 
#   initialises an object in the same step)
# Skip step 6? (can't find anything corresponding to 
#   X509_STORE_CTX_set_purpose, not sure if we need to anyway???)
# 
# It all falls apart at this point, as steps 7 and 8 don't have any corresponding
# functions in M2Crypto -- I even grepped the entire source code of M2Crypto, and
# neither of the following functions are present in it:
# Step 7: X509_STORE_CTX_set_cert - Tell the context which certificate to validate.
# Step 8: X509_verify_cert - Finally, validate it

所以我已经做到一半了,但我似乎还是无法完成验证!我是不是漏掉了什么?我应该使用M2Crypto中的其他函数吗?还是应该找一个完全不同的OpenSSL的Python封装?我该如何在Python中完成这个任务呢!?

请注意,我使用证书来加密/解密文件,所以我对基于SSL连接的对等证书验证不感兴趣(这个问题已经有人回答过了),因为我没有任何SSL连接。

4 个回答

-1

你可以使用一个不太有文档说明的 X509.verify 方法来检查这个证书是否是用CA的私钥签名的。这个方法在后台会调用OpenSSL的 x509_verify,所以我相信它也会正确检查所有的参数,比如证书是否过期等:

from M2Crypto X509

cert = X509.load_cert("certificate-filename")

caCertificate = X509.load_cert("trusted-ca-filename")
caPublic = caCertificate.get_pubkey()

if cert.verify(caPublic) == 1:
     # Certificate is okay!
else:
     # not okay
0

使用这个命令:

/Applications/Python\ 3.9/Install\ Certificates.command

注意不要改动空格,只需确保用你自己安装的Python版本替换掉其中的“3.9”。

5

你不能仅仅使用普通的 M2Crypto,因为它没有封装一些必要的功能。不过好消息是,如果你安装了 SWIG,你可以自己封装这些功能,然后和 M2Crypto 的代码一起使用。我之前做过一个模块,增加了一些额外的功能,现在决定发布出来,因为它可以进行这种验证。你可以在这里查看:https://github.com/abbot/m2ext。下面是一个使用这个模块验证证书的例子:

import sys
from m2ext import SSL
from M2Crypto import X509

print "Validating certificate %s using CApath %s" % (sys.argv[1], sys.argv[2])
cert = X509.load_cert(sys.argv[1])
ctx = SSL.Context()
ctx.load_verify_locations(capath=sys.argv[2])
if ctx.validate_certificate(cert):
    print "valid"
else:
    print "invalid"

不幸的是,M2Crypto 的开发似乎停滞不前(在过去两年里,错误追踪器里没有关闭的问题),而且维护者一直忽视我关于这些问题和其他补丁的邮件...

撰写回答