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

Jas*_*ion 4 c++ ssl openssl certificate certificate-authority

我有一个工作的应用程序,建立到服务器的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);
Run Code Online (Sandbox Code Playgroud)

并在服务器上:

  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;
  }
Run Code Online (Sandbox Code Playgroud)

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

在客户端上,我在SSL_CTX_load_verify_locations()调用之后添加了这个:

if ( SSL_CTX_use_certificate_file(_ctx, "generic_client.pem", SSL_FILETYPE_PEM ) != 1 )
{
    return false;
}
Run Code Online (Sandbox Code Playgroud)

在服务器上,我在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 );
Run Code Online (Sandbox Code Playgroud)

连接失败,因为证书未验证.客户端似乎加载了证书,如果我注释掉SSL_CTX_set_verify行,客户端连接没有问题(因为它的证书永远不会被验证).

似乎服务器并不认为客户端的证书授权链是好的.我在这里错过了什么?

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

caf*_*caf 6

在服务器上,您还必须打电话SSL_CTX_load_verify_locations().此函数告诉服务器用于证书验证的证书; 该SSL_CTX_set_client_CA_list()函数设置在握手中发送给客户端的允许CA列表.两者都是必需的.

(在SSL_CTX_use_PrivateKey_file()通话结束后,您还需要在客户端上use_certificate_file拨打电话,但我猜您正在这样做,只是将其拒之门外).