準備開發用數字證書編程
通常學習和開發調試場合,不會隨便使用正式的SSL服務器證書的私鑰。因爲服務器驗證對於SSL來講是必須的,SSL服務器端必須有擁有一個服務器 證書,即可以訪問到證書的私鑰。對於要求客戶端驗證的SSL,對客戶端有着一樣的要求,客戶端須要擁有與本身聲稱的身份對應的數字證書。安全
Windows SDK中有一個製做測試開發用的臨時數字證書的命令行工具:makecert.exe。這一工具也被包含在Visual Studio中。打開SDK或者Visual Studio的命令行提示窗口,輸入以下的命令:服務器
makecert –ss 「MY」網絡
會在當前用戶的我的證書存儲中建立一個新的數字證書,證書用途有「全部」(All),這種證書既可以用於服務器驗證,又可以用於用戶驗證。下圖中名 爲Joe’s-Software-Emporium的證書就是makecert命令所生成的,咱們隨後把它用於服務端的身份驗證。咱們再建立一個名爲 Test2的證書,這個證書將會在後面用於客戶端驗證。生成名稱爲Test2的證書命令以下:ide
Makecert -n 「CN=Test2」 -ss 「MY」函數
到這裏,SSL服務器端和客戶端兩邊的證書就都準備好了。須要注意的是,這兩個證書目前都沒有獲得系統的信任,下面的編程調試過程當中,咱們將會討論對證書信任的處理。工具
SSL服務端實現學習
Ssl服務端示例1的功能是在端口443等待客戶端的SSL握手請求,SSL握手成功後,接收客戶端的數據,而後給客戶端發送一段應答數據。測試
首先是實現TCP服務端,使用一個TcpListener對象啓動偵聽,等待鏈接,接受鏈接得到一個與客戶端對等的TcpClient對象。這個比TCP客戶端稍微要複雜一點兒。這裏不詳述,不清楚的讀者能夠閱讀Tcp服務端編程相關的參考資料。代碼片斷以下:ui
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握手。
代碼執行狀況以下:
程序輸出是:
若是咱們強行讓客戶端負責證書檢驗的函數ValidateServerCertificate返回true的話,SSL握手可以完成,後面的加密數據收發也能進行。可是這樣作意味着客戶端會接受任何服務器證書,這樣的ssl客戶端程序對ssl中間人***處於不設防狀態。 咱們不打算在這裏提供這種糟糕的示例,性急的讀者能夠本身改,把上圖中斷點處代碼直接改爲return true,就完事了。須要切記,那樣的ValidateServerCertificate代碼只能用於SSL編程學習玩玩,決不能用於任何正式產品之 中!或者,開發者強行讓計算機信任簽發測試證書的CA,也能讓客戶端示例1完成SSL握手;可是這樣意味着系統信任了一個測試用CA,這會危及整個計算機 的公鑰信任,咱們在這裏也不這麼作。
儘管最簡單的SSL客戶端示例1沒法鏈接這個服務端,可是對於不要求客戶端驗證的SSL服務端,這個服務端代碼已經完整了。若是服務器端加載的是一個由Verisign這樣的公衆信任的CA簽發的有效服務器證書,客戶端示例1將可以正常鏈接並完成數據的加密收發。
因爲多數讀者不會有這樣一個服務器證書,客戶端示例1這樣的,只信任系統信任的證書的安全SSL客戶端,會拒絕與使用測試用證書的SSL服務端創建SSL鏈接。