简体   繁体   English

TLS:如何验证使用RSA密钥自签名的证书

[英]TLS: How to verify a certificate self-signed with an RSA key

I am trying to use OpenSSL and TLS to provide SSH-like trust model. 我正在尝试使用OpenSSL和TLS来提供类似SSH的信任模型。 That means that the two peers have an RSA key pair stored each one, no certificates. 这意味着两个对等体每个都存储一个RSA密钥对,没有证书。 They have also exchanged their public keys prior to the TLS session establishment. 他们还在TLS会话建立之前交换了他们的公钥。 To achieve this I am using some OpenSSL's undocumented functions so I still have doubts, here is how: 为了实现这一点,我使用了一些OpenSSL的未记录的函数,所以我仍然有疑问,这里是如何:

  • During initialisation peers generate an in-memory, temporary x509 certificate. 在初始化期间,对等体生成内存中的临时x509证书。 It contains the minimal dummy data I could get away with, ie a dummy CN, issuer, and many years before expiring. 它包含我可以逃脱的最小虚拟数据,即虚拟CN,发行者,以及到期前许多年。 These are never checked anyway . 无论如何都不会检查这些 SSL context is setup to exchange both certificates both ways. 设置SSL上下文以双向交换两个证书。

  • The important step is that the certificate contains the host's public key and it is signed using the private key: 重要的一步是证书包含主机的公钥,并使用私钥进行签名:

     EVP_PKEY *pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey, PRIVKEY); X509_set_pubkey(x509, pkey); X509_sign(x509, pkey, EVP_sha384()); 
  • This certificate is assigned to SSL_CTX and used for the whole application lifetime. 此证书分配给SSL_CTX并用于整个应用程序生命周期。

What I'm mostly worried about is the verification process when the TLS session is established. 我最担心的是TLS会话建立时的验证过程。 I'm disabling all verification performed by OpenSSL using SSL_CTX_set_cert_verify_callback(always_true_func) and roll my own like this: 我正在使用SSL_CTX_set_cert_verify_callback(always_true_func)禁用OpenSSL执行的所有验证,并像我这样自己滚动:

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;

The question: Is this proper usage of the OpenSSL API? 问题:这是OpenSSL API的正确用法吗? Do you see any security holes, especially on the last part, verification of the received key? 您是否看到任何安全漏洞,特别是在最后一部分,验证收到的密钥? Any better way to achieve the same result? 有没有更好的方法来实现相同的结果?

EDIT: The answer: To verify that a self-signed certificate received during TLS handshake matches the stored RSA key, there is no need to check the certificate's signature , ie there is no need for X509_verify . 编辑:答案:要验证在TLS握手期间收到的自签名证书是否与存储的RSA密钥匹配, 则无需检查证书的签名 ,即不需要X509_verify The comparison of the received public key to the expected one is enough. 收到的公钥与预期公钥的比较就足够了。

The reason is that (quoting Dr Stephen Henson, OpenSSL project core developer) " Depending on the ciphersuite either an RSA decryption operation or an RSA signature operation is performed by the server. So if the handshake completes successfully you can be sure that the same key is used as the one present in the certificate ". 原因是(引用OpenSSL项目核心开发人员Stephen Henson博士)“ 根据密码套件,服务器执行RSA解密操作或RSA签名操作。因此,如果握手成功完成,您可以确保相同的密钥用作证书中的一个 “。

Certificates bind a public key and additional information (such as a identifier and other attributes) together. 证书将公钥和附加信息(例如标识符和其他属性)绑定在一起。 What makes this association between the public key and the additional information a certificate is the fact it is signed. 是什么使公钥和附加信息之间的关联成为证书签署的事实。

The reason X.509 certificates are signed and issued by a CA is because the CA asserts the binding between the public key and the rest of the content of the certificate (in particular its subject). X.509证书由CA签名和颁发的原因是因为CA断言公钥与证书的其余内容(特别是其主题)之间的绑定。 The purpose of this is to let a party that knows the CA but doesn't necessarily know the entity to which the certificate was issued verify that the content of the certificate is true, in particular that the public key belongs to the certificate's subject. 这样做的目的是让知道CA的一方但不一定知道颁发证书的实体验证证书的内容是否为真,特别是公钥属于证书的主题。

Since your authentication scheme relies on pre-established knowledge of who or what owns the public keys anyway, and since you'll ignore the content of the certificate (besides the public key), there is no point verifying that the association between the public key and the rest of the certificate is true (whether self-signed or not). 由于您的身份验证方案依赖于预先知道谁拥有公钥或者拥有公钥的哪些知识,并且由于您将忽略证书的内容(除公钥之外),因此无需验证公钥之间的关联证书的其余部分为真(无论是否自签)。

What you must verify is that the public key you're receiving matches one of the public keys you already know. 您必须验证的是,您收到的公钥与您已知的公钥之一匹配。

EDIT: 编辑:

But second is to actually verify that the self-signed certificate is validly signed, since anyone can send me the host's public key (it's public...). 但其次是实际验证自签名证书是否有效签名,因为任何人都可以向我发送主机的公钥(它是公开的......)。

Anyone can send you a certificate with the host's public key, but only the entity with the private key matching that public key will be able to negotiate the master secret. 任何人都可以使用主机的公钥向您发送证书,但只有具有与该公钥匹配的私钥的实体才能协商主密钥。 How this is done depends on the cipher suite, but only the server that has the private key will be able to carry on with the TLS connection. 如何完成这取决于密码套件,但只有具有私钥的服务器才能继续使用TLS连接。

The client will at least always at least know that it has established a TLS connection with the entity that has the private key for the public key in the server certificate (independently of knowing who that cert belongs to). 客户端至少总是至少知道它已经与具有服务器证书中的公钥的私钥的实体建立了TLS连接(独立于知道该证书属于谁)。

This really is completely independent from the mechanism used to verify the identity of the server (traditionally, PKI + host name verification). 这实际上完全独立于用于验证服务器身份的机制(传统上,PKI +主机名验证)。

If you know the host's public key with certainty (eg by looking it up in a list you already know), verifying the certificate signature is irrelevant (whether it's self-signed or signed by a party you don't know). 如果您确定地知道主机的公钥(例如,通过在您已知的列表中查找),验证证书签名是无关紧要的(无论是自签名还是由您不知道的一方签名)。

The same applies for client certificates: the handshake will not complete if the client that sent its certificate is unable to send the correct signature (in the Certificate Verify message) made using the private key matching the client certificate it has sent. 这同样适用于客户端证书:如果发送证书的客户端无法使用与其发送的客户端证书匹配的私钥发送正确的签名(在证书验证消息中),则握手将无法完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM