2012-03-15 44 views
4

我試圖在.NET和Java之間創建一個SSL套接字服務器/客戶端。在這種情況下,我的SSL套接字服務器將以.net運行,並且客戶端在Linux下以Java運行。我的問題是在握手期間連接失敗,特別是當服務器從客戶端請求證書時,客戶端無法發回某些內容並且連接失敗。使用客戶端身份驗證的.Net和Java之間的SSL Socket

在.net我使用sslStream建立連接,並在Java上使用標準的SSLSocket。一些代碼片段在下面,但這是我迄今爲止:

在服務器端(Windows),我在MMC下的個人/證書文件夾中有私人證書。我有可信人員/證書中的客戶的公共證書。這兩個證書都是由同一個CA頒發的。兩個證書的證書鏈都有多個級別,但兩者都是相同的。鏈中的根級證書也安裝在受信任的證書頒發機構/證書文件夾中。

在客戶端(Linux)上,我有一個密鑰存儲庫,其中包含與服務器上安裝的公用證書匹配的專用證書。我有一個信任存儲庫,其中包含來自服務器的公共證書,與服務器的私人證書相匹配。

在服務器端(.NET)我使用的是插座,做一個異步讀取,然後它被包裹成一個SSLStream,代碼片段是這樣的:

NetworkStream ns = new NetworkStream(socket, false); 
SslStream ssl = new SslStream(ns, true); 
ssl.AuthenticateAsServer(serverCertificate, true, SslProtocols.Default, true); 

客戶端代碼是相當很多標準代碼:

SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 
InetAddress addr = InetAddress.getByName(servername); 
SSLSocket socket = (SSLSocket) factory.createSocket(addr,port); 
socket.setUseClientMode(true); 
socket.setNeedClientAuth(true); 
socket.setWantClientAuth(true); 
socket.startHandshake(); 
os = new DataOutputStream(socket.getOutputStream()); 
is = new DataInputStream(socket.getInputStream()); 
byte[] outBuf = new byte[50]; 
os.write("SEND SOMETHING".getBytes("UTF-8")); 
is.read(outBuf); 

在java中,我已經設置了適當的變量來指向信任和密鑰存儲與他們的密碼。現在

,按照標準SSL握手,這是發生了什麼:

  • 客戶問候
  • 服務器問候
  • 服務器發送公證書
  • 客戶端上的信任存儲的一個公證書相匹配
  • 服務器發送證書請求
  • 隨着證書請求服務器sen ds列出有效的CA,在此列表上僅發送我的根CA(在其他衆所周知的CA的長列表中)。
  • 客戶端證書爲空。
  • 服務器從客戶端收到空證書,從而關閉連接。

而就是這樣,客戶端不會將有效的證書發送回服務器。我有這方面的一些問題:

有沒有人經歷過這樣的事情? 關於服務器發送的CA列表(Windows),.net如何確定要發送給客戶端的內容?有沒有辦法修改該列表? 我是否需要發送用於在該CA列表中籤署我的證書的鏈中的所有權限?或者是一個足夠的根?

我是否在代碼的任何一側缺少某些東西?

任何幫助將不勝感激。 在

+0

問題出在客戶端的證書上。證書不包含完整鏈,因此,當服務器發送包括僅有根CA的有效CA列表時,客戶端無法在存儲中找到匹配的證書。我們將全鏈式證書重新導入密鑰存儲區,所有事情都開始正常工作。 – 2012-03-17 12:07:29

+0

那麼你是如何得到它在JAVA端的工作?任何信息將不勝感激。謝謝 – 2015-02-19 15:04:09

+1

@ Mr.Noob抱歉,對此回覆有很長很長的延遲。在Java方面,這是同樣的問題。證書需要具有完整的CA鏈,因爲驗證是針對鏈進行的。 – 2015-12-03 17:30:57

回答

1

以下兩個語句是在客戶端無用的(雖然他們不應該傷害):

socket.setNeedClientAuth(true); 
socket.setWantClientAuth(true); 

,你看到的證書請求消息和客戶端證書的信息,這表明服務器配置正確。

想到客戶端證書消息中缺少證書的最可能原因是密鑰庫(在客戶端)可能沒有正確配置。您可能對this answer感興趣,以確保您的客戶密鑰存儲已正確配置。更具體地說,您需要確保您的客戶端證書的私鑰以與證書鏈相同的別名導入(並且它是鏈回到證書請求消息中通告的CA)。 (關於您的其餘問題,我不確定如何修改服務器在C#中使用SslStream時發送的CA列表。This earlier question似乎表明沒有解決方案,但.Net的新版本可能會已經解決了這個問題,因爲這個問題被問到,我一直沒有找到任何可以通過查看API文檔和相關類的方法來找到任何問題,但這並不意味着它不存在。)

+0

服務器發送的CA列表來自其信任庫,除非有覆蓋,例如,用Java術語來說,覆蓋'X509TrustManager.getAcceptedIssuers()'。 – EJP 2012-03-16 01:38:04

+0

@EJP,我已經編輯澄清,對不起。我從Java方面知道這一點。我不知道的是.Net的'SslStream'等價物(這是一個C#服務器)。 – Bruno 2012-03-16 01:44:56

+0

肯定它使用Windows信任庫,與IE的相同? – EJP 2012-03-16 05:24:02

相關問題