OpenSSl错误:peer没有返回证书

时间:2015-11-09 12:09:13

标签: c++ unix openssl ssl-certificate

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

证书是通过在AIX上执行以下命令创建的,并且客户端证书和创建的密钥正在使用时,即Windows:

/ /用于创建CA权限的命令

  1. openssl genrsa -des3 -out Keys / RootCA_test.key 2048

  2. openssl req -new -x509 -days 360 -key Keys / RootCA_test.key -out Certificates / RootCA_test.crt

  3. //创建服务器证书的命令

    1. openssl genrsa -out Keys / server_test.key 2048
    2. openssl req -new -key Keys / server_test.key -out CSR / server_test.csr
    3. openssl ca -days 360 -in CSR / server_test.csr -out Certificates / server_test.crt -keyfile Keys / RootCA_test.key -cert Certificates / RootCA_test.crt
    4. //创建客户端证书的命令

      1. openssl genrsa -out Keys / client_test.key 2048

      2. openssl req -new -key Keys / client_test.key -out CSR / client_test.csr

      3. openssl ca -days 360 -in CSR / client_test.csr -out Certificates / client_test.crt -keyfile Keys / RootCA_test.key -cert Certificates / RootCA_test.crt

      4. 整合代码后如下:

        客户端代码 - 在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_CTX * ctx;         SSL * ssl;

            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:对等方未返回证书: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&gt; openssl s_client -connect xx.xx.xxx.xxx:4005

        输出如下在客户端(服务器显示相同的错误: 1152921504606846944:错误:140890C7:SSL例程:SSL3_GET_CLIENT_CERTIFICATE:对等方未返回证书: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:**
        

        错误:验证错误:num = 19:证书链中的自签名证书似乎指向某种类型的证书签名过程。我查看了各种论坛和opessl.org,但似乎没有给出适当的解决方案。

        请以您认为可以解决这些问题的方式帮助我。 提前致谢.... !!

1 个答案:

答案 0 :(得分:0)

我认为部分问题可能是您SSL_CTX_load_verify_locations()函数中没有调用LoadCertificates例如

请求客户端通过CertificateRequest消息发送证书的一部分是在该请求中包含服务器信任的CA列表( ie 它将用于验证任何客户提供的证书)。服务器可以信任多个不同的CA,并且给定的客户端可以具有多个不同的证书以供选择。因此,CertificateRequest消息包含CA列表,然后客户端将选择哪些客户端证书与这些CA匹配。

因此,要使用用于验证客户端证书的CA列表配置OpenSSL,您可以使用SSL_CTX_load_verify_locations()函数,并将其指向连接证书的PEM文件和/或受信任证书的目录(哈希值)使用OpenSSL c_rehash实用程序。如果没有这个,您的服务器可能正在发送CertificateRequest消息,但是有一个空的CA列表,因此客户端不会/不能选择要发送哪个客户端证书。

希望这有帮助!