证书的应用之一 —— TCPSSL通信实例及协议分析(上)
SSL(Security Socket Layer)是TLS(Transport Layer Security)的前身,是一種加解密協議,它提供了再網絡上的安全傳輸,它介于網絡通信協議的傳輸層與應用層之間。
為實現TCP層之上的ssl通信,需要用到數字證書。本文通過具體例子來說明如何使用數字證書來實現網絡上的安全傳輸。需要用到.net提供的SslStream, TcpListener, TcpClient, X509Certificate2,X509Store,X509Certification2Collection等類。終于開始涉及到代碼了。
一.服務器端
1.指定證書
常用的有兩種方式:從文件獲取和從certificate store中獲取
a.從文件
從文件讀取證書 1 OpenFileDialog dialog = new OpenFileDialog();2 dialog.Filter = "Cert files(*.pfx;*.p7b;*.cer)|*.pfx;*.p7b;*.cer|All files(*.*)|*.*";
3 DialogResult dr = dialog.ShowDialog();
4 if (dr == DialogResult.OK)
5 {
6 Console.WriteLine("Input the password for the cert:");
7 StringBuilder stringBuilder = new StringBuilder();
8 while (true)
9 {
10 ConsoleKeyInfo passInfo = Console.ReadKey(true);
11 if (passInfo.Key == ConsoleKey.Enter)
12 {
13 break;
14 }
15 stringBuilder.Append(passInfo.KeyChar);
16 }
17 return new X509Certificate2(dialog.FileName, stringBuilder.ToString(), X509KeyStorageFlags.Exportable);
18 }
19 else
20 {
21 return null;
22 }
注意X509Certificate2構造函數第三個參數,如果想把調用Export方法將cert對象到處,此處必須使用Exportable標記,否則在導出時會拋出異常。
pfx格式的證書包含有private key,因此需要密碼的保護,構造函數的第二個參數就是密碼。
選取的證書必須包含有private key,否則在SSL的server端使用時會拋出AuthenticationException。
怎么得到pfx文件:使用MMC->File->Add/Remove Sanp-in->Add->Certificates->Add->My user account/Computer account->Finish 查看存儲在本機當前用戶和所有用戶的證書,選擇用導出的證書,
右鍵->All Tasks...->Export...注意要勾選[Yes, export the private key],如果該Radio button被禁用,說明該證書的private key不能被導出,可能是在導入該證書時沒有選擇標記private key為可導出,如下圖所示:
b.從certificate store
?
從store讀取證書 1 X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);2 store.Open(OpenFlags.ReadOnly);
3 X509Certificate2Collection collection = X509Certificate2UI.SelectFromCollection(store.Certificates,
4 "Select Certificate",
5 "Please select a certificate from the following list",
6 X509SelectionFlag.SingleSelection);
注意:
Server端指定的cert必須含有privatekey,且Enhanced key usage必須含有Server Authentication (1.3.6.1.5.5.7.3.1)
沒有private key:
NotSupportedException: The server modeSSL must use a certificate with the associated private key.
證書purpose不對:
server端:AuthenticationException: A call to SSPIfailed, see inner exception.
client端:IOException: Unable to read data from the transport connection: Anexisting connection was forcibly closed by the remote host..
2.開始TCP監聽
?
TCP監聽 1 TcpListener listener = new TcpListener(IPAddress.Any, 8080);2 listener.Start();
3 while (true)
4 {
5 Console.WriteLine("Waiting for a client to connect...");
6 TcpClient client = listener.AcceptTcpClient();
7 ......
8 }
?
3.指定服務器證書
?
指定服務器證書 1 // A client has connected. Create the2 // SslStream using the client's network stream.
3 ? SslStream sslStream = new SslStream(client.GetStream(), false);
4 // Authenticate the server but don't require the client to authenticate.
5 ? try
6 {
7 sslStream.AuthenticateAsServer(cert, false, SslProtocols.Default, false);
8
9 // Set timeouts for the read and write to 5 seconds.
10 ? sslStream.ReadTimeout = 5000;
11 sslStream.WriteTimeout = 5000;
12 ......
13 }
?
4.發送數據
?
1 byte[] message = Encoding.UTF8.GetBytes("Hello from the server.<EOF>");2 sslStream.Write(message);
3 sslStream.Flush();
?
5.接收數據
?
接收數據 1 byte[] buffer = new byte[2048];2 StringBuilder messageData = new StringBuilder();
3 int bytes = -1;
4 do
5 {
6 // Read the client's message.
7 ? bytes = sslStream.Read(buffer, 0, buffer.Length);
8 messageData.Append(Encoding.UTF8.GetString(buffer, 0, bytes));
9 // Check for EOF or an empty message.
10 ? if (messageData.ToString().IndexOf("<EOF>") != -1)
11 {
12 break;
13 }
14 } while (bytes != 0);
15
16 return messageData.ToString();
?
注意:Write后需要調用Flush將數據立刻發送,Read需要多次調用,確定讀不到數據位置,因為TCP連接時Stream方式的,在網絡中傳輸可能會分包到達,一次無法全部讀取,還需要消息邊界。
6.結束
?
1 sslStream.Close();2 client.Close();
?
二.客戶端
1.與服務器端建立TCP連接
?
1 TcpClient client = new TcpClient(machineName, 8080);2.與服務端建立SSL握手
?
客戶端與服務端建立SSL握手 1 SslStream sslStream = new SslStream(2 client.GetStream(),
3 false,
4 new RemoteCertificateValidationCallback(ValidateServerCertificate),
5 null
6 );
7 try
8 {
9 // The server name must match the name on the server certificate.
10 ? X509Certificate2 cert = GetCert();
11 X509Certificate2Collection collection = new X509Certificate2Collection();
12 if(cert != null)
13 {
14 collection.Add(cert);
15 }
16 sslStream.AuthenticateAsClient(serverName, collection, SslProtocols.Default, false);
17 }
18 catch (AuthenticationException e)
19 {
20 Console.WriteLine("Exception: {0}", e.Message);
21 if (e.InnerException != null)
22 {
23 Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
24 }
25 Console.WriteLine("Authentication failed - closing the connection.");
26 client.Close();
27 return;
28 }
?
如果服務端在調用AuthenticateAsServer方法時指定不需要客戶端的證書,則客戶端在調用AuthenticateAsClient時可以不指定證書,
如果server在AuthenticateAsServer是指定client需要cert,而client在調用AuthenticateAsClient時沒有指定cert或者cert沒有private key時:
server端:AuthenticationException:The remote certificate is invalid according to the validationprocedure.
client端:IOException: Unable to read data from the transportconnection: An established connection was aborted by the software in your hostmachine.
?
Client在AuthenticateAsClient方法指定的名字需要與server端使用cert的名字一致,否則在RemoteCertificateValidationCallback事件中SslPolicyErrors會是RemoteCertificateNameMismatch
3.發送接收數據,關閉連接,與服務器端方法相同
使用Wireshark Network Analyzer工具進行抓包分析,發現在建立TCP連接后,首先進行SSL握手,之后傳輸的數據都是被加密的,如下圖所示:
對SSL的握手和加密傳輸的詳細過程,將在下節分析。
下載Demo
轉載于:https://www.cnblogs.com/piyeyong/archive/2010/06/20/1761458.html
總結
以上是生活随笔為你收集整理的证书的应用之一 —— TCPSSL通信实例及协议分析(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: endnote x9打开闪退_最新最全!
- 下一篇: ssm上传文件进度条_ssm学习笔记-三