我發現Java客戶端和瀏覽器通過Apache HTTP服務器訪問站點時發生間歇性SSL握手錯誤。這種情況很少發生,但它每天都會破壞構建並影響用戶體驗。服務器配置爲建立安全連接,但不需要來自客戶端的證書。Apache HTTP服務器發生間歇性SSL握手錯誤
我已經在Java測試客戶端和服務器上開啓了SSL調試輸出(見下文)。我所觀察到的是,無論何時發生握手異常,服務器似乎都發送了客戶端證書的請求。我不明白爲什麼它會這樣做,爲什麼這隻會偶爾發生。當它發送證書請求時,幾乎總是發生錯誤,但是我也在成功的情況下捕獲了請求(可能有1%的時間,99%的失敗)。
客戶端使用Java 8(1.8.0_31-b13),Apache HTTP服務器版本爲2.2.19。
下面是從日誌片段:
1)Apache配置摘錄
SSLProtocol ALL -SSLv2 -SSLv3
SSLCertificateFile <path-to-pem1>
SSLCertificateChainFile <path-to-pem2>
SSLCACertificateFile <path-to-pem3>
SSLVerifyDepth 10
SSLVerifyClient none
的.PEM文件是可讀的。
2)客戶端日誌(severly略)
*** ClientHello, TLSv1.2
***
*** ServerHello, TLSv1
***
*** Certificate chain
***
*** Diffie-Hellman ServerKeyExchange
*** CertificateRequest
*** ServerHelloDone
*** Certificate chain
***
*** ClientKeyExchange, DH
*** Finished
***
...
main, WRITE: TLSv1 Handshake, length = 48
main, waiting for close_notify or alert: state 1
main, Exception while waiting for close java.net.SocketException: Software caused connection abort: recv failed
main, handling exception: java.net.SocketException: Software caused connection abort: recv failed
%% Invalidated: [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = unexpected_message
...
main, WRITE: TLSv1 Alert, length = 32
main, Exception sending alert: java.net.SocketException: Software caused connection abort: socket write error
main, called closeSocket()
3)服務器日誌(略)
[info] [client x.x.x.x] Connection to child 1 established (server XXX:443)
[info] Seeding PRNG with 0 bytes of entropy
[debug] ssl_engine_kernel.c(1866): OpenSSL: Handshake: start
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: before/accept initialization
[debug] ssl_engine_io.c(1897): OpenSSL: read 11/11 bytes from BIO#82f6820 [mem: 82c5290] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: XX XX XX XX XX XX XX XX-XX XX XX ........... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1897): OpenSSL: read 245/245 bytes from BIO#82f6820 [mem: 82c529b] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX ................ |
...
[debug] ssl_engine_io.c(1869): | 00f0: XX XX XX XX XX ..... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_kernel.c(1987): [client x.x.x.x] SSL virtual host for servername XXX found
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write certificate A
[debug] ssl_engine_kernel.c(1274): [client x.x.x.x] handing out temporary 1024 bit DH key
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write key exchange A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write certificate request A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 flush data
[debug] ssl_engine_io.c(1897): OpenSSL: read 5/5 bytes from BIO#82f6820 [mem: 82c5290] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: 16 03 01 00 8d ..... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1897): OpenSSL: read 141/141 bytes from BIO#82f6820 [mem: 82c5295] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX ................ |
...
[debug] ssl_engine_io.c(1869): | 0080: XX XX XX XX XX XX XX XX-XX XX XX XX XX ............. |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_kernel.c(1884): OpenSSL: Write: SSLv3 read client certificate B
[debug] ssl_engine_kernel.c(1903): OpenSSL: Exit: error in SSLv3 read client certificate B
[debug] ssl_engine_kernel.c(1903): OpenSSL: Exit: error in SSLv3 read client certificate B
[info] [client x.x.x.x] SSL library error 1 in handshake (server XXX:443)
[info] SSL Library Error: 336105671 error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate No CAs known to server for verification?
[info] [client x.x.x.x] Connection closed to child 1 with abortive shutdown (server XXX:443)
在良好的情況下,我們始終沒有看到 「*** CertificateRequest」 在客戶端和這樣輸出的服務器上
[debug] ssl_engine_kernel.c(1987): [client x.x.x.x] SSL virtual host for servername XXX found
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write certificate A
[debug] ssl_engine_kernel.c(1274): [client x.x.x.x] handing out temporary 1024 bit DH key
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write key exchange A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server done A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 flush data
[debug] ssl_engine_io.c(1897): OpenSSL: read 5/5 bytes from BIO#82d82d8 [mem: 82c8790] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: 16 03 01 00 86 ..... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1897): OpenSSL: read 134/134 bytes from BIO#82d82d8 [mem: 82c8795] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX ................ |
...
[debug] ssl_engine_io.c(1869): | 0080: XX XX XX XX XX XX ...... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client key exchange A
Java客戶端代碼大綱:
URL url = new URL("https://...");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " + DatatypeConverter.printBase64Binary((user + ":" + pass).getBytes(Charset.forName("UTF-8"))));
connection.setReadTimeout(60*1000);
connection.setUseCaches(false);
connection.connect();
與
java -Djavax.net.ssl.trustStore=... -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=... -Djavax.net.debug=all ...
問題運行:
- 是什麼讓服務器發送證書請求,在客戶端上引起 輸出中 「*** CertificateRequest」?
- 設置「SSLVerifyClient none」是否阻止證書請求?
- 關於接下來看什麼的任何建議?
更新:我注意到,當使用Java 6時,Java客戶端從不顯示錯誤。 Java 7和8以及Chrome,Internet Explorer和Firefox都會出現問題。這似乎指向TLSv1.1或TLSv1.2的問題(另請參閱https://serverfault.com/questions/513961/how-to-disable-tls-1-1-1-2-in-apache「OpenSSL v1.0.1在TLSv1.2中存在一些已知問題」)。我將盡力至少檢查在Java客戶端中禁用TLSv1.1/2是否會導致問題消失。
它在CertificateRequest中發送給客戶端。沒有理由發送它,否則。 – EJP
@EJP - 啊,你說得對。對於那個很抱歉。 – jww
增加了Java示例代碼,OpenSSL不在那裏使用。我無法訪問實際的機器。系統管理員告訴我「安裝了OpenSSL 1.0.1h 2014年6月5日,<第三方公司名稱>擴展3.0.16.0」。我假設Apache使用共享庫。 – JanDasWiesel