3

我正在尝试使用 OpenSSL 和 TLS 来提供类似 SSH 的信任模型。这意味着两个对等点都存储了一个 RSA 密钥对,没有证书。他们还在 TLS 会话建立之前交换了他们的公钥。为了实现这一点,我使用了一些 OpenSSL 的未记录函数,所以我仍然有疑问,这里是如何:

  • 在初始化期间,对等点生成内存中的临时 x509 证书。它包含我可以逃脱的最小虚拟数据,即虚拟 CN、发行人以及到期前的许多年。这些无论如何都不会被检查。SSL 上下文设置为双向交换两个证书。

  • 重要的一步是证书包含主机的公钥,并使用私钥签名:

    EVP_PKEY *pkey = EVP_PKEY_new();
    EVP_PKEY_assign_RSA(pkey, PRIVKEY);
    X509_set_pubkey(x509, pkey);
    X509_sign(x509, pkey, EVP_sha384());
    
  • 此证书分配给SSL_CTX并用于整个应用程序生命周期。

我最担心的是建立TLS会话时的验证过程。我正在禁用 OpenSSL 执行的所有验证,SSL_CTX_set_cert_verify_callback(always_true_func)并像这样滚动我自己的:

X509 *received_cert = SSL_get_peer_certificate(conn_info->ssl);
EVP_PKEY *received_pubkey = X509_get_pubkey(received_cert);
if (EVP_PKEY_type(received_pubkey->type) != EVP_PKEY_RSA)
    error();
ret = X509_verify(received_cert, received_pubkey);
if (ret <= 0)
    error("trust_failed");

// Compare received public key with expected one
RSA *expected_rsa_key = read_RSA_key_from_disk();
EVP_PKEY expected_pubkey = { 0 };
EVP_PKEY_assign_RSA(&expected_pubkey, expected_rsa_key);
EVP_PKEY_cmp(received_pubkey, &expected_pubkey);

if (ret == 1)
    return true; // identity verified!
else
    return false;

问题:这是对 OpenSSL API 的正确使用吗?您是否看到任何安全漏洞,特别是在最后一部分,验证收到的密钥?有更好的方法来达到相同的结果吗?

编辑:答案:要验证在 TLS 握手期间收到的自签名证书是否与存储的 RSA 密钥匹配,不需要检查证书的签名,即不需要X509_verify. 将收到的公钥与预期的公钥进行比较就足够了。

原因是(引用 OpenSSL 项目核心开发人员 Stephen Henson 博士的话)“取决于密码套件,服务器执行 RSA 解密操作或 RSA 签名操作。因此,如果握手成功完成,您可以确保相同的密钥用作证书中存在的那个”。

4

1 回答 1

2

证书将公钥和附加信息(例如标识符和其他属性)绑定在一起。使公钥和附加信息之间的这种关联成为证书的原因在于它已被签名。

X.509 证书由 CA 签名和颁发的原因是因为 CA 断言公钥与证书的其余内容(特别是其主题)之间的绑定。这样做的目的是让知道 CA 但不一定知道颁发证书的实体的一方验证证书的内容是真实的,特别是公钥属于证书的主题。

由于您的身份验证方案依赖于预先建立的关于谁或什么拥有公钥的知识,并且由于您将忽略证书的内容(除了公钥),因此验证公钥之间的关联毫无意义并且证书的其余部分是真实的(无论是否自签名)。

您必须验证的是您收到的公钥与您已经知道的公钥之一匹配。

编辑:

但第二个是实际验证自签名证书是否有效签名,因为任何人都可以向我发送主机的公钥(它是公开的......)。

任何人都可以向您发送带有主机公钥的证书,但只有具有与该公钥匹配的私钥的实体才能协商主密钥。这如何完成取决于密码套件,但只有拥有私钥的服务器才能继续进行 TLS 连接。

客户端至少总是至少知道它已经与拥有服务器证书中公钥的私钥的实体建立了 TLS 连接(与知道该证书属于谁无关)。

这确实完全独立于用于验证服务器身份的机制(传统上,PKI + 主机名验证)。

如果您确定地知道主机的公钥(例如通过在您已经知道的列表中查找它),验证证书签名是无关紧要的(无论它是自签名的还是由您不认识的一方签名的)。

这同样适用于客户端证书:如果发送其证书的客户端无法发送使用与其发送的客户端证书匹配的私钥生成的正确签名(在证书验证消息中),则握手将不会完成。

于 2013-08-13T17:16:54.597 回答