当前位置: 首页 > 知识库问答 >
问题:

TLS服务器不接收来自客户端的证书,无法终止握手

令狐新翰
2023-03-14

我有一个客户端和一个服务器试图相互验证对方并启动TLS连接。我现在使用的证书是自签名的。

在服务器代码中,我设置了SSL\u验证\u失败\u如果\u没有\u对等\u证书。握手成功,但SSL\u get\u peer\u certificate在服务器端返回空指针。如果客户端没有返回证书,为什么握手没有失败?

如果我在服务器端注释掉SSL\u get\u peer\u certificate检查,则客户端和服务器确实连接并能够通信,但它不是TLS连接。当我看到他们通过wireshark交换数据包时,我只看到TCP流量。

服务器代码:

BIO *acceptTLSConnection(char *port) {

  BIO *sbio, *bbio, *acpt = NULL;
  SSL_CTX *ctx = NULL;
  SSL *ssl = NULL;

  SSL_library_init();

  ctx = SSL_CTX_new(TLSv1_server_method());

  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);

  if(!SSL_CTX_use_certificate_file(ctx,"servercert.pem",SSL_FILETYPE_PEM)
    || !SSL_CTX_use_PrivateKey_file(ctx,"serverkey.pem",SSL_FILETYPE_PEM)
    || !SSL_CTX_check_private_key(ctx)) {
    ERR_print_errors_fp(stderr);
    fatalError("Error setting up SSL_CTX.");
  }

  if(!SSL_CTX_load_verify_locations(ctx, "clientcert.pem", NULL))
    fatalError("Could not load trusted CA certificates.");

  sbio=BIO_new_ssl(ctx,0);

  BIO_get_ssl(sbio, &ssl);

  if(!ssl) {
    fatalError("Can't locate BIO SSL pointer.");
  }

  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

  bbio = BIO_new(BIO_f_buffer());
  sbio = BIO_push(bbio, sbio);

  acpt=BIO_new_accept(port);
  BIO_set_accept_bios(acpt,sbio);

  /* Setup accept BIO */
  if(BIO_do_accept(acpt) <= 0) {
    ERR_print_errors_fp(stderr);
    fatalError("Error in setting up accept BIO");
  }

  /* Now wait for incoming connection */
  if(BIO_do_accept(acpt) <= 0) {
    ERR_print_errors_fp(stderr);
    fatalError("Error in connection");
  }

  sbio = BIO_pop(acpt);
  BIO_free_all(acpt);

  if(BIO_do_handshake(sbio) <= 0) {
    ERR_print_errors_fp(stderr);
    fatalError("Error in SSL handshake");
  }

  /* Verify a client certificate was presented during the negotiation */
  X509* cert = SSL_get_peer_certificate(ssl);
  if(cert) { X509_free(cert); } /* Free immediately */
  if(NULL == cert) fatalError("Client did not present a cert during handshake.");

  /* Verify the result of chain verification */
  int res = SSL_get_verify_result(ssl);
  if(!(X509_V_OK == res)) fatalError("Cert presented by client couldn't be verified.");

  return sbio;
}

客户代码:

BIO *makeTLSConnection(char *servIP, char *servPort) {

  char *servLoc = calloc(strlen(servIP) + strlen(servPort) + 2, sizeof(char));
  strcat(servLoc, servIP);
  strcat(servLoc, ":");
  strcat(servLoc, servPort);

  BIO *sbio = NULL;
  SSL_CTX *ctx = NULL;
  SSL *ssl = NULL;

  SSL_library_init();

  ctx = SSL_CTX_new(TLSv1_client_method());

  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

  if(!SSL_CTX_use_certificate_file(ctx,"clientcert.pem",SSL_FILETYPE_PEM)
    || !SSL_CTX_use_PrivateKey_file(ctx,"clientkey.pem",SSL_FILETYPE_PEM)
    || !SSL_CTX_check_private_key(ctx)) {
    ERR_print_errors_fp(stderr);
    fatalError("Error setting up SSL_CTX.");
  }

  if(!SSL_CTX_load_verify_locations(ctx, "servercert.pem", NULL))
    fatalError("Could not load trusted CA certificates.");

  sbio = BIO_new_ssl_connect(ctx);

  BIO_get_ssl(sbio, &ssl);

  if(!ssl) {
    fatalError("Can't locate SSL pointer.");
  }

  BIO_set_conn_hostname(sbio, servLoc);

  if(BIO_do_connect(sbio) <= 0) {
    ERR_print_errors_fp(stderr);
    fatalError("Error connecting to server.");
  }

  if(BIO_do_handshake(sbio) <= 0) {
    ERR_print_errors_fp(stderr);
    fatalError("Error establishing SSL connection.");
  }

  /* Verify a server certificate was presented during the negotiation */
  X509* cert = SSL_get_peer_certificate(ssl);
  if(cert) { X509_free(cert); } /* Free immediately */
  if(NULL == cert) fatalError("Server did not present a cert during handshake.");

  /* Verify the result of chain verification */
  int res = SSL_get_verify_result(ssl);
  if(!(X509_V_OK == res)) fatalError("Cert presented by server couldn't be verified.");

  return sbio;
}

共有1个答案

卫骏
2023-03-14

看起来您错过了对服务器上的SSL_CTX_use_certificate_chain_fileSSL_CTX_set_client_CA_list的调用。我相信SSL_CTX_set_client_CA_list触发机器执行客户端身份验证(即,它在交换期间从第7.4.6节中的RFC中引出Client证书消息)。

如果SSL\u CTX\u set\u client\u CA\u list导致了您正在查找的故障,那么我倾向于相信它是OpenSSL库中的一个bug。在服务器上指定SSL\u-VERIFY\u-PEERSSL\u-VERIFY\u-FAIL\u-IF\u-NO\u-PEER\u-CERT时应该会失败,因为文档中是这么说的。

另请参见OpenSSL用户邮件列表上的SSL\u VERIFY\u PEER\SSL\u VERIFY\u fail\u如果没有SSL\u CTX\u set\u client\u CA\u证书,则验证将失败。这是对这个问题的回答。

另请参阅使用OpenSSL测试SSL/TLS客户端身份验证和OpenSSL客户端不发送客户端证书。

 类似资料:
  • 我不知道我到底需要在哪里包含客户机证书。现在,我的第一个问题是我不信任服务器。我尝试使用默认的Java密钥库文件(cacerts),其中包含Thawte和Digicert,这些是我试图与之通信的服务器的根权限。我使用

  • 我想为我的REST API使用TLS,我计划为它创建自签名证书,并为我的restapi的客户端提供公钥。 我的restapi部署在tomcat catalina容器(tomcat版本8.0.42)上。 我的测试步骤如下, 服务器端 1) 我使用openssl创建了一个自签名证书 2) 已创建bundle 3) 然后将tomcat配置为启用TLS(keystoreType为“PKCS12”),并启动

  • 我有一个使用OpenSSL的C客户机,在服务器上的SSL_do_handshake()调用期间,使用服务器端验证失败的证书时,该客户机的测试失败。当应用程序使用TLS 1.2时,服务器上的SSL_do_handshake()故障将在客户端调用SSL_do_handshake()作为故障返回值时报告给客户端。 在将我的应用程序升级到OpenSSL 1.1.1和TLS 1.3时,我注意到验证错误仍在服

  • 问题内容: 我正在连接到以前成功使用过的Web服务,但是现在他们已经更改了主机名并向我发送了两个.pem文件。一个是CA,另一个是我的新客户证书。 (我将Java 1.5,Spring + Spring Web Services与Apache httpclient一起使用,但是我怀疑我的问题是证书,密钥和SSL本身。) 我已经导入了.pem文件以及从Firefox导出到cacerts中的主机的.c

  • 服务器: 客户: 但最终,客户端阻塞了read(buffer)语句。

  • 验证 SSH 服务器证书(客户端) 和 SSH 用户证书 类似,使用客户端机构认证来验证主机。需要一个 SSH 服务器数字证书认证机构签发服务器证书,客户端只需要保存 CA 的公钥。 使用一台处于气隙系统下的计算机来生成服务器数字证书认证机构的根证书: ❯ ssh-keygen -C "SSH Server Certificate Authority" -f sshserver.root.ca 使