我試圖在我的應用程序中使用原始C套接字來實現OpenSSL,我遇到的唯一問題是啓動KeyExchange階段的代碼的SSL_accept/SSL_connect部分,但似乎無法在服務器端完成它。C++ OpenSSL在非阻塞模式下接受時無法執行握手。什麼是正確的方法?
我已經看過無數的網站和Q & A在StackOverflow上的這裏讓我自己通過OpenSSL API,因爲這基本上是我第一次嘗試在應用程序中實現SSL,但我唯一能做的還沒有找到如何妥善管理失敗的握手。
基本上,運行作爲服務器的進程A將偵聽傳入的連接。一旦我運行作爲客戶端的進程B,它將成功連接到進程A,但SSL_accept(在服務器上)失敗,錯誤代碼爲-2 SSL_ERROR_WANT_READ。
根據openssl handshake failed,通過在循環中調用SSL_accept,直到它最終返回1(它成功連接並完成握手),可以「輕鬆」解決該問題。然而,我不相信這是做事的正確方式,因爲它看起來像一個骯髒的伎倆。爲什麼我認爲這是一個骯髒的伎倆是因爲我試圖運行一個我在https://www.cs.utah.edu/~swalton/listings/articles/(ssl_client和ssl_server)上找到的小應用程序,並且神奇地,一切正常。沒有多個對SSL_accept的調用,並且握手立即完成。
下面是一些代碼在那裏我接受服務器上的SSL連接:
if (SSL_accept(conn.ssl) == -1)
{
fprintf(stderr, "Connection failed.\n");
fprintf(stderr, "SSL State: %s [%d]\n", SSL_state_string_long(conn.ssl), SSL_state(conn.ssl));
ERR_print_errors_fp(stderr);
PrintSSLError(conn.ssl, -1, "SSL_accept");
return -1;
}
else
{
fprintf(stderr, "Connection accepted.\n");
fprintf(stderr, "Server -> Client handshake completed");
}
這是PrintSSLError的輸出:
SSL State: SSLv3 read client hello B [8465]
[DEBUG] SSL_accept : Failed with return -1
[DEBUG] SSL_get_error() returned : 2
[DEBUG] Error string : error:00000002:lib(0):func(0):system lib
[DEBUG] ERR_get_error() returned : 0
[DEBUG] errno returned : Resource temporarily unavailable
而這裏的客戶端代碼片段,其連接到服務器:
if (SSL_connect(conn.ssl) == -1)
{
fprintf(stderr, "Connection failed.\n");
ERR_print_errors_fp(stderr);
PrintSSLError(conn.ssl, -1, "SSL_connect");
return -1;
}
else
{
fprintf(stderr, "Connection established.\n");
fprintf(stderr, "Client -> Server handshake completed");
PrintSSLInfo(conn.ssl);
}
連接成功建立客戶端(SSL_c ONNECT不返回-1)和PrintSSLInfo輸出:
Connection established.
Cipher: DHE-RSA-AES256-GCM-SHA384
SSL State: SSL negotiation finished successfully [3]
而且這是我包裹交流電插座到SSL:
SSLConnection conn;
conn.fd = fd;
conn.ctx = sslContext;
conn.ssl = SSL_new(conn.ctx);
SSL_set_fd(conn.ssl, conn.fd);
這裏的代碼片段駐留,需要一個文件 - 在函數內原始套接字上接受的傳入連接的描述符以及要使用的SSL上下文。
要初始化SSL上下文我使用TLSv1_2_server_method()和TLSv1_2_client_method()。是的,我知道如果客戶不支持TLS 1.2,這會阻止客戶連接,但這正是我想要的。無論誰連接到我的應用程序,都必須通過我的客戶端來完成。
無論哪種方式,我做錯了什麼?我想在身份驗證階段避免循環,以避免由於意外的無限循環而導致應用程序可能的掛起/減速,因爲OpenSSL沒有指定可能需要多少次嘗試。
奏效,但我想避免的解決方法,是這樣的:
while ((accept = SSL_accept(conn.ssl)) != 1)
而while循環我檢查裏面存放接受退貨代碼中。
事情我已經試圖解決該SSL_ERROR_WANT_READ錯誤:
- 新增usleep(50)while循環內(還需要幾個週期來完成)
- 新增SSL_do_handshake(conn.ssl)之後,所以SSL_connect和SSL_accept(在最終結果中沒有改變任何東西)
- 查看roxlu.com上顯示的代碼(在Google上搜索「使用OpenSSL與內存BIO - Roxlu」)來指導我完成握手階段但由於我是新手,我不直接在我的代碼中使用BIO,而是簡單地將我的本地C套接字包裝到SSL中,的混亂。我也無法重新編寫應用程序的網絡部分,因爲它現在對我來說會是太多的工作。
我已經使用openssl命令行做了一些測試,以排除問題,但它沒有提供任何錯誤。握手似乎成功,因爲沒有錯誤,例如:
24069864:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:656
出現。下面是該命令的輸出全
openssl s_client -connect IP:Port -tls1_2 -prexit -msg
注意事項:1。 我使用的是最新版本的OpenSSL 1.0.2h 2.應用程序運行在Unix系統 3.使用自簽證書加密網絡流量
謝謝大家誰會幫我。
編輯: 我忘了提及套接字處於非阻塞模式,因爲應用程序一次服務多個客戶端。儘管在客戶端他們處於阻塞模式。
EDIT2: 離開這個位置以供將來參考:jmarshall.com/stuff/handling-nbio-errors-in-openssl.html
您的套接字是否處於非阻塞模式? –
是的。我忘了補充一點。因爲它必須服務於多個客戶端,所以它都是非阻塞的。 –