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 the
2 // 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通信实例及协议分析(上)相关推荐

  1. 分布式专题-分布式消息通信之ActiveMQ02-ActiveMQ原理分析(上)

    目录导航 前言 持久化消息和非持久化消息的发送策略 消息同步发送和异步发送 消息的发送原理分析图解 消息发送的流程图 ProducerWindowSize的含义 消息发送的源码分析 持久化消息和非持久 ...

  2. iOS 用自签名证书实现 HTTPS 请求的原理实例讲解

    在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求.默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info ...

  3. android socket通信如何抓取,安卓Socket通信实例(客户端、服务端)

    安卓Socket通信实例 本文摘自:https://whatsblog.icu/index.php/Android/17.html 1.Socket通信必须知道的地方 1.首先,Socket通信采用T ...

  4. [python学习] 专题七.网络编程之套接字Socket、TCP和UDP通信实例

    很早以前研究过C#和C++的网络通信,参考我的文章:                  C#网络编程之Tcp实现客户端和服务器聊天                 C#网络编程之套接字编程基础知识   ...

  5. Android串口通信实例分析【附源码】

    Android 串口通信实例分析,用的时开源的android-serialport-api 这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖- ...

  6. java socket发送定长报文_一个基于TCP协议的Socket通信实例

    原标题:一个基于TCP协议的Socket通信实例 1. 前言 一般接口对接多以http/https或webservice的方式,socket方式的对接比较少并且会有一些难度.正好前段时间完成了一个so ...

  7. Java 网络实例三(获取URL响应头的日期信息、获取URL响应头信息、解析URL、ServerSocket和Socket通信实例)

    获取 URL响应头的日期信息 以下实例演示了如何使用 HttpURLConnection 的 httpCon.getDate() 方法来获取 URL响应头的日期信息: import java.net. ...

  8. qt android 网络编程实例,QT网络编程Tcp下C/S架构的即时通信实例

    先写一个客户端,实现简单的,能加入聊天,以及加入服务器的界面. #ifndef TCPCLIENT_H #define TCPCLIENT_H #include #include #include # ...

  9. Java Socket 通信实例 - 转载

    基于Tcp协议的简单Socket通信实例(JAVA) 好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络 ...

最新文章

  1. boost::hana::is_just用法的测试程序
  2. rmmod: can't change directory to '/lib/modules': No such file or directory问题解决
  3. sandy引擎学习笔记: 创建一个立方体
  4. 超越Linux!华为鸿蒙明年将成“第五大操作系统”,网友:何时超过iOS?
  5. vrp 节约算法 c++_滴滴技术:浅谈滴滴派单算法
  6. @getmapping注解的作用_@Transactional注解失效了?你遇到的是这6种场景吧!
  7. setjmp.h(c标准库)
  8. 【linux】为什么 mmap 比系统调用快
  9. 利用Python进行数据分析笔记-时间序列(时区、周期、频率)
  10. JQuery版本下载链接
  11. 从功夫胖挞看软件开发
  12. 在Mac上保存网页上的图片
  13. 如何在Jetson NANO上安装无线WIFI模块
  14. 也谈分库分表在实际应用的实践
  15. OS性能监控及优化——osw工具详解
  16. chrome浏览器当鼠标碰到超链接的时候会窗口会抖动
  17. UE4-VaRest插件
  18. 读后感:李敖先生北大演讲
  19. 2019年最推荐的五大Linux发行版
  20. 恢复win10/win11自带文件管理器

热门文章

  1. matlab调用哈希表,ros与matlab联动使用
  2. 有奶瓶的linux系统,用U盘启动BEINI(奶瓶)系统
  3. oracle 依赖包自动安装包,ORACLE 安装提示缺少依赖包
  4. linux 设备 major 253,redhat5.5测试环境中使用udev配置raw设备
  5. mysql授权 改表_mysql开启远程登陆(修改数据表和授权两种方法)
  6. mysql简单聚合函数根据条件单表查询
  7. mysql mysqld.sock_MySQL笔记-最简单的方法来解决找不到mysqld.sock文件的问题
  8. 表示数值的字符串(有限状态自动机与搜索)
  9. 《一天聊一个设计模式》 策略
  10. 剑指offer:45-48记录