【问题标题】:Failing to verify certificate in SSL无法在 SSL 中验证证书
【发布时间】:2021-02-03 16:01:13
【问题描述】:

我有一个 C++ tls 库,旨在连接到受 HTTP 保护的站点。代码如下:

#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>

#include <netdb.h>
#include <string.h>
#include <unistd.h>

#include <vector>
#include <string>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/conf.h>
class Website
{
    int status, sock;
    struct addrinfo hints;
    struct addrinfo *servinfo;
    SSL_CTX* ctx = NULL;
    BIO *web = NULL, *out = NULL;
    SSL *ssl = NULL;
    long res = 1;
 
    struct URL
    {
        std::string host;
        std::string port;
        std::string protocol;
    };
    URL url;
    public:
      Website(std::string url){
          parseUrl(url);
          if(Website::url.protocol == "http"){
            establishConn();
          } else if(Website::url.protocol == "https"){
            initSSL();
            initCTX();
            establishConn();
            if(SSL_set_fd(ssl, sock) == 0) throw "Error setting fd";
            int SSL_status = SSL_connect(ssl);
            switch(SSL_get_error(ssl,SSL_status)){
                case SSL_ERROR_NONE:
                    //No error, do nothing
                    break;
                case SSL_ERROR_ZERO_RETURN:
                    throw "Peer has closed connection";
                    break;
                case SSL_ERROR_SSL:
                    ERR_print_errors_fp(stderr);
                    SSL_shutdown(ssl);

                    throw "Error in SSL library";
                    break;
                 default:
                    throw "Unknown error";
                    break;
            } 

          }
      }
     
      std::string get(std::string loc, int maxsize){
        std::string request = "GET "+ loc + "\r\n\r\n";
        char * recvBuf = new char[maxsize]();  
        Website::sendToSite(request);
        Website::recvFromSite(recvBuf, maxsize);
        std::string reply(recvBuf);
        return reply;
      }
    ~Website(){
      close(sock);
      freeaddrinfo(servinfo);
      if(Website::url.protocol == "https"){
        SSL_free(ssl);
        SSL_CTX_free(ctx);
      }
     }

    private:
      void sendToSite(std::string request){
        if(Website::url.protocol == "http"){
            if (send(sock, request.c_str(), strlen(request.c_str()), 0)  == -1) throw "Error sending message";
        } else if(Website::url.protocol == "https"){
           if((SSL_write(ssl, request.c_str(), strlen(request.c_str()))) == 0) throw "Error sending https message"; 
        }
      }
      void recvFromSite(char buf[], int maxsize){
        if(Website::url.protocol == "http"){
            if (recv(sock, buf, maxsize, 0) == -1) throw "Error receving message";
        } else if(Website::url.protocol == "https"){
            if((SSL_read(ssl, buf, strlen(buf))) == 0) throw "Error receving https message";
        }
      }
      //Setting up the SSL
      void initSSL(void){
        SSL_library_init();
      }
      void initCTX(){
        const SSL_METHOD* method = TLS_method();
        if((ctx = SSL_CTX_new(method)) == NULL) throw "Could not create CTX";
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
        SSL_CTX_set_verify_depth(ctx, 4);
        if((ssl = SSL_new(ctx)) == NULL) throw "Couldn't create SSL";
        if(SSL_CTX_load_verify_locations(ctx, "random-org-chain.pem", NULL) == 0){
            ERR_print_errors_fp(stderr);
            throw "Error verifying certificate";
        }

 
  
      }
      void establishConn(){
        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        if((status = getaddrinfo(Website::url.host.c_str(), Website::url.port.c_str(), &hints, &servinfo)) != 0) throw "Something wrong with getaddrinfo";
        if((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) throw "Something wrong with creating socket";
        if((connect(sock, servinfo->ai_addr, servinfo->ai_addrlen)) != 0) throw "Error in connecting to website";       
      }
   //Filles struct Website::url  with host as first argument and path as second
  void parseUrl(std::string url){
    // Check wether url is http or https
    if(url.rfind("http://", 0) == 0){
        Website::url.port = "80";
        Website::url.host = url.substr(7);
        Website::url.protocol = "http";  
    } else if (url.rfind("https://", 0) == 0){
        Website::url.port = "443";
        Website::url.host = url.substr(8);
        Website::url.protocol = "https";
    } else {
        throw "Invalid url, must start with http:// or https://";
    }
  }
};

当我尝试致电 Google 时,我收到此错误:

140404870709056:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:69:fopen('random-org-chain.pem','r')
140404870709056:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:76:
140404870709056:error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib:crypto/x509/by_file.c:199:
Error: Error verifying certificate

如何获得能够连接网站的证书?

【问题讨论】:

    标签: c++ ssl openssl


    【解决方案1】:

    您可以使用以下命令从网站获取证书:-

    #echo -n | openssl s_client -connect <website_url>:<website_port> | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/`hostname -f`.pem
    

    【讨论】:

    • 我可以在 c++ 中使用 ssl 函数来获取它吗?
    猜你喜欢
    • 1970-01-01
    • 2015-04-21
    • 2013-12-06
    • 2010-11-30
    • 2011-08-19
    • 2017-05-27
    • 2015-06-24
    • 2013-09-26
    • 1970-01-01
    相关资源
    最近更新 更多