SSL編程(3).NET實現SSL服務端

準備開發用數字證書

一般學習和開發調試場合,不會隨便使用正式的SSL服務器證書的私鑰。由於服務器驗證對於SSL來說是必須的,SSL服務器端必須有擁有一個服務器 證書,即能夠訪問到證書的私鑰。對於要求客戶端驗證的SSL,對客戶端有着同樣的要求,客戶端需要擁有與自己聲稱的身份對應的數字證書。

Windows SDK中有一個製作測試開發用的臨時數字證書的命令行工具:makecert.exe。這一工具也被包含在Visual Studio中。打開SDK或者Visual Studio的命令行提示窗口,輸入如下的命令:

makecert –ss “MY”

會在當前用戶的個人證書存儲中創建一個新的數字證書,證書用途有“所有”(All),這種證書既能夠用於服務器驗證,又能夠用於用戶驗證。下圖中名 爲Joe’s-Software-Emporium的證書就是makecert命令所生成的,我們隨後把它用於服務端的身份驗證。我們再創建一個名爲 Test2的證書,這個證書將會在後面用於客戶端驗證。生成名稱爲Test2的證書命令如下:

Makecert -n “CN=Test2” -ss “MY”

myMakeCerts

到這裏,SSL服務器端和客戶端兩邊的證書就都準備好了。需要注意的是,這兩個證書目前都沒有得到系統的信任,下面的編程調試過程中,我們將會討論對證書信任的處理。

SSL服務端實現

Ssl服務端示例1的功能是在端口443等待客戶端的SSL握手請求,SSL握手成功後,接收客戶端的數據,然後給客戶端發送一段應答數據。

首先是實現TCP服務端,使用一個TcpListener對象啓動偵聽,等待連接,接受連接獲得一個與客戶端對等的TcpClient對象。這個比TCP客戶端稍微要複雜一點兒。這裏不詳述,不清楚的讀者可以閱讀Tcp服務端編程相關的參考資料。代碼片段如下:

TcpListener listener = new TcpListener(IPAddress.Any, 443);

listener.Start();

while (true)

            {

Console.WriteLine("Waiting for a client to connect...");

// 應用程序會阻塞在這裏,直到有一個客戶端發起連接.

TcpClient client = listener.AcceptTcpClient();

           ProcessClient(client);

            }

代碼運行到ProcessClient時,服務端已經有了由一個TcpClient對象代表的Tcp連接。到這裏,在網絡通信層面上,服務端與客戶 端成爲對等的。我們使用從服務器端的TcpClient對象的IO流構造一個SslStream對象,處理SSL協議。服務端與客戶端的差異在於服務器端 要調用AuthenticateAsServer函數,把自己設定爲SSL服務端模式,並進入等待對端作爲客戶端發起SSL握手。 AuthenticateAsServer函數必須有一個服務器證書作爲輸入,加載名爲Joe's-Software-Emporium的服務器證書代碼 片段如下:

X509Store store = new X509Store("MY", StoreLocation.CurrentUser );
store.Open(OpenFlags.ReadOnly);    
X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates.Find(X509FindType.FindBySubjectName, @"Joe's-Software-Emporium",false);    
serverCertificate = storecollection[0];


把獲得的serverCertificate對象作爲服務器證書輸入,啓動SSL服務端:

SslStream sslStream = new SslStream(

           client.GetStream(), false,

new RemoteCertificateValidationCallback(ValidateClientCertificate));

// Authenticate the server but don't require the client to authenticate.

try

            {

                 sslStream.AuthenticateAsServer(serverCertificate,

                                                                 false, // 這個參數決定是否需要客戶端出示數字證書對客戶端身份進行驗證.

                                                                 SslProtocols.Tls, false);

             // Display the properties and settings for the authenticated stream.

建立連接後,服務器調用SslStream的Read, Write函數,進行數據的安全收發處理。

SSL連接測試

我們仍然使用前面的簡單SSL客戶端示例1,修改目標地址和端口連接SSL服務端示例1。客戶端立即報告服務端出示的證書無效,結束了SSL握手。

代碼執行情況如下:

p_w_picpath

程序輸出是:

p_w_picpath

如果我們強行讓客戶端負責證書檢驗的函數ValidateServerCertificate返回true的話,SSL握手能夠完成,後面的加密數據收發也能進行。但是這樣做意味着客戶端會接受任何服務器證書,這樣的ssl客戶端程序對ssl中間人***處於不設防狀態。 我們不打算在這裏提供這種糟糕的示例,性急的讀者可以自己改,把上圖中斷點處代碼直接改成return true,就完事了。需要切記,那樣的ValidateServerCertificate代碼只能用於SSL編程學習玩玩,決不能用於任何正式產品之 中!或者,開發者強行讓計算機信任簽發測試證書的CA,也能讓客戶端示例1完成SSL握手;但是這樣意味着系統信任了一個測試用CA,這會危及整個計算機 的公鑰信任,我們在這裏也不這麼做。

儘管最簡單的SSL客戶端示例1無法連接這個服務端,但是對於不要求客戶端驗證的SSL服務端,這個服務端代碼已經完整了。如果服務器端加載的是一個由Verisign這樣的公衆信任的CA簽發的有效服務器證書,客戶端示例1將能夠正常連接並完成數據的加密收發。

由於多數讀者不會有這樣一個服務器證書,客戶端示例1這樣的,只信任系統信任的證書的安全SSL客戶端,會拒絕與使用測試用證書的SSL服務端建立SSL連接。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章