OpenSSL错误:对等项未返回证书

kyxcudwk  于 2022-10-17  发布在  Unix
关注(0)|答案(1)|浏览(167)

我在我的现有代码上使用OpenSSL集成来实现SSL安全性。我的客户端代码是用C++编写的,运行在Windows操作系统上,而后端代码、服务器代码则运行在AIX上。

证书是在AIX上按照以下命令创建的,客户端(即Windows)正在使用创建的客户端证书和密钥:

//创建CA颁发机构的命令
1.openssl genrsa-des3-out密钥/RootCA_test.key 2048
1.openssl req-new-x509天360密钥密钥/RootCA_test.key-out证书/RootCA_test.crt

  • //创建服务器证书的命令*

1.openssl genrsa-out密钥/server_test.key 2048
1.openssl req-new-key Key/server_est.key-out CSR/server_est.csr
1.openssl ca-day 360-in csr/服务器_est.csr-out证书/server_test.crt-key文件密钥/RootCA_test.key-cert证书/RootCA_test.crt

  • //创建客户端证书的命令*

1.openssl genrsa-out密钥/CLIENT_Test.Key 2048
1.openssl请求-新密钥密钥/CLIENT_TEST.KEY-OUT CSR/CLIENT_TEST.csr
1.openssl ca-day 360-in csr/CLIENT_TEST.csr-OUT证书/CLIENT_Test.crt-KEYFILE密钥/RootCA_Test.key-cert证书/RootCA_est.crt

集成后的代码如下:
客户端代码-在Windows上


# include "stdafx.h"

    #include <string>
    #include <stdio.h>
    #include <openssl/ssl.h> // SSL and SSL_CTX for SSL connections
    #include <openssl/err.h> // Error reporting

    SOCKET s;
    SSL_CTX *ctx;
    SSL *ssl;
    int OpenConnection(const char *hostname, int port)
    {   int sd;
        struct hostent *host;
        struct sockaddr_in addr;

        if ( (host = gethostbyname(hostname)) == NULL )
        {
            perror(hostname);
            abort();
        }
        sd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);    
        memset(&addr,0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = *(long*)(host->h_addr);
        if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
        {
            close(sd);
            perror(hostname);
            abort();
        }
        return sd;
    }

    BOOL InitOpenSSL()//OPENSSL
    {
        //set default locations for trusted CA certificates
        CString sslCrtFilePath  = "C:\\Program Files\\cv\\certificates\\client_test.crt";
        CString sslKeyFilePath  = "C:\\Program Files\\cv\\certificates\\client_test.key";
        CString sslRootFilePath = "C:\\Program Files\\cv\\certificates\\RootCA_test.crt";
        int server;
        char buf[1024];
        int bytes;
        char hostname[]="20.17.127.235";   
        int portnum = 4005;
        SSL_library_init();
        SSL_METHOD *method;    

        OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
        SSL_load_error_strings();   /* Bring in and register error messages */
        method = SSLv23_client_method();//SSLv23_method();  /* Create new client-method instance */
        ctx = SSL_CTX_new(method);   /* Create new context */
        if ( ctx == NULL )
        {        
            abort();
        }
        if (!(LoadCertificates(sslRootFilePath.GetBuffer(sslRootFilePath.GetLength()),sslCrtFilePath.GetBuffer(sslCrtFilePath.GetLength()), sslKeyFilePath.GetBuffer(sslKeyFilePath.GetLength()))))
        {
            s = INVALID_SOCKET;     
            cout << "Failed to load certificate file and key file.";
            return false;
        }   
        ctx  = SSL_CTX_new(method);   /* Create new context */  
        ssl = SSL_new(ctx);      /* create new SSL connection state */
        if ( ctx == NULL )
        {
            ERR_print_errors_fp(stderr);
            s = INVALID_SOCKET;
            cout << "Error in creating SSL_CTX object.";
            return FALSE;
        }
        server = OpenConnection(hostname, portnum);
        SSL_set_fd(ssl, server);    /* attach the socket descriptor */   
        int n = SSL_connect(ssl);
        if ( n != 1 )   /* perform the connection */
        {
            int rc = SSL_get_error(ssl,n);  
            cout << "Error in SSL_connect";      
            exit(1);
        }
        else
        {   char *msg = "Hello! I am Client.Who are you ?\n";
            cout << "Connected with " << SSL_get_cipher(ssl) << " encryption" ;        
            SSL_write(ssl, msg, strlen(msg));   /* encrypt & send message */
            bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
            buf[bytes] = 0;
            cout << buf;
            SSL_free(ssl);        /* release connection state */
        }
        close(server);         /* close socket */
        SSL_CTX_free(ctx);        /* release context */
        return 0;   

    }
    bool LoadCertificates(char* sslRootFilePath,char* CertFile, char* KeyFile)//OPENSSL
    {
         if(!SSL_CTX_load_verify_locations(ctx,sslRootFilePath , NULL))
            {
                /* Handle error here */ 
                s = INVALID_SOCKET;
                cout << "Failed to load root CA certificate.";
                return FALSE;
            }       
            /*Set cipher list*/
            if (SSL_CTX_set_cipher_list(ctx,CIPHER_LIST) <= 0) 
            {
                cout << "Error setting the cipher list.";
            }

            if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM ) <= 0 )
            {
                cout << "Failed in setting the local certificate from CertFile.";
                return false;
            }
            /* set the private key from KeyFile (may be the same as CertFile) */
             if ( SSL_CTX_use_PrivateKey_file (ctx, KeyFile , SSL_FILETYPE_PEM) != 1 ) //SSL_FILETYPE_PEM
            {
                cout << "Failed in setting the private key from KeyFile.";
                return false;        
            }
            /* verify private key */
            if ( !SSL_CTX_check_private_key(ctx) )
            {
                cout << ("Failed in verifying private key.", MB_TOPMOST | MB_SETFOREGROUND|MB_OK);
                return false;        
            }
    }
    int main()
    {   
        BOOL st = InitOpenSSL();
        return 0;
    }

AIX上的服务器代码

Ssl_ctxctx;sslssl;

string root,key,cert;
    int OpenListener(int port)
    {
         cout <<  "OpenListener() Start" << endl ;
         int sd;
        struct sockaddr_in addr;   
        int portno = 4005;
        sd = socket(AF_INET, SOCK_STREAM, 0); 
         memset(&addr,0, sizeof(addr));

         addr.sin_family = AF_INET;
         addr.sin_port = htons(portno);
         addr.sin_addr.s_addr = INADDR_ANY;

        if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
        {
            cout << "can't bind port" << endl;
            abort();
        }
        if ( listen(sd, 10) != 0 )
        {
         cout << "Can't configure listening port" << endl;
         abort();
        }
        cout << "Port : " <<  addr.sin_port  << " Address : " << addr.sin_addr.s_addr << endl;
        cout <<  "OpenListener() End" << endl ;
        return sd;
    }
    void Servlet(SSL* ssl) 
    {
     cout <<  "Servlet() Start" << endl;
     char buf[1024];
     char reply[1024];
     int sd, bytes;

     if ( SSL_accept(ssl) != 1 )     /* do SSL-protocol accept */
     ERR_print_errors_fp(stderr);
     else
      {
            cout <<  "SSL_accept() executed" << endl;
            ShowCerts();        /* get any certificates */
            bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
            if ( bytes > 0 )
            {
                buf[bytes] = 0;
                cout << "Client msg: " <<  buf << endl;            
                SSL_write(ssl, reply, strlen(reply)); /* send reply */
            }
            else
              {
                cout << " Bytes returned by SSL_read() is 0" << endl;
                ERR_print_errors_fp(stderr);
               }
        }
        sd = SSL_get_fd(ssl);       /* get socket connection */
        SSL_free(ssl);         /* release SSL state */
        close(sd);          /* close connection */
        cout <<  "Servlet() End" << endl;
    }
    void ShowCerts()
    {
        cout <<  "ShowCerts() Start " << endl;
        X509 *cert;
        char *line;
        cout << "SSL_get_peer_certificate Initiated " << endl;
        cert = SSL_get_peer_certificate(ssl);       /* Get certificates (if available) */
        if ( cert != NULL )
        {
            cout << "Server certificates: " << endl;
            line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
            cout << "Subject: " << line  << endl;
            free(line);
            line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
            cout << "Issuer: " << line  << endl;
            free(line);
            X509_free(cert);
        }
        else
          cout << "SSL_get_peer_certificate() returns NULL  " << endl;

        cout <<  "ShowCerts() End " << endl;

    }

    bool InitOpenSSL()
    {
        cout <<  "InitOpenSSL() Starts" << endl;
        SSL_library_init();
        SSL_METHOD *method;

        OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
        SSL_load_error_strings();   /* Bring in and register error messages */
        method = const_cast <SSL_METHOD *> (SSLv23_server_method());  /* Create new server-method instance */
        ctx  = SSL_CTX_new(method);   /* Create new context */

            if ( ctx == NULL )
            {
                    ERR_print_errors_fp(stderr);
                    cout << "Error in creating SSL_CTX object."  << endl;
                    return false;
            }
            //set default locations for trusted CA certificates
            cout << "Server Certificate Used : " << cert << endl;
            cout << "Server Key Used         : " << key  << endl;
            if (!(LoadCertificates(const_cast<char *> (cert.c_str()), const_cast <char*> (key.c_str()))) )
            {
                    cout << "Failed to load certificate file and key file." << endl;
                    return false;
            }
           SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
           SSL_CTX_set_verify_depth(ctx, 4); 
           if(!SSL_CTX_load_verify_locations(ctx,root.c_str() , NULL) )
              cout << "SSL_CTX_load_verify_locations failed." << endl;
           else
              cout << "SSL_CTX_load_verify_locations passed." << endl;

           int  server = OpenListener(4005);                                /* create server socket */
           cout << "OpenListener() returns : " << server << endl;
           while (1)
           {
             cout << "In While(1) Loop " << endl;
             struct sockaddr_in addr;
             socklen_t len = sizeof(addr);
             cout << "::accept() called, get ready!" << endl ;
             int client = ::accept(server, (struct sockaddr*)&addr, &len);          /* accept connection as usual */
             cout << "::accept() returns " << client << endl;
             //printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
             cout << "Connection " << inet_ntoa(addr.sin_addr) << ntohs(addr.sin_port) << endl;
             ssl = SSL_new(ctx);                                            /* get new SSL state with context */
             SSL_set_fd(ssl, client);                                               /* set connection socket to SSL state */
             Servlet(ssl);                                                                  /* service connection */
           }
        close(server);                                                                              /* close server socket */
        SSL_CTX_free(ctx);                                                                  /* release context */
        cout <<  "InitOpenSSL() Ends" << endl;
    }
    bool LoadCertificates(char* CertFile, char* KeyFile)
    {
        cout <<  "LoadCertificates() Start" << endl;
        bool rc = true;
         /* set the local certificate from CertFile */
        if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
            {
               cout << "Failed to get the certificate file" << endl;
               rc = false;
            }
            /* set the private key from KeyFile (may be the same as CertFile) */
        if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
        {
               cout << "Failed to get the private key file" << endl;
               rc = false;
            }
            /* verify private key */
        if ( !SSL_CTX_check_private_key(ctx) )
        {
              cout << "Private key does not match the public certificate" << endl;
              rc = false;
            }
        cout <<  "LoadCertificates() End" << endl;
            return rc;
    }

    int main()
    {
            cout << "Root path:" << endl;
            cin >> root;
            cout << "Key path:" << endl;
            cin >> key;
            cout << "Cert path:" << endl;
            cin >> cert;

            InitOpenSSL();
            return 0;
    }

在AIX上运行服务器,然后在Windows上运行客户端,输出如下所示:

Root path:
/tmp/Certificates/RootCA_test.crt
Key path:
/tmp/Keys/server_test.key 
Cert path:
/tmp/Certificates/server_test.crt

InitOpenSSL() Starts
Server Certificate Used : /tmp/Certificates/server_test.crt
Server Key Used         : /tmp/Keys/server_test.key
LoadCertificates() Start
LoadCertificates() End
SSL_CTX_load_verify_locations passed for /tmp/Certificates/RootCA_test.crt
OpenListener() Start
Port : 4005 Address : 0
OpenListener() End
OpenListener() returns : 3
In While(1) Loop
::accept() called, get ready!
::accept() returns 4
Connection xx.xx.xx.xxxxx
Servlet() Start    

**1152921504606846944:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate:s3_srvr.c:3281:**

Servlet() End
In While(1) Loop
::accept() called, get ready!

请帮助我解决此错误:1152921504606846944:错误:140890C7:ssl例程:SSL3_GET_CLIENT_CERTIFICATE:Peer未返回证书:s3_srvr.c:3281:
我尝试了各种链接,也用谷歌搜索了一下,但似乎没有一个答案对此有效!
我创建证书和密钥的方式可以吗?
在上面给出的客户端/服务器代码片段中,是否需要添加或删除任何代码?因为有很多不同的方法来做同样的事情!
一个有趣的结论是,当我在AIX服务器上运行OpenSSL命令时,它似乎建立了一个连接

my_server_07:  openssl s_server -cert /tmp/Certificates/server_test.crt -key /tmp/Keys/server_test.key -port 4005
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT

-----BEGIN SSL SESSION PARAMETERS-----
MFUCAQECAgMDBALAMAQABDDNSf27vf0Jg6GLr+Z7DP/DasT0+dCDRprYoQ4kMMIk
bwtptVYQUgIpkLk/SRDhdhqhBgIEVkB9J6IEAgIBLKQGBAQAAAAB
-----END SSL SESSION PARAMETERS-----
Shared ciphers:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:IDEA-CBC-SHA:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA
CIPHER is ECDHE-RSA-AES256-GCM-SHA384
Secure Renegotiation IS supported
Hello! I am Client.Who are you ?
I am Server AIX :)
  • 这工作得很好,这给我的印象是我的客户端代码和证书都是正常的,并且工作得很好,因为我能够在服务器上接收客户端消息,在客户端上接收服务器消息。不是吗?*

但是,当我在AIX上运行我的服务器端代码和客户端openssl命令时,如下所示:C:\WINDOWS\SYSTEM32>openssl s_client-Connect xx.xx.xxx.xxx:4005
输出如下客户端(服务端显示相同错误:1152921504606846944:错误:140890C7:ssl例程:SSL3_GET_CLIENT_CERTIFICATE:Peer未返回证书:s3_srvr.c:3281:)

Loading 'screen' into random state - done
CONNECTED(000000D0)
depth=1 /C=IN/ST=XX/L=AAA/O=BBB/OU=CCC/CN=root_crt/emailAddress=ans@gmail.com
verify error:num=19:self signed certificate in certificate chain
verify return:0
1520:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:.\ssl\s3_pkt.c:1146:SSL alert number 40
1520:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:.\ssl\s23_lib.c:178:**
  • 证书链中的Error:Verify Error:Num=19:自签名证书似乎指向某种类型的证书签名过程。我查看了各种论坛和opessl.org,但似乎没有任何地方对此给出了适当的有效解决方案。*
  • 请以您认为可以导致解决这些问题的任何方式帮助我。提前感谢...!!*
fwzugrvs

fwzugrvs1#

我认为问题的一部分可能是在您的LoadCertificates函数中缺少对SSL_CTX_load_verify_locations()的调用。
请求客户端经由M1N2O1P消息发送其证书的一部分在该请求中包括服务器信任的CA的列表(即,它将用于验证任何客户端提供的证书)。服务器可能信任多个不同的CA,而给定的客户端可能有多个不同的证书可供选择。因此,CertificateRequest消息包含CA的列表,然后客户端将选择它的哪些客户端证书与那些CA匹配。
因此,要使用用于验证客户端证书的CA列表配置OpenSSL,您可以使用SSL_CTX_load_verify_locations()函数,并将其指向串联证书的PEM文件和/或受信任证书的目录(使用openssl c_rehash实用程序进行散列)。否则,您的服务器可能正在发送CertificateRequest消息,但带有空的CA列表,因此客户端不能/不能选择要发送的客户端证书。
希望这能有所帮助!

相关问题