证书的应用之一 —— TCPSSL通信实例及协议分析(上)

SSL(Security Socket Layer)是TLS(Transport Layer Security)的前身,是一种加解密协议,它提供了再网络上的安全传输,它介于网络通信协议的传输层与应用层之间。

为实现TCP层之上的ssl通信,需要用到数字证书。本文通过具体例子来说明如何使用数字证书来实现网络上的安全传输。需要用到.net提供的SslStream, TcpListener, TcpClient, X509Certificate2,X509Store,X509Certification2Collection等类。终于开始涉及到代码了。

一.服务器端

1.指定证书

常用的有两种方式:从文件获取和从certificate store中获取

a.从文件

ContractedBlock.gifExpandedBlockStart.gif从文件读取证书
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为可导出,如下图所示:

2010062017132692.png

b.从certificate store

 

ContractedBlock.gifExpandedBlockStart.gif从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)

2010062017400679.png

没有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监听

 

ContractedBlock.gifExpandedBlockStart.gifTCP监听
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.指定服务器证书

 

ContractedBlock.gifExpandedBlockStart.gif指定服务器证书
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.接收数据

 

ContractedBlock.gifExpandedBlockStart.gif接收数据
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握手

 

ContractedBlock.gifExpandedBlockStart.gif客户端与服务端建立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时可以不指定证书,

如果serverAuthenticateAsServer是指定client需要cert,而client在调用AuthenticateAsClient时没有指定cert或者cert没有private key时:

server端:AuthenticationExceptionThe 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.

 

ClientAuthenticateAsClient方法指定的名字需要与server端使用cert的名字一致,否则在RemoteCertificateValidationCallback事件中SslPolicyErrors会是RemoteCertificateNameMismatch

3.发送接收数据,关闭连接,与服务器端方法相同


使用Wireshark Network Analyzer工具进行抓包分析,发现在建立TCP连接后,首先进行SSL握手,之后传输的数据都是被加密的,如下图所示:

2010062017430124.png


对SSL的握手和加密传输的详细过程,将在下节分析。

下载Demo

转载于:https://www.cnblogs.com/piyeyong/archive/2010/06/20/1761458.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/462959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自旋锁和互斥锁的区别

自旋锁和互斥锁的区别 POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套API。线程同步是并行编程中非常重要的通讯手段&#xff0c;其中最典型的应用就是用 Pthreads提供的锁机制(lock)来对多个线程之间的共享临界区(Critical Section)进行保护(另一种常用的同步…

校内模拟赛 Zbq's Music Challenge

Zbqs Music Challenge 题意&#xff1a; 一个长度为n的序列&#xff0c;每个位置可能是1或者0&#xff0c;1的概率是$p_i$。对于一个序列$S$&#xff0c;它的得分是 $$BasicScoreA\times \sum_{i1}^{n}{S_i} \tag{1}$$ $$ combo(i)\left\{ \begin{aligned} &S_i & &…

TSQL中实现ORACLE的多列IN 多列匹配。

期望效果&#xff1a;&#xff08;我是拿到一对关系去另一表中的一对关系去对比&#xff09;select * From Empoylee Where (Address1,Address2) in (Select Address1,Address2 From EmpoyleeAdresses Where Country Canada)以上无法实现用这种方案也可以实现 不过速度很慢的s…

ClickedOnce部署方法

1.ClickedOnce部署时有些DLL和配置文件无法自动部署到系统当中&#xff0c;只能用Manifest Manager Tool 修改manifest 文件 /Files/Tonyyang/Software/ManifestManagerUtility.rar 2.部署文件结构 3.部署方法 首先用VS自带的ClickedOnce发布应用程序&#xff08;博客园有&…

自旋锁/互斥锁/读写锁/递归锁的区别与联系

自旋锁 互斥锁 读写锁 递归锁 互斥锁(mutexlock)&#xff1a; 最常使用于线程同步的锁&#xff1b;标记用来保证在任一时刻&#xff0c;只能有一个线程访问该对象&#xff0c;同一线程多次加锁操作会造成死锁&#xff1b;临界区和互斥量都可用来实现此锁&#xff0c;通常情况下…

树莓派安装MySQL数据库与卸载

出处&#xff1a; 1、http://www.cnblogs.com/liyangLife/p/4500115.html 2、https://blog.csdn.net/huayucong/article/details/49736427 3、https://www.imooc.com/article/23132?block_idtuijian_wz 4、http://www.runoob.com/mysql/mysql-install.html&#xff08;Debian系…

关于selectNodes与selectSingleNode的用法的区别

今天在网上看到一个关于selectNodes与selectSingleNode的用法的区别。 由于之前没有特别在意&#xff0c;因而今日看见是很是惊异。特复制过来&#xff0c;供大家一起学习&#xff01; 其中文中提到了最重要的区别是在运用操作后的变化。 selectnodes: selectNodes和ChildNo…

第七章 数组

7.1、数组概述 7.1.1、为什么需要数组 答&#xff1a;有时候需要存储或处理一系列数据&#xff0c;数组就可以充当这样的角色&#xff0c;它在内存中是相连的数据&#xff0c;并且在栈中的引用只有一个&#xff0c; 如果不用数组&#xff0c;那数据就得一个一个定义一个一个声明…

notify_one() 或 notify_all() 在c++中的使用要点

notify_one() 或 notify_all() 如果在锁(mutex spin_lock)里调用&#xff0c;可能会导致被立刻唤醒的线程继续阻塞&#xff0c;因为锁被notify线程持有。 c标准上说&#xff0c;一些实现(尤其是许多 pthread 的实现)为了归避这种情况&#xff0c;在通知调用中&#xff0c;直接将…

[转载]Asp.net MVC中Controller返回值类型

Asp.net MVC中Controller返回值类型在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求&#xff1a; 必须是一个public方法必须是实例方法没有标志NonActionAttribute特性的(NoAction)不能被重载必须返回ActionResult类型如: [cs…

Visual Studio.net 2010 Windows Service 开发,安装与调试

本示例完成一个每隔一分钟向C:\log.txt文件写入一条记录为例&#xff0c;讲述一个Windows Service 程序的开发,安装与调试 原程序&#xff0c;加文档示例下载 /Files/zycblog/SourceCode.rar 目录索引 1 开发工具 2 开发过程 3 安装 4 开发调试 5 注意事项 6 参考资料…

ArcGis dbf读写——挂接Excel到属性表 C#

ArcMap提供了挂接Excel表格信息到属性表的功能&#xff0c;但是当数据量较大到以万计甚至十万计的时候这个功能就歇菜了&#xff0c;当然&#xff0c;你可以考虑分段挂接。这个挂接功能只是做了一个表关联&#xff0c;属性记录每个字段的信息需要通过“字段计算器”计算过来。 …

JQuery. Parse XML children recursively. How? - Stack Overflow

JQuery. Parse XML children recursively. How? - Stack OverflowJQuery. Parse XML children recursively. How?

presto领读 查询引擎翻译

原文链接&#xff1a;https://prestodb.io/docs/current/overview/concepts.html#data-sources 最近在看presto-分布式SQL查询引擎的代码&#xff0c;使用翻译工具翻译了一版&#xff0c;有些概念比较难以理解&#xff0c;整理如下&#xff1a; 一、概览 虽然很容易理解语句和…

VisualStudioAddIn2017.vsix的下载安装和使用

本加载项是用于Visual Studio的&#xff0c;下载以后按照如下步骤进行安装&#xff1a; 完全退出Visual Studio把下载了的文件解压缩&#xff0c;会产生一个VisualStudioAddIn2017.vsix文件双击该文件&#xff0c;按照提示安装重启Visual Studio安装完成后的使用方法&#xff0…

Presto基本概念

Presto基本概念 Presto是Facebook开源的MPP SQL引擎&#xff0c;旨在填补Hive在速度和灵活性&#xff08;对接多种数据源&#xff09;上的不足。相似的SQL on Hadoop竞品还有Impala和Spark SQL等。这里我们介绍下Presto的基本概念&#xff0c;为后续的笔记做基础。 Operator …

2019春第六周编程总结

这个作业属于哪个课程C语言程序设计Ⅱ这个作业要求在哪里https://edu.cnblogs.com/campus/zswxy/MS/homework/2829我在这个课程的目标是利用指针知识解决相关实际问题在具体哪方面帮我实现目标设计密码开锁、交换变量解决问题以及电码加密参考文献C语言基础、http://www.w3scho…

昨天7月21号,笑笑又生病了

21号从上午就开始发烧,中午吃了安瑞克烧退了,但是下午6点左右又开始发烧了,再次吃安瑞克,效果不是太好,还是烧,睡了觉之后烧退了。晚上十点又开始发烧&#xff0c;吃美林悬浮液烧还是没退&#xff0c;又吃安瑞克&#xff0c;还是烧&#xff0c;到了一点钟,烧,但稍微好一点 22号…

Exchange企业实战技巧(26)在Outlook中打开多个邮箱

工作中&#xff0c;有时要需要让某个用户在outlook中同时打开多个exchange邮箱&#xff0c;对于outlook2010来说&#xff0c;是支持多个Exchange邮箱用户账户的并存&#xff0c;而outlook2007则不支持。那该功能有没其他实现方法呢&#xff1f;答案是有的。 如果你的Exchange是…

sql 为什么要用where 1=1或者where 1 =0 ?

一、不用where 11 在多条件查询中的困扰   举个例子&#xff0c;如果您做查询页面&#xff0c;并且&#xff0c;可查询的选项有多个&#xff0c;同时&#xff0c;还让用户自行选择并输入查询关键词&#xff0c;那么&#xff0c;按平时的查询语句的动态构造&#xff0c;代码…