精华内容
下载资源
问答
  • mtproxy:MTProxyTLS一键安装绿色脚本
  • 不要由于java混淆了本质,其实就是TLS的概念,去问问搞linux的前辈,TLS的目的是为了线程同步和互斥?完全不同的概念 简直误人子弟,我在OSCHINA看到两篇关于ThreadLocal的文档了,都是说“ThreadLocal是解决线程...

    OSCHINA上看到了好几篇帖子在介绍Java的ThreadLocal类,但是,说到该类的作用是,竟然一致的都和线程的同步/互斥扯上关系,将其划作与Synchronized功能一样的,用来解决多线程间并发访问共享资源的一种方式。 觉得实在有必要澄清一下,下面汇总了我回的一些内容,作为澄清。

    首先Java的ThreadLocal本质上就是TLS(Thread Local Storage),所以TLS的作用究竟是什么那?

    不要由于java混淆了本质,其实就是TLS的概念,去问问搞linux的前辈,TLS的目的是为了线程同步和互斥?完全不同的概念

    简直误人子弟,我在OSCHINA看到两篇关于ThreadLocal的文档了,都是说“ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题”。 TLS(Thread Local Storage) 是为了解决线程安全和并发访问共享资源的目的?! 线程互斥技术是为了解决,多个线程间共享的,大家都要访问和读写的资源,如何在线程并发时不会有问题,典型的打印机问题!注意,这里的资源,是需要在多个线程间共享的!

    而TLS究竟是解决什么问题那? TLS解决了这样一个需求,就是希望在一个/每个线程的线程上下文/环境下执行的任何实体(函数,组件等)内,都能访问某一个变量。 那么很明显,这个变量是需要做成全局的,但是,普通全局的会污染别的线程。所以,此时需要TLS。 举个最简单的例子,假设我的程序会连续启动6个线程去创建文件,线程代码是完全一样的。那么,我就可以使用TLS来记录线程上下文中的文件句柄。此时,我使用一致的文件操作代码,却能保证不管在任何实体中操作的文件句柄,都自动的是当前线程下的打开文件的文件句柄

     

    TLS更多的是用来存储线程上下文相关的信息,使得在一致的代码中,自动访问差异性的线程绑定的上下文相关信息

     

    对TLS更简单的,但是更直观的理解可以如下(基于C语言):

    1. 全局对象,全局变量的作用域和生命周期是全局的,这里的全局是指进程范畴,也就是说,如果你将其设计为全局对象,全局变量,就意味着你希望在多线程的环境中,仍然能共享和访问。 全局对象,全局变量不是说不让多线程来访问,而是说有的时候不期望他们同时访问,此时引入了线程的互斥,互斥的后果是保证不同时访问,但是,并没有改变共享的本质!

    2. 如果设计的时候,就希望将某个对象,变量设计为线程局部的,那典型的是可以将其设计为函数的局部变量。 可是,我如果又希望在线程执行时,任意的函数和对象里面都可以访问到它那?! 此时,可能会想到用全局对象,全局变量,但是,它又会使得这种访问域上升到进程级别,其实,我只是想在线程局部环境中,全局访问该对象。 此时TLS应运而生,TLS就是达到了这种, 在线程局部环境(或者称呼为线程执行环境,线程上下文)下可以全局访问的对象/变量。

    关于TLS的实际应用,更多的是定义一个TLS对象来存储一些线程上下文相关的信息。

     

    给你取这样一个典型的例子吧,你可以看到TLS实际的应用场合。

    在一个支持单进程,多线程的轻量级移动平台中,假设我实现了一个APP Framework,每一个APP单独运行在一个独立的线程中,APP运行时关联了很多信息,比如打开的文件,引用的组件,启动的Timer等等。我希望框架能实现自动垃圾回收,什么概念,就会应用退出的时候,即便应用没有主动释放打开的文件句柄,没有主动cancel Timer,没有主动释放组件的引用,框架也可以自动完成这些收尾工作,否则,后果是不堪想象的。

    好了,假设应用的退出是调用了框架的 ExitApp API, 该API允许应用调用后关闭自己,也允许关闭别的应用。 那么,假设该API触发了应用的退出,最终调用到框架的App_CleanUp函数,那么App_CleanUp函数除了完成应用本身实例的释放外,肯定是在这里来完成我们上面说的收尾工作,怎么来做哪?! 很明显,这里典型的,就可以使用TLS了。具体如下:

    在Framework的API中,当应用的线程启动时,New 一个AppContext的对象或者结构体,然后将对象的指针或者结构体的指针以TLS的方式存储起来。 AppContext内部包含了文件句柄,timer引用,组件引用等等。 然后,后续任何框架的文件操作/Timer操作时,取当前线程的TLS,然后转换成AppContext后,将更新的文件句柄,timer引用等更新入AppContext对象内部。  然后,应用退出时,获取TLS,然后转换成AppContext,取出非空的文件句柄,组件引用,Timer引用等,来完成Cancel和Close操作。


    其他不想说了,如果你能明白这个实际的例子,你就可以明白TLS的用途了。 上述的例子,来源于BREW/BMP框架内部的实际实现,当然有差别,但是思想是一样的

     

    转载于:https://my.oschina.net/u/735298/blog/115434

    展开全文
  • SSL/TLS单向认证和双向认证介绍

    千次阅读 2020-06-19 15:05:20
    为了便于理解SSL/TLS的单向认证和双向认证执行流程,这里先介绍一些术语。 1. 散列函数(Hash function):又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字”指纹”的方法。散列函数把消息或数据压缩成...

    为了便于理解SSL/TLS的单向认证和双向认证执行流程,这里先介绍一些术语。

    1. 散列函数(Hash function):又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字”指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values, hash codes, hash sums)的指纹。散列值通常用一个短的随机字母和数字组成的字符串代表。好的散列函数在输入域中很少出现散列冲突。

    散列函数的工作原理如下图所示:把输入(消息、文件等)看成n比特块的序列。对输入用迭代方式每次处理一块,生成n比特的散列函数。

    所有散列函数都有如下一个基本特性:如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的。这个特性是散列函数具有确定性的结果,具有这种性质的散列函数称为单向散列函数。但另一方面,散列函数的输入和输出不是唯一对应关系的,如果两个散列值相同,两个输入值很可能是相同的,但也可能不同,这种情况称为”散列碰撞(collision)”,这通常是两个不同长度的输入值,刻意计算出相同的输出值。输入一些数据计算出散列值,然后部分改变输入值,一个具有强混淆特性的散列函数会产生一个完全不同的散列值。典型的散列函数都有非常大的定义域,比如SHA-2最高接受(2^64-1)/8长度的字节字符串。同时散列函数一定有着有限的值域,比如固定长度的比特串。在某些情况下,散列函数可以设计成具有相同大小的定义域和值域间的单射。在密码学中,散列函数必须具有不可逆性。

    为满足在消息认证中的应用,散列函数H必须具有下列性质:

    (1).H可适用于任意长度的数据块。

    (2).H能生成固定长度的输出。

    (3).对于任意给定的x,计算H(x)相对容易,并且可以用软/硬件方式实现。

    (4).对于任意给定值h,找到满足H(x)=h的x在计算上不可行。满足这一特性的散列函数称为具有单向性,或具有抗原像攻击性。

    (5).对于任意给定的数据块x,找到满足H(y)=H(x)的y!=x在计算上是不可行的。满足这一特性的散列函数被称为具有抗第二原像攻击性,有时也称为具有抗弱碰撞攻击性。

    (6).找到满足H(x)=H(y)的任意一对(x,y)在计算上是不可行的。满足这一特性的散列函数被称为抗碰撞性,有时也被称为抗强碰撞性。

    前三个性质是使用散列函数进行消息认证的实际可行要求。第四个属性,抗原像攻击,是单向性:给定消息容易产生它的散列码,但是给定散列码几乎不可能恢复出消息。抗第二原像攻击性质保证了对于给定的消息,不可能找到具有相同散列值的可替换消息。满足上面前5个性质的散列函数称为弱散列函数。如果还满足第6个性质则称其为强散列函数。除提供认证之外,消息摘要还能验证数据的完整性。

    应用最为广泛的散列函数是安全散列算法(SHA)。SHA是基于散列函数MD4,按照消息摘要大小,可分为SHA-1、SHA-224、SHA-256、SHA-384、SHA-512,后4种又被称为SHA-2,它们输出摘要大小依次为160bits、224bits、256bits、384bits、512bits。SHA-1不再认可。

    2. HMAC(Hash-based Message Authentication Code):基于Hash的消息认证码,又称散列消息认证码,是一种通过特别计算方式之后产生的消息认证码(MAC),使用密码散列函数,同时结合一个加密密钥。它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证。HMAC运算利用哈希算法,以一个密钥和一个消息作为输入,生成一个消息摘要作为输出。使用消息摘要算法MD2、MD4、MD5、SHA-1、SHA-224、SHA-256、SHA-384、SHA-512所构造的HMAC,分别称为HMAC-MD2、HMAC-MD4、HMAC-MD5、HMAC-SHA1、HMAC-SHA-224、HMAC-SHA-384、HMAC-SHA-512。

    3. 数字签名(digital signature):又称公钥数字签名,是一种功能类似写在纸上的普通签名,但是使用了公钥加密领域的技术,以用于鉴别数字信息的方法。一套数字签名通常会定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。数字签名了的文件的完整性是很容易验证的,而且数字签名具有不可抵赖性(即不可否认性),其过程如下图所示:

    每个人都有一对”钥匙”(数字身份),其中一个只有本人知道(私钥),另一个公开的(公钥)。签名的时候用私钥,验证签名的时候用公钥。又因为任何人都可以落款申称他就是使用者本人,因此公钥必须向接受者信任的人(身份认证机构)来注册。注册后身份认证机构给使用者发一数字证书。对文件签名后,使用者把此数字证书连同文件及签名一起发给接受者,接受者向身份认证机构求证是否真地是用使用者的密钥签发的文件。

    信息发布者可以使用数字签名,信息发布的目的是让人们知道信息,虽然没必要对消息进行加密,但是必须排除有人伪装信息发布者发布假消息的风险,这时信息发布者就可以使用数字签名。而对明文消息施加的签名,称为明文签名(clearsign)。软件的作者可以加上数字签名,以便用户下载后对签名进行验证。认证机构(CA)也可以为用户的公钥加上数字签名生成证书,以便人们确认用户公钥的合法性。SSL/TLS使用服务器证书(加上了数字签名的服务器公钥)认证服务器身份是否合法。

    通常我们使用公钥加密,用私钥解密。而在数字签名中,我们使用私钥加密(相当于生成签名),公钥解密(相当于验证签名)。我们可以直接对消息进行签名(即使用私钥加密,此时加密的目的是为了签名,而不是保密),验证者用公钥正确解密消息,如果和原消息一致,则验证签名成功。但通常我们会对消息的散列值签名,因为通常散列值的长度远小于消息原文,使得签名(非对称加密)的效率大大提高。注意,计算消息的散列值不是数字签名的必要步骤。在实际使用中,我们既想加密消息,又想签名,所以要对加密和签名组合使用,比如TLS就组合了加密和签名。数字签名应用了公钥密码领域使用的单向函数原理。单向函数指的是正向操作非常简单,而逆向操作非常困难的函数,比如大整数乘法。一般签名对象为消息的散列值

    4. 公开密钥认证(public key certificate,或公钥证书),又称数字证书(digital certificate)或身份证书(identity certificate):是用于公开密钥基础建设的电子文件,用来证明公开密钥拥有者的身份。此文件包含了公钥信息、拥有者身份信息(主体)、以及数字证书认证机构(发行者)对这份文件的数字签名,以保证这个文件的整体内容正确无误。拥有者凭着此文件,可向电脑系统或其他用户表明身份,从而对方获得信任并授权访问或使用某些敏感的电脑服务。电脑系统或其他用户可以透过一定的程序核实证书上的内容,包括证书有否过期、数字签名是否有效,如果你信任签发的机构,就可以信任证书上的密钥,凭公钥加密与拥有者进行可靠的通信。简而言之,认证机构用自己的私钥对需要认证的人(或组织机构)的公钥施加数字签名并生成证书,即证书的本质就是对公钥施加数字签名。数字证书的其中一个最主要好处是在认证拥有者身份期间,拥有者的敏感个人数据(如出生日期、身份证号码等)并不会传输至索取数据者的电脑系统上。透过这种数据交换模式,拥有者既可证实自己的身份,亦不用过度披露个人数据,对保障电脑服务访问双方皆有好处。人们透过信任数字证书认证机构的根证书、及其使用公开密钥加密作数字签名核发的公开密钥认证,形成信任链架构,已在TLS实现并在万维网的HTTPS、在电子邮件的SMTPS和STARTTLS广泛应用。业界现行的标准是国际电信联盟电信标准化部门制定的X.509,并由IETF发行的RFC 5280详细述明。

    证书种类:根证书(自签证书)、中介证书和终端实体(TLS服务器/客户端)证书的关系,如下图所示:

    (1).自签证书:在用于小范围测试等目的的时候,用户也可以自己生成数字证书,但没有任何可信赖的人签名,这种自签名证书通常不会被广泛信任,使用时可能会遇到电脑软件的安全警告。

    (2).根证书:获得广泛认可,通常已预先安装在各种软件(包括操作系统、浏览器、电邮软件等),作为信任链的起点,来自于公认可靠的政府机关、软件公司、证书颁发机构公司等,与各大软件商透过严谨的核认程序才在不同的软件广泛部署。由于部署程序复杂费时,需要行政人员的授权及机构法人身份的核认,一张根证书有效期可能长达十年以上。在某些企业,也可能会在内部电脑自行安装企业自签的根证书,以支持内部网的企业级软件;但是这些证书可能未被广泛认可,只在企业内部适用。

    (3).中介证书(或中间证书):认证机构的一个重要任务就是为客户签发证书,虽然广泛认可的认证机构都已拥有根证书,相对应的私钥可用以签署其他证书,但因为密钥管理和行政考虑,一般会先行签发中介证书,才为客户作数字签署。中介证书的有效期会较根证书为短,并可能对不同类别的客户有不同的中介证书作分工。

    (4).授权证书:又称属性证书,本身没有公钥,必须依附在一张有效的数字证书上才有意义,其用处是赋予相关拥有人签发终端实体证书的权力;某些情况下,如果只在短期内授予证书机构签发权力,便可以不改变(缩短)该机构本身持有的证书的有效期。这种情况,类似于某人持有长达十年期的护照,而只透过签发短期入境签证,来个别赋予护照持有人额外权力。

    (5).终端实体证书(或叶子证书):其他不会用作签发其他证书的,都可称为终端实体证书,在实际的软件中部署,以便创建加密通道时应用。

    (6).TLS服务器证书:服务器通常以域名形式在互联网上提供服务,服务器证书上主体的通用名称就会是相应的域名,相关机构名称则写在组织或单位一栏上。服务器证书(包括公钥)和私钥会安装于服务器,等待客户端连接时协议加密细节。客户端的软件(如浏览器)会运行认证路径验证算法以确保安全,如果未能肯定加密通道是否安全(例如证书上的主体名称不对应网站域名、服务器使用了自签证书、或加密算法不够强),可能会警告用户。

    (7).通配符证书:如果服务器证书上主体的通用名称(或主体别名)一栏以通配符前缀,则该证书可以用于旗下的所有子域名,特别适合较具规模、或设有多个子网站的机构一次过申领,套用于多个服务器上;即使未来创建新的子域名,也可以套用。但通配符不可用于扩展认证证书上。

    (8).TLS客户端证书:有时候,某些TLS服务器可能会在创建加密通道时,要求客户端提供客户端证书,以验证身份及控制访问权限。客户端证书包含电子邮件地址或个人姓名,而不是主机名。但客户端证书比较不常见,因为考虑到技术门槛及成本因素,通常都是由服务提供者验证客户身份,而不是依赖第三方认证机构。通常,需要使用到客户端证书的服务都是内部网的企业级软件,他们会设立自己的内部根证书,由企业的技术人员在企业内部的电脑安装相关客户端证书以便使用。在公开的互联网,大多数网站都是使用登录密码和Cookie来验证用户,而不是客户端证书。客户端证书在RPC系统中更常见,用于验证连接设备的许可授权。

    证书申领:(1).鲍伯在自己的机器上使用密码学安全伪随机数生成器产生一对足够强的密钥,鲍伯的私钥不会向任何人发送。(2).鲍伯把他的公钥,连同主体消息、使用目的等组成证书签署请求,发送给认证机构伊凡。(3).伊凡(用另外一些渠道)核实鲍伯的身份。(4).如果伊凡信任这个请求,他便使用鲍伯的公钥和主体消息,加上证书有效期、用途等限制条件,组成证书的基本数据。(5).伊凡用自己的私钥对鲍勃的公钥加上数字签名并生成证书。(6).伊凡把生成的证书发送给鲍伯(伊凡也可以透过证书透明度公布他签发了新的证书)。

    证书使用:(1).鲍伯可以随便把证书向外发布。(2).鲍伯与爱丽丝事先可能互不认识,但鲍伯与爱丽丝都信任伊凡,爱丽丝使用认证机构伊凡的公钥验证数字签名,如果验证成功,便可以信任鲍勃的公钥是真正属于鲍伯的。(3).爱丽丝可以使用证书上的鲍勃的公钥加密明文,得到密文并发送给鲍伯。(4).鲍伯可以可以用自己的私钥把密文解密,得到明文。

    电子证书可以二进制或Base64形式存储,常见的文件扩展名有.cer、.crt、.der和.pem。如果把证书和私钥一起存储,则可以使用PKCS#12(.p12)格式。

    5. X.509:ITU-T推荐标准X.509是X.500推荐标准系列的一部分,X.500系列推荐标准定义了一套目录服务。所谓目录服务,实际上是指用于维护用户信息数据库的一个或一组分布式服务器。这些信息包括从用户名到网络地址的映射关系,以及其他关于用户的属性和信息。X.509定义了一个使用X.500目录向用户提供认证服务的框架。该目录可以作为公钥证书存储库。每个证书都包括用户的公钥,并由一个可信任的认证中心用私钥签名。除此之外,X.509定义了另一个基于使用公钥证书的认证协议。

    X.509是密码学里公钥证书的格式标准。X.509证书已应用在包括TLS/SSL在内的众多网络协议里。X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名。除了证书本身功能,X.509还附带了证书吊销列表和用于从最终对证书进行签名的证书签发机构直到最终可信点为止的证书合法性验证算法。X.509是ITU-T标准化部门基于他们之前的ASN.1定义的一套证书标准。

    X.509基于公钥加密体制和数字签名的使用。这个标准并没有强制使用某个特定的算法,但是推荐使用RSA。数字签名方案假定需要使用散列函数。同样,这个标准也没有强制使用某种特定的散列算法。

    X.509方案的核心是与每个用户相关联的公钥证书。这些用户证书是由可信任的认证中心(CA)创建的,并由CA或用户放在目录中。目录服务器本身不负责公钥的产生和认证功能,它只为用户获取证书提供一个容易访问的场所。

    浏览器(如Firefox、Internet Explorer、Microsoft Edge、Safari以及Google Chrome)和操作系统都预装有可信任的根证书列表,所以主流CA发布的TLS证书都直接可以正常使用

    证书文件扩展名:X.509有多种常用的扩展名,不过其中的一些还用于其它用途,就是说具有这个扩展名的文件可能并不是证书,比如说可能只是保存了私钥。

    (1).pem:DER编码的证书再进行Base64编码的数据存放在"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----"之中。

    (2).cer, .crt, .der:通常是DER二进制格式的,但Base64编码后也很常见。

    (3).p7b, .p7c:PKCS#7 SignedData structure without data, just certificate(s) or CRL(s)。

    (4).p12:PKCS#12格式,包含证书的同时可能还有带密码保护的私钥。

    (5).pfx:PFX,PKCS#12之前的格式(通常用PKCS#12格式,比如那些由IIS产生的PFX文件)。

    PKCS#7是签名或加密数据的格式标准,官方称之为容器。由于证书是可验真的签名数据,所以可以用SignedData结构表述。.P7C文件是退化的SignedData结构,没有包括签名的数据。

    PKCS#12由PFX进化而来的用于交换公共的和私有的对象的标准格式。

    证书的一般结构包含以下要素,如下图所示:一般遵从X.509格式规范的证书,会有以下的内容,它们以字段的方式表示。

    (1).版本:区别连续版本中的证书格式,默认为版本1;如果证书中有发放者唯一标识符或者主体唯一标识符,则说明此值一定为2;如果存在一个或多个扩展,则此值一定为3。现行通用版本是3。

    (2).序号:一个整数值,此值在发放证书的CA中唯一,且明确与此证书相关联。

    (3).签名算法标识符:用于进行签名证书的算法和一切有关的参数。由于此信息在证书末尾的签名域中被重复,此域基本没有用处。

    (4).发放者名称:创建和签发该证书的CA的X.500名称。

    (5).有效期:包括两个日期:证书有效的最初日期和最晚日期。

    (6).主体名称:此证书指向用户的名称。也就是说,此证书核实拥有相关私钥的主体的公钥。

    (7).主体公钥信息:主体的公钥,加上一个表明此公钥用于何种加密算法的标识和任何相关参数。

    (8).发放者唯一标识符:一个可选的比特串域,在X.500名称被重用于不同实体中的情况下,它用来唯一地确定发放证书的CA。

    (9).主体唯一标识符:一个可选的比特串域,在X.500名称被重用于不同实体中的情况下,它用来唯一地确定主体。

    (10).扩展:一个和多个扩展域组成的集合。在版本3中加入扩展。

    (11).签名:包括此证书的一切其他的域。它包含用CA的私钥加密过的其他域的散列码。此域包含签名算法标识符。

    6. 认证中心(Certificate Authority , CA):数字证书认证机构,也称为电子商务认证中心、电子商务认证授权机构,是负责发放和管理数字证书的权威机构,并作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。

    CA中心为每个使用公开密钥的用户发放一个数字证书,数字证书的作用是证明证书中列出的用户合法拥有证书中列出的公开密钥。CA机构的数字签名使得攻击者不能伪造和篡改证书。它负责产生、分配并管理所有参与网上交易的个体所需的数字证书,因此是安全电子交易的核心环节。在SET交易中,CA不仅对持卡人、商户发放证书,还要对获款的银行、网关发放证书。CA是证书的签发机构,它是PKI(Public Key Infrastructure)的核心。CA是负责签发证书、认证证书、管理已颁发证书的机关。它要制定政策和具体步骤来验证、识别用户身份,并对用户证书进行签名,以确保证书持有者的身份和公钥的拥有权。用户若欲获取证书,应先向CA提出申请,CA判明申请者的身份后,为之分配一个公钥,并将该公钥与其身份信息绑定,为该整体签名,签名后的整体即为证书,发还给申请者。如果一个用户想鉴别另一个证书的真伪,他就用CA的公钥对那个证书上的签字进行验证,一旦验证通过,该证书就被认为是有效的。

    7. SSL/TLS:Secure Sockets Layer/ Transport Layer Security(安全套接层/传输层安全性协议),是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。TLS的前身是SSL。网景公司(Netscape)在1994年推出HTTPS协议,以SSL进行加密,这是SSL的起源。IETF将SSL进行标准化,1999年公布TLS 1.0标准文件(RFC 2246)。随后又公布TLS 1.1(RFC 4346, 2006年)、TLS 1.2(RFC 5246, 2008年)和TLS 1.3(RFC 8446, 2018年)。目前已成为互联网上保密通信的工业标准。

    SSL包含记录层(Record Layer)和传输层,记录层协议确定传输层数据的封装格式。传输层安全协议使用X.509认证,之后利用非对称加密演算来对通信方做身份认证,之后交换对称密钥作为会谈密钥(Session key)。这个会谈密钥是用来将通信两方交换的数据做加密,保证两个应用间通信的保密性和可靠性,使客户与服务器应用之间的通信不被攻击者窃听。

    TLS协议采用主从式架构模型,用于在两个应用程序间透过网络创建起安全的连线,防止在交换数据时受到窃听及篡改。TLS协议的优势是与高层的应用层协议(如HTTP、FTP、Telnet等)无耦合。应用层协议能透明地运行在TLS协议之上,由TLS协议进行创建加密信道需要的协商和认证。应用层协议传送的数据在通过TLS协议时都会被加密,从而保证通信的私密性。

    TLS协议是可选的,必须配置客户端和服务器才能使用。主要有两种方式实现这一目标:一个是使用统一的TLS协议端口(例如:用于HTTPS的端口443);另一个是客户端请求服务器连接到TLS时使用特定的协议机制(例如:电子邮件常用的STARTTLS)。一旦客户端和服务器都同意使用TLS协议,他们通过使用一个握手过程协商出一个有状态的连接以传输数据。通过握手,客户端和服务器协商各种参数用于创建安全连接

    在客户端和服务器开始交换TLS所保护的加密信息之前,他们必须安全地交换或协定加密密钥和加密数据时要使用的密码。用于密钥交换的方法包括:使用RSA算法生成公钥和私钥(在TLS握手协议中被称为TLS_RSA)、Diffie-Hellman(在TLS握手协议中被称为TLS_DH)、临时Diffie-Hellman(在TLS握手协议中被称为TLS_DHE)、椭圆曲线迪菲-赫尔曼(在TLS握手协议中被称为TLS_ECDH)、临时椭圆曲线Diffie-Hellman(在TLS握手协议中被称为TLS_ECDHE)、匿名Diffie-Hellman(在TLS握手协议中被称为TLS_DH_anon)和预共享密钥(在TLS握手协议中被称为TLS_PSK)。在交换过程中使用的公钥/私钥加密密钥的长度和在交换协议过程中使用的公钥证书也各不相同,因而提供强健性安全。

    SSL使用TCP提供一种可靠的端对端的安全服务。SSL不是单个协议,它由两层协议组成,如下图所示:

    SSL记录协议对各种更高层协议提供基本的安全服务。尤其是,超文本传输协议(Hypertext Transfer Protocol, HTTP)是为Web客户端/服务器的交互提供传输服务的协议,它可以在SSL的顶层运行。SSL中定义的三个较高层协议分别是:握手协议、修改密码规范协议和警报协议。这些SSL协议规范用来管理SSL的交换。

    SSL协议中的两个重要概念是SSL会话和SSL连接,按照规范文件,它们的定义如下:

    (1).连接:是一种能够提供合适服务类型(按照OSI分层模型定义)的传输。对SSL来说,这种连接是点对点的关系而且都是短暂的。每一条连接都与一个会话相关联。

    (2).会话:SSL会话是客户与服务器之间的一种关联。会话是通过握手协议来创建的。所有会话都定义了密码安全参数集合,这些参数可以在多个安全连接之间共享。会话通常用来减少每次连接建立安全参数的昂贵协商费用。

    会话状态由下列参数定义:

    (1).会话标识符:由服务器产生的用于标识活动或可恢复的会话状态的一个任意字节序列。

    (2).对等实体证书:对等实体的X.509v3证书。会话状态的这一元素可以为空。

    (3).压缩方法:加密前用于压缩数据的算法。

    (4).密码规格:包括大块数据加密算法(例如空算法、AES算法等)规格和用于计算MAC(消息认证码)的散列算法(如MD5或SHA-1算法等)规格。它还定义了一些密码属性,例如散列值长度等。

    (5).主密钥:客户端和服务器共享的48字节的会话密钥。

    (6).可恢复性:表明会话是否可被用于初始化新连接的标志。

    连接状态由下列参数定义:

    (1).服务器和客户端随机数:由服务器和客户端为每个连接选定的字节串。

    (2).服务器写MAC密钥:服务器发送数据时用于计算MAC值的密钥。

    (3).客户端写MAC密钥:客户端发送数据时用于计算MAC值的密钥。

    (4).服务器写密钥:服务器用于加密数据、客户端用于解密数据的加密密钥。

    (5).客户端写密钥:客户端用于加密数据、服务器用于解密数据的对称加密密钥。

    (6).初始化向量:在CBC模式中,需要为每个密钥配置一个初始化向量(IV)。最初的IV值由SSL的握手协议初始化。之后,每个记录的最后一个密码块被保存,以作为后续记录的IV。

    (7).序列号:建立连接的各方为每条连接发送和接收的消息维护单独的序列号。当一方发送或接收改变密码规格的消息时,相应的序列号应置零。序列号的值不能超过2^64-1。

    SSL握手协议:这一协议允许客户端和服务器相互认证,并协商加密和MAC算法,以及用于保护数据使用的密钥通过SSL记录传送。握手协议在任何应用数据被传输之前使用。握手协议由客户端和服务器之间的一系列消息交换组成

    下图说明了为建立客户端和服务器之间的逻辑连接需要进行的初始交换。这些交换可分为4个阶段:

    第一阶段:客户端发起建立连接请求:这一阶段主要是发起逻辑连接并建立与之关联的安全能力。交换首先由客户端通过发送下列client_hello消息启动:

    (1).版本:客户端的SSL最高版本。

    (2).随机数:由客户端产生的随机序列,由32比特时间戳以及安全随机数生成器产生的28字节随机数组成。这些数没有任何意义,主要用于密钥交换过程中防止重放攻击。

    (3).会话ID:可变长度的会话标识符。非零值表示客户端希望更新现有连接的参数,或为该会话创建一条新连接。零值表示客户端希望在新会话上建立一条新连接。

    (4).密码套件:按优先级的降序排列的、客户端支持的密码算法列表。列表中的每一行(即每一个密码套件)同时定义了密钥交换算法和密码规格。

    (5).压缩方法:客户端支持的压缩方法列表。

    发送完client_hello消息后,客户端将等待server_hello消息,该消息所包含的参数与client_hello消息包含的参数相同。同时server_hello消息遵循以下的惯例。版本域包含客户端支持的较低版本和服务器支持的最高版本。服务器产生一个独立于客户端随机域的新随机数域。如果客户端会话ID域的值非零,那么服务器应采用相同的取值。否则,服务器的会话ID域将包括一个新会话值。密码套件域将包括服务器从客户端提供的可选方案中选定的唯一一组密码套件。压缩域包括服务器从客户端建议中选定的压缩方法。密码套件参数的第一项内容是密钥交换方法(如传统加密密钥和MAC交换方法)。

    第二阶段:服务器认证和密钥交换:如果需要认证,则这一阶段的开始以服务器发送其证书为标志。发送的消息包括一个X.509证书或一个X.509证书链。之后,如果有必要,将发送一个服务器密钥交换(server_key_exchange)消息。接下来,服务器可以向客户端请求证书。certificate_request(证书请求)消息包括两个参数:certificate_type(证书类型)和certificate_authorities(证书机构)。证书类型指出了公钥算法及其用法。第二阶段中的最后一条消息(也是始终需要存在的消息之一)是server_done(服务器结束)消息。该消息由服务器发出并示意服务器的hello及相关消息已经结束。该消息没有参数,发送完这个消息后,服务器要等待客户的响应。

    第三阶段:客户端认证和密钥交换:接收到server_done(服务器结束)消息后,如果需要,客户端应该验证服务器提供的证书是否有效,同时还要检查server_hello参数是否是可接受的。如果所有这些条件均满足,那么客户端将返回一条或更多消息给服务器。如果服务器已请求证书,则以客户端发送一条certificate消息为这一阶段的开始。如果没有合适的证书可用,那么客户端发送一个no_ceritificate alert(无证书警报)。接下来是client_key_exchange(客户端密钥交换)消息。该消息必须在这一阶段发送,消息内容由密钥交换类型决定。最后,在这一阶段,客户端可以发送certificate_verify(证书验证)消息,以便对客户端证书进行显示验证。仅当客户端证书具有签名功能时才会发送该消息。这个消息是对一个散列码的签名,该散列码基于前面的消息。

    第四阶段:完成:这一阶段完成安全连接的建立。客户端发送一个change_cipher_spec(修改密码规格)消息,并把挂起的密码规格复制到当前密码规格中。值得注意的是,该消息不是握手协议的一部分,而是使用修改密码规格协议发送的。客户端在新算法、新密钥和新秘密值下立即发送finished(结束)消息。finished消息用于验证密钥交换和认证过程是否成功。作为对客户发送的这两条消息的响应,服务器发送自己的change_cipher_spec_message(修改密码规格消息),把未定的密码规格转变为当前的密码规格并发送其finished消息。到此为止握手过程已经完成,客户端与服务器可以开始交换应用层数据。

    了解了上面一些术语后,接下来介绍下SSL/TLS的单向认证和双向认证过程,其实就是握手协议。单向认证如通过浏览器访问某个网站,双向认证如使用U盾登入网上银行,需客户端和服务器相互认证。除认证外,还要协商加密和MAC算法,以及用于保护数据使用的密钥。由客户端和服务器之间的一系列消息组成。

    假设ca.crt为CA的证书,server.crt为服务器证书,client.crt为客户端证书,server.key为服务器私钥,client.key为客户端私钥,server.pub为服务器公钥,client.pub为客户端公钥。ca.crt应该已默认存在于客户端。

    1. SSL/TLS单向认证过程:

    (1).客户端发起连接请求:请求消息包括客户端支持的最高SSL协议、客户端支持的密码套件列表、客户端支持的压缩算法列表、随机数、会话ID等信息。

    (2).服务器返回消息:该消息所包含的参数与(1)中相同,包括客户端支持的SSL协议较低版本和服务器支持的最高版本;服务器从客户端提供的可选方案中选定的唯一一组密码套件(协议支持的密钥交换方法包括RSA,固定Diffie-Hellman等,密码规格包括密码算法如RC4等,MAC算法如MD5、SHA-1等);服务器从客户端提供的可选方案中选定的压缩算法;随机数等信息;同时返回消息中还包括服务器证书server.crt,此证书里有服务器公钥和签名,它是一个X.509证书或一个X.509证书链。

    (3).客户端通过本地的ca.crt验证server.crt的合法性:证书是否过期、通过ca.crt获取server.crt中的公钥、验证此公钥是否能正确解开server.crt中的数字签名、证书上的域名是否和服务器的实际域名相匹配。验证通过后继续通信,否则终止通信。

    (4).客户端向服务发送自己支持的对称加密算法列表,供服务器进行选择。

    (5).服务器在客户端提供的加密方案中选择加密程度最高的加密算法,并将选定好的加密方案通过明文方式返回给客户端。

    (6).客户端接收到服务器端返回的加密方案后,生成随机码,用作通信过程中对称加密的密钥,使用服务器端的公钥进行加密,将加密后的随机码发送至服务器。

    (7).服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。

    在接下来的数据传输中,服务器和客户端将会使用该密钥进行对称加密,保证通信过程中的信息安全。

    2. SSL/TLS双向认证过程:

    (1).客户端发起连接请求:请求消息包括客户端支持的最高SSL协议、客户端支持的密码套件列表、客户端支持的压缩算法列表、随机数、会话ID等信息。

    (2).服务器返回消息:该消息所包含的参数与(1)中相同,包括客户端支持的SSL协议较低版本和服务器支持的最高版本;服务器从客户端提供的可选方案中选定的唯一一组密码套件(协议支持的密钥交换方法包括RSA,固定Diffie-Hellman等,密码规格包括密码算法如RC4等,MAC算法如MD5、SHA-1等);服务器从客户端提供的可选方案中选定的压缩算法;随机数等信息;同时返回消息中还包括服务器证书server.crt,此证书里有服务器公钥和签名,它是一个X.509证书或一个X.509证书链。服务器请求客户端证书。

    (3).客户端通过本地的ca.crt验证server.crt的合法性:证书是否过期、通过ca.crt获取server.crt中的公钥、验证此公钥是否能正确解开server.crt中的数字签名、证书上的域名是否和服务器的实际域名相匹配。验证通过后继续通信,否则终止通信。

    (4).客户端向服务器发送client.crt,还包括客户端支持的对称加密算法列表,供服务器进行选择。

    (5).服务器验证client.crt,验证通过后会获取到客户端公钥,否则拒绝连接;服务器在客户端提供的加密方案中选择加密程度最高的加密算法,并将选定好的加密方案通过客户端公钥加密后返回给客户端。

    (6).客户端接收到服务器返回的加密方案后,使用客户端私钥进行解密,生成随机码,用作通信过程中对称加密的密钥,使用服务器的公钥进行加密,将加密后的随机码发送至服务器。

    (7).服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。

    在接下来的数据传输中,服务器和客户端将会使用该密钥进行对称加密,保证通信过程中的信息安全。

    注:以上内容来自网络整理,主要参考:

    1. 《网络安全基础应用与标准》

    2. 维基百科:散列函数  数字签名  数字证书  TLS

    GitHubhttps://github.com//fengbingchun/OpenSSL_Test

    展开全文
  • TLS1.3 概述

    千次阅读 2020-04-08 17:15:20
    TLS1.3的最终版本,在2018年8月发布,它包含着很多不同以往版本的改进,相对于之前版本安全性以及性能具有极大的提高,同时它也具备了更多的扩展和握手模式,那么从实现完整TLS1.3结构的角度去学习TLS,我们应该从...

    tls1.3
    TLS1.3的最终版本,在2018年8月发布,它包含着很多不同以往版本的改进,相对于之前版本安全性以及性能具有极大的提高,同时它也具备了更多的扩展和握手模式,那么从实现完整TLS1.3结构的角度去学习TLS,我们应该从哪些方面入手呢?

    什么是TLS


    TLS代表传输层安全性,并且是SSL(安全套接字层)的后继者。TLS提供了Web浏览器和服务器之间的安全通信。连接本身是安全的,因为使用对称密码术对传输的数据进行加密。密钥是为每个连接唯一生成的,并且基于在会话开始时协商的共享机密(也称为TLS握手)。HTTP + TLS = HTTPS

    TLS历史

    history

    TLS1.2


    TLS1.2握手原理

    tls1.2
    握手的过程主要包括两部分:

    • 参数协商
      客户端向服务器发送client Hello消息,里面包含client所支持的参数(密码套件等等),还包含一些有用的参数(version、random、sessionId等等),server会从中选取自己支持的密码套件、版本,通过server Hello发送给client,其中也包含一个随机数还有一些其他字段。
    • 密钥交换
      之后server会通过Server Key Exchange消息向client发送自己用于协商的公钥,用于协商的算法是:ECDHE或DHE,同样client通过 Client Key Exchange 发送自己的公钥,这样双方都具有了彼此的公钥,用它们生成临时私钥。client在收到server的Certificate消息之后会验证server的身份,验证通过才会发送Client Key Exchange,其中还包含着pre-Masterkey,是对client生成的随机数加密得来,最后使用三个随机数生成Masterkey用于会话密钥。

    观察图片我们可以看出,TLS1.2整个握手过程需要2个RTT时间,而且每次握手都用到了非对称加密算法签名或者解密的操作,比较耗时和耗 CPU,每次都要传输证书,证书比较大会消耗带宽。

    • RTT
      Round-Trip Time,往返时延,在计算机网络中它也是一个重知要的性能指标,它表示从发送端发道送数据开始,到发送端收到来自接收端的确认版(接收端收到数据后便立即发送确认),总共经历的时延。

    TLS1.2会话恢复

    • SessionID
      将协商好的会话参数缓存在客户端与服务器中,client下次握手时会带上上次握手的SessionID,server对其查询,若存在直接复用。
    • SessionTicket
      server将协商好的会话参数和密钥加密发送给客户端,client下次握手会将这个SessionTicket带上,如果server解密成功就复用上次的会话参数和密钥。

    在TLS1.3中没有了SessionID这种会话恢复模式,但是在client Hello中还会存在该字段,主要是为了兼容版本。并且在SessionTicket模式中,添加了Ticket age,指的是会话是存在时间限制的,如果超过了该时间,那么也就不能进行会话恢复。

    sessionid
    我们可以看到,使用SessionID恢复会话的时候,需要花费1个RTT的时间,在TLS1.3中一定情况下恢复会话只需要花费0个RTT!

    在握手的过程中很多数据都会临时计算,如果我们把这些数据提前计算出来,然后存入扩展当中,这样就可以减少握手的时间为1个RTT,TLS1.3实现的主要思想就是这样的。

    TLS1.3


    TLS1.3握手

    更快的访问速度
    TLS1.2handshake
    这是一张TLS1.2的握手过程图片,前面也分析过,它需要2个RTT的时间才能完成整个握手过程,下面我们看一下TLS1.3的握手过程图:

    tls1.3extension
    我们会发现,其中存在一些以前版本从来没有出现过的extension,比如:key_share、signature_algorithms等等,这只是一部分,还包含很多扩展,我会一一细说。正因为这些扩展才使得TLS1.3的握手速度大大提高。

    注:

    • +:上一消息的扩展消息
    • *:可选发送
    • {}:用握手层流密钥加密
    • []:用流密钥加密

    client Hello

    当client第一次连接server的时候,它需要向server发送client Hello 消息。

    clientHello消息的结构:

      uint16 ProtocolVersion;
          opaque Random[32];
    
          uint8 CipherSuite[2];    /* Cryptographic suite selector */
    
          struct {
              ProtocolVersion legacy_version = 0x0303;    /* TLS v1.2 */
              Random random;
              opaque legacy_session_id<0..32>;
              CipherSuite cipher_suites<2..2^16-2>;
              opaque legacy_compression_methods<1..2^8-1>;
              Extension extensions<8..2^16-1>;
          } ClientHello;
    

    简单介绍一下比较重要的几个字段的含义:

    • legacy_version
      在 TLS 以前的版本里,这个字段被用来版本协商和表示 Client 所能支持的 TLS 最高版本号。经验表明,很多 Server 并没有正确的实现版本协商,导致了 “version intolerance” —— Sever 拒绝了一些本来可以支持的 ClientHello 消息,只因为这些消息的版本号高于 Server 能支持的版本号。在TLS1.3中,设置了一个supported_version的扩展来表明client所支持的版本。legacy_version 字段必须设置成 0x0303,这是 TLS 1.2 的版本号。在 TLS 1.3 中的 ClientHello 消息中的 legacy_version 都设置成 0x0303,supported_versions 扩展设置成 0x0304。主要是为了兼容之前的TLS版本。
    • legacy_session_id
      前面我也提到过,TLS1.3中不再使用SessionID进行会话恢复,这一特性已经和预共享密钥PSK合并了,设置这个字段的意义,主要也是为了兼容之前版本,如果 Client 有 TLS 1.3 版本之前的 Server 设置的缓存 Session ID,那么这个字段要填上这个 ID 值。兼容模式下,这个值必须是非空的,所以如果Client不能提供之前版本的值,那么需要重新生成一个32字节的值。

    还有cipher_suites、legacy_compression_methods,包含的是Client支持的密码套件和压缩算法,压缩算法TLS1.3也已经不再支持了,这个字段主要还是为了兼容版本,对于每个 ClientHello,该向量必须包含一个设置为 0 的一个字节,它对应着 TLS 之前版本中的 null 压缩方法。

    supported_groups

    这个扩展表明了 Client 支持的用于密钥交换的命名组。按照优先级从高到低。这个扩展中的 “extension_data” 字段包含一个 “NamedGroupList” 值:

     enum {
    
              /* Elliptic Curve Groups (ECDHE) */
              secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019),
              x25519(0x001D), x448(0x001E),
    
              /* Finite Field Groups (DHE) */
              ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102),
              ffdhe6144(0x0103), ffdhe8192(0x0104),
    
              /* Reserved Code Points */
              ffdhe_private_use(0x01FC..0x01FF),
              ecdhe_private_use(0xFE00..0xFEFF),
              (0xFFFF)
          } NamedGroup;
     struct {
              NamedGroup named_group_list<2..2^16-1>;
          } NamedGroupList;
    

    key_share

    这个扩展我觉得是TLS1.3的重大改变,它里面包含了Client对应于supported_groups中参数的公钥集,如果使用了曲线,则会表明所使用的曲线以及对应的公钥。

       struct {
              NamedGroup group;
              opaque key_exchange<1..2^16-1>;
          } KeyShareEntry;
    
    • group:
      要交换的密钥的命名组。
    • key_exchange:
      密钥交换信息。这个字段的内容由特定的组和相应的定义确定。主要包含特定组的公钥等信息。

    在 ClientHello 消息中,“key_share” 扩展中的 “extension_data” 包含 KeyShareClientHello 值:

      struct {
              KeyShareEntry client_shares<0..2^16-1>;
          } KeyShareClientHello;
    
    • client_shares:
      按照 Client 偏好降序顺序提供的 KeyShareEntry 值列表。

    在golang中该结构的实现:

    type KeyShareEntry struct {
    	group 			NamedGroup
    	length			uint16
    	keyExchange		[]byte
    }
    
    type KeyShareClientHello struct {
    	length 			uint16
    	clientShares	[]KeyShareEntry
    }
    

    如果我们只实现椭圆曲线的话,首先需要选择要使用的椭圆曲线,之后再选取随机数生成公钥,将公钥存入keyExchange字段中,也就是说这个扩展已经将Client用于协商会话密钥的参数提前计算出来,并存储了起来,这与之前版本的形式server先选择参数,然后发给Client,然后Client再计算相比较,极大的节省了时间和握手过程中占用的CPU。

    Client 可以提供与其提供的 support groups 一样多数量的 KeyShareEntry 的值。每个值都代表了一组密钥交换参数。例如,Client 可能会为多个椭圆曲线或者多个 FFDHE 组提供 shares。每个 KeyShareEntry 中的 key_exchange 值必须独立生成。Client 不能为相同的 group 提供多个 KeyShareEntry 值。Client 不能为,没有出现在 Client 的 “supported_group” 扩展中列出的 group 提供任何 KeyShareEntry 值。Server 会检查这些规则,如果违反了规则,立即发送 “illegal_parameter” alert 消息中止握手。

    当选用PSK密钥协商模式时,即使在supported_groups中不存在支持的算法也不会终止握手,这时候,server会向Client发送和serverhello具有相同结构的消息:HelloRetryRequest,它的目的主要是想让Client作出一些改变以使得握手正常进行,在这种情况下,在 HelloRetryRequest 消息中,“key_share” 扩展中的 “extension_data” 字段包含 KeyShareHelloRetryRequest 值。

        struct {
              NamedGroup selected_group;
          } KeyShareHelloRetryRequest;
    
    • selected_group
      表明server所选择的NamedGroup中组

    Client收到此消息之后也会对其进行验证,selected_group是否在NamedGroup中出现了,selected_group 没有在原始的 ClientHello 中的 “key_share” 中出现过。如果上面 的检查都失败了,那么 Client 必须通过 “illegal_parameter” alert 消息来中止握手。否则,在发送新的 ClientHello 时,Client 必须将原始的 “key_share” 扩展替换为仅包含触发 HelloRetryRequest 的 selected_group 字段中指示的组,这个组中只包含新的 KeyShareEntry。

    在 ServerHello 消息中,“key_share” 扩展中的 “extension_data” 字段包含 KeyShareServerHello 值。

      struct {
              KeyShareEntry server_share;
          } KeyShareServerHello;
    
    • server_share:
      与 Client 共享的位于同一组的单个 KeyShareEntry 值。

    我们再来看一下ECDHE的参数,对于 secp256r1,secp384r1 和 secp521r1,内容是以下结构体的序列化值:

          struct {
              uint8 legacy_form = 4;
              opaque X[coordinate_length];
              opaque Y[coordinate_length];
          } UncompressedPointRepresentation;
    

    对端还要验证对方的公钥以确保为有效的点:

    • 验证公钥不是无穷大点
    • 两个整数x、y中间有正确的间隔
    • x、y是椭圆曲线方程的正确的解

    小结

    TLS 1.3 中优化握手:

    • client发送clientHello(extension)消息,extension中的support_groups中携带client支持的椭圆曲线的类型,并且在扩展key_share中计算出了相对应的公钥,一起发送给server
    • server收到clientHello后会首先选择相应的椭圆曲线参数计算自身的公钥,从key_share扩展中提取相应的公钥作为密钥协商的参数,计算主密钥,并且把自身计算出的公钥放到serverHello的扩展key_share中,然后发送serverHello等消息给client,Client从key_share中取出公钥计算主密钥。

    TLS1.3会话恢复

    在本文前面我提到过TLS1.3已经不再使用SessionID进行会话恢复了,现在主要使用的是SessionTicket进行会话恢复,但是又不同于TLS1.2中使用SessionTicket进行会话恢复的过程,也做出了一些改变,或者说是进行了一些更新(PSK)。

    tls1.3handshake
    会话恢复所花费的时间是1个RTT,这与整个的握手时间是一样的。在TLS1.3中采用的会话恢复机制是PSK它与SessionTicket有些类似,Client通过PSK发送被server加密的会话缓存参数,如果server解密成功就可以直接复用会话,不需要再重新传输证书和协商密钥了。

    密钥交换模式

    • PSK-Only
    • (EC)DHE
    • PSK with (EC)DHE(暂时还没出现)

    PSK handshake

    在使用PSK密钥交换模式时我们首先要了解几个ClientHello的其它扩展:

    Pre-Shared Key Exchange Modes

    为了使用PSK,client还需要发送Pre-Shared Key Exchange Modes扩展,它的含义是Client 仅支持使用具有这些模式的 PSK,这就限制了在这个 ClientHello 中提供的 PSK 的使用,也限制了 Server 通过 NewSessionTicket 提供的 PSK 的使用。
    如果Client提供了 pre_shared_key扩展,那么就必须提供该扩展

      enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
    
          struct {
              PskKeyExchangeMode ke_modes<1..255>;
          } PskKeyExchangeModes;
    
    • psk_ke:
      仅 PSK 密钥建立。在这种模式下,Server 不能提供 key_share 值
    • psk_dhe_ke:
      PSK 和 (EC)DHE 建立。在这种模式下,Client 和 Server 必须提供 key_share值。

    这样的话就可以进行模式选择,并作出相应的改变。未来分配的任何值都必须要能保证传输的协议消息可以明确的标识 Server 选择的模式。目前 Server 选择的值由 ServerHello 中存在的 key_share 表示。

    Pre-Shared Key

    该扩展是用来协商标识的,该标识是与PSK密钥相关联的给定握手所使用的预共享密钥的标识。或者说是New Session Ticket+binders,由于在TLS1.3中,New Session Ticket可以在握手结束后可能多次发送,所以Pre-Shared Key可能会存储多组对应的值,下面我们具体来了解一下它的结构。

    struct {
              opaque identity<1..2^16-1>;
              uint32 obfuscated_ticket_age;
          } PskIdentity;
    
          opaque PskBinderEntry<32..255>;
    
          struct {
              PskIdentity identities<7..2^16-1>;
              PskBinderEntry binders<33..2^16-1>;
          } OfferedPsks;
    
          struct {
              select (Handshake.msg_type) {
                  case client_hello: OfferedPsks;
                  case server_hello: uint16 selected_identity;
              };
          } PreSharedKeyExtension;
    
    • identity:
      一个预共享密钥的标签。
    • obfuscated_ticket_age:
      SessionTicket的寿命的混淆版本,为了防止一些相关连接的被动观察者。而在TLS1.2中是不存在这样的字段,即不会标识出客户端已存在的时间,server收到后主要靠里面的内容来判断Ticket是否过期,而在TLS1.3中就增加了这样一个字段来表示Ticket的寿命,因为是明文传输所以会被观察者发现,所以给时间加了一些调味品,是New Session Ticket中的ticket_age_add,因为New Session Ticket本身就是被加密的,所以这个ticket_age_add只有通信两端才知道。
    • 混淆的方法:
      用 ticket 时间(毫秒为单位)加上 “ticket_age_add” 字段,最后对 2^32 取模。注意,NewSessionTicket 消息中的 “ticket_lifetime” 字段是秒为单位,但是 “obfuscated_ticket_age” 是毫秒为单位。
    • identities:
      Client 愿意和 Server 协商的 identities 列表,其内容就是NewSessionTicket中的ticket部分。如果和 early_data 一起发送,第一个标识被用来标识 0-RTT 的。有关early_data后面还会说到。
    • selected_identity:
      server选择的标识,是server在自己的 Pre-Shared Key扩展中自己设置的选择的标识,表明正常解析了Client的扩展,其实选择的话就是一个序号。

    0-RTT

    前面已经提到过TLS1.3已经将握手时间优化到了1-RTT,对比之前版本的速度已经快了很多,但是TLS1.3最终极的做法是0-RTT,即握手的时间是0-RTT。

    Client发送ClientHello消息,除了在PSK模式中提到的那些扩展外,还应该具有一个early_data扩展,同理server发送serverHello中也应该包括该扩展,并表示其愿意接受early_data,client发送完early_data后,发送End_Of_Early_Data报文表示client自己发送完了early_data。

    如果 Server 提供了 early_data 扩展,Client 必须验证 Server 的 selected_identity 是否为 0。如果返回任何其他值,Client 必须使用 “illegal_parameter” alert 消息中止握手。下面我们看一下它的结构:

      struct {} Empty;
    
          struct {
              select (Handshake.msg_type) {
                  case new_session_ticket:   uint32 max_early_data_size;
                  case client_hello:         Empty;
                  case encrypted_extensions: Empty;
              };
          } EarlyDataIndication;
    

    其中的max_early_data_size字段表明,允许Client发送的最大0-RTT的数据量。

    发生错误会导致0-RTT降级到1-RTT。

    New Session Ticket

    Post-Handshake Messages在 Server 接收到 Client 的 Finished 消息以后的任何时刻,它都可以发送 NewSessionTicket 消息。此消息在 ticket 值和从恢复主密钥派生出来的 PSK 之间创建了唯一的关联。

       struct {
              uint32 ticket_lifetime;
              uint32 ticket_age_add;
              opaque ticket_nonce<0..255>;
              opaque ticket<1..2^16-1>;
              Extension extensions<0..2^16-2>;
          } NewSessionTicket;
    
    • ticket_lifetime:
      这个字段表示 ticket 的生存时间,这个时间是以 ticket 发布时间为网络字节顺序的 32 位无符号整数表示以秒为单位的时间。Server 禁止使用任何大于 604800秒(7 天)的值。值为零表示应立即丢弃 ticket。无论 ticket_lifetime 如何,Client 都不得缓存超过 7 天的 ticket,并且可以根据本地策略提前删除 ticket。Server 可以将 ticket 视为有效的时间段短于 ticket_lifetime 中所述的时间段。
    • ticket_age_add:
      安全的生成的随机 32 位值,用于模糊 Client 在 “pre_shared_key” 扩展中包含的 ticket 的时间。Client 的 ticket age 以模 2 ^ 32 的形式添加此值,以计算出 Client 要传输的值。Server 必须为它发出的每个 ticket 生成一个新值。
    • ticket_nonce:
      每一个 ticket 的值,在本次连接中发出的所有的 ticket 中是唯一的。初始值是0,发送一个则++
    • ticket:
      这个值是被用作 PSK 标识的值

    TLS1.3一些其他扩展和机制

    降级保护机制

    主要通过随机数来实现,当协商TLS1.2或更老的版本,为了响应ClientHello在random后8个字节填入特定的随机值,若为TLS1.2则后8个字节的值为:

    44 4F 57 4E 47 52 44 01
    

    supported_version

    主要功能的话前面也有提到,对Client标明所支持的TLS版本,对Server标明正在使用的TLS版本,如果协商TLS之前的版本,这个扩展必须带上,若不存在该扩展,server要协商之前的版本,则中止握手,若存在server将禁止使用ClientHello中的legacy_version作为版本协商的值,只能使用supported_versions中的值。
    对于server:

    • 版本<TLS1.3 则设置serverHello.version,不能发送supported_version
    • 版本>=TLS1.3则必须发送supported_version扩展,还要设置serverHello.legacy_version为0x0303,若扩展存在Client会忽略serverHello.legacy_version,而去读取supported_version的值。
        struct {
              select (Handshake.msg_type) {
                  case client_hello:
                       ProtocolVersion versions<2..254>;
    
                  case server_hello: /* and HelloRetryRequest */
                       ProtocolVersion selected_version;
              };
          } SupportedVersions;
    
    展开全文
  • SSL/TLS协议详解(下)——TLS握手协议 本文翻译自:https://www.wst.space/ssl-part-4-tls-handshake-protocol/ 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,...

    SSL/TLS协议详解(下)——TLS握手协议
    本文翻译自:https://www.wst.space/ssl-part-4-tls-handshake-protocol/

    在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容的关键要点:

    TLS适用于对称密钥
    对称密钥可以通过安全密钥交换算法共享
    如果请求被截获,密钥交换可能会被欺骗
    使用数字签名进行身份验证
    证书颁发机构和信任链。
      在这篇文章中,使用WireShark的工具来查看网络流量,我个人使用的是Linux(Ubuntu 16.04)系统,可以使用以下命令轻松安装WireShark:

    $sudo apt install wireshark
      以sudo的权限打开WireShark并选择提供互联网连接的接口,我这里是eth0,然后点击WireShark右上角的“开始捕获数据包”按钮,Wireshark将立即开始抓取通过机器的所有流量。现在我们从浏览器中加载github.com。Github使用TLS进行所有通信,将重新定向到https并加载。现在关闭浏览器,看看WireShark抓到了什么。

    DNS解析
      这并不是TLS的一部分,但我们在WireShark中看到了它。
    在这里插入图片描述
      我已将Google DNS设置为我的DNS服务器,它的地址是8.8.8.8,在图像中可以看到请求已发送到8.8.8.8查询github.com的A记录,也就是我们想要连接的Github的IP地址。
    在这里插入图片描述
      DNS服务器使用github.com的IP响应为192.30.253.113,蓝色表示选择显示相应的部分,现在,浏览器已获取了将要用来连接服务器的目标IP。

    发起TLS握手
      解析IP后,浏览器将通过http请求页面,如果服务器支持TLS,那么它将发送协议升级请求来响应浏览器,这个新的地址https://github.com ,将使用端口号443来指定,随后浏览器将启动TLS握手请求。大多数现代浏览器都存有与Web服务器的最后一次连接的记录,如果最后一次连接是通过https进行的,那么下次浏览器将自动启动https请求而无需等待服务器。
    TLS握手分为以下几个步骤:

    客户端发送Hello报文
    服务器接收Hello报文
    共享证书和服务器密钥交换
    更改密码规范
    加密握手
    客户端发送Hello报文
      从这里开始,我将会重点讨论图片中标记为蓝色的主题,Client发送的Hello报文如下图所示。
    在这里插入图片描述
      我们知道TLS是在TCP之上实现的协议,TLS本身是一层协议并且它的底层叫做记录协议(Record protocol),这意味着所有数据都被记录。典型的记录格式如下:

    HH V1:V2 L1:L2 data
    HH是单个字节,表示记录中的数据类型。共定义了四种类型:change_cipher_spec(20),alert(21),handshake(22)和application_data(23)。
    V1:V2是协议版本,用两个以上的字节表示。对于当前定义的所有版本,V1的值为0x03,而对于SSLv3,V2的值为0x00,对于TLS 1.0为0x01,对于TLS 1.1为0x02,对于TLS 1.2为0x03。
    L1:L2是数据的长度,以字节为单位(使用big-endian约定:长度为256 * L1 + L2),数据的总长度不能超过18432字节,但实际上它无法达到这个值。
      在图中,可以看出内容类型是Handshake,TLS版本1.0,数据长度为512.真实数据位于名为 Handshake Protocol:Client Hello的下拉列表中。我们继续观察下Client Hello中共享的数据。

    客户端发送Hello报文的内容
      浏览器与服务器共享以下详细信息
    在这里插入图片描述

    客户端版本
      按优先顺序列出的客户端支持的协议版本,首选客户希望支持的最新协议版本。

    客户端的随机数
      一个32字节的数据,其中前4个字节表示epoch格式的当前日期时间。纪元时间是自1970年1月1日以来的秒数。其余28个字节由加密强随机数生成器生成(例如,Linux中的/dev/urandom),客户端随机会在后面用到,请先记住这点。

    会话id(Session id)
      如果客户端第一次连接到服务器,那么这个字段就会保持为空。在上图中,您可以看到Session id正在给服务器发送东西,之所以会发生这种情况是由于我之前是通过https连接到github.com的,在此期间,服务器将使用Session id映射对称密钥,并将Session id存储在客户端浏览器中,为映射设置一个时间限。如果浏览器将来连接到同一台服务器(当然要在时间限到期之前),它将发送Session id,服务器将对映射的Session进行验证,并使用以前用过的对称密钥来恢复Session,这种情况下,就不需要完全握手。

    密码套件
      客户端还将发送自己已经知道的密码套件列表,这个是由客户按优先顺序排列的,但完全由服务器来决定发送与否。TLS中使用的密码套件有一种标准格式。
    在这里插入图片描述
    我们从列表中用一个例子来进行分析.

    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
    TLS:指使用的协议是TLS
    ECDHE:密钥交换算法
    ECDSA:签名或验证算法
    AES_128_GCM:称为批量加密算法。对称密钥加密算法是AES,密钥长度为128位,AES是块密码,也就是对输入的纯文本用固定长度的块来进行加密,加密后的每个块按再顺序发送,最后按类似的方式来进行解密。按标准规定,AES块固定长度为128位,但是输入的明文不要求必须是128的倍数,所以我们可能需要对最后一个块中进行填充,使其为固定的长度128位。除此之外,为了提高平均信息量,通常在加密之前会添加一些随机的比特到明文中,我们称为初始化矢量(IV)。有很多算法都可以在块上添加IV实现填充。在我们的例子Galois/Counter Mode(GCM)中用到过。或许详细解释GCM模式会使事情变得复杂,可见这并不是一个好主意。
    SHA256:消息验证代码(MAC)算法。我们将详细讨论MAC。
    压缩数据
      为了减少带宽,可以进行压缩。但从成功攻击TLS的事例中来看,其中使用压缩时的攻击可以捕获到用HTTP头发送的参数,这个攻击可以劫持Cookie,这个漏洞我们称为CRIME。从TLS 1.3开始,协议就禁用了TLS压缩。

    扩展名
      其他参数(如服务器名称,填充,支持的签名算法等)可以作为扩展名使用,我们可以任意对用作扩展名的内容研究一番。

    这些是客户端问候的一部分,如果已收到客户端问候,接下来就是服务器的确认,服务器将发送服务器问候。
    在这里插入图片描述

    服务器接收Hello报文
      收到客户端问候之后服务器必须发送服务器问候信息,服务器会检查指定诸如TLS版本和算法的客户端问候的条件,如果服务器接受并支持所有条件,它将发送其证书以及其他详细信息,否则,服务器将发送握手失败消息。
    在这里插入图片描述
    图中,我们可以看到服务器响应0x0303表示服务器同意使用TLS 1.2,我们来检查一下服务器问候中的记录。

    服务器接收Hello报文的内容
      服务器问候消息包含以下信息。
    在这里插入图片描述
    加下来我们会在这里讨论其中一些重要的参数。

    服务器版本
      如果客户端可以支持,则服务器将选择客户端指定的TLS版本,这里选择了TLS 1.2

    服务器的随机数
      类似于客户端随机,服务器随机也占32字节,前4个字节表示服务器的Unix纪元时间,后面加上28字节的随机数。客户端和服务器随机将用来创建加密密钥,我待会儿会解释。

    密码套件
      还记得我们已经将发送支持的密码套件发送到客户端问候中的github.com吗?Github从名单中选出了第一个,也就是:

    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    会话id(Session id)
      服务器将约定的Session参数存储在TLS缓存中,并生成与其对应的Session id。它与Server Hello一起发送到客户端。客户端可以写入约定的参数到此Session id,并给定到期时间。客户端将在Client Hello中包含此id。如果客户端在此到期时间之前再次连接到服务器,则服务器可以检查与Session id对应的缓存参数,并重用它们而无需完全握手。这非常有用,因为服务器和客户端都可以节省大量的计算成本。

    在涉及亚马逊和谷歌等流量巨大的应用程序时,这种方法存在缺点。每天都有数百万人连接到服务器,服务器必须使用Session密钥保留所有Session参数的TLS缓存。这是一个巨大的开销。为了解决之前介绍过的Session Tickets的问题, 在这里,客户端可以在client hello中指定它是否支持Session Ticket。然后,服务器将创建一个新的会话票证(Session Ticket),并使用只有服务器知道的经过私钥加密的Session参数。它将存储在客户端上,因此所有Session数据仅存储在客户端计算机上,但Ticket仍然是安全的,因为该密钥只有服务器知道。

    此数据可以作为名为Session Ticket的扩展包含在Client Hello中。在我们的例子中,此参数为空,因为这是第一次连接到github.com或前一个Session的浏览器已过期。
    在这里插入图片描述

    压缩数据
      如果支持,服务器将同意客户端的首选压缩方法。在这里,您可以看到服务器响应为空响应,则意味着不需要压缩。

    服务器不在ServerHello消息中发送任何证书; 它会在正确命名的证书消息中发送证书。

    服务器证书的信息
    在这里插入图片描述
      在我们的例子中,证书消息长度为3080字节。毫无疑问,这是包含所有信息的服务器证书。服务器按信任链的顺序发送完整的证书列表。该链中的第一个是服务器证书,接着是颁发服务器证书的intermediate CA 的证书,然后是下一个intermediate CA 的证书…直到Root CA的证书。服务器不可以发送Root CA证书,因为在大多数情况下,浏览器可以从任何intermediate CA 识别Root CA。

    在我们的例子中,您可以看到第一个证书是github.com,第二个证书是中间件Digicert SHA2扩展验证Server CA。 检查下图中的id-at-commonName参数。
    在这里插入图片描述
    让我们分析证书的内容,看看浏览器如何验证它。

    证书的内容
      证书被发送到浏览器,因此我们可以在访问github.com时查看Github的证书。来自Firefox的CA证书内容:
    在这里插入图片描述
    可以通过单击"详细信息"选项卡查看github的intermediate CA 和Root CA.
    在这里插入图片描述
    让我们了解这些领域是什么以及它们的用途。

    版本和序列号
      版本表示使用的是哪个版本的X.509标准。X.509是用于定义公钥证书格式的标准。X.509有3个版本,github使用最新版本version 3。

    从RFC 5280开始,CA为每个证书分配的序列号必须是正整数。因此对于每个发布CA证书,它必须是唯一的(即颁发者名称和序列号标识唯一的证书)。所以,CA必须强制serialNumber为非负整数。

    证书的签名算法与值
      浏览器需要知道签名算法以验证签名。如果使用的是RSA签名,则需要相同的算法来验证签名。对于Github,使用的是PKCS#1 SHA-256和RSA加密,即SHA-256用于生成散列,RSA用于签名。

    从我们上一篇文章中,证书数据使用SHA-256算法进行哈希处理,并使用RSA加密过Github的私钥对此哈希进行签名。

    颁布机构
      此字段包含颁发证书的颁发机构的详细信息。Github的证书由Digicert的intermediate CA 颁发。
    在这里插入图片描述

    合法性
      该字段有两个值Not Before 和Not After 。如果当前日期时间不在这些值之间,则证书无效。浏览器就不会信任该证书。

    子公钥信息(Subject Public Key Info)
      该字段携带公钥和用于生成公钥的算法。此密钥用于交换密钥,我们将在稍后讨论。

    指纹
      浏览器生成了两个指纹SHA 1和SHA-256,而且不会发送到服务器。这些指纹分别是通过SHA 1和SHA-256函数散列DER格式的证书产生的。我们可以通过将证书下载到我们的机器并应用哈希函数来验证这一点。

    单击详细信息选项卡左下角的“ 导出” 按钮以下载证书,保存为.crt 扩展名,并在终端上运行以下命令以生成证书的指纹。

    $ openssl x509 -noout -fingerprint -sha256 -inform pem -in [certificate-file.crt]

    $ openssl x509 -noout -fingerprint -sha1 -inform pem -in [certificate-file.crt]
    在这里插入图片描述

    这应该产生与您在浏览器中看到的结果相同的结果。这些值不是证书的一部分,而是根据证书计算出来的。Root CA证书的指纹将在浏览器中进行硬编码,因此可以轻松地进行交叉验证。除此之外,这些指纹主要用于识别和组织证书。不要将Signature与指纹混淆。

    我们在这里讨论的证书信息是关于github.com的服务器证书。Github的intermediate CA 证书也将在同一请求中发送给客户,所有上述字段也适用于该证书。您可以通过转到详细信息选项卡并单击intermediate CA 来检查,如下所示。
    在这里插入图片描述

    服务器端密钥交换
      随后是Server Hello和证书消息(Certificate message),服务器密钥交换(Server Key Exchange)是可选的。仅当服务器提供的证书不足以允许客户端交换预主密钥时,才会发送此消息。让我们看看为什么github.com必须发送服务器密钥交换消息。
    在这里插入图片描述

    我们可以看到github.com首选Session的密码套件是TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256。这意味着双方使用Elliptic Curve Diffie Hellman算法来交换密钥。在Diffie-Hellman中,客户端无法自行计算预主密钥; 双方都有助于计算它,因此客户端需要从服务器获取Diffie-Hellman公钥。(不要对"Pre-Master Secret"一词感到困惑,我们将在下面深入讨论它。)当使用Elliptic Curve Diffie-Hellman时,该公钥不在证书中。因此,服务器必须在单独的消息中向客户端发送其DH公钥,以便客户端可以计算预主密钥。这可以在上面的图像中看到。请注意,此密钥交换也由签名保护。

    服务器密钥交换完成后,服务器将发送Server Hello Done 消息。客户端将开始计算Pre-Master Secret。我们来看看如何。

    如何计算Pre-Master Secret
      Pre-Master Secret计算取决于商定的密钥交换算法的类型。当使用RSA进行密钥交换时,从客户端(即浏览器)计算预主密钥,客户端通过连接协议版本(2个字节)和客户端随机生成的一些字节(46个字节)来生成48字节的预主密钥。客户端从加密安全的伪随机数发生器(PRNG)获得这46个字节。实际上,这意味着使用操作系统提供的PRNG,例如/dev/urandom。然后,使用服务器的公共和共享对此Pre-Master密钥进行加密,以便服务器稍后可以使用它来创建主密钥。

    但是,在Github的情况下,如上所述,Diffie-Hellman算法用于密钥交换。这里的情况略有不同。服务器立即生成一对DH私钥 - 公钥。然后,与客户共享公钥。这是如上所述的"服务器密钥交换消息( Server Key Exchange)"。作为响应,客户端还将创建DH密钥对,并通过客户端密钥交换消息与服务器共享公钥,如下所示。
    在这里插入图片描述

    您可以看到共享的客户端公钥。现在,如果您了解Diffie-Hellman算法的工作原理,您就知道客户端和服务器可以从这些共享公钥到达公共密钥。新生成的密钥称为Pre-Master密钥。

    使用Diffie Hellman算法进行TLS密钥交换具有优势。客户端和服务器都为每个新会话生成一个新密钥对。一旦计算出预主密钥,将立即删除客户端和服务器的私钥。这意味着私钥永远不会被窃取,确保完美的前向保密。

    客户端密钥交换
      我们已经在上面讨论过,客户端的DH公钥通过客户端密钥交换消息共享给服务器。但是如果使用RSA,则客户端将如上所述通过其自己计算预主密钥,使用服务器的公钥(RSA公钥)对其进行加密,并通过客户端密钥交换消息将其发送回服务器。然后,服务器可以使用其私钥解密它。无论算法是什么,此时客户端和服务器都达到了共同的Pre-Master Secert 。完成此操作后,客户端将发送Change Cipher Spec 消息,如下所示。
    在这里插入图片描述

    让我们往下走,看看如何在主密钥从预备主密钥来计算。

    如何计算主秘钥
      现在客户端和服务器都有哪些随机数据呢?根据RFC 5346标准,在问候消息期间客户端和服务器共享的预主密钥和随机值(还记得吗?)都会使用PRF(伪随机函数)产生的值来计算主密钥。

    master_secret = PRF(pre_master_secret,“master secret”,ClientHello.random + ServerHello.random)[0…47];
    这里,

    pre_master_secret - 双方计算的48字节Pre-Master密码。

    “master secret” - 它只是一个使用ASCII字节的字符串。

    ClientHello.random - 客户端hello中共享的随机值

    ServerHello.random - 服务器hello中共享的随机值。
      主密钥的大小共48个字节,好吧,到目前为止还不是太乱。双方都可以使用主密钥加密数据并来回发送,确实如此,但程序还没结束。你认为双方使用相同的秘钥是个好办法吗?当然不是!TLS为客户端和服务器分配了单独的密钥,它们都来自主密钥本身,换句话说,主密钥不直接用于加密数据,而是将单独的加密密钥用于客户端和服务器。由于双方都有两个密钥,服务器用其密钥加密的数据可以由客户端轻松解密,反之亦然。

    还没完,TLS还具有用于对称密钥加密的附加安全机制。

    消息验证代码(MAC)和TLS数据完整性
      窃听者可以对传输中的加密数据进行两种可能的攻击:尝试解密数据或尝试修改数据。只要密钥安全,我们就可以认为解密基本上是不可能的,但如果是修改数据呢?客户端和服务器是怎么知道攻击者没有修改过数据呢?如上所述,TLS不仅仅是加密数据,还可以保护数据,使其免受未检测到的修改,换句话说,TLS可以检查数据的完整性。让我们看看它是怎么做到的。

    当服务器或客户端使用主密钥加密数据时,它还会计算明文数据的校验和(哈希值),这个校验和称为消息验证代码(MAC)。然后在发送之前将MAC包含在加密数据中。密钥用于从数据中生成MAC,以确保传输过程中攻击者无法从数据中生成相同的MAC,故而MAC被称为HMAC(哈希消息认证码)。另一方面,在接收到消息时,解密器将MAC与明文分开,然后用它的密钥计算明文的校验和,并将其与接收到的MAC进行比较,如果匹配,那我们就可以得出结论:数据在传输过程中没有被篡改。

    客户端和服务器必须使用相同的散列算法来创建以及验证MAC,还记得Github同意的密码套件的最后一部分吗?
    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_ SHA256。即SHA256 是用于处理HMAC的哈希函数,为了提高安全性,客户端和服务器使用MAC密钥。让我们看看这些是什么。

    MAC密钥和IV密钥
      根据要求,有4个密钥用于加密和验证每个消息的完整性,他们是:

    客户端写入加密密钥:客户端用赖加密数据,服务器用来解密数据。
    服务器写入加密密钥:服务器用来加密数据,客户端用来解密数据。
    客户端写入MAC密钥:客户端用来创建MAC,服务器用来验证MAC。
    服务器写入MAC密钥:服务器用来创建MAC,客户端用来验证MAC。
      这些密钥块由主密钥上的相同的PRF反复地生成,直至密钥有了足够的字节。

    key_block = PRF(SecurityParameters.master_secret,“密钥扩展”,SecurityParameters.server_random + SecurityParameters.client_random);
      如您所见,除了客户端 - 服务器随机值和字符串“密钥扩展”之外,主密钥还用来增加密钥的平均信息量。PRF可以生成任意长度的密钥,这点是很有用的,因为默认情况下不同的散列函数具有不同的长度。在我们的例子中用的是SHA256,它是256位,但MD5的默认长度为128位。

    除此之外,我们知道我们使用的AES和GCM算法是一种分组密码,它需要一组比特来作为初始化向量(IV)。在讨论密码套件时,我们已经提到IV用于改善AES加密的平均信息量,换句话说,当多次加密同一文件时,IV能够生成不同的密文,这些随机的字节也由相同的PRF生成,并且被称为客户端写入IV 和服务器写入IV ,术语是自解释的。我不会对IV的细节再进行更多讲解,因为它是一个很大的主题,超出了本文的范围。

    生成测试数据
      现在双方都有了加密密钥,我们准备加密,但是在将TLS放到应用层之前,我们需要像每个进程一样来测试并验证客户端加密数据是否可以由服务器解密,反之亦然。为此,客户端将使用伪随机函数(PRF)计算12字节的verify_data,如下所示。

    verify_data = PRF(master_secret, “client finished”, MD5(handshake_messages) + SHA-1(handshake_messages) ) [12]
      其中handshake_messages 是所有握手消息的缓冲区,以上版本适用于版本1.2的TLS。版本1.2略有变化,即verify_data的长度取决于密码套件而不总是12字节,任何未明确指定verify_data_length的密码套件都等于12。此外,伪随机函数(PRF)中的MD5 / SHA-1组合具有已被密码套件指定的PRF替换。所以根据最新规范,

    Verify_data = PRF(master_secret, finished_label, Hash(handshake_messages)) [0…verify_data_length-1];
      因此我们有测试数据,用密钥和算法来加密测试数据。客户端所需要做的就是用客户端加密密钥(或简称客户端写入密钥)使用AES算法加密测试数据,如上所述还得计算HMAC,客户端获取结果并添加记录头字节“0x14”表明“已完成”,再通过客户端生成消息并且发送到服务器。这是由实体和客户端发送的最后一次握手消息之间协商的算法和密钥保护的第一条消息。由于消息是完全加密的,因此WireShark只会看到加密的内容,并通过名称为加密握手的消息来调用完成的握手信息,如下所示。
    在这里插入图片描述

    验证磋商
      服务器处理过程也几乎相同。它发出一个Change Cipher Spec ,然后发送一条包含所有握手消息的已完成信息。更改标记在该服务器切换到新协商的加密套件和键点的密码SPEC消息,然后再加密后续客户端的记录。除此之外,服务器的完成消息将包含对客户端的完成消息进行解密的版本,一旦客户端收到此数据,它将使用服务器写入密钥对其进行解密。故而这就向客户证明了服务器能够成功解密我们的消息。KABOOM!我们完成了TLS握手。

    所有的加密都是基于协商的算法。在我们的例子中,算法是AES_128_GCM,这里没有必要进行进一步的解释,因为当涉及到其他网站时,服务器指定的算法可能会有所不同。如果您有兴趣了解这些算法的工作原理,维基百科有一个列表。我也是通过TLS基础知识来学习密码学。

    加密应用程序数据
      我们现在在应用层。如果你有一个中等速度的互联网连接,我们只是连接了几百毫秒。想象一下,在如此短的时间内会发生多少事情?

    我要求的页面是homepade aka www.github.com

    。所以在Mozilla Firefox的开发者工具中显示的纯文本请求是,

    GET https://github.com/

    Host: github.com

    User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0

    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8

    Accept-Language: en-US,en;q=0.5

    Accept-Encoding: gzip, deflate, br

    Connection: keep-alive

    Upgrade-Insecure-Requests: 1

    Cache-Control: max-age=0
    请参阅下图:
    在这里插入图片描述

    前3个字节17 03 03 表示内容的数据类型(应用程序数据)和TLS版本(TLS 1.2)。

    尾声
    对,就是这样。我们结束了。

    在本系列的下一部分中,我会添加一些在本文中无法包含的别的内容。我还发布了结构化的参考链接,这对于学习TLS中的密码学还是很有用的。
      我想在这里再写点什么。整篇文章写的都是我对TLS的理解上的兴趣,就是说我所学到/理解的一切都在这里了,或许并不完整,或许会有错误,或许各位的看法和我有出入。总之,不管是什么,欢迎您在评论区中分享,我很高兴能和诸位一起学习更多的东西!

    展开全文
  • TLS 1.3 协议详解

    万次阅读 多人点赞 2018-08-09 10:46:08
    TLS 1.3 握手流程详解 需要的背景知识: (1):对 TLS 1.2 协议有一定程度的了解,包括秘钥交换、会话复用等。 第一节 TLS 1.3 的握手概述 协议分析的第一步就是看报文。TLS 1.3的报文,有个特点,就是通过抓...
  • SS端加密以及obfs混淆推荐

    万次阅读 2019-08-26 20:59:19
    SS端加密以及obfs混淆 ...(排名分先后)推荐的混淆obfs:首选http、次选tls ​ 注:加密方式推荐是因为AEAD本身有新的特性,另外主推荐aes-256-gcm是因为这个加密实测多数主流设备下都可以通过硬件加解...
  • TLS 1.3详解

    千次阅读 2020-04-28 18:45:15
    he Transport Layer Security (TLS) Protocol Version 1.3 (draft-ietf-tls-tls13-20) 与TLS1.2的主要区别: 以下是TLS 1.2和TLS 1.3之间主要功能的差异列表。 它不是详尽的,有很多微小的区别。 支持的对称...
  • TLS协议分析

    千次阅读 2016-12-25 17:00:25
    TLS协议分析 2015-09-06 本文目标: 学习鉴赏TLS协议的设计,透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛,读者需要对现代密码学...
  • WEB性能(3)--TLS

    2019-09-04 21:36:47
    一、传输层安全(TLS)介绍 SSL(Secure Sockets Layer,安全套接层)协议最初是网景公司为了保障网上交易安全而开发的,SSL协议在直接位于TCP上一层的应用层被实现。SSL不会影响上层协议(HTTP),但能够保证上层...
  • 学习鉴赏TLS协议的设计,透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛,读者需要对现代密码学有清晰而系统的理解,建议花精力补足背景知识再读。...
  • 解密TLS协议全记录之利用wireshark解密

    千次阅读 热门讨论 2020-07-17 01:33:34
    为什么会突然有使用wireshark学习TLS的想法,主要是为了在nike官网抢限量球鞋,但是发现路子好像走歪了,唯一的价值好像就是多了这么一篇博客,查阅了很多有根据,没根据的博客内容,总结出这篇自以为还算全面,结实...
  • 删除了“正在使用...”文本,因为该文本与stdout混淆,并且如果您要以自动化方式使用此程序,则其他程序将更难以解析该程序的输出。 添加了NoSchannel参数,该参数绕过证书和SChannel内容,直接进入密码扫描。
  • TLS1.3规范(RFC文档)

    万次阅读 2017-01-05 11:07:44
    The Transport Layer Security (TLS) Protocol Version 1.3 (draft-ietf-tls-tls13-latest) TLS支持三种基本的密钥交换模式: (EC)DHE (Diffie-Hellman both the finite field and elliptic curve varieties)...
  • SSL vs TLS vs STARTTLS

    千次阅读 2018-08-14 07:11:32
    SSL, TLS和STARTTLS都是在计算机安全里面, 都很容易让人混淆的词. SSL和TLS都提供了加密2台计算机(如服务器和客户端)之间通信的办法. TLS是SSL的继任者, 所以除非提到具体协议的版本,TLS和SSL这2个词是可以混用的, ...
  • TLS/SSL 协议详解 (9) Client hello

    万次阅读 2017-09-06 16:03:29
    SSL报文格式可以大致分为2部分,Record层 和 Handshake层,Record层中指定了后续数据的类型,SSL版本(一般来说...例如上图中显示的那样,SSL报文头部是TVL格式: Content Type: Handshake Version: TLS 1.0 Len...
  • 我已经很长一段时间没有担任过重要的职务了,所以现在该是发表一些有用和有趣的文章的时候了。 尽管不是特定于Java的,但对于... 这篇文章仅作为SSL / TLS攻击的“简短”介绍。 如果您想了解更多信息,请看一下本文...
  • mbedtls 探索

    2021-04-26 10:19:53
    mbedtls库使开发人员在嵌入式产品中加入加密和 SSL/TLS 功能。 包含3个组件: SSL/TLS 协议实施 一个加密库 一个 X.509 证书处理库 SSL“安全套接层”协议,TLS“安全传输层”协议,都属于是加密协议,在其网络数据...
  • WPF开发教程

    万次阅读 多人点赞 2019-07-02 23:13:20
    最常见的形式是使用线程本地存储 (TLS) 来存储状态。线程关联要求执行的每个逻辑线程仅由操作系统中的一个物理线程所拥有,这将占用大量内存。最后,WPF 的线程处理模型保持与具有线程关联的单一线程执行的现有 User...
  • 只要做程序开发、特别是网络传输相关的内容,总是绕不开加密,一直想把对称/非对称加密、SSL/TLS、公钥、私钥、签名、验证签名、openssl、x509、crt、key、crs等等这些概念统一的梳理一下,就当是复习功课,也供大家...
  • (这里在谈ECDH而不是ECDHE,评论区有同学混淆了两者概念,区别见:https://blog.csdn.net/mrpre/article/details/78025940) 比如说服务器选择了ECDH_RSA加密套件,但是发送的证书却是ECDSA签名的证书,虽然说证书...
  • ssl/tls sshInsecure connections would be the last thing we’d want nowadays. So how do the latest communication protocols manage to have them securely? 不安全的连接将是当今我们想要的最后一件事。 那么...
  • 本文将探索整个SSL/TLS握手过程。 在此之前,先简述下最后这块内容的关键要点: TLS适用于对称密钥 对称密钥可以通过安全密钥交换算法共享 如果请求被截获,密钥交换可能会被欺骗 使用数字签名进行身份验证 ...
  • SSL/TLS/DTLS对比

    千次阅读 2015-01-11 22:32:20
    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(TransportLayer Security,TLS & Datagram ...DTLS、TLS与SSL在传输层对网络连接进行加密,DTLS在UDP传输协议之上,而TLS则在TCP传输协议之上。 各协议
  • TLS协议分析------

    万次阅读 2017-06-07 15:03:08
    TLS协议分析 2015-09-06 本文目标: 学习鉴赏TLS协议的设计,透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛,读者需要对现代密码学...
  • ssl/tls 很长一段时间以来,我都没有担任过重要的职务,所以现在是时候进行一些有用和有趣的事情了。 尽管不是特定于Java的,但这篇文章对某些人可能仍然很有趣。 阅读前的简短警告:这是篇很长的文章,但是-信不信...
  • TLS协议分析 (七) 安全性分析

    千次阅读 2017-04-11 09:13:28
    9. TLS协议的安全分析 安全分析,重中之重,也是大家最关心的。 安全分析的第一步是建立攻击模型,TLS的攻击模式是: 攻击者有充足的计算资源 攻击者无法得到私钥,无法得到客户端和服务器内存...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,717
精华内容 1,486
关键字:

tls混淆