【问题标题】:Obtaining ssl certificate on windows using C++使用 C++ 在 Windows 上获取 ssl 证书
【发布时间】:2012-05-21 15:57:39
【问题描述】:

我正在尝试在 Windows 上获取远程服务器的 ssl 证书。我发现的一种选择是使用 openssl。如internet 上的一些帖子所示,执行此操作的命令是:

openssl.exe s_client -showcerts -connect {REMOTE_SERVER_IP}:{REMOTE_SERVER_PORT}

这很好用,但我的问题是上面的命令有 300 秒的超时。证书本身打印得非常快,当我在前几秒内得到我想要的一切时,我认为没有理由等待 300 秒。我仍然认为没有办法更改 s_client 上的超时参数。所以我试图想办法在给定的一段时间后杀死windows上的一个进程,但又没有运气。关于如何做到这一点的任何想法?如果有其他 Windows 方法可以获取远程服务器 ssl 证书并将其存储在文件中,这也可以完成。

编辑:根据布鲁诺的要求添加更多信息。 我正在尝试创建一个获取远程服务器的 SSL 证书并将其存储在文件中以供进一步处理的 c++ 应用程序。由于我的应用程序已经使用了 openssl.exe,我要么需要一个使用 openssl.exe 的解决方案,要么需要一个标准的 windows 命令(即不需要任何额外的库)。

EDIT2:我找到了一种避免在 linux 中等待的方法 - 只需创建一个空文件并将 openssl s_client 的输入重定向到它(或使用管道传递空输入)。这也适用于 Windows,但适用于旧版本的 openssl(0.9.8l)。我用 0.9.8r 和 1.0.1b 尝试过,将输入重定向到一个空文件并没有帮助。

【问题讨论】:

  • 你试过按Ctrl+C还是Ctrl+D?
  • 命令从程序启动。如果我从命令行运行它 ctrl+c 就可以了,但这不是我需要的。
  • 到目前为止,这看起来像是一个超级用户问题(因此投票结束)。如果您确实从程序中运行它,请告诉我们如何(以及使用哪种语言)。
  • 我添加了更多信息,希望现在更清楚。
  • openssl 也是一个库。一种解决方案是从 C++ 对 libssl 进行 C 调用,以获取证书。您可以使用 s_client 作为示例实现。

标签: c++ windows ssl openssl ssl-certificate


【解决方案1】:

这是我创建的一个简约程序,它连接到服务器并将其 ssl 证书打印到标准输出。希望它能帮助其他人解决类似的问题:

#ifdef WIN32
#include <windows.h>
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif

#include <openssl/ssl.h>    
#include <cstdlib>
#include <iostream>

static const char *host= "10.23.10.12";
static int port=443;

int tcp_connect(const char *host,int port)
{
#ifdef WIN32
   WSADATA wsaData;
   WORD version;
   int error;

   version = MAKEWORD( 2, 0 );

   error = WSAStartup( version, &wsaData );

   /* check for error */
   if ( error != 0 )
   {
       /* error occured */
       return -1;
   }

   /* check for correct version */
   if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 0 )
   {
       /* incorrect WinSock version */
       WSACleanup();
       return -1;
   }

   /* WinSock has been initialized */
#endif

   struct hostent *hp;
   struct sockaddr_in addr;
   int sock;

   if(!(hp=gethostbyname(host)))
      printf("Couldn't resolve host");
   memset(&addr,0,sizeof(addr));
   addr.sin_addr=*(struct in_addr*)
         hp->h_addr_list[0];
   addr.sin_family=AF_INET;
   addr.sin_port=htons(port);

   if((sock=(int)socket(AF_INET,SOCK_STREAM,
                   IPPROTO_TCP))<0)
      printf("Couldn't create socket");
   if(connect(sock,(struct sockaddr *)&addr,
              sizeof(addr))<0)
      printf("Couldn't connect socket");

   return sock;
}

int main(int argc,char **argv)
{
   SSL_CTX *ctx;
   SSL *ssl;
   BIO *sbio;
   int sock;

   SSL_METHOD *meth=NULL;
   meth=SSLv23_client_method();
   OpenSSL_add_ssl_algorithms();
   SSL_load_error_strings();
   ctx=SSL_CTX_new(meth);

   /* Connect the TCP socket*/
   sock=tcp_connect(host,port);

   /* Connect the SSL socket */
   ssl=SSL_new(ctx);
   sbio=BIO_new_socket(sock,BIO_NOCLOSE);
   SSL_set_bio(ssl,sbio,sbio);

   if(SSL_connect(ssl)<=0)
     printf("SSL connect error");

   X509 *peer;
   peer=SSL_get_peer_certificate(ssl);
   PEM_write_X509(stdout, peer);

   SSL_CTX_free(ctx);

   close(sock);
#ifdef WIN32
   closesocket(sock);
   WSACleanup();
#else
   close(sock);
#endif
   exit(0);
}

代码是this post 建议的here 示例的修改版本。

编辑:我不断收到错误 OPENSSL_UPLINK: no OPENSSL_APPLINK on windows。在互联网上进行了大量搜索后,我找到了this post 并将其添加到我的代码中:

extern "C" {
   #include <openssl/applink.c>
}

似乎这是一些避免编译器和运行时选项兼容性要求的解决方法。

【讨论】:

  • 我可以使用站点的域名来提取证书吗? (不是 IP 地址和端口) f.e. “google.com”而不是“10.23.10.12”端口=443
  • 这段代码应该可以正常工作。注意这个调用:gethostbyname(host) 它应该尝试解析主机名。
  • 我可以从 gethostbyname(host) 返回的 hostent 结构中获取“IP 地址”和“端口”吗?
  • 对不起,现在我明白了,443 - 是https端口,主机可以是域名。谢谢!
  • 知道为什么“SSL_connect(ssl)”失败了吗?
猜你喜欢
  • 2013-03-29
  • 1970-01-01
  • 2019-06-14
  • 2013-02-22
  • 2021-12-18
  • 1970-01-01
  • 2021-08-21
  • 2019-10-11
  • 1970-01-01
相关资源
最近更新 更多