在 产品使用中,实施人员常常报告服务器与客户端无法连接.究其原因是因为客户端机器与服务端机器系统时间不一致.原因在于系统使用了OpenSSL,证书中 有一个有效时间段,当客户端或服务器的系统时间不在这个时间段内时SSL会因证书验证失败而无法连接.在实施中系统时间错误是很常见的,因不能上网而未开 时间自动同步,bios没电了,客户疏忽等原因都会导致系统时间设置有误.如果连接失败后再查看系统时间设置总是一项麻烦的事情,那么有哪些办法可以自动 避免这个问题呢?
一,将证书的有效期设得够大:如:1970-2099
这样估计可以在一定程度上解决这个问题,不过这也是个馊主意.
二,检测及必要时自动同步客户端与服务器的时间
通过用wireshake抓包分析SSL建立连接的过程,发现在SSL握手过程中,会向对方传送本机的系统时间.因此一个显而易见的办法就是获取对方的时间,然后在必要时将本机的系统时间改为对方的系统时间,失败后再连一次.下面是具体的示例代码:
- #include <openssl/ssl.h>
- #include <openssl/bio.h>
- #include <openssl/err.h>
- #include <winsock2.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
-
- typedef struct _TimeInfo
- {
- time_t client;
- time_t server;
- } TimeInfo;
-
-
-
-
- BOOL syncSystemTime(time_t t)
- {
- SYSTEMTIME st;
- FILETIME ft;
- LONGLONG ll;
-
- ll = Int32x32To64(t, 10000000) + 116444736000000000;
-
- ft.dwLowDateTime = (DWORD)ll;
- ft.dwHighDateTime = (DWORD)(ll >> 32);
-
- return FileTimeToSystemTime(&ft, &st) && SetSystemTime(&st);
- }
-
-
-
-
- void getSSLHandleShakeTimeInfo(int write_p,
- int version,
- int content_type,
- const unsigned char* buf,
- size_t len,
- SSL *ssl,
- TimeInfo *ti)
- {
- if(content_type != 22)
- return;
- if(len < 42)
- return;
- if(buf[0] == 1)
- ti->client = htonl(*((u_long*)(buf + 6)));
- else if(buf[0] == 2)
- ti->server = htonl(*((u_long*)(buf + 6)));
- else
- return;
- }
-
- int main()
- {
- BIO * bio;
- SSL * ssl;
- SSL_CTX * ctx;
- TimeInfo timeInfo = {-1, -1};
- BOOL timeSynced = FALSE;
- long result;
-
-
- SSL_library_init();
- ERR_load_BIO_strings();
- SSL_load_error_strings();
-
-
- ctx = SSL_CTX_new(SSLv3_client_method());
- if(ctx == NULL)
- {
- fprintf(stderr, "Error new SSL_CTX\n");
- ERR_print_errors_fp(stderr);
- SSL_CTX_free(ctx);
- return 0;
- }
-
-
- SSL_CTX_set_msg_callback(ctx, getSSLHandleShakeTimeInfo);
- SSL_CTX_set_msg_callback_arg(ctx, &timeInfo);
-
-
- if(! SSL_CTX_load_verify_locations(ctx, ".\\certs\\cacert.pem", NULL))
- {
- fprintf(stderr, "Error loading trust store\n");
- ERR_print_errors_fp(stderr);
- SSL_CTX_free(ctx);
- return 0;
- }
-
-
- bio = BIO_new_ssl_connect(ctx);
-
-
- BIO_get_ssl(bio, & ssl);
- SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
-
-
- BIO_set_conn_hostname(bio, "192.168.1.5:5555");
- if(BIO_do_connect(bio) <= 0)
- {
- fprintf(stderr, "Error attempting to connect\n");
- ERR_print_errors_fp(stderr);
- BIO_free_all(bio);
- SSL_CTX_free(ctx);
- return 0;
- }
-
-
- switch(SSL_get_verify_result(ssl))
- {
- case X509_V_OK:
- break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_CERT_HAS_EXPIRED:
- if(timeInfo.server != -1 && timeInfo.client != -1)
- {
- printf("当前客户端时间: %s", ctime(&timeInfo.client));
- printf("当前服务器时间: %s", ctime(&timeInfo.server));
- printf("尝试与服务器时间同步");
-
- if(syncSystemTime(timeInfo.server))
- printf("成功\n");
- else
- printf("失败\n");
- printf("请重试连接服务器!\n");
- }
- default:
- fprintf(stderr, "Certificate verification error: %i\n", SSL_get_verify_result(ssl));
- BIO_free_all(bio);
- SSL_CTX_free(ctx);
- return 0;
- }
-
-
- BIO_free_all(bio);
- SSL_CTX_free(ctx);
- return 0;
- }
(zqt520) |