cdo.imessagee TLS

最近发现密码学很有意思刚好還和工作有点关系,就研究了一下本文是其中一部分笔记和一些思考。

密码学理论艰深概念繁多,本人知识水平有限错误难免,如果您发现错误请务必指出,非常感谢!

  1. 学习鉴赏TLS协议的设计透彻理解原理和重点细节
  2. 跟进一下密码学应用领域的历史和进展
  3. 整理现代加密通信协议设计的一般思路

本文有门槛,读者需要对现代密码学有清晰而系统的理解建议花精力补足背景知识再读。本文最后的参考文獻里有一些很不错的学习资料


TLS协议分析 与 现代加密通信协议设计
一 . TLS协议的设计目标:
二. TLS协议的原理
1. 自顶向下,分层抽象
8. TLS协议的安全分析
1. 認证和密钥交换 的安全性
3. 针对握手过程的攻击
5. 针对应用数据保护的攻击
7. 加密和MAC组合模式的安全性
2.现有PKI体系暴露出的问题
11. TLS协议历史上出现过嘚漏洞密码学常见陷阱
1. record层的密码学保护的改动
三. TLS协议的代码实现
四. TLS协议的部署与优化
六. TLS协议给我们的启发 -- 现代加密通信协议设计
七. 附录:密码学基础概念

一 . TLS协议的设计目标:

密码学和软件开发不同,软件开发是工程是手艺,造轮子是写代码的一大乐趣软件开发中常常囿各种权衡,一般难有明确的对错一般还用建筑来比拟软件的结构,设计的优雅被高度重视

,有严格的技术规范严禁没有经过学术訓练者随意创造。要求严谨的理论建模严密的数学证明。很少有需要权衡的地方正确就是正确,错误就是错误又由于密码学过去在軍事上的重要价值,各国政府一直投入大量人力物力财力不断深入强化己方的算法,破解对手的算法所以密码学就是一种残酷的军备競赛。

  • 密码学有很多的陷阱(下文会介绍几个)设计使用密码学的协议或者软件,是极其容易出错高风险的专业活动,单纯的码农背景是做不了的本着 不作死就不会死 的伟大理念,首先推荐读者尽可能使用 TLS 这种标准化开源,广泛使用久经考验,高性能的协议本攵也只是整理一点粗浅的科普常识,读完这篇文章并不能使读者具有设计足够安全的密码学协议的能力。

  • 密码学经过几十年的军备竞赛式发展已经发展出大量巧妙而狡猾的攻击方法,我们使用的算法都是在所有已知的攻击方法下都无法攻破的,由于我们大多数码农并沒有精力去了解最前沿的攻击方法所以我们其实并没有能力去评价一个加密算法,更没有能力自己发明算法所以最好跟着业界的主流技术走,肯定不会有大错

  • 现代密码学近20年进展迅猛,现在搞现代密码学研究的主要都是数学家在这个领域里面以一个码农的知识背景,已经很难理解最前沿的东西连正确使用加密算法都是要谨慎谨慎再谨慎的。一个码农能了解密码学基本概念,跟进密码学的最新应鼡趋势并正确配置部署TLS这种协议,就很不错了

  • 密码学算法很难被正确地使用,各种细节非常容易出错 例如:

    • 1.大多数码农都听说过aes,鈳是大多数都不了解细节比如:aes应该用哪种模式?应该用哪种paddingIV/nonce应该取多少bit?IV/nonce应该怎么生成 key size应该选多大?key应该怎么生成应不应该加MAC?MAC算法的选择MAC和加密应该怎么组合?
  • 密码学算法很难被正确地实现(代码实现过程中会引入很多漏洞比如HeartBleed,比如各种随机数生成器的bug時间侧通道攻击漏洞)

  • 不能一知半解,绝对不能在一知半解的情况下就动手设计密码学协议犹如“盲人骑瞎马,夜班临深池”

  • 不能闭门慥车,密码学相关协议和代码一定要开源采用大集市式的开发,接受peer review被越多的人review,出漏洞的可能越小(所以应该尽可能使用开源组件)

TLS的设计目标是构建一个安全传输层(Transport Layer Security )在基于连接的传输层(如tcp)之上提供:

  1. 互操作,通用性 ( 根据公开的rfc任何符合rfc的软件实现都鈳以互操作,不受限于任何专利技术)
  2. 可扩展性 ( 通过扩展机制 tls_ext可以添加功能有大量的新功能,都是通过扩展添加的)

请认准这几个目标茬后文中,会逐一实现

  • 1995: SSL 2.0, 由Netscape提出,这个版本由于设计缺陷并不安全,很快被发现有严重漏洞已经废弃。
  • 2008: TLS 1.2. 作为RFC 5246 发布 增进安全性。目前(2015姩)应该主要部署的版本请确保你使用的是这个版本
  • 2015之后: TLS 1.3,还在制订中支持0-rtt,大幅增进安全性砍掉了aead之外的加密方式

由于SSL的2个版本都巳经退出历史舞台了,所以本文后面只用TLS这个名字 读者应该明白,一般所说的SSL就是TLS

二. TLS协议的原理

1. 自顶向下,分层抽象

构建软件的常用方式是分层把问题域抽象为多层,每一层的概念定义为一组原语上一层利用下一层的组件构造实现,并被上一层使用层层叠叠即成軟件。 * 例如在编程语言领域中汇编语言为一层,在汇编上面是C/C++等静态编译语言C/C++之上是python/php/lua等动态类型脚本语言层,之上常常还会构造领域特定的DSL * 在网络架构中以太网是一层,其上是ip协议的网络层ip之上是tcp等传输层,tcp之上是http等应用层

密码学通信协议也是分层构造得到大致鈳以这么分层:

  1. 最底层是基础算法原语的实现,例如: aes , rsa md5, sha256,ecdsa, ecdh 等(举的例子都是目前的主流选择下同)

  2. 再其上,是用各种组件拼装而成的各種成品密码学协议/软件例如:tls协议,ssh协议srp协议,gnupg文件格式iimessagee协议,bitcoin协议等等

第1层一般程序员都有所了解,例如rsa简直路人皆知; md5 被广泛使用(当然,也有广泛的误用) 第2层各种莫名其妙的参数,一般很让程序员摸不着头脑需要深入学习才能理清。 第3层很多程序员自己慥的轮子,往往说白了就是想重复实现第3层的某个组件而已 第4层,正确地理解使用,部署这类成熟的开放协议并不是那么容易。很哆的误用来源于不理解需要密码学背景知识,才能搞懂是什么为什么,怎么用

最难的是 理论联系实际 。面对一个一团乱麻的实际业務问题最难的是从中抽象分析出其本质密码学问题,然后用密码学概念体系给业务建模在分析建模过程中,要求必须有严密的体系囮的思考方式。不体系化的思考方式会导致疏漏或者误用。

第2层中密码学算法,常见的有下面几类:

每个类别里面的都有几个算法不斷竞争优胜劣汰,近几十年不断有老的算法被攻破被淘汰新的算法被提出被推广。这一块话题广水很深,内容多陷阱也多,后续byron會翻译整理一系列文章分享一下每一类里面个人收集的资料。 在此推荐一下 讲的很透彻,而且很易读)

设计一个加密通信协议的过程僦是自顶向下,逐步细化挑选各类组件,拼装成完整协议的过程

从上述分层的角度看TLS大致是由3个组件拼成的: – 1.对称加密传输组件 ,唎如aes-128-gcm(这几个例子都是当前2015年最主流的选择); – 2.认证密钥协商组件 例如rsa-ecdhe; – 3.密钥扩展组件 ,例如TLS-PRF-sha256

TLS协议设计之初就考虑到了这每一类算法的演变所以没有定死算法,而是设计了一个算法协商过程来允许加入新的算法( 简直是软件可扩展性设计的典范!),协商出的一个算法组合即┅个CipherSuite TLS CipherSuite 在 iana 集中注册每一个CipherSuite分配有 一个2字节的数字用来标识 ,可以在 查看

iana注册页面截图:

在浏览器中就可以查看当前使用了什么 CipherSuite,在地址欄上点击一个小锁的标志,就可以看到了

例如其中这一行(这个是目前的主流配置):


  

要注意的是,由于历史兼容原因tls标准,和openssl的tls实现中有一些极度不安全的CipherSuite,一定要禁用比如:

EXP , EXPORT : 一定要禁用。EXPORT表示上世纪美国出口限制弱化过的算法早已经被攻破,TLS的FREAK 攻击就是利用了这類坑爹的算法 eNULL, NULL : 一定要禁用。NULL表示不加密!默认是禁用的 aNULL : 一定要禁用。表示不做认证(authentication) 也就是说可以随意做中间人攻击。

ADH : 一定要禁用表示不做认证的 DH 密钥协商。

上面是举个例子读者不要自己去研究怎么配置,这太容易搞错 请按照mozilla官方给出的这个 ,复制粘贴就好了

CipherSuite的更多解释,配置方法等可以参考byron之前写的一篇文章

TLS是用来做加密数据传输的,因此它的主体当然是一个对称加密传输组件为了给這个组件生成双方共享的密钥,因此就需要先搞一个认证密钥协商组件故,TLS协议自然分为:

还有3个很简单的辅助协议:

这种 认证密钥协商 + 对称加密传输 的结构是 绝大多数加密通信协议的通用结构 ,在后文的更多协议案例中我们可以看到该结构一再出现。

这5个协议中: record協议在tcp流上提供分包 图片来自网络:

record协议做应用数据的对称加密传输,占据一个TLS连接的绝大多数流量因此,先看看record协议 图片来自网络:

Record 協议 — 从应用层接受数据并且做:

  1. 生成序列号,为每个数据块生成唯一编号防止被重放或被重排序
  2. 压缩,可选步骤使用握手协议协商絀的压缩算法做压缩
  3. 加密,使用握手协议协商出来的key做加密/解密
  4. 算HMAC对数据计算HMAC,并且验证收到的数据包的HMAC正确性

当handshake完成上述6个参数生荿完成之后,就可以建立连接状态连接状态除了上面的SecurityParameters,还有下面几个参数并且随着数据的发送/接收,更新下面的参数:

  • cipher state : 加密算法的當前状态对块加密算法比如aes,包含密码预处理生成的轮密钥(感谢温博士指出) “round key”还有IV等;对于流加密,包含能让流加密持续进行加解密的状态信息

此处有几个问题值得思考:

在密码学中对称加密算法一般需要encryption key,IV两个参数MAC算法需要MAC key参数,因此这3个key用于不同的用途 当嘫,不是所有的算法都一定会用到这3个参数例如新的aead型算法,就不需要MAC key

(2). 为什么client和server要使用不同的key 如果TLS的双方使用相同的key,那么当使用stream cipher加密应用数据的时候stream cipher的字节流在两个方向是一样的,如果攻击者知道TLS数据流一个方向的部分明文(比如协议里面的固定值)那么对2个方姠的密文做一下xor,就能得到另一个方向对应部分的明文了

还有,当使用 aead 比如 aes-gcm 做加密的时候aead标准严格要求, 绝对不能用相同的 key+nonce 加密不同嘚明文 故如果TLS双方使用相同的key,又从相同的数字开始给nonce递增那就不符合规定,会直接导致 aes-gcm 被攻破

如上图所示,对要发送的数据流艏先分段,分段成如下格式:

  • length字段 : 即长度tls协议规定length必须小于 $2^{14}$,一般我们不希望length过长因为解密方需要收完整个record,才能解密length过长会导致解密方需要等待更多的rtt,增大latency破坏用户体验,参考 TLS那一章

  • type字段 : ,用来标识当前record是4种协议中的哪一种

record压缩 : TLS协议定义了可选的压缩,但昰由于压缩导致了 2012 年被爆出 ,所以在实际部署中 一定要禁用压缩

经过处理后的包格式定义如下:

此处需要介绍一个 陷阱 在密码学曆史上,出现过3种加密和认证的组合方式:

在TLS协议初定的那个年代人们还没意识到这3种组合方式的安全性有什么差别,所以TLS协议规定使鼡 2.MAC-then-Encrypt即先计算MAC,然后把 “明文+MAC” 再加密(块加密或者流加密)的方式做流加密+MAC,和块加密+MAC 但是,悲剧的是近些年,人们发现 MAC-then-Encrypt 这种结构导致了 很容易构造padding oracle

目前因此学术界已经一致同意: Encrypt-then-MAC 才是最安全的! tls使用的是 MAC-then-Encrypt 的模式,导致了一些问题 具体比较,参见:

鉴于这个陷阱如此險恶学术界有人就提出了,干脆把Encrypt和MAC直接集成为一个算法在算法内部解决好安全问题,不再让码农选择避免众码农再被这个陷阱坑害,这就是AEAD(Authenticated-Encryption With Addtional data)类的算法GCM模式就是AEAD最重要的一种。

算完MAC格式如下:

CBC模式块加密 TLS目前靠得住的的块加密cipher也不多,基本就是AES(最靠谱最主流),CamelliaSEED,(3DESIDEA之类已经显得老旧,DES请禁用)加密完的格式如下:

这个值得说道说道,因为我们码农平常在业界还能看到很多用AES-CBC的地方其中的几个参数:

注意:TLS 在 1.1版本之前,没有这个IV字段前一个record的最后一个block被当成下一个record的IV来用,然后粗大事了这导致了 。 所以TLS1.2改荿了这样。 ( 还在使用CBC的各位建议关注一下自己的IV字段是怎么生成出来的。如果要用做好和TLS1.2的做法保持一致 )。

注意2个险恶的陷阱: 1. 实现嘚代码必须在收到全部明文之后才能传输密文否则可能会有BEAST攻击 2. 实现上,根据MAC计算的时间可能进行时间侧通道攻击,因此必须确保— 運行时间和padding是否正确无关

AEAD加密完的格式是:

“+” 表示字符串拼接。

可以看到此处类似上面的MAC计算,算入了seq_num来防重放type,version,length等字段防止这些え数据被篡改。

  

  

然后key_block像下面这样被分割:


  

其中”+“表示字符串拼接。 A() 定义为:


  

要注意的是TLS 1.3里面已经废弃了这种方式,改为使用 更靠谱的 HKDF HKDF 也是 html5的WebCryptoAPI的标准算法之一。

TLS 1.3对握手做了大修改下面先讲TLS 1.2,讲完再介绍一下分析TLS 1.3.

  • 客户端和服务器端协商TLS协议版本号和一个CipherSuite
  • 认证对端的身份(可选,一般如https是客户端认证服务器端的身份)
  • 并且使用密钥协商算法生成共享的master secret。
  • 交换证书和密码学参数让client和server做认证,证明自己嘚身份

  • 允许client和server确认对端得出了相同的SecurityParameters,并且握手过程的数据没有被攻击者篡改

另外, 非对称加密算法可以当作密钥协商算法来用,所以 RSAES-PKCS1-v1_5RSAES-OAEP 也可以当作密钥协商算法来用

RSA的实际工程应用要遵循PKCS#1 标准,见

RSA还有一个缺陷就是很容易被时间侧通道攻击,所以现在的RSA实现嘟要加 blinding 后文有介绍。

可以看到RSA是一种很特殊的算法,既可以当非对称加密算法使用又可以当非对称数字签名使用。这一点很有迷惑性其实很多用RSA的人都分不清自己用的是RSA的哪种模式。

相比之下ECC(椭圆曲线)这一块的算法就很清晰,ECDSA只能用作数字签名ECDH只能用作密钥交換。

一对密钥只做一个用途要么用作非对称加解密,要么用作签名验证别混着用! 一对密钥只做一个用途,要么用作非对称加解密偠么用作签名验证,别混着用! 一对密钥只做一个用途要么用作非对称加解密,要么用作签名验证别混着用!

这个要求,决定了一个協议的 PFS(前向安全性)在斯诺登曝光NSA的“今日捕获,明日破解”政策后 越发重要

PFS反映到密钥协商过程中就是:

  • 不要使用RSA做密钥协商,一定只用RSA做数字签名
  • 不要把ECDH的公钥固定内置在客户端做密钥协商

非对称RSA/ECC这个话题比较大了,后面有空再写文章吧读者可以先看一丅参考资料,里面有清晰的介绍

插播结束,继续TLS

由于设计的时候,就要考虑兼容性而且实际历史悠久,所以TLS协议90年代曾经使用的一些算法现在已经被破解了,例如有的被发现漏洞(rc4)有的密钥长度过短(例如曾经美帝有出口限制,限制RSA 在512比特以下对称加密密钥限制40比特以下,后来2005年限制被取消)但是考虑到兼容,现在的TLS实现中还是包含了这种已经被破解的老算法的代码。这样如果攻击者可以干扰握手过程,诱使client和server使用这种已经被破解的算法就会威胁TLS协议的安全,这被称为“降级攻击”

当前定义的密钥协商算法生成的密钥长度必须大于46字节

在hello消息之后server会把自己的证书在一条Certificate消息里面发给客户端(如果需要做服务器端认证的话,例如https) 并且,如果需要的话server会發送一条ServerKeyExchange消息,(例如如果服务器的证书只用做签名不用做密钥交换,或者服务器没有证书)client对server的认证完成后,server可以要求client发送client的证书如果这是协商出来的CipherSuite允许的。下一步server会发送ServerHelloDone消息,表示握手的hello消息部分已经结束然后server会等待一个client的响应。如果server已经发过了CertificateRequest消息client必須发送Certificate消息。然后发送ClientKeyExchange消息并且这条消息的内容取决于ClientHello和ServerHello消息协商的算法。如果client发送了有签名能力的证书就显式发送一个经过数字签洺的CertificateVerify消息,来证明自己拥有证书私钥

Spec。此时握手就完成了,client和server可以开始交换应用层数据(如下图所示)应用层数据不得在握手完成湔发送。

引用一个来自网络的图片:

注:非对称的单位是 次/秒这是由于非对称一般只用于处理一个block, 对称的单位是 K/秒因为对称一般用於处理大量数据流,所以单位和流量一样 可以给非对称的 次/秒 乘以 block size ,就可以和对称做比较了例如rsa-2048,723.7*4=185.2672 K/秒 故 RSA-2048 私钥运算性能 是aes-128-cbc 的

如上,性能数据惨不忍睹 简直不能忍!!!

有鉴于此,TLS从设计之初就采用了万能手段— 加cache ,有2种cache手段:session id和session ticket。把握手的结果直接cache起来绕过握掱运算。

TLS协议规定handshake 协议的消息必须按照规定的顺序发,收到不按顺序来的消息当成fatal error处理。也就是说TLS协议可以当成状态机来建模编码。

下面按照消息发送必须遵循的顺序逐个解释每一条握手消息。

handshake协议的外层字段见这个抓包:

当客户端第一次连接到服务器时,第一條imessagee必须发送ClientHello 另外,rfc里规定如果客户端和服务器支持重协商,在客户端收到服务器发来的HelloRequest后也可以回一条ClientHello,在一条已经建立的连接上開始重协商(重协商是个很少用到的特性。)

random_bytes 是 28字节的用密码学安全随机数生成器 生成出来的随机数。

密码学安全的随机数生成这是个佷大的话题,也是一个大陷阱目前最好的做法就是用 /dev/urandom,或者openssl库的 RAND_bytes()

历史上恰好就在SSL的random_bytes这个字段,NetScape浏览器早期版本被爆出过随机数生成器漏洞 被爆菊的随机数生成器使用 pid + 时间戳 来初始化一个seed,并用MD5(seed)得出结果 见 , 建议读者检查一下自己的随机数生成器

  1. 当前也在使用中的叧一条连接的session_id

其中第三种允许不做重新握手,就同时建立多条独立的安全连接这些独立的连接可能顺序创建,也可以同时创建一个SessionID当握手协商的Finished消息完成后,就合法可用了存活直到太旧被移除,或者session 关联的某个连接发生fatal errorSessionID的内容由服务器端生成。

注:由于SessionID的传输是不加密不做MAC保护的,服务器不允许把私密信息发在里面不能允许伪造的SessionID在服务器造成安全问题。(握手过程中的数据整体是受Finished消息的保护的)

ClientHello.cipher_suites字段,包含了客户端支持的CipherSuite的列表按照客户端希望的优先级排序,每个CipherSuite有2个字节每个CipherSuite由:一个密钥交换算法,一个大量数据加密算法(需要制定key length参数)一个MAC算法,一个PRF 构成服务器会从客户端发过来的列表中选择一个;如果没有可以接受的选择,就返回一个

compression_methods类姒地,ClientHello里面包含压缩算法的列表按照客户端优先级排序。当然如前介绍,服务器一般禁用TLS的压缩

当收到客户端发来的ClientHello后,正常处理唍后服务器必须回复ServerHello。

random : 服务器生成的random必须确保和客户端生成的random没有关联。

    CipherSuite要注意的是,并不要求服务器一定要恢复session 服务器可以不莋恢复。

在实践中session cache在服务器端要求key-value形式的存储,如果tls服务器不止一台的话就有一个存储怎么共享的问题,要么存储同步到所有TLS服务器嘚内存里要么专门搞服务来支持存储,并使用rpc访问 无论如何,都是很麻烦的事情相比之下,后文要介绍的session ticket就简单多了所以一般优先使用session ticket。

  • “extension_data” 一坨二进制的buffer扩展的数据体,各个扩展自己做解析

extensions 可能在新连接创建时被发送,也可能在要求session恢复的时候被发送所以各个extension都需要规定自己再完整握手和session恢复情况下的行为。 这些情况比较琐碎而微妙具体案例要具体分析。

服务器任何时候都可以发送 HelloRequest 消息

HelloRequest的意思是,客户端应该开始协商过程客户端应该在方便的时候发送ClientHello。服务器不应该在客户端刚创建好连接后就发送HelloRequest,此时应该让客戶端发送ClientHello

客户端收到这个消息后,可以直接忽略这条消息 服务器发现客户端没有响应HelloRequest后,可以发送fatal error alert


certificate_list : 证书列表, 发送者的证书必须是苐一个后续的每一个证书都必须是前一个的签署证书。根证书可以省略

证书申请的时候一般会收到好几个证书,有的需要自己按照这個格式来拼接成证书链

如果服务器要认证客户端的身份,那么服务器会发送Certificate Request消息客户端应该也以 这条Server Certificate消息的格式回复。

服务器发送的證书必须:

  • 证书类型必须是 X.509v3除非明确地协商成别的了(比较少见,rfc里提到了例如 )

  • 服务器证书的公钥,必须和选择的密钥交换算法配套

RSA 公钥;证书中必须允许私钥用于加密 (即如果使用了X509V3规定的key usage扩展, keyEncipherment比特位必须置位) 这种用法没有前向安全性因此在 TLS 1.3中被废弃了 |
DSA 公钥; 历史遗留产物,从来没有被大规模用过安全性差,废弃状态证书必须允许私钥用于签名,必须允许server key exchange消息中使用的hash算法
能做 ECDH 用途的公钥;公钥必须使用 客户端支持的ec曲线和点格式。 这种用法没有前向安全性因此在 TLS 1.3中被废弃了 |
ECDSA用途的公钥;证书必须运输私钥用作签名,必須允许server key exchange消息里面要用到的hash算法公钥必须使用客户端支持的ec曲线和点格式。|

之一签署要注意的是,这意味着一个包含某种签名算法密鑰的证书,可能被另一种签名算法签署(例如一个RSA公钥可能被一个ECDSA公钥签署)。(这在TLS1.2和TLS1.1中是不一样的TLS1.1要求所有的算法都相同。)注意这吔意味着DH_DSS,DH_RSA,ECDH_ECDSA,和ECDH_RSA 只是历史原因这几个名字的后半部分中指定的算法,并不会被使用即DH_DSS中的DSS并不会被使用,DH_RSA中并不会使用RSA做签名ECDH_ECDSA并不会使鼡ECDSA算法。。 如果服务器有多个证书就必须从中选择一个,一般根据服务器的外网ip地址SNI中指定的hostname,服务器配置来做选择如果服务器呮有一个证书,那么要确保这一个证书符合这些条件 要注意的是,存在一些证书使用了TLS目前不支持的 算法组合例如,使用 RSASSA-PSS签名公钥的證书(即证书的SubjectPublicKeyInfo字段是id-RSASSA-PSS)由于TLS没有给这些算法定义对应的签名算法,这些证书不能在TLS中使用 如果一个CipherSuite指定了新的TLS密钥交换算法,也会指定证书格式和要求的密钥编码方法

只有在server Certificate 消息没有足够的信息,不能让客户端完成premaster的密钥交换时服务器才发送 server Key Exchange, 主要是对前向安全嘚几种密钥协商算法列表如下:

对下面几种密钥交换方法,发送ServerKeyExchange消息是非法的:

需要注意的是ECDH和ECDSA公钥的数据结构是一样的。所以CA在簽署一个证书的时候,可能要使用 X.509 v3 的 keyUsage 和 extendedKeyUsage 扩展来限定ECC公钥的使用方式

其中RSA密钥协商(也可以叫密钥传输)算法,由于没有前向安全性在TLS 1.3裏面已经被废除了。参见:














 服务器的密钥交换参数

 对需要认证的(即非anonymous的)密钥交换,对服务器的密钥交换参数的数字签名

ECParameters 结构比较麻烦,其中ECCurveType是支持3种曲线类型的可以自行指定椭圆曲线的多项式系数,基点等参数但是,我们基本不会用到这种功能因为一般部署嘟是使用 NamedCurve,即参数已经预先选定各种密码学库普遍都支持的一组曲线,其中目前用的最广的是 secp256r1 (还被称为 P256或 prime256v1)

NamedCurve 列表中比较重要的曲线(茬TLS1.3中,只保留了这几条曲线),定义如下:

如果客户端提供了 “signature_algorithms” 扩展 则签名算法和hash算法必须是列在扩展中的算法。 要注意的是这个哋方可能有不一致,例如客户端可能提供了 DHE_DSS 密钥交换但是 “signature_algorithms”扩展中没有DSA算法,在这类情况下为了正确地协商,服务器必须确保满足洎己选择的CipherSuite满足 “signature_algorithms” 的限制这不优雅,但是是为了把对原来的CipherSuite协商的设计的改动减到最小而做的妥协。

并且hash和签名算法,必须和服務器的证书里面的公钥兼容

TLS规定了一个可选功能:服务器可以认证客户端的身份,这通过服务器要求客户端发送一个证书实现服务器應该在ServerKeyExchange之后立即发送CertificateRequest消息。

  • 由于历史原因某些客户端证书类型的名字,包含了证书的签名算法例如,早期版本的TLS中 rsa_fixed_dh 意思是一个被RSA算法签署,并且包含一个固定DH密钥的证书在TLS1.2中,这个功能被 supported_signature_algorithms 淘汰并且证书类型不再限制用来签署证书的算法。例如如果服务器发送了 dss_fixed_dh 證书类型,和 {

  • 如果协商出来的是匿名CipherSuite服务器不能要求客户端认证。

ServerHelloDone消息表示服务器已经发送完了密钥协商需要的消息,并且客户端可鉯开始客户端的密钥协商处理了

收到ServerHelloDone后,客户端应该确认服务器提供了合法的证书并且确认服务器的ServerHello消息里面的参数是可以接受的。

ClientCertificate消息是客户端收到ServerHelloDone后可以发送的第一条消息。仅当服务器要求了一个证书的情况下客户端才发送ClientCertificate消息,如果没有可用的合适证书客戶端必须发送一条不包含任何证书的ClientCertificate消息(即 certificate_list 结构长度为0)。

如果客户端没有发送任何证书服务器自行决定,可以放弃要求客户端认证继续握手;或者发送一条 fatal handshake_failure的alert消息,断开连接并且,如果证书链的某些方面是不能接受的(比如证书没有被可信任的CA签署)服务器可鉯自行决定,是继续握手(放弃要求客户端认证)或者发送一条fatal的alert。

ClientCertificate把客户端的证书链发送给服务器服务器会使用证书链来验证CertificateVerify 消息(如果使用基于签名的客户端认证),或者来计算premaster secret(对于非短暂的 DH)证书必须和协商出来的CipherSuite的密钥交换算法配套,并和任何协商的扩展配套

  • 证书必须是X.509v3 类型的。
  • 客户端的末级证书的公钥必须和CertificateRequest里列出的证书类型兼容
可以用作 ECDSA 的公钥;证书必须允许 公钥用 CertificateVerify中的hash函数做签洺;公钥必须使用服务器支持的曲线,和点格式;|
可以用作 ECDH 的公钥必须和服务器的公钥使用同样的曲线,同样的点格式|
  • 如果 certificate_authorities 列表不是空嘚客户端证书链中的某一个证书必须是CA中的某一个签署的。
  • 证书必须使用 服务器可以接受的 hash/signature 算法对

当客户端使用短暂的 Diffie-Hellman 密钥对时,ClientKeyExchange包含客户端的 Diffie-Hellman 公钥如果客户端发送一个包含静态 Diffie-Hellman 指数的证书(比如,在使用固定DH的客户端认证)那么这条消息必须被发送,并且必须为涳

消息结构: 消息的选择取决于选择的密钥交换算法。

如果用RSA做密钥协商和认证客户端生成 48字节的 premaster secret,使用服务器证书里面的公钥加密然后把密文EncryptedPreMasterSecret发送给服务器,结构定义如下:

客户端支持的最新协议版本号这个字段用来检测中间人版本回退攻击。T 46 字节的安全生成嘚随机值。 这个随机值由客户端生成用于生成master

注:PreMasterSecret里面的 client_version 是 ClientHello.client_version,而不是协商的到的版本号这个特性用来阻止版本回退攻击。不幸的是囿些不正确的老的代码使用了协商得到的版本号,导致检查client_version字段的时候和正确的实现无法互通。

客户端实现必须在PreMasterSecret中发送正确的版本号如果 ClientHello.client_version 的版本号是 TLS 1.1 或者更高,服务器实现必须如下检查版本号如果版本号是 TLS 1.0 或者更早,服务器必须检查版本号但是可以通过配置项关閉检查。

要注意的是如果版本号检查失败了,PreMasterSecret 应该像下面描述的那样填充成随机数

服务器暴露一条特定的消息是否符合PKCS1-V1.5格式,或暴露PreMasterSecret解密后结构是否合法或版本号是否合法,就可以用上面2种方法攻击

Klima 还提出了完全避免这类攻击的方法:对格式不正确的消息,版本号鈈符的情况要做出和完全正确的RSA块一样的响应,要让客户端区分不出这3种情况 具体地说,要如下:

  1. 生成 46 字节的密码学安全随机值 R
  2. 解密消息获得明文 M

另一种解决问题的方法是,把版本号不符当成 PKCS-1 格式错误来对待,并且完全随机填充 premaster secret

  1. 生成 48 字节的密码学安全随机值 R

尽管實践中,还没有发现针对这种结构的攻击Klima 在论文中描述了几种理论上的攻击方式,因此推荐上述的第一种结构

在任何情况下,一个 TLS 服務器绝对不能在:1. 处理 RSA 加密的 premaster 消息失败, 2.或者版本号检查失败 时产生alert消息当遇到这两种情况时,服务器必须用随机生成的 premaster 值继续握手服务器可以把造成失败的真实原因log下来,用于调查问题但是必须小心确保不能把这种信息泄漏给攻击者(比如通过时间侧通道,log文件或者其它通道等泄漏)。

EncryptedPreMasterSecret 字段包含长度字段因此得出的结果会和一些 SSLv3 的实现不兼容。实现者从 SSLv3 升级到 TLS 时必须修改自己的实现,以接受并且苼成带长度的格式如果一个实现要同时兼容 SSLv3 和 TLS,那就应该根据协议版本确定自己的行为

blinding,或者Boneh论文中提到的其他抵抗时间侧通道攻擊的技术。

如果客户端已经发送了一个包含合适的 DH 公钥的证书(即 fixed_dh 客户端认证方式)那么Yc已经隐式包含了,不需要再发送这种情况下,ClientKeyExchange消息必须发送并且必须是空的。

ECDH 是目前最重要的密钥协商算法

当需要做客户端认证时客户端发送CertificateVerify消息,来证明自己确实拥有客户端證书的私钥这条消息仅仅在客户端证书有签名能力的情况下发送(就是说,除了含有固定 Diffie-Hellman 参数的证书以外的证书)CertificateVerify必须紧跟在ClientKeyExchange之后发送。

hello开始一直到CertificateVerify之前的所有消息,包括handshake消息的type和length字段这是之前所有握手结构体的拼接。要注意这要求双方在握手过程中,都得缓存所有消息或者在握手过程中,用每一种可能的hash算法计算到CeritificateVerify为止的hash值

Finished 消息是第一条用刚刚协商出来的参数保护的消息。接收方必须确认Finished消息的内容是正确的一旦某一方发送了,并且确认了对端发来的Finished消息就可以开始在连接上发送和接收应用数据了。

在下面这些场景下尤其有用:

用户量巨大,session id的方式耗费服务器内存过多 服务器希望长时间缓存session 服务器有多台不希望服务器间有共享状态 服务器内存不足 愙户端在 ClientHello中设置一个 SessionTicket 扩展来标识自己支持 SessionTicket。如果客户端本地没有存之前收到的ticket就把这个扩展设为空。

消息之前在服务器验证通过客户端的Finished消息之后发送。

客户端把收到的ticket和master secret等其它与当前session有关的参数一起缓存起来。 单客户端希望恢复会话时就把ticket包含在 ClientHello 的 SessionTicket 扩展中发给服務器。 服务器收到后解密ticket,算MAC确认ticket没有被篡改过然后从解密的内容里面,获取session

显然这种情况下,相比完整握手可以省掉1个RTT。如下圖:

如果服务器不能或者不想使用客户端发来的ticket,那服务器可以忽略ticket启动一个完整的握手流程。

如果服务器拒绝收到的ticket服务器可能仍然希望在完整的握手之后,下发新的ticket 此时流程和全新 ticket 生成下发的区别,就是ClientHello的SessionTicket不是空的

在完整握手的情况下,客户端必须在确认服務器的Finished消息正确之后才能认为NewSessionTicket 里面的ticket合法。

ticket_lifetime_hint 字段包含一个服务器的提示提示客户端本ticket应该存多长时间就失效。单位是秒网络字节序。当时间到期时客户端应该删掉ticket和关联的状态。客户端也可以提前删除服务器端也可以提前认为ticket失效。

对于客户端来说ticket就是一块二進制buffer,客户端并不管里面的内容所以ticket具体怎么加密加MAC服务器可以为所欲为,无需顾及客户端的感受

ticket的格式像这样:

其中,key_name 用来标识一組key这样服务器端就可以使用多组key。

实际在openssl 中的session用asn1格式序列化保存了下面这些字段:

ChangeCipherSpec用来通知对端,开始启用协商好的Connection State做对称加密内嫆只有1个字节。 这个协议是冗余的在TLS 1.3里面直接被删除了。

其中level是等级不同等级要求不同的处理。

其中有一种:close_notify用来通知对端,我不會再发送更多数据了这个可以让对端主动close fd,这样可以减少我方tcp timewait状态的socket 量

application data协议,就是把应用数据直接输入record层做分段,算MAC加密,传输 抓包举例如下:

8. TLS协议的安全分析

安全分析,重中之重也是大家最关心的。

安全分析的第一步是建立攻击模型TLS的攻击模式是: * 攻击者囿充足的计算资源 * 攻击者无法得到私钥,无法得到客户端和服务器内存里面的密钥等保密信息 * 攻击者可以抓包修改包,删除包重放包,篡改包

这个模型其实就是密码学里面一般假定的攻击模型。

好了在这个模型下,TLS的安全性分析如下:

1. 认证和密钥交换 的安全性

TLS有三種认证模式:双方认证服务器认证,无认证 只要包含了有服务器端认证,就可以免疫 man-in-the-middle 攻击但是完全匿名的会话是可以被 MITM 攻击的。匿洺的服务器不能认证客户端

匿名密钥交换是一种历史遗留的不安全方式。 匿名密钥交换缺失认证(Authentication)所以绝大多数场景下,我们应该禁用這种方式

当使用RSA的时候,合并了密钥交换 和 服务器端认证 RSA公钥包含在服务器证书中。要注意的是一旦服务器证书的RSA私钥泄露,之前鼡该证书保护的所有流量都会变成可以破解的即没有前向安全性(Perfect Forward Secrecy)。 需要前向安全性的TLS用户应该使用 DHE 或者 EC TLS users desiring Perfect Forward Secrecy should use DHE 类的CcipherSuite。这样如果私钥泄露,呮需要更换私钥和证书就行不会有更大的损失。

RSA密钥交换和认证的安全性基于在验证了服务器的证书之后,客户端用服务器的公钥加密一个 pre_master_secret 成功地解密 pre_master_secret 并产生正确地 Finished 消息之后,就可以确信服务器拥有证书对应的私钥

如果使用了客户端认证,通过 CertificateVerify 消息来认证客户端愙户端会签署一个之前所有握手消息的hash值,这些握手消息包括 服务器的证书ServerHello.random 。其中服务器证书确保客户端签署了和本服务器有关的绑定(即不能重放和别的服务器的握手)ServerHello.random 确保签名和当前握手流程绑定(即不能重放)。

当使用 DH 密钥交换的时候服务器:

  1. 或者发送包含固定 DH参数的证書
  2. 或者发送一组临时DH参数,并用 ECDSA/RSA/DSA 证书的私钥签署而且在签署之前,临时DH参数和 hello.random 都参与hash计算来确保攻击者不能重放老的签名值。

无论如哬客户端都可以通过验证证书,或者验证签名来确保收到的DH参数确实来自真正的服务器。

如果客户端有一个包含固定 Diffie-Hellman 参数的证书则證书包含完成密钥交换所需的参数。要注意的是这种情况下,客户端和服务器每次都会协商出相同的 DH 结果(就是 pre_master_secret) 为了尽可能减少 pre_master_secret 存在在內存里面的时间,当不再需要的时候尽快将其清除,pre_master_secret 应该尽早转换成 master_secret 的形式 为了进行密钥交换,客户端发送的 Diffie-Hellman 参数必须和服务器发送嘚兼容

如果客户端有一个标准的 DSA 或者 RSA 证书,或者 客户端没有被认证那么客户端在ClientKeyExchange中发送一组临时参数,或者可选地发送一个CertificateVerify消息来证奣自己的身份

如果相同的 DH 密钥对,被多次用于握手协商不管是由于客户端或服务器使用了固定DH密钥的证书,还是服务器在重用 DH 密钥嘟必须小心避免 small subgroup 攻击。实现都必须遵循 rfc2785 中的标准

最简单避免 small subgroup 攻击的方法是使用一种 DHE CipherSuite,并且每次都握手都生成一个新的 DH 私钥 X如果选择了┅个合适的base(例如2),g X mod p 的计算可以非常快因而性能开销会最小化。并且每次都使用一个新的DH密钥可以提供前向安全性。当使用 DHE 类的CipherSuite时实现必须每次握手都生成一个全新的DH私钥(即 X )。

由于TLS允许服务器提供任意的 DH 群客户端必须确认服务器提供的DH 群的大小适合本地策略。 客户端必须确认 DH 公共指数有足够的大小 如果DH群已知的话,客户端做简单比对就行了因此服务器可以使用一个已知的群,来方便客户端的检查

由于 TLS 历史上出现过多个版本,服务器端实现可能会兼容多个版本的协议而像 SSL 2.0 这样的版本是有严重安全问题的,因此攻击者可能会尝试诱骗客户端和服务器来使TLS连接回退到 SSL 2.0这种老版本。

3. 针对握手过程的攻击

攻击者可能会尝试影响握手过程来使双方选择不安全嘚加密算法。

对这种攻击的解决办法是如果握手消息被篡改了,那么在Finished消息里客户端和服务器都会计算 握手消息的hash,如果攻击者篡改叻握手消息那么双方得出的hash就不一样,这样Finished消息就会验证不过就会发现攻击。

只有在客户端和服务器都同意的情况下才会做session resuming。只要囿任意一方怀疑 session 泄漏或者证书过期/被吊销,就可以要求对端做完整的握手 一个session的生命周期建议定位24小时。由于如果攻击者获得了 master_secret 就可鉯在session ID过期之前伪装成被泄漏者所以要加一个生命期限制。 运行在不安全环境的应用程序不应该把session ID写入持久存储。

5. 针对应用数据保护的攻击

在CBC和stream cipher的情况下 发送出去的数据,在发送前用MAC保护来避免消息重放,避免篡改 MAC根据 MAC key,序列号消息长度,消息内容固定字符串算出。 消息类型字段(content type)是必须的来确保握手消息,ChangeCipherSpec消息应用数据消息不会被混淆。 序列号用来确保删除包或者打乱包顺序的攻击无法得逞 由于序列号是64位的,可以认为不会回绕 从一方发给对端的消息,不能被插入对端发来的字节流中这是用于两端使用不同的 MAC key。 類似地server write key 和 client write key相互独立。因此stream cipher的key只使用了一次避免了类似问题。

如果攻击者获取了加密key那么就可以解密所有的消息。 类似地泄漏MAC key,会使攻击者可以篡改消息

如前文所述,TLS 1.0是把前一条消息的最后一个block当作下一条消息的第一个IV的,这促成了2004年公开的 BEAST 攻击后来就改成这種显式IV的更安全的方式了。

7. 加密和MAC组合模式的安全性

前文介绍CBC和AEAD时已有分析此处略过。

TLS容易遭受某些 DoS 攻击例如,攻击者创建很多TCP连接就可以让服务器忙于做 RSA 解密计算。然而由于TLS运行在TCP之上,只要操作系统TCP栈的 SYN-ACK里seqnum是随机的攻击者就无法隐藏自己的ip,这样就可以和一般的TCP连接一样做DOS防御

由于TLS运行在TCP上,每个独立的连接都可能遭受一系列DOS攻击尤其是,攻击者可以伪造RST包来中断一条TCP+TLS连接。或者伪造蔀分TLS记录导致连接阻塞挂起。不过这些攻击都是任何TCP协议都有问题不是TLS特有的。

下面分析在各种攻击方法下的安全性

TLS协议要求当发現错误的时候,把TLS session变为无效

这不会影响到ticket的安全性。

攻击者或者中间人可能会窃取到ticket,并且尝试用来和server建立会话 然而,由于ticket是加密過的并且攻击者不知道密钥,窃取到的ticket无法使攻击者恢复会话 TLS服务器必须使用强加密和MAC算法,来保护ticket

一个恶意用户可能会伪造,或鍺篡改一个ticket来恢复一个会话,来延长ticket的生命周期或者假装成另一个用户。

然而由于服务器使用了强的校验保护算法,比如带密码的 HMAC-SHA1 因此无法得逞。

推荐ticket 格式中的 key_name 字段帮助服务器有效地拒绝不是自己签发的票据 因此,一个攻击者可能发送大量的ticket让服务器忙于验证ticket。 然而只要服务器使用了高效的加密和MAC算法,就不会有问题(现实中,加密和MAC算法效率都极高这根本不是问题)

加密ticket的key的管理,推薦的做法:

  • key 应该用密码学安全的随机数生成器生成按照RFC4086。
  • key 和加密算法最少应该是 128 比特安全程度的
  • key 除了加密和解密ticket以外,不应该有其他鼡途
  • 当ticket格式更换,或者算法更换时应该更换key

TLS服务器控制ticket的生命周期。服务器根据配置来决定可以接受的ticket生命周期 ticket的生命周期可能会長于24小时。TLS客户端可能会接受到一个ticket生命周期的提示当然,客户端本地的策略最终决定ticket保存多久

如果没使用推荐的ticket格式,那必须小心哋分析方案的安全性尤其是,如果保密数据比如保密密钥传输给了客户端那必须用加密方式传输,来防止泄露或篡改

ticket的加密和加MAC,僦保证了敏感信息不会泄露

由于在ticket解密之前的TLS握手,无法隐藏客户端的特征因此中间人可能根据相同的ticket被复用,发现相同的ticket属于相同嘚用户TLS对这种情况不提供保证。

几个比较重要的TLS扩展:

  1. Server Name Indication (SNI) 由于在SNI提出之前tls握手过程中没有字段标明客户端希望连接服务器端的哪个域名,这样如果一个服务器端口上有多个域名服务器就无法给出正确的证书。随着ipv4地址空间紧张这个问题越发突出。因此提出了SNI

  2. TLSEXT_ALPN 上层协議协商,就是在握手过程中标明TLS里面是什么协议,例如 http2就是 h2

X.509是PKI的一个标准其中内容包括:

  • 证书路径验证算法(CA/证书 链的格式)

X.509使用ASN.1语法做序列化/反序列化

ASN1 就是一个数据序列化/反序列化格式,跟 protobuf 差不多可以算作竞争对手。

DER 就是用 ASN1 序列化某些数据结构的格式

证书链,以┅个或多个CA证书开头的证书的列表其中:

  • 每一个证书都被下一个证书的私钥签署
  • 最后一个证书是 根证书(“root CA”),在TLS握手中不会被发送

证书里媔包含公钥和其它一些字段(比如证书用途,有效期签发者等等) x509.v3证书的字段:

2.你的root CA证书必须为apple平台的用户提供广泛的商业价值。例洳一个组织内内部使用的证书不能被接受为root证书。 3.你签的证书必须含有可以公开访问的CRL地址

Webtrust审计介绍: Webtrust是由世界两大著名注册会计师協会(美国注册会计师协会,AICPA和加拿大注册会计师协会CICA)制定的安全审计标准,主要对申请对象的系统及业务运作逻辑安全性、保密性等共计七项内容进行近乎严苛的审查和鉴证只有通过Webtrust国际安全审计认证,才有可能成为全球主流浏览器根信任的证书签发机构

的网站仩右下角,有个图标: 点开就可以看到 KPMG 对 geotrust 公司的

2011年 荷兰CA公司DigiNotar颁发假googleFacebook,微软证书被发现后发现被入侵,导致该公司破产

CA公司签署一个证書的成本是0 。 CA公司的主要成本构成:审核 验证CSR成本,支持成本法律成本(保险费用,担保费用) 要进入各个浏览器的根证书列表,CA公司烸年必须过 WebTrust 年度审计是很大的开销。 一些浏览器厂商还会对植入根证书列表的CA收费 基础设施开销,CRL 和 OCSP 服务器成本 验证CSR:就是提交证書申请后,CA要做多项验证越是高级的证书(比如EV)验证越麻烦。不固定开销有些要花费很多人力和时间来完成。 法律开销:CA公司得买保险保险费跑不了。 CA链费用:新开的CA公司要等5-10年才会被普遍信任,才能广泛进入根证书链要想加快点,就得给别的大牌CA公司掏钱買次级证书。

2.现有PKI体系暴露出的问题

11. TLS协议历史上出现过的漏洞密码学常见陷阱

漏洞分析很耗时间,这里总结一些资料有兴趣的自己看吧。

虽然TLS的设计已经尽可能的严密但是随着技术进步的滚滚车轮,历史上还是出现过很多漏洞 可以参看这个rfc,做了总结:

TLS 协议最近一些年被爆出过的设计缺陷尤其是在用的最多的 AES-CBC 和 RC4 上。

2013 年, AlFardan发表了对 RC4 的一个攻击分析展示如何恢复 RC4 传输的连接上的数据。这种恢复攻击利鼡了RC4的一些已知弱点例如RC4最初的一些字节的显著统计特征。

最近几年TLS的代码实现引起了安全研究者的关注,这导致了新漏洞不断发现 2014年,OpenSSL库爆出了好几个漏洞例如 HeartBleed,还有 CVE- ( Microsoft SChannel 的实现漏洞)等.

可怕的向后兼容要求导致迟迟不能废弃一些老算法。

先举几个加密协议被破解的唎子给大家助兴:

网上有一些资料,有兴趣自己看吧:

tls 1.3的草案在 相比tls 1.2, 1.3改动巨大这些改动对加密通信协议的一般设计也有重要启发。

TLS 1.3 的改動 值得关注的重大改进有:

  • 改为使用HKDF做密钥拓展
  • 彻底禁止aead以外的其他算法
  • 去除了AEAD的AD中的长度字段
  • 去除静态RSA和DH密钥协商

移动互联网兴起之后rtt延迟变得更重要,可以看到tls 1.3 的各项改进,主要就是针对移动互联网场景的

1. record层的密码学保护的改动

由于只保留了aead,所以不需要MAC key了

aead的具体参数用法也有调整,前文有

要注意的是,此 PSK 和 tls 1.2中一个很生僻的psk(见 )并不是一回事

DH还是ECDH还是RSA,ECDHE用什么曲线DH用什么群生成元,用什么模数等等),这些算法和参数都依赖第一个rtt去协商出来 TLS1.3大刀阔斧地砍掉了各种自定义DH群,砍掉了ECDH的自定义曲线砍掉了RSA协商,密钥协商嘚算法只剩下不多几个而且其实大家实际应用中基本都用 ECDH P-256,也没啥人用别的所以干脆让客户端缓存服务器上一次用的是啥协商算法,紦 KeyExchange直接和入第一个rtt客户端在第一个rtt里直接就用缓存的这个算法发KeyExchange的公钥,如果服务器发现客户端发上来的算法不对那么再告诉正确的,让客户端重试好了 这样,就引入了 HelloRetryRequest 这个消息

这样,基本没有副作用就可以降到 1-RTT。 这是TLS 1.3 的完整握手

显然,如果一个协议只有一种密钥协商算法比如定死为 ECDH P-256,那一定可以做到 1-RTT

0-RTT应该是受Google的QUIC协议的启发 如果服务器把自己的 ECDH 公钥长期缓存在客户端,那么客户端就可以用緩存里的ECDHE公钥构造一个电子信封,在第一个RTT里直接就发送应用层数据了。 这个长期缓存在客户端的ECDH公钥称为 半静态 ECDH 公钥( semi-static (EC)DH share ) ECDH公钥通過 ServerConfiguration

这个0-rtt优化是有副作用的:

  1. 0-RTT发送的应用数据没有前向安全性。
  2. 跨连接可以重放0-RTT里的应用数据(任何服务器端无共享状态的协议都无法做箌跨连接防重放)
  3. 如果服务器端 半静态 ECDH公钥对应的私钥泄露了,攻击者就可以伪装成客户端随意篡改数据了

PSK CipherSuite可以 把PSK和ECDHE结合起来用,这样昰有前向安全性的 也可以仅仅使用PSK,这样就没有前向安全性

TLS 1.3 中,综合考虑的 session ticket的各种情况后提出了 ES,SS 两个概念统一处理密钥协商的各种情况。 在各种handshake模式下ES和SS的取值来源不同。

Ephemeral Secret (ES) : 每个连接新鲜的 ECDHE 协商得出的值凡是从 ES 得出的值,都是前向安全的(当然在 PSK only模式下,不昰前向安全的)

  1. 纯 PSK,这种场景完全没有前向安全性应该避免。




三. TLS协议的代码实现

openssl是其中代码最糟糕的(没有之一) openssl提供了的api都太过於底层,api设计的也很费解而且严重匮乏文档。 请参考

不幸的是OpenSSL是用的最广泛的,是事实上的标准

四. TLS协议的部署与优化

这个方面网上嘚文章还是不少的,本文就简略一点

全站https时代正在到来!, 移动互联网对人们生活的介入越来越深人用户越来越多的隐私数据和支付数據通过网络传输,人们的隐私意识安全意识不断提高;运营商流量劫持强行插入广告越来越引起反感。因此各互联网大厂都开始切换箌https。

例如2015年3月百度全站切换到https,百度运维部的介绍文章:

不久后淘宝切了全站https,

国外:由Snowden爆料美国人发现NSA在大范围深度地监听互联網; 还有openssl连续被爆多个严重安全漏洞。之后近2年各种加密通信协议,软件项目开始热门,各大厂商开始关注密码协议做数据加密,信息安全(openssl资助,pfs被重视)

可以参考byron之前给出的一个介绍nginx配置的文章 ,本人提供售后咨询服务哈哈。

全站切https值得关注的一个点是cdn切https,如果cdn资源不使用cdn提供商的域名的话之前会有私钥必须得交给cdn提供商的安全风险,但是幸运的是cloudflare提出了keyless ssl方案解决了这个问题 ,cdn切https应该可以借鉴

有时候我们会用wireshark之类的工具抓包,来调试http协议但是切换到https后,都变成二进制密文了直接抓包是行不通了,那怎么调试协议呢 囿个简单的解决办法:

时间有限,下面有些协议就没有做详细的分析了读者自己去看吧。

QUIC值得借鉴的地方有:crypto算法选择0-RTT的实现方法,證书压缩省流量

QUIC的crypto算法选择: 密钥交换算法只有2种:

对称加密只使用AEAD并且只有2种:

handshake的结果是为了协商出来下面这些参数:

先这样吧,后續再分析

Apple 的 iimessagee系统的密码学安全机制设计,端到端加密前向安全(PFS),签名使用ECDSA P-256非对称加密使用RSA 1280 bit,苹果自己维护一个 用户名—》公钥 的目錄服务

iimessagee在注册时,给每个用户生成一对 RSA-1280 密钥用作非对称加密一对 NIST P-256 ECDSA 密钥用作签名,2个私钥本地保存公钥上传给Apple的目录服务器(IDS)。

当要发送消息的时候根据接收方的用户名,从IDS里面找到RSA公钥 和 APNS 地址然后随机生成 128 比特密钥,用 AES-CTR-128 加密要发送的消息用接收方的 RSA 1280 公钥,使用 OAEP 填充加密 128比特aes密钥然后拼接 aes密文和rsa密文,对结果使用发送方的 ECDSA 私钥用sha1算一次数字签名。 然后把aes密文rsa密文,数字签名拼接起来发给 APNS 投遞给接收方。

如果要发送大文件就生成一个key,用 aes-ctr-256 加密文件并计算一个sha1,然后把key和sha1 放入消息里面发送

Apple的HomeKit,是 WWDC2014 上提出的 iot 智能家居开发平囼 (iot啊目前最火的概念啊,各种高大上啊) 可以看到 HomeKit 作为一个全新的协议, 抛弃了历史遗留算法直接采用了目前最先进的算法

随后使用Curve25519做密钥协商,生成共享key

这篇文章介绍了NaCL和openssl相比的各方面改进

一款实用NaCL的端到端加密im

  • 电子信封加密,KMS内置了电子信封

发给对方,这樣只有公钥对应私钥的拥有者才能打开信封。典型应用比如 OpenPGP

其中的 one-pass ECDH,大概意思是: 发起方有一对长期使用的签名密钥对发起方生成┅对临时的 ECDH 密钥,用自己的长期签名密钥签署 临时ECDH公钥对端有一对长期 ECDH 密钥,收到发起方发来的 ECDH 公钥后验证签名,并且用自己的长期ECDH私钥和收到的公钥协商出共享密钥 整个过程中,只是用了一对临时ECDH密钥2对长期密钥。

ECDHE就是比较典型的ECDHE了和TLS用法一样:双方都持有一對长期使用的签名密钥对,并拥有对方的签名公钥然后分别生成一对临时ECDH密钥,用自己的签名私钥签署ECDH公钥把得出的签名和ECDH公钥发给對方, 双方收到对方的ECDH公钥后验证签名,通过后用对方的ECDH公钥和自己的ECDH私钥协商出共享密钥DONE。

白皮书中还举了几个例子

六. TLS协议给我們的启发 — 现代加密通信协议设计

在看了这么多的分析和案例之后,我们已经可以归纳出加密通信协议设计的普遍问题和常见设计决策,

  1. 四类基础算法 加密/MAC/签名/密钥交换 如何选择 对称加密目前毫无疑问应该直接用aead,最佳选择就是 aes-128-gcm/aes-256-gcm/chacha20-poly1305了 数字签名/验证方案如果是移动互联网,应该考虑直接放弃 RSA考虑 P-256 的 ECDSA 公钥证书,或者更进一步的 ed25519 公钥证书 密钥交换算法,目前最佳选择就是

  2. 对称加密算法+认证算法如何选择?或者直接用aead

  3. 考虑将来的算法调整,要加版本号机制吗 建议是加上,起码在密钥协商的步骤要加上版本号。便于将来更新算法

  4. RSA用莋密钥交换是一个好的选择吗?考虑PFS 建议直接放弃RSARSA服务器端性能比ECDSA更差,签名更大费流量而且没有前向安全性,给私钥保管带来更大風险

  5. 自建PKI,是个好的选择吗crl如何解决? 自建PKI可以做到更安全比如简单的客户端内置数字签名公钥。可是当需要紧急吊销一个证书的時候只能通过紧急发布新版客户端来解决。

  6. 重放攻击如何解决某种seq?或者nonce如何生成

  7. 握手过程被中间人篡改的问题怎么解决?

  8. 延迟:密钥协商需要几个rtt最少多少?加上cache后和tcp对比如何

  9. TLS的性能(主要指服务器cpu消耗)还有空间可以压榨吗?我能设计一个性能更牛逼的吗

七. 附錄:密码学基础概念

本文已经很长了,基础概念的内容更多再展开介绍就太长了,下面就列一下点贴一下参考资料,就先这样,以后再說吧

当然,最好的资料是下面列的书

《AES后分组密码的研究现状 及发展趋势》

aead的介绍(作者是大神)

[RC4加密已不再安全,破解效率极高(含视频)]

RSA入门必读(斯坦福普渡的课件):

在openssl的evp接口中有直接支持:

三大公钥体制:RSA,DSAECDSA RSA目前是主流,占据绝大多数市场份额 DSA已经被废棄 ECDSA是未来的趋势例如bitcoin就用ECDSA

}

我尝试使用TLS发送电子邮件端口號为587,服务器名称为但始终出现错误“错误'8004020e'”。我将SSL设置为false因为端口587身份验证是TLS。我的代码有什么不对吗

}

我要回帖

更多关于 message 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信