OpenSSL 在 C++ 中验证对等(客户端)证书

发布于 2024-10-04 05:45:06 字数 1824 浏览 10 评论 0原文

我有一个正在运行的应用程序,它与服务器建立 SSL 连接。服务器使用自签名证书,客户端加载证书颁发机构链以告诉它服务器可以信任。我在客户端上使用这样的代码做到了这一点:

SSL_METHOD* method = TLSv1_client_method();
_ctx = SSL_CTX_new(method);
if ( SSL_CTX_load_verify_locations(_ctx, "ca-all.crt", NULL) != 1 )
{
    return false;
}
_ssl = SSL_new(_ctx);
int val = SSL_set_fd(_ssl, _socket->GetFD());
if ( val != SSL_SUCCESS )
{
    int err = SSL_get_error(_ssl, val);
    return false;
}
val = SSL_connect(_ssl);

在服务器上:

  if ( SSL_CTX_use_certificate_chain_file( g_ctx, "ca-chain1.crt" ) <= 0 ) {
    return 1;
  }
  ppem_file = getenv( "PEM_FILE" );
  if ( ppem_file == NULL ) {
    ppem_file = pem_file;
  }
  if ( SSL_CTX_use_certificate_file( g_ctx, ppem_file,
                                     SSL_FILETYPE_PEM ) <= 0 ) {
    return 1;
  }
  if ( SSL_CTX_use_PrivateKey_file( g_ctx, ppem_file,
                                    SSL_FILETYPE_PEM ) <= 0 ) {
    return 2;
  }

我试图修改此代码,以便服务器也验证客户端的对等证书(自签名,使用与服务器相同的颁发者)并有一点的麻烦。我在任何地方都没有找到好的“概念概述”文档,这似乎是 OpenSSL 库的一个典型障碍。

在客户端上,我在 SSL_CTX_load_verify_locations() 调用后添加了此内容:

if ( SSL_CTX_use_certificate_file(_ctx, "generic_client.pem", SSL_FILETYPE_PEM ) != 1 )
{
    return false;
}

在服务器上,我在 SSL_CTX_use_PrivateKey_file() 调用后添加了此内容:

  STACK_OF(X509_NAME) *list;
  list = SSL_load_client_CA_file( "ca_chain2.crt" );
  if( list == NULL ) {
    return 4;
  }
  SSL_CTX_set_client_CA_list( g_ctx, list );
  SSL_CTX_set_verify( g_ctx, SSL_VERIFY_PEER, NULL );

连接失败,因为证书未验证。客户端似乎可以很好地加载证书,如果我注释掉 SSL_CTX_set_verify 行,则客户端可以毫无问题地连接(因为其证书从未经过验证)。

看来服务器不认为客户端的证书颁发机构链是好的。我在这里缺少什么?

从命令行我可以运行: openssl 验证-CAfile ca-chain2.crt generic_client.pem 它通过了,所以我有正确的证书数据可用,我一定只是以某种方式错误地使用了它。

I have a working application that establishes an SSL connection to a server. The server uses a self-signed certificate and the client loads a certificate authority chain to tell it that the server is OK to trust. I did that with code like this on the client:

SSL_METHOD* method = TLSv1_client_method();
_ctx = SSL_CTX_new(method);
if ( SSL_CTX_load_verify_locations(_ctx, "ca-all.crt", NULL) != 1 )
{
    return false;
}
_ssl = SSL_new(_ctx);
int val = SSL_set_fd(_ssl, _socket->GetFD());
if ( val != SSL_SUCCESS )
{
    int err = SSL_get_error(_ssl, val);
    return false;
}
val = SSL_connect(_ssl);

And on the server:

  if ( SSL_CTX_use_certificate_chain_file( g_ctx, "ca-chain1.crt" ) <= 0 ) {
    return 1;
  }
  ppem_file = getenv( "PEM_FILE" );
  if ( ppem_file == NULL ) {
    ppem_file = pem_file;
  }
  if ( SSL_CTX_use_certificate_file( g_ctx, ppem_file,
                                     SSL_FILETYPE_PEM ) <= 0 ) {
    return 1;
  }
  if ( SSL_CTX_use_PrivateKey_file( g_ctx, ppem_file,
                                    SSL_FILETYPE_PEM ) <= 0 ) {
    return 2;
  }

I'm trying to modify this code so that the server also verifies the client's peer certificate (self-signed, using same issuer as the server) and having a bit of trouble. I haven't found good "conceptual overview" documentation anywhere, and that seems to be a typical hurdle with the OpenSSL libraries.

On the client I added this after the SSL_CTX_load_verify_locations() call:

if ( SSL_CTX_use_certificate_file(_ctx, "generic_client.pem", SSL_FILETYPE_PEM ) != 1 )
{
    return false;
}

On the server I added this after the SSL_CTX_use_PrivateKey_file() call:

  STACK_OF(X509_NAME) *list;
  list = SSL_load_client_CA_file( "ca_chain2.crt" );
  if( list == NULL ) {
    return 4;
  }
  SSL_CTX_set_client_CA_list( g_ctx, list );
  SSL_CTX_set_verify( g_ctx, SSL_VERIFY_PEER, NULL );

The connection fails because the certificate doesn't validate. The client seems to load the certificate fine and if I comment out the SSL_CTX_set_verify line, the client connects without trouble (because its certificate is never verified).

It seems that the server doesn't think that the client's certificate authority chain is good. What am I missing here?

From the commandline I can run:
openssl verify -CAfile ca-chain2.crt generic_client.pem
And it passes, so I have the right certificate data available, I must just be using it wrong somehow.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

画▽骨i 2024-10-11 05:45:06

在服务器上,您还必须调用 SSL_CTX_load_verify_locations()。该函数告诉服务器使用什么证书进行证书验证; SSL_CTX_set_client_CA_list() 函数设置在握手中发送到客户端的允许的 CA 列表。两者都是必需的。

(在 use_certificate_file 调用之后,您还需要在客户端上进行 SSL_CTX_use_PrivateKey_file() 调用,但我猜您正在这样做,只是将其排除在外)。

On the server, you must also call SSL_CTX_load_verify_locations(). This function tells the server what certificates to use for certificate verification; the SSL_CTX_set_client_CA_list() function sets the list of allowed CAs that are sent to the client in the handshake. Both are required.

(You also need a SSL_CTX_use_PrivateKey_file() call on the client, after the use_certificate_file call, but I guess you're doing that and just left it out).

明月夜 2024-10-11 05:45:06

SSL_CTX_set_client_CA_list 设置 CA 列表。根据定义,CA 证书不同于用户证书(例如,它具有 CA 位集)。因此,我建议您创建一个适当的 CA(其 CA 证书是自签名的),并使用它来签署客户端和服务器证书。我假设 OpenSSL 并不期望客户端实际上也使用 CA 证书进行通信。

SSL_CTX_set_client_CA_list sets the CA list. A CA certificate, by definition, is distinct from a user certificate (e.g. it has the CA bit set). So I recommend you create a proper CA (whose CA certificate is self-signed), and use that to sign both the client and the server certificate. I assume that OpenSSL isn't expecting that the client will actually use the CA certificate for communication also.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文