2016-08-13 33 views
0

我試圖在我的應用程序中使用原始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錯誤:

  1. 新增usleep(50)while循環內(還需要幾個週期來完成)
  2. 新增SSL_do_handshake(conn.ssl)之後,所以SSL_connect和SSL_accept(在最終結果中沒有改變任何東西)
  3. 查看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 

http://pastebin.com/9u1bfuf4

注意事項:1。 我使用的是最新版本的OpenSSL 1.0.2h 2.應用程序運行在Unix系統 3.使用自簽證書加密網絡流量

謝謝大家誰會幫我。

編輯: 我忘了提及套接字處於非阻塞模式,因爲應用程序一次服務多個客戶端。儘管在客戶端他們處於阻塞模式。

EDIT2: 離開這個位置以供將來參考:jmarshall.com/stuff/handling-nbio-errors-in-openssl.html

+0

您的套接字是否處於非阻塞模式? –

+0

是的。我忘了補充一點。因爲它必須服務於多個客戶端,所以它都是非阻塞的。 –

回答

1

您已經澄清,插座的問題是非阻塞的。

那麼,這是你的答案。顯然,當套接字處於非阻塞模式時,握手無法立即完成。握手包括客戶端和服務器之間的協議數據包交換,每個協議數據包都必須等待接收來自其對等端的響應。當套接字處於其默認的阻塞模式時,這工作正常。該庫只需read() s和write()s,它會阻止並等待,直到消息成功讀取或寫入。當套接字處於非阻塞模式時,這顯然不會發生。 read()write()立即成功,或失敗,如果沒有什麼要讀取或者套接字的輸出緩衝區已滿。

SSL_accept()SSL-connect()的手冊頁說明了當底層套接字處於非阻塞模式時必須實施的執行SSL握手的過程。不要在這裏重複整個事情,你應該自己閱讀手冊頁。膠囊摘要是使用SSL_get_error()來確定握手是否實際失敗,或者如果庫想要從套接字讀取或寫入;並在這種情況下致電poll()select(),相應地,再次呼叫SSL_accept()SSL_connect()

任何其他方法,如在這裏和那裏噴灑愚蠢的sleep()調用都會​​導致卡片不可靠,這將導致隨機失敗。

+0

感謝您的回覆。對於我來說,這個解決方案就像它爲來自SO的其他用戶所做的一樣,正是通過使用SSL_get_error並檢查OpenSSL希望我們做什麼。我想我的擔心主要是因爲我沒有使用這些錯誤代碼來正確處理循環,所以我認爲它可能會最終陷入無限循環。剛纔我遇到了ACE庫的SSL實現,它給了我一個關於如何處理它的實際見解。在其他人感興趣的情況下:http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/SSL/SSL_SOCK_Acceptor.cpp –

相關問題