问题:
SYN、ACK、FIN具体含义是什么?
TCP建立连接超时的表现?
为什么需要证书来下发服务端公钥?
客户端是如何验证证书合法性的?
对称秘钥是如何协商出来的?
为什么不直接让客户端自己生成一个秘钥发送给服务端使用?
TLS如何避免重放攻击?
TCP数据段分为首部+数据两部分。
首部又分为固定首部和可选项首部。
通过对TCP数据包格式的分析,就是了解TCP协议定义的过程。
简单一句话就是接收方可以动态控制发送方下次发送的TCP包数据段的大小。
当接收方处理数据较慢时,就可以通过WIN字段,在ACK包中告知发送方:“以后的数据段少发一些,我处理不过来了。”
在极端情况下,接收方连1字节的数据也不能处理了,那么WIN字段就设置为0,发送方就会停止发送后续的TCP包。
那么,当接收方缓过气来,可以处理更多数据时,发送方是怎么知道的呢?答案是Zero Window Probe(零窗口探针)技术。
发送方会在一定时间间隔内重复发送ZWP包,这时接收方就有机会告知发送方最新的窗口大小。
又有极端情况,接收方一直返回WIN为0,那么发送方在发送一定次数的ZWP后,就会发送RST包来断开连接(不同的系统有不同的实现)。
另外一种极端情况,接收方返回的WIN值特别小,相对于TCP的首部来说,发送较少的数据时一种浪费。这个时候接收方就会使用David D Clark’s 方案。接收方直接返回WIN为0,知道接收方有足够的能力处理新数据时再把WIN打开。
如果是由于发送方发送的数据特别少引起的,那么发送方就会使用Nagle’s algorithm。将多个小的数据包缓存起来,直到满足发送条件。
当两个支持ECN的TCP端进行TCP连接时,对于支持ECN的TCP端来说,SYN包的ECE和CWR标志都被设置了。SYN-ACK只设置ECE标志。
一个支持ECN的TCP主机在支持ECN的TCP连接上发送设置了IP头部为10或者01的TCP包。支持ECN的路由器在经历拥塞时设置IP头部的ECN域为11。当一个TCP接收端发送针对收到的一个设置ECN位为11的TCP包的响应时,它设置TCP包头中的ECE,并且在接下来的ACK中也做同样设置。
当发送主机接收到设置了ECE标志的ACK时,它就像感知到包丢失一样,开始减少发送窗口,运行慢启动过程和拥塞避免算法。在下一个数据包中,发送者设置CWR标志。在接收到新的设置CWR标志的包时,接受者停止在接下来的ACK中设置ECE标志。
建立连接时:
如果发送方在发送一个SYN包后,在超时时间内没有收到确认包,则发送方会重新发送,称为超时重发。
默认Linux重试次数为5次,重试时间间隔由1s开始每次翻倍,即1s,2s,4s,8s,16s。如果经过1+2+4+8+16+32=63s后,仍没有收到确认包,则发送方认为接收方已掉线,会主动断开当前连接。
数据传输时:
为了网络整体的稳定,需要动态的根据往返时间设置数据包的超时时间。这里就不展开说具体算法过程了。
RTO(Retransmission Timeout)重传超时时间
RTT(Round-Trip Time)往返时间
慢启动
拥塞避免
快速重传
快速恢复
这是简单的三次握手流程示意图,三次握手意思是需要在发送方和接收方之间传递三个数据包。通过设置不同的标识位,来告知对方当前数据包的意图。
第一次:C发送一个数据包P1给S,并将标识位的SYN置为1,表明“我要和你建立连接”。
第二次:S如果可以接受C的请求,会给C回发一个数据包P2,并将标识位SYN置为1,表明“我同意和你建立连接”。同时将ACK位置为1,表明“确认号ack”字段有效,其值为P1数据包序列号+1。
第三次:C接到P2后,会再次向S发送数据包P3,将ACK为置为1,其值为P2数据包的序列号+1,表明“我知道了你同意了”。
至此,连接就被建立完成了,双方就可以任意发送数据了。
但是,在三次握手过程中,除了要协商连接的建立,还有其他通讯参数的设置。下面以一个真实请求在三次握手过程中发生的数据交换作说明:
这是TCP连接断开时四次挥手的示意图。划重点:
下面是三次握手实现的连接断开的报文传输细节:
第一次:
第二次:
第三次:
Https 超文本传输安全协议(Hypertext Transfer Protocol Secure),1994年由网景公司提出,Https经由Http进行通信,但利用SSL/TLS来加密数据,即在Http协议与TCP协议之间添加SSL/TLS层。
安全防护:
安全前提:
系统或浏览器正确的实现了Https并安装了正确的证书颁发机构
对称加密
算法公开(AES)
一个秘钥,秘钥不公开
加解密速度快
非对称加密
算法公开(RSA)
两个秘钥,公钥公开,私钥不公开
公钥加密的数据,私钥可以解密。私钥加密的数据,公钥可以解密
加解密速度慢
非对称加密算法除了可以直接将隐私数据加密外,还可以实现对非隐私数据的防篡改校验功能,也就是数字签名。
Hash/散列/摘要算法
以任意长度的数据为输入,输出固定长度的数字“指纹”。
MAC,消息认证码,是带秘钥的Hash算法,即在对数据计算散列值时将秘钥和数据同时作为输入,并采用二次散列迭代的方式。
在没有SSL/TLS的世界里,Alice和Bob的通讯是这样的。
Alice(i love you)–明文(i love you)–>Bob(i love you)
一些坏人可以在明文的传输过程中,对数据进行更改。
Alice(i love you)–>坏人(i hate you)–>Bob(i hate you)
Bob(i still love you )–>坏人(i hate you too)–>Alice(i hate you too)
当两人见面后,发现对方误会了自己,就想到这个世界还是有坏人,然后双方约定将通信内容加密后再发送给对方。约定的加密算法为AES,秘钥为“Alice/Bob”。
加密后就会出现两种情况:
Alice(i love you)–加密(123abc)–>坏人(123abc)–>Bob(123abc)–>解密(i love you)
Alice(i love you)–加密(123abc)–>坏人(!!!)–>Bob(!!!)–>解密(???)
单纯使用对称加密会有两个问题:
所以,我们要解决这些问题,需要做到:
Alice和Bob非常聪明,他们想到了非对称加密算法RSA,Bob拿着私钥,然后把公钥给Alice,当Alice想要和Bob通信时,利用手中的公钥将对称加密算法的秘钥加密后发送给Bob,Bob拿着自己的私钥将对称加密的秘钥解密后,双方就可以继续用对称加密算法将数据加密后通信了。当然,其他人也可以拿到Bob的公钥,与Bob通信。
Alice(我想和你说话,给我公钥)------->Bob(我想和你说话,给我公钥)
Bob(给你公钥(Pubkey)) --------->Alice(拿到公钥PubKey)
Alice(秘钥:123)–>公钥PubKey加密(321)–>Bob(321)–>私钥解密(123)
Alice(i love you)–>秘钥123加密(123abc+摘要签名)---->Bob(123abc+摘要签名)–>正确性验证–>秘钥123解密(i love you)
上述第二个过程是无懈可击的,但是第一个过程中,如果存在坏人的话,就变成下面的情形
Bob(给你公钥(PubKey))---->坏人(PubKey换成自己的PubKey1)--------->Alice(拿到公钥PubKey1)
Alice(秘钥:123)–>公钥PubKey1加密(abc)–>坏人(abc),自己的私钥解密123,再用PubKey加密321–>Bob(321)–>私钥解密(123)
完犊子了,对称加密的秘钥被坏人窃取了,通信数据又相当于裸奔了。其中核心问题就是:
那如果把公钥事先告知Alice可以么?也就是内置在系统中。理论上是没问题的,但当Alice需要和更多的人通信时,她需要记住很多很多的公钥,这是不可行的。
所以Alice和Bob需要商量出一套方案,能保证公钥在网络上安全的传输,如果受到篡改,接收方能感知到。这时,他们想到数字签名的方式。
Bob(给你公钥+签名(摘要的私钥加密))------>Alice(公钥+签名,对签名解密,并再次计算摘要,然后比对)
上述方式可以做到防篡改么?可以,但是做不到防替换。中间人可以把签名连同公钥全部换成自己的。
接下来就到了数字签名证书出场的时刻了。
Bob找到了一个非常权威的机构,“人民政府”。
Bob向“人民政府”证明“我是真Bob”,并提供自己的公钥。
“人民政府”根据Bob的信息和公钥颁发给Bob一个证书文件.cer,里面写了颁发机构的信息、Bob的信息和公钥、摘要算法以及最重要的颁发机构的签名。
公钥下发过程变成了数字证书下发过程。
同时,Alice也是非常相信“人民政府”的,只要是“人民政府”签名的证书,Alice就认为证书上面的公钥就是Bob的。
但是,Alice并不能无脑的相信,她需要判断了两点:
那么具体的判断流程是怎样的呢?
问题:Bob的公钥不是由”人民政府“签发的,而是由其下属的”地方政府“签发的。而Alice只有”人民政府“的自签名政府,如何判断证书合法性呢?
答:在证书下发过程中,实际是下发的一个证书链,类似于”Bob的证书“–>“地方政府的证书”–>”人民政府的证书“,Alice可以逐级查找,直到根证书。
Https证书格式遵循的是X.509标准。X.509是ITU-T标准化部门基于他们之前的ASN.1定义的一套证书标准。
在浏览器中随便下载一个证书,通过以下命令获取到其文本格式。
openssl x509 -in *.xxx.com.cer -inform der -text -noout >> cer.txt
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
09:3e:8a:aa:5a:f8:14:de:9d:d9:4d:28:2e:97:a8:16
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=GeoTrust RSA CA 2018 //颁发者信息
Validity
Not Before: Aug 22 00:00:00 2018 GMT
Not After : Nov 12 12:00:00 2020 GMT
Subject: C=CN, ST=\xE5\x8C\x97\xE4\xBA\xAC, L=\xE5\x8C\x97\xE4\xBA\xAC,
O=Beijing Qfpay Technology Co., ltd., CN=*.qfpay.com //公钥主题信息,公钥所有者的信息
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:e6:c0:8b:f0:12:1e:f0:92:9c:17:7d:7e:d5:69:
47:fc:dd:0b:51:5a:0e:79:df:b1:0e:b4:d6:7d:d0:
5a:bc:f9:93:f6:3c:e3:40:a8:66:9f:d0:ae:3c:e1:
f8:9a:55:a2:84:0e:9c:1d:65:f9:d2:63:51:48:b2:
88:a5:09:a6:be:92:80:f8:3b:eb:b8:78:1b:35:58:
47:ac:eb:47:cd:3d:7f:36:74:30:7a:01:86:48:96:
b3:7b:14:82:b6:63:0b:b6:43:20:98:3f:07:9d:1a:
56:76:25:cf:cd:d5:49:fd:6e:dc:86:f0:7f:15:f3:
7d:58:98:75:a5:7f:f9:ab:b2:c4:ec:fc:30:bd:75:
27:b3:0e:72:3d:44:d1:04:42:52:65:9b:3e:53:9b:
a5:c2:eb:ac:c5:01:b6:1d:0d:2f:75:79:7d:98:d4:
2b:b6:c0:28:ea:c7:dc:14:04:b6:4d:a3:dc:01:2c:
f0:14:13:b9:d2:29:31:00:37:af:17:d6:82:a6:f9:
57:9e:4c:2f:27:27:08:50:16:e3:ca:fa:58:32:c7:
f5:04:43:b4:5d:0e:97:81:e9:c3:01:36:f9:b7:c8:
14:ec:98:27:e9:31:86:ab:f5:c4:ff:50:aa:c4:df:
cc:6e:7d:1c:5a:fa:b8:47:c9:fa:78:b4:de:6d:15:
8d:27
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier: //授权秘钥标识符
keyid:90:58:FF:B0:9C:75:A8:51:54:77:B1:ED:F2:A3:43:16:38:9E:6C:C5
X509v3 Subject Key Identifier: //主题秘钥标识符
EC:99:74:D5:FF:C6:1B:4F:FB:39:88:8C:E2:C1:7B:8D:90:59:AB:1F
X509v3 Subject Alternative Name:
DNS:*.xxx.com, DNS:xxx.com
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 CRL Distribution Points:
Full Name:
URI:http://cdp1.digicert.com/GeoTrustRSACA2018.crl
X509v3 Certificate Policies:
Policy: 2.16.840.1.114412.1.1
CPS: https://www.digicert.com/CPS
Policy: 2.23.140.1.2.2
Authority Information Access:
OCSP - URI:http://ocsp1.digicert.com
CA Issuers - URI:http://cacerts.geotrust.com/GeoTrustRSACA2018.crt
Signature Algorithm: sha256WithRSAEncryption
07:8d:b9:34:62:e8:4b:83:00:af:ab:38:d4:b1:24:12:a4:37:
5e:8f:e7:ff:d9:96:48:ae:72:6f:d2:0b:41:6a:55:92:2a:06:
39:86:a9:78:18:cd:0d:5f:33:fa:22:81:50:b7:67:2f:dc:a1:
b4:ee:0f:6c:f8:73:87:0d:65:e7:19:9a:55:07:49:a4:2d:09:
11:8b:5f:1c:c1:46:ce:94:22:fa:b0:1b:88:f0:f0:6f:63:11:
e4:56:f4:51:3c:12:90:db:44:63:8b:fd:17:d2:e5:7a:66:5e:
f5:d8:90:70:5c:d6:c2:74:d9:74:b3:75:ce:83:e3:db:57:bb:
b6:3a:81:e7:ca:7a:48:82:6c:0b:01:a8:ed:a2:8e:d0:b0:ed:
25:15:a2:2a:7f:6f:a5:6d:da:5a:ac:91:f4:dc:23:d8:9f:9d:
d3:0a:f4:c7:8f:b0:c2:18:54:97:f5:00:30:36:65:e1:aa:25:
9c:f1:b8:77:d6:7d:33:79:39:0e:41:86:1d:79:47:0e:34:cc:
fd:e8:63:83:9d:f5:86:d6:e2:0c:fa:58:d5:d2:81:c1:92:da:
e7:41:45:bc:a0:91:d5:40:6e:c8:22:76:69:e4:67:9a:d4:03:
ca:8d:28:d5:ca:98:09:e0:d6:dd:ae:c2:6f:08:82:1b:89:79:
14:d6:ca:b7
上图中的Modulus和exponent字段就是服务端的公钥,而且是明文的。
SSL协议属于分层协议,一个SSL报文可以包含多个记录层,每个记录层分为两部分:头部 + 协议数据。
握手协议是最主要的协议,负责协商会话的安全属性。按照不同的功能区分为不同握手类型。
enum {
hello_request(0), client_hello(1), server_hello(2),
certificate(11), server_key_exchange (12),
certificate_request(13), server_hello_done(14),
certificate_verify(15), client_key_exchange(16),
finished(20), (255)
} HandshakeType;
struct {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;
每种握手协议类型,也都包含一些通用字段,如
HandshakeType
Version
Length
下面具体说明每种握手类型的作用:
Hello Request
”你好,请求“,该类型的握手协议作为一个简单的通知,由服务端发送,告知客户端重新开始协商过程。作为响应,客户端应该在方便时发送ClientHello消息。
如果客户端不希望重新协商会话,可以选择忽略此消息,或者返回一个no_renegotitation消息。
如果服务端发送HelloRequest后没有收到ClientHello作为响应,它可能会通过致命警报关闭连接。
Client Hello
”你好,我是客户端“,该类型的消息用于首次连接服务器时,或响应服务端发送的HelloRequest,或主动发送,以便重新协商连接中的安全参数。
Random 由安全随机数生成器生成的28字节随机数,用于对称秘钥计算
Session ID 会话标识,可变长,用于会话恢复时重用其安全参数
Cipher Suites 加密算法套件,客户端提供支持的密码算法套件列表,按照客户端的偏好顺序排列,一般由四个算法组成,格式为秘钥交换算法+身份认证算法+批量加密算法+摘要算法
例:Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
ECDHE 秘钥交换算法,由于对称秘钥并不是客户端直接生成发送给服务端的,而是双方又各自生成了一对"公私钥",然后互相交换“公钥”,这里生成“公私钥”的算法就是ECDHE
ECDSA 身份认证算法,用于加密握手消息,确认未被篡改
AES_256_GCM 批量加密算法,用于应用数据加密,它还包括秘钥大小及显示和隐式初始化向量的长度
SHA384 散列算法,用于计算主秘钥和创建会话消息摘要
Compression Methods 压缩算法列表
这四个属于固定字段,如果还需要协商其他内容,可以通过下面的扩展字段。
Server Hello
”你好,我是服务端“,该类型的消息用于响应ClientHello消息。如果服务器找到一组可以接受的算法套件时,则回复此消息,否则响应握手失败的警报。
Random 由服务端独立生成的随机数,28字节,用于对称秘钥的计算。
Session ID 当前的会话标识,如果ClientHello的参数SessionID不为空,则服务器将在其会话告诉缓存中查找匹配项,找到并且愿意是定指定的会话状态建立连接,则服务器使用与客户端提供的SessionID作为响应,然后恢复会话并进入Finished消息流程。否则将重新生成该值以标识新会话。如果SessionID为空表明服务端不缓存此会话,无法恢复。
Cipher Suite 服务端从ClientHello.cipher_suites列表中选择的单个密码套件。如果是恢复会话,此字段为正在恢复的会话状态的值。
例:Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
ECDHE 椭圆曲线离散对数算法
RSA 非对称加密算法
AES_256_GCM 高级加密算法,对称加密,32字节的秘钥 GCM为加密模式
SHA384 安全散列算法
Compress Method 服务端从ClientHello.CompressionMethods列表中选择的压缩算法
Server Hello消息也可以包含扩展,但是这些扩展必须在ClientHello中有相同的扩展类型,服务端不能擅自添加。如果客户端在ServerHello中收到它未在ClientHello请求中关联的扩展类型,客户端必须使用unsupported_extension致命警告来终止握手。
Certificate
”服务器证书“,只要商定的秘钥交换方法使用证书进行身份验证,则服务端必须发送该证书消息。该消息紧跟在Server Hello消息后,用于向客户端下发证书。
什么时候服务端不需要下发证书呢?就是在秘钥协商过程中使用DH_anon(Diffie-Hellman ANON)匿名Diffie-Hellman算法,即不配合其他身份验证算法,而单独只读使用DH算法,这样无法保证数据被”篡改“。
证书限制
Server Key Exchange
”服务器秘钥交换“,用于发送服务端的预主秘钥。此消息在Certificates消息后立即发送。
当且仅当与秘钥交换算法相关联的证书类型不能为客户端提供足够的信息来交换预主秘钥时,才会发送服务器秘钥交换信息。
该消息主要描述了使用协商的秘钥交换算法后,服务端计算出来的公开秘钥。
本示例中使用的是ECDHE算法。其原理简单理解如下所示:
服务端为了证明此消息是真实可靠的,需要用自己证书私钥和ClientHello提供的扩展signature_algorithms里选择合适摘要和签名算法对参数进行签名。
Certificate Request 可选
”要求证书“,如果服务端需要客户端提供证书以验证客户端身份,则使用此消息。消息格式与服务端下发给客户端的证书消息格式相同。
Server Hello Done
“服务器Hello完成”,表示服务端已经把支持秘钥交换的消息发送完成。发送此消息后,服务端等待客户端响应。客户端应该检查服务器是否提供了有效的证书(如果需要),并检查服务端Hello消息参数是否可接受。
Client Certificate
“客户端证书”,用于将客户端证书发送给服务端。
这是客户端在收到ServerHelloDone消息后可以发送的第一条消息。仅当服务器请求证书时才会发送此消息。如果没有合适的证书,客户端必须发送不包含证书的证书消息。也就是说,certificate_list结构的长度为零。如果客户端没有发送任何证书,服务器可以自行决定是否在没有客户端身份验证的情况下继续握手,或者使用致命的handshake_failure警报进行响应。此外,如果证书链的某些方面是不可接受的(例如,它没有由已知的,可信的CA签名),服务器可以自行决定是继续握手(考虑客户端未经身份验证)还是发送致命警报。
Client Key Exchange
“客户端秘钥交换”,用于发送客户端计算的预主秘钥。该消息是在客户端收到ServerHelloDone消息后发送的第一条消息。或者是跟在Client Certificate消息后发送。
这个消息内容比较简单,就是用服务端证书公钥加密的预主秘钥。
Certificate Verify
“证书验证”,此消息用于客户端证书的显示验证。发送这个消息的前提有两个:
此时,客户端需要证明自己拥有该证书,需要用自己的私钥签名一段数据发送给服务端做验证。
签名的数据为:此消息之前的所有接收和发送过的握手消息。
Finished
“协商完成”,此消息是第一个使用上述握手过程中协商的算法和秘钥来加密的消息。接收方必须验证内容是否正确。
该消息在Change Cipher Spec消息之后被发送,以验证密钥交换和身份验证过程是否成功。
发送的数据为:PRF(master_secret, finished_label, Hash(handshake_messages))
finished_label为“client finished”/“server finished”
handshake_messages包含除去Hello Request消息之外的之前所有发送和接收的握手消息。
更改密码规范协议,该协议在TSL1.3被移除。
Change Cipher Spec
“变更秘钥规范”,用于通知接收方后续的通讯数据将在新协商的秘钥规范保护下交换。
此消息在Finished消息之前被发送。
客户端在交换预主秘钥后,就立即发送了“Change Cipher Spec”消息。
之后,服务端也发送一个“Change Cipher Spec”消息。
应用数据协议
如果握手过程结束一切正常,Alice和Bob就用这条加密信道放心的发送数据了,这些数据都是被加密过的。
http-over-tls
警报消息传达消息的严重性(警告或致命)以及警报的描述。 具有致命级别的警报消息导致连接立即终止。在这种情况下,对应于会话的其他连接可以继续,但是会话标识符必须无效,防止失败的会话被用于建立新连接。与其他消息一样,警报消息按当前连接状态的指定进行加密和压缩。
警报协议包含很多异常场景,如证书过期、没有符合密码套件、未知的ca等,这里就不一一列出了。
Client Server
ClientHello ----------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<----------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished ----------->
[ChangeCipherSpec]
<----------- Finished
Application Data <-----------> ApplicationData
中括号号标识的协议不属于握手协议
星号标识的不是必须的握手流程
至此TLS握手过程说完了,但貌似没有说到**对称秘钥(会话秘钥)**是如何被计算出来的?
我们知道,通过前面的握手流程,客户端和服务端都知道了以下信息:
通过这三个参数,客户端和服务端就可以分别计算出主秘钥:
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
master_secret 长度为48个字节。
PRF (pseudo random function)伪随机函数,也就是选择的加密套件中的第四个算法SHA384。计算完主秘钥,就应当把预主秘钥从内存中删除。
PRF算法需要一个“秘钥”、一个“种子”和一个“文本标识”作为输入,然后产生一个不定长的输出。
其中的“秘钥”就是预主秘钥,“种子”就是两个随机数的和,“文本标识”就是 master secret。
因为客户端和服务端的输入参数都是一样的,所以计算出来的主秘钥也是一致的。
主秘钥是用来做对称加密的秘钥的么?
不是,需要由主秘钥再次计算,主秘钥在创建会话秘钥时作为一个熵来源。最终计算出来的结果如下:
客户端写入MAC密钥
服务器写入MAC密钥
客户端写入加密密钥
服务器写入加密密钥
客户端写入IV
服务端写入IV
实际上是生成了两个会话秘钥:
当客户端向服务端发送消息时,使用“客户端写入MAC秘钥”生成消息摘要附加在消息结尾,使用“客户端写入秘钥”加密;服务端接收到消息后,使用“客户端写入秘钥”解密,使用“客户端写入MAC秘钥”做消息摘要并对比两次摘要结果。
反过来则是,服务端向客户端发送消息时,使用“服务端写入MAC秘钥”生成消息摘要附加在消息结尾,使用“服务端写入秘钥”加密;客户端接收到消息后,使用“服务端写入秘钥”解密,使用“服务端写入MAC秘钥”做消息摘要并对比两次摘要结果。
如果需要在TLS层压缩数据,则在加密之前先压缩。
一些AEAD(认证加密)秘钥套件可能额外需要一个客户端写入向量和服务端写入向量
那么这些值是怎么计算出来的呢?
key_block = PRF(master_secret,“key expansion”,server_random + client_random);
= P_hash(master_secret, “key expansion"+server_random + client_random)
P_hash定义为:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
A(0) = seed;
A(i) = HMAC_hash(secret, A(i-1));
...
HMAC: 基于消息认证码的哈希算法,也就是对消息进行哈希运算时添加一个秘钥。
以TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384为例,AES256会话加密算法需要32字节的会话秘钥,而我们需要2个会话秘钥(2 * 32)和2个MAC秘钥(2 * 48),就是2 * 32 + 2 * 48= 160字节。而摘要算法SHA384每次的运算输出为48字节,为了能满足160个字节,至少需要计算4次,拼接后得到172字节的输出。
然后按照上述顺序:
剩下的12字节则舍弃。
总结:
握手过程中,客户端和服务端交换了哪些东西?
握手过程中,哪些消息是经过加密的?加密的目的是什么?
如果服务端的私钥泄漏,坏人能否解密会话数据?
RSA 可以
DH 不可以
PSK 不可以
参考:TLS握手协议分析与理解——某HTTPS请求流量包分析
解密应用数据方式:
启动Chrome并制定SSL的日志文件
sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --ssl-key-log-file=/Users/joye/Downloads/sslkeylog.log
在WireShark中Preferences->Protocols->SSL-(Pre)-Master-Secret log filename设置日志文件