我正在尝试构建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,对我来说很好,但我想弄清楚阻塞套接字失败的原因。