确定 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 certificateX509StoreContextError 【参考方案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 位的另一种组合。可以肯定的是,最终实体证书无法断言 keyCertSigncRLSign 位,因为最终实体证书无法签署其他证书。

以上是关于确定 SSL 证书是不是使用 Python 自签名的主要内容,如果未能解决你的问题,请参考以下文章

让 SmtpClient 使用自签名 SSL 证书

如何让 Python 请求信任自签名 SSL 证书?

MAC申请自签名的ssl证书

企业为啥不能使用自签名SSL证书?

带有 Python SSL 套接字的自签名证书

如何连接 Python IMAP4_SSL 和自签名服务器 SSL 证书?