确定 SSL 证书是不是使用 Python 自签名
Posted
技术标签:
【中文标题】确定 SSL 证书是不是使用 Python 自签名【英文标题】:Determine if SSL certificate is self signed using Python确定 SSL 证书是否使用 Python 自签名 【发布时间】:2019-11-07 20:14:31 【问题描述】:我正在尝试确定 SSL 证书是否是自签名的。目前我有以下代码比较颁发者 CN 和主题 CN,如果它们相同,则将结果标记为自签名。
with open(cert_file, "r") as f:
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, f.read())
result =
'subject': dict(x509.get_subject().get_components()),
'issuer': dict(x509.get_issuer().get_components()),
'serialNumber': x509.get_serial_number(),
'version': x509.get_version(),
'notBefore': datetime.strptime(x509.get_notBefore(), '%Y%m%d%H%M%SZ'),
'notAfter': datetime.strptime(x509.get_notAfter(), '%Y%m%d%H%M%SZ'),
extensions = (x509.get_extension(i) for i in range(x509.get_extension_count()))
extension_data = e.get_short_name(): str(e) for e in extensions
result.update(extension_data)
if result['issuer']['CN'] == result['subject']['CN']:
result.update('self-signed': True)
else:
result.update('self-signed': False)
这种比较非常简单,但适用于很多情况。我不是要验证 SSL 证书或重新实现 OpenSSL。我怎样才能更好地做到这一点并且大约 95% 确定证书是否是自签名的?
我的一个要求是我想在 Python 中执行此操作,而不是调用其他进程或使用 shell 命令。
【问题讨论】:
您还需要确保签名有效... @PatrickMevzek 我不太关心证书的有效性,还是说这是确定证书是否是自签名的一部分? 这应该有帮助吗? security.stackexchange.com/questions/93162/… 证书在使用自己的私钥签名时是自签名的。使用嵌入在证书中的公钥验证证书的数字签名。在大多数情况下比较主题和颁发者字符串会起作用,但如果你想保证 100%,你必须验证签名 您可以在上下文中验证证书。crypto.X509StoreContext(store, cert).verify_certificate()
在自签名证书上引发带有代码 18、深度 0 和消息 self-signed certificate
的 X509StoreContextError
。
【参考方案1】:
OpenSSL definition of self-signed 是:
主题和颁发者名称匹配,扩展值表示它是自签名的。
code that determines whether a cert is self-signed 是:
/* Return 1 is a certificate is self signed */
static int cert_self_signed(X509 *x)
X509_check_purpose(x, -1, 0);
if (x->ex_flags & EXFLAG_SS)
return 1;
else
return 0;
还有code that sets EXFLAG_SS
:
/* Does subject name match issuer ? */
if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
x->ex_flags |= EXFLAG_SI;
/* If SKID matches AKID also indicate self signed */
if (X509_check_akid(x, x->akid) == X509_V_OK &&
!ku_reject(x, KU_KEY_CERT_SIGN))
x->ex_flags |= EXFLAG_SS;
所以基本上要检查三件事:
主题名称和颁发者名称必须匹配 主题密钥标识符和授权密钥标识符必须匹配 证书必须包含设置了KU_KEY_CERT_SIGN
位的密钥使用扩展
您已经在比较主题名称和颁发者名称。接下来要做的重要事情是比较 SKID 和 AKID。在粗略地浏览了一下 pyopenssl 之后,它看起来并没有提供检查这一点的方法,所以如果你想要一个纯 Python 解决方案,你可能必须扩展该库。但是,即使您拥有的代码也可能在您说希望它涵盖的 95% 的情况下涵盖您。
【讨论】:
您还需要使用其公钥验证证书的签名。 RFC5280 声明 “自签名证书上的签名是使用与证书的主题公钥相关联的私钥生成的。(这证明颁发者拥有公钥和私钥。)在这种情况下,主题和授权密钥标识符将相同,但证书路径构建只需要主题密钥标识符。 似乎 OpenSSL 正在严格检查 KU_KEY_CERT_SIGN,但阅读 RFC5280 并不清楚它是否是强制性的,并且可以将证书视为“自签名”而无需密钥使用扩展和 keyCertSig 位。请参阅此线程中的 dcooper16 评论 github.com/openssl/openssl/issues/1418#issuecomment-238316454 该问题包含关于 X509 合规性的辩论,并且在 3 年后仍然开放......不知道 OP 是否应该努力使他的代码比 OpenSSL 更符合。 IIRC OpenSSL 实际上并不检查自签名证书的签名,因为“它不会增加任何安全性” @pedrofb - 我认为这取决于证书的类型 - 最终实体 (CA:FALSE
) 或证书颁发机构 (CA:TRUE
)。如果CA:TRUE
,则可以设置KU和EKU的部分位;否则可以设置 KU 和 EKU 位的另一种组合。可以肯定的是,最终实体证书无法断言 keyCertSign
和 cRLSign
位,因为最终实体证书无法签署其他证书。以上是关于确定 SSL 证书是不是使用 Python 自签名的主要内容,如果未能解决你的问题,请参考以下文章