SSL_connect返回SSL_ERROR_SYSCALL,ERR_get_error总是返回零

时间:2017-08-24 13:40:47

标签: c sockets openssl

我正在尝试构建ssl客户端并使用s_server提供的openssl对其进行测试。在socket的连接之前,一切都很好但SSL_connect()失败并返回SSL_ERROR_SYSCALL

  

SSL_ERROR_SYSCALL:发生了一些I / O错误。 OpenSSL错误队列可能包含有关错误的更多信息。如果错误队列为空(即ERR_get_error()返回0),则可以使用ret查找有关错误的更多信息:如果ret == 0,则观察到违反协议的EOF。如果ret == -1,则底层BIO报告了I / O错误(对于Unix系统上的套接字I / O,请参阅errno以获取详细信息)。

正如文档所述,我进一步诊断为ERR_get_error()并返回0。如何在Windows中查看errno?另一方面,服务器也没有显示很多。

D:\server>openssl s_server -accept 5555 -cert server.crt -key server.key -msg -debug  
Using default temp DH parameters
ACCEPT
read from 0x600077c90 [0x600096e40] (11 bytes => 0 (0x0))
ERROR
shutting down SSL
CONNECTION CLOSED

编辑今天我尝试打印错误字符串

err = SSL_connect(ssl);
ERR_error_string(SSL_get_error(ssl, err), buf);
printf("Error: %s\n", buf);

,输出

Error: error:00000005:lib(0):func(0):DH lib

这看起来像Diffie-Hellmann问题。还有另外discussion个约dH个参数,但正如他们所提到的,我自己并没有设置dh个参数。

其他类似的questions谈论ssl版本。我也尝试了他们的建议,但没有帮助。

环境:我在Windows上,gcc(cygwin)编译器,openssl-1.02k

我也尝试使用errno,但它会返回No Error

case SSL_ERROR_SYSCALL:
    perror(errno);
    break;

来自客户的完整代码

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/crypto.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

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

#define ON      1
#define OFF     0
#define RETURN_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(1); }
#define RETURN_NULL(x) if ((x)==NULL) exit (1)
int sock_conn;
SSL_CTX *ctx;
#define DEFAULT_BUF_SIZE 64
void handle_error(const char *file, int lineno, const char *msg) {
  fprintf(stderr, "** %s:%i %s\n", file, lineno, msg);
  ERR_print_errors_fp(stderr);
  exit(1);
}

void Errors_SSL(const char * file, int line)
{
    char *buf;
    unsigned long code;
    code = ERR_get_error();
    while (code)
    {
        ERR_error_string(code, buf);
        printf(buf);
        printf("error code: %lu in %s line %d.\n", code, file, line);
        code = ERR_get_error();
    }
}

#define ssl_error() Errors_SSL( __FILE__, __LINE__)

#define int_error(msg) handle_error(__FILE__, __LINE__, msg)

void die(const char *msg) {
  perror(msg);
  exit(1);
}

int startTCPConnection()
{
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0 )
        int_error("socket() fails");

    struct sockaddr_in server_addr;

    memset (&server_addr, '\0', sizeof(server_addr));
    server_addr.sin_family      = AF_INET;
    server_addr.sin_port        = htons(5555);       /* Server Port number */
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server IP */

    if ( connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0 )
        int_error("connect() fails");

    printf("TCP Socket Connected\n");
    return sock; 
}

SSL_CTX *createSSLObject()
{
    int verify_client = OFF;
    SSL_CTX *ct = SSL_CTX_new(SSLv23_client_method());
    if (ct == NULL)
        int_error("SSL_CTX_new() returned 0");

    if(verify_client == ON)
    {
        /* Load the client certificate into the SSL_CTX structure */
        if (SSL_CTX_use_certificate_file(ct, "device.pem", SSL_FILETYPE_PEM) <= 0) 
        {
           ERR_print_errors_fp(stderr);
           exit(1);
        }

        /* Load the private-key corresponding to the client certificate */
        if (SSL_CTX_use_PrivateKey_file(ct, "device.key", SSL_FILETYPE_PEM) <= 0) 
        {
            ERR_print_errors_fp(stderr);
            exit(1);
        }

        /* Check if the client certificate and private-key matches */
        if (!SSL_CTX_check_private_key(ct)) 
        {
            fprintf(stderr,"Private key does not match the certificate public key\n");
            exit(1);
        }
    }

    //SSL_CTX_set_mode(ct, SSL_MODE_AUTO_RETRY);

    if (!SSL_CTX_load_verify_locations(ct, "rootCA.pem", NULL))
        int_error("SSL_CTX_load_verify_locations() failed");

    SSL_CTX_set_verify(ct, SSL_VERIFY_PEER, NULL);
    SSL_CTX_set_verify_depth(ct,2);

    return ct;
}

int main()
{
    int err, e;
    char    hello[80];
    //printf ("Message to be sent to the SSL server: ");
    //fgets (hello, 80, stdin);

    SSL_library_init(); // load all cipher and crypto algorithms
    SSL_load_error_strings();  // error strings for libssl
    ERR_load_BIO_strings();    
    ERR_load_crypto_strings(); // error strings for libcrypto

    ctx = createSSLObject();
    sock_conn = startTCPConnection();

    SSL * ssl = SSL_new(ctx);
    RETURN_NULL(ssl);
    SSL_set_fd(ssl, sock_conn);
    SSL_set_connect_state(ssl);

    do 
    {
        err = SSL_connect(ssl);
        if (err < 0)
        {
            switch (SSL_get_error(ssl, err))
            {
                case SSL_ERROR_NONE:
                    printf("SSL_ERROR_NONE");
                    break;
                case SSL_ERROR_ZERO_RETURN:
                    printf("SSL_ERROR_ZERO_RETURN");
                    break;
                case SSL_ERROR_WANT_READ: 
                    printf("SSL_ERROR_WANT_READ\n");
                    break;
                case SSL_ERROR_WANT_WRITE:
                    printf("SSL_ERROR_WANT_WRITE\n");
                    break;
                case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT:
                    printf("SSL_ERROR_WANT_CONNECT || SSL_ERROR_WANT_ACCEPT\n");
                    break;
                case SSL_ERROR_WANT_X509_LOOKUP:
                    printf("SSL_ERROR_WANT_X509_LOOKUP");
                    break;
                case SSL_ERROR_SYSCALL:
                    do
                    {
                        e = ERR_get_error();
                        if (e > 0)
                            int_error("Error");
                    }while (e > 0);

                    printf("SSL_ERROR_SYSCALL\n");
                    break;
                case SSL_ERROR_SSL:
                    printf("SSL_ERROR_SSL");
                    break; 
                default:
                    break;       
            }
            //ERR_clear_error();
        }
    }while(SSL_is_init_finished(ssl) == 0);   

    printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

    X509  *server_cert = SSL_get_peer_certificate (ssl);    
    if (server_cert != NULL)
    {
        printf ("Server certificate:\n");
        char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
        printf ("\t subject: %s\n", str);
        free (str);
        str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0);
        printf ("\t issuer: %s\n", str);
        free(str);
        X509_free (server_cert);
    }


    return 0;
}

很久以前我得到了这个problem并且没有得到任何解决方案,并且由于时间问题再也没有工作过。

注意:我也尝试过许多来自其他人的现成教程客户端示例,所有这些示例都在connect失败。还有另一个非阻塞套接字solution,对我来说很好,但我想弄清楚阻塞套接字失败的原因。

0 个答案:

没有答案