TLS 1.2 协议(一)

之前学习了很多与密码学相关的理论,但其实一直忽视了密码学在实际生活,尤其是网络世界中的应用,未知攻,焉知防。但是连其本身的体制流程都不了解,又如何攻呢?于是在学习密码学这个方向上的漏洞挖掘之前,还想了解一下当前密码学的实际应用场景。那么自然是先从我们的网络通讯协议TLS入手。参考网站The Illustrated TLS 1.2 Connection,其本身已经是对 TLS 1.2 细致入微的解读了,因此笔者也只是稍添一点自己的解读,方便读者也方便自己理解其流程的背后逻辑。。

TLS 1.2 完整流程

TLS 1.2 完整流程

上述是从未建立过 TLS 连接的客户端与服务端完整的通讯流程。

  1. 首先用户发出握手消息,请求建立连接
  2. 服务端收到消息后,首先会发送自己的证书给用户,证明自己是用户想要连接的对象。然后会在本地生成一个交换密钥,用于生成通讯密钥(对于熟悉DH密钥交换协议的读者应该不难理解),并发送给用户。
  3. 用户收到服务端的证书并验证后,本地生成一个交换密钥,随后利用服务端的交换密钥计算生成通讯密钥,并用该通讯密钥加密一段验证消息,这段验证消息包含在此之前握手阶段所发送所有握手消息的哈希值。最后将用户端的交换密钥和加密后的验证消息发送给服务端。用户端握手阶段完毕,准备进行加密通讯。
  4. 服务端收到用户的交换密钥后也计算生成通讯密钥并解密用户端发来的密文,随后也会用这个通讯密钥加密一段验证消息发送给用户。这段验证消息同样是在此之前握手阶段所发送所有握手消息的哈希值。服务端握手阶段完毕,准备进行加密通讯。
  5. 用户收到服务端发来的验证密文,利用通讯密钥解密后,如果解密明文通过验证,那么加密通讯开始。
  6. 通讯结束后,由用户端发出关闭连接的告警消息,该告警消息也是加密的。

至此,一次完整的加密通讯就完成了。

在粗略的熟悉了流程后,也许读者会有诸多疑问?是不是每一次通讯都要协商密钥呢?握手信息里都有些啥呢?我们继续往下,对 TLS 进行一个”庖丁解牛“。

客户端请求(Client Hello)

示例:16 03 01 00 a5 01 00 00 a1 03 03 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 00 00 20 cc a8 cc a9 c0 2f c0 30 c0 2b c0 2c c0 13 c0 09 c0 14 c0 0a 00 9c 00 9d 00 2f 00 35 c0 12 00 0a 01 00 00 58 00 00 00 18 00 16 00 00 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00 05 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 03 ff 01 00 01 00 00 12 00 00

客户端最开始的请求包括以下内容

  • protocol version (协商协议版本)
  • client random data (used later in the handshake) (客户端随机数)
  • an optional session id to resume (可选项,已建立的会话id)
  • a list of cipher suites(使用的密码学组件)
  • a list of compression methods(使用的数据压缩方式)
  • a list of extensions(拓展项列表)

记录标头 Record Header16 03 01 00 a5

0x16:握手记录的标识符

0x03 0x01:表示协议 3.1 版本,即 TLS 1.0;但我们这里不是TLS 1.2 协议么?这是为了兼容部分服务器,如果协议版本高于 TLS1.0,可能会握手失败)

0x00 0xa5:长度——接下来将有 165 字节的握手消息

握手标头 Handshake Header01 00 00 a1

0x01:客户端请求( Client Hello)的标识符

0x00 0x00 0xa1: 长度——接下来将有161字节的请求消息

客户端所用协议版本:03 03

0x03 0x03:TLS 1.2

客户端随机数(32字节): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

0x00 0x01 0x02 … 0x1f:随机数

会话 ID (Session ID)00

0x00:长度——接下来将用 0 个字节表示会话ID的长度(如果之前建立过连接,那么就会有一个会话ID,32字节)

可选密码学组件 Cipher Suites: 00 20 cc a8 cc a9 c0 2f c0 30 c0 2b c0 2c c0 13 c0 09 c0 14 c0 0a 00 9c 00 9d 00 2f 00 35 c0 12 00 0a

0x00 0x20:接下来将用 32 个字节表示可选密码学组件

0xcc 0xa8:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

0xcc 0xa9:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

0xc0 0x2f:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

0xc0 0x30:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

0xc0 0x2b:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

0xc0 0x2c:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

0xc0 0x13:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

0xc0 0x09:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA

0xc0 0x14:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

0xc0 0x0a:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA

0x00 0x9c:TLS_RSA_WITH_AES_128_GCM_SHA256

0x00 0x9d:TLS_RSA_WITH_AES_256_GCM_SHA384

0x00 0x2f:TLS_RSA_WITH_AES_128_CBC_SHA

0x00 0x35:TLS_RSA_WITH_AES_256_CBC_SHA

0xc0 0x12:TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA

0x00 0x0a:TLS_RSA_WITH_3DES_EDE_CBC_SHA

数据压缩方法:01 00

0x01:长度——接下来将用 1 个字节表示数据压缩方法

0x00:不压缩,压缩的特性会削弱加密数据的安全性(参见CRIME)。因此,该功能已从未来的TLS协议中删除。

拓展项:

0x00 0x58:长度——接下来会使用 88 个字节表示拓展内容;

  1. 服务器名称(Server Name)

    00 00 00 18 00 16 00 00 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74

    客户端提供了它联系的服务器的名称,也称为SNI(服务器名称指示)。

    如果没有此扩展,HTTPS服务器将无法为单个IP地址(虚拟主机)上的多个主机名提供服务,因为在协商TLS会话并发出HTTP请求之前,它无法知道要发送哪个主机名的证书。

    0x00 0x00:Server Name 的标识符

    0x00 0x18:长度——Server Name 将占用24个字节

    0x00 0x16:长度——列表第一个(也是唯一一个)元素将占用22个字节

    0x00:列表类型是 “DNS hostname”

    0x13:长度——hostname 将占用 19 个字节

    0x65 0x78 0x61 … 0x6e 0x65 0x74 :具体的hostname:”example.ulfheim.net”

  2. 状态请求 (Status Request ):

    00 05 00 05 01 00 00 00 00

    客户端允许服务器在其响应中提供OCSP信息。OCSP可用于检查证书是否已被吊销。

    但是由于服务器是根据客户端的拓展项一一进行回复的,所以客户端在这里需要发送一个该扩展的空内容,这样服务器在返回时就可以用数据填充该扩展然后进行回复。

    0x00 0x05:Status Request的标识符

    0x00 0x05:长度——Status Request 将占用 5 个字节

    0x01:证书状态类型:OCSP

    0x00:回复者ID信息的长度:这里是客户端,所以是0

    0x00:所请求的消息的拓展消息的长度:这里是客户端,所以是0

  3. (密码学体制)支持的群结构 (Supported Groups):

    00 0a 00 0a 00 08 00 1d 00 17 00 18 00 19

    客户端表示它支持4条曲线的椭圆曲线(EC)加密。此扩展最初命名为“椭圆曲线”,但已重命名为“Supported Groups”,以便与其他密码类型通用。

    0x00 0x0a:Supported Groups的标识符

    0x00 0x0a:Supported Groups的具体内容将占用 10 个字节

    0x00 0x08:长度——曲线列表将占用 8 字节

    0x00 0x1d:表示曲线 “x25519”

    0x00 0x17:表示曲线 “secp256r1”

    0x00 0x18:表示曲线 “secp384r1”

    0x00 0x19:表示曲线 “secp521r1”

  4. 椭圆曲线表示形式 (EC Point Formats):

    00 0b 00 02 01 00

    在椭圆曲线(EC)加密过程中,客户端和服务器将以压缩或未压缩的形式交换所选点的信息。此扩展表示客户端只能解析来自服务器的未压缩信息。

    在TLS的下一版本中,不存在协商点的能力(而是为每条曲线预先选择一个点),因此不会发送此扩展。

    0x00 0x0b:EC points format 的标识符

    0x00 0x02:长度——EC points format 的具体内容将占用 2 个字节

    0x01:长度——所支持格式列表中元素占用 1 个字节

    0x00:表示格式:不压缩

  5. 签名算法 (Signature Algorithms):

    00 0d 00 12 00 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 03

    随着TLS的发展,有必要支持更强的签名算法(如SHA-256),同时仍支持使用MD5和SHA1的早期实现。此扩展指示客户端能够理解哪些签名算法,并可能影响服务器向客户端发送的证书的选择。

    0x00 0x0d:Signature Algorithms 的标识符

    0x00 0x12:长度——Signature Algorithms的内容将占用18字节

    0x00 0x10:长度——支持签名列表中元素将占用 16 个字节

    0x04 0x01:RSA/PKCS1/SHA256

    0x04 0x03:ECDSA/SECP256r1/SHA256

    0x05 0x01:RSA/PKCS1/SHA384

    0x05 0x03:ECDSA/SECP384r1/SHA384

    0x06 0x01:RSA/PKCS1/SHA512

    0x06 0x03:ECDSA/SECP521r1/SHA512

    0x02 0x01:RSA/PKCS1/SHA1

    0x02 0x03:ECDSA/SHA1

  6. 重新协商信息 (Renegotiation Info):

    ff 01 00 01 00

    此扩展是为了防止利用TLS重新协商的攻击类型。

    此协议的下一版本(TLS 1.3)已删除重新协商的功能,因此将来不再需要此扩展。

    0xff 0x01:Renegotiation Info 的标识符

    0x00 0x01:长度——Renegotiation Info 的内容将占用1字节

    0x00:Renegotiation Info 具体内容的长度为 0,因为这是一次新的连接

  7. 签名证书时间戳 (SCT,signed certificate timestamp):

    00 12 00 00

    客户端发送一个空的扩展,这个拓展是用于服务器发送自己签名证书的时间戳,或者根据发送了扩展的客户端更改行为。

    0x00 0x12:SCT 的标识符

    0x00 0x00:长度——接下来 SCT 的内容将占用 0 字节

服务端回应(Server Hello)

示例:16 03 03 00 31 02 00 00 2d 03 03 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 00 c0 13 00 00 05 ff 01 00 01 00

接下来是服务端的回应,想必也是跟客户端一一对应的,包括以下内容

  • the selected protocol version(确定选择的协议版本)
  • server random data (used later in the handshake)(服务端随机数)
  • the session id(可选项,已建立的会话id)
  • the selected cipher suite(使用的密码学组件)
  • the selected compression method使用的数据压缩方式)
  • a list of extensions(拓展项)

报文结构:

记录标头 (Record Header)16 03 01 00 31

0x16:握手记录的标识符

0x03 0x01 :协议是3.1版本, TLS 1.0;

0x00 0x31:长度——接下来握手消息将占用49字节

握手标头 (Handshake Header):``02 00 00 2d`

0x02:服务端握手请求 Server Hello)

0x00 0x00 0x2d:长度——接下来的请求消息将占用45字节

服务端所用协议版本 (Server Version)03 03

0x03 0x03: TLS 1.2

服务端随机数 (Server Random)70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f

0x70 0x71 … 0x8f:32字节随机数

会话 ID (Session ID)00

00:长度——接下来会话ID将占用 0 字节 (如果之前建立过连接,那么就会有一个会话ID,32字节)

选择的密码学组件 (Cipher Suite)c0 13

0xc0 0x13:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

压缩方式 (Compression Method)00

0x00:从客户端提供的选项中,选择不压缩

拓展项 (Extensions)00 05 ff 01 00 01 00

0x00 0x05:长度——接下来拓展项内容占用 5 字节

重新协商信息(Renegotiation Info):``ff 01 00 01 00`

0xff 0x01:Renegotiation Info 的标识符

0x00 0x01:长度——Renegotiation Info 的内容将占用1字节

0x00:长度——Renegotiation Info 具体内容的长度为 0(因为这是一次新的连接)

服务端证书(Server Certificate)

示例:16 03 03 03 2f 0b 00 03 2b 00 03 28 00 03 25 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0

服务端发送给客户端的证书包括以下内容

  • the hostname of the server(服务端的主机名)
  • the public key used by this server(服务端的公钥)
  • proof from a trusted third party that the owner of this hostname holds the private key for this public key(出据可信任第三方的证明,证明该服务掌握着该公钥对应的私钥)

记录标头 (Record Header)16 03 03 03 2f

0x16:握手记录的标识符

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x03 0x2f:长度——接下来握手消息将占用815字节

握手标头 (Handshake Header):``0b 00 03 2b`

0x0b:服务端证书标识符 (certificate)

0x00 0x03 0x2b:长度——接下来的请求消息将占用811字节

证书 (Certificate)00 03 28 00 03 25

0x00 0x03 0x28:长度——接下来证书的长度将占用808字节

0x00 0x03 0x25:长度——接下来第一个(也是唯一一个)证书的长度将占用805字节

0x30 0x82 0x03 … 0x0a:证书具体内容,格式可参考 https://tls12.xargs.org/certificate.html

服务端交换密钥生成(Server Key Exchange Generation)

与同客户端交换密钥生成步骤相同

服务器计算用于密钥交换的私有/公共密钥对。密钥交换是一种技术,在这种技术中,双方可以就同一个数字达成一致,而窃听者无法知道它是什么。

密钥交换的计算原理(即椭圆曲线上的运算)可见 X25519 。私钥一般是 $0$ 到 $2^{256}-1$ 之间的一个整数,服务器是通过生成32字节(256位)的随机数据来选择。这里我们所选私钥为:

909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf

我们可以利用 openssl 计算特定私钥的公钥,命令为:openssl pkey -noout -text < server-ephemeral-private.key

1
2
3
4
5
6
7
8
9
10
11
12
### requires openssl 1.1.0 or higher
$ openssl pkey -noout -text < server-ephemeral-private.key

X25519 Private-Key:
priv:
90:91:92:93:94:95:96:97:98:99:9a:9b:9c:9d:9e:
9f:a0:a1:a2:a3:a4:a5:a6:a7:a8:a9:aa:ab:ac:ad:
ae:af
pub:
9f:d7:ad:6d:cf:f4:29:8d:d3:f9:6d:5b:1b:2a:f9:
10:a0:53:5b:14:88:d7:f8:fa:bb:34:9a:98:28:80:
b6:15

得到与私钥相关的公钥是

9fd7ad6dcff4298dd3f96d5b1b2af910a0535b1488d7f8fabb349a982880b615

服务端发送交换密钥(Server Key Exchange)

服务器为密钥交换提供信息。作为密钥交换过程的一部分,服务器和客户端都将拥有公钥和私钥的密钥对,并将向另一方发送公钥。然后,将使用各方的私钥和另一方的公钥的组合来生成共享加密密钥。

双方就使用ECDHE的密码组件达成一致,这意味着密钥将基于选定的椭圆曲线,然后使用Diffie-Hellman协商密钥,并且这个密钥是临时的(为每个连接生成),而不是使用证书中的公钥/私钥。

示例:16 03 03 01 2c 0c 00 01 28 03 00 1d 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 28 80 b6 15 04 01 01 00 04 02 b6 61 f7 c1 91 ee 59 be 45 37 66 39 bd c3 d4 bb 81 e1 15 ca 73 c8 34 8b 52 5b 0d 23 38 aa 14 46 67 ed 94 31 02 14 12 cd 9b 84 4c ba 29 93 4a aa cc e8 73 41 4e c1 1c b0 2e 27 2d 0a d8 1f 76 7d 33 07 67 21 f1 3b f3 60 20 cf 0b 1f d0 ec b0 78 de 11 28 be ba 09 49 eb ec e1 a1 f9 6e 20 9d c3 6e 4f ff d3 6b 67 3a 7d dc 15 97 ad 44 08 e4 85 c4 ad b2 c8 73 84 12 49 37 25 23 80 9e 43 12 d0 c7 b3 52 2e f9 83 ca c1 e0 39 35 ff 13 a8 e9 6b a6 81 a6 2e 40 d3 e7 0a 7f f3 58 66 d3 d9 99 3f 9e 26 a6 34 c8 1b 4e 71 38 0f cd d6 f4 e8 35 f7 5a 64 09 c7 dc 2c 07 41 0e 6f 87 85 8c 7b 94 c0 1c 2e 32 f2 91 76 9e ac ca 71 64 3b 8b 98 a9 63 df 0a 32 9b ea 4e d6 39 7e 8c d0 1a 11 0a b3 61 ac 5b ad 1c cd 84 0a 6c 8a 6e aa 00 1a 9d 7d 87 dc 33 18 64 35 71 22 6c 4d d2 c2 ac 41 fb

报文结构:

记录标头 (Record Header)16 03 03 01 2c

0x16:握手记录的标识符

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x03 0x2f:长度——接下来握手消息将占用300字节

握手标头 (Handshake Header)0c 00 01 28

0x0c:服务端密钥交换标识符 (Server Key Exchange)

0x00 0x01 0x28:长度——接下来发送的消息将占用296字节

曲线信息 (Curve Info): 03 00 1d

0x03:曲线名称的标识符,接下来的字节将指定某一条特定曲线。

0x00 0x1d:曲线 curve x25519

公钥(Public Key):20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 28 80 b6 15

0x20:长度——接下来发送的公钥将占用32字节

0x9f 0xd7….. 0x15:前面计算得到的公钥

签名 (Signature):

04 01 01 00 04 02 b6 61 f7 c1 91 ee 59 be 45 37 66 39 bd c3 d4 bb 81 e1 15 ca 73 c8 34 8b 52 5b 0d 23 38 aa 14 46 67 ed 94 31 02 14 12 cd 9b 84 4c ba 29 93 4a aa cc e8 73 41 4e c1 1c b0 2e 27 2d 0a d8 1f 76 7d 33 07 67 21 f1 3b f3 60 20 cf 0b 1f d0 ec b0 78 de 11 28 be ba 09 49 eb ec e1 a1 f9 6e 20 9d c3 6e 4f ff d3 6b 67 3a 7d dc 15 97 ad 44 08 e4 85 c4 ad b2 c8 73 84 12 49 37 25 23 80 9e 43 12 d0 c7 b3 52 2e f9 83 ca c1 e0 39 35 ff 13 a8 e9 6b a6 81 a6 2e 40 d3 e7 0a 7f f3 58 66 d3 d9 99 3f 9e 26 a6 34 c8 1b 4e 71 38 0f cd d6 f4 e8 35 f7 5a 64 09 c7 dc 2c 07 41 0e 6f 87 85 8c 7b 94 c0 1c 2e 32 f2 91 76 9e ac ca 71 64 3b 8b 98 a9 63 df 0a 32 9b ea 4e d6 39 7e 8c d0 1a 11 0a b3 61 ac 5b ad 1c cd 84 0a 6c 8a 6e aa 00 1a 9d 7d 87 dc 33 18 64 35 71 22 6c 4d d2 c2 ac 41 fb

因为服务器正在生成临时密钥,所以它没有使用服务器证书中提供的公钥。为了证明服务器拥有服务器证书(在TLS会话中提供证书有效性),它使用证书的私钥签署临时密钥。可以使用证书的公钥验证此签名。

0x04 0x01:作为 RSA with SHA256 hash 签名算法的保留字

0x01 0x00:长度——接下来签名信息将占用 256 字节

0x04 0x02 0xb6 … 0xfb:信息摘要 SHA256(client_hello_random + server_hello_random + curve_info + public_key) 的RSA签名(这里就使用了本次连接客户端和服务端的随机数,使得攻击者无法进行重放攻击。)

签名的计算也可以用 openssl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
### client random from Client Hello
$ echo -en '\x00\x01\x02\x03\x04\x05\x06\x07' > /tmp/compute
$ echo -en '\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' >> /tmp/compute
$ echo -en '\x10\x11\x12\x13\x14\x15\x16\x17' >> /tmp/compute
$ echo -en '\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' >> /tmp/compute
### server random from Server Hello
$ echo -en '\x70\x71\x72\x73\x74\x75\x76\x77' >> /tmp/compute
$ echo -en '\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f' >> /tmp/compute
$ echo -en '\x80\x81\x82\x83\x84\x85\x86\x87' >> /tmp/compute
$ echo -en '\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f' >> /tmp/compute
### the curve info section from this message
$ echo -en '\x03\x00\x1d' >> /tmp/compute
### the public key sections from this msg
$ echo -en '\x20\x9f\xd7\xad\x6d\xcf\xf4\x29' >> /tmp/compute
$ echo -en '\x8d\xd3\xf9\x6d\x5b\x1b\x2a\xf9' >> /tmp/compute
$ echo -en '\x10\xa0\x53\x5b\x14\x88\xd7\xf8' >> /tmp/compute
$ echo -en '\xfa\xbb\x34\x9a\x98\x28\x80\xb6\x15' >> /tmp/compute
$ openssl dgst -sign server.key -sha256 /tmp/compute | hexdump

0000000 04 02 b6 61 f7 c1 91 ee 59 be 45 37 66 39 bd c3
... snip ...
00000f0 7d 87 dc 33 18 64 35 71 22 6c 4d d2 c2 ac 41 fb

服务端回复完毕(Server Hello Done)

服务器表示它完成了握手的一半。

示例:16 03 03 00 04 0e 00 00 00

记录标头 (Record Header)16 03 03 00 04

0x16:握手记录的标识符

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x04:长度——接下来握手消息将占用4字节

握手标头 (Handshake Header)0e 00 00 00

0x0e:服务端回复完毕的标识符 (server hello done)

0x00 0x00 0x00:长度——接下来发送的消息将占用0字节

客户端交换密钥生成(Client Key Exchange Generation)

同服务端交换密钥生成

这里我们设所选私钥为:202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f

那么对应公钥就是:358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254

客户端发送交换密钥(Client Key Exchange)

同服务端发送交换密钥,但是不会发送曲线信息,因为客户端会按照服务端确定的曲线进行计算;也不会发送签名,因为客户端并没有公私钥

示例:16 03 03 00 25 10 00 00 21 20 35 80 72 d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54

报文结构:

记录标头 (Record Header)16 03 03 00 25

0x16:握手记录的标识符

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x25:长度——接下来握手消息将占用37字节

握手标头 (Handshake Header)10 00 00 21

0x10:服务端密钥交换标识符 (certificate)

0x00 0x00 0x21:长度——接下来发送的消息将占用33字节

公钥(Public Key):20 35 80 72 d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54

0x20:长度——接下来发送的公钥将占用32字节

0x20 0x35….. 0x54:前面计算得到的公钥

客户端通讯密钥计算(Client Encryption Keys Calculation)

同服务端通讯密钥计算

客户端现在有了计算双方将使用的加密密钥的信息。它在计算中使用以下信息:

服务端随机数(来自 Server Hello)

客户端随机数(来自 Client Hello)

服务器公钥(来自 Server Key Exchange)

客户端私钥(来自 Client Key Generation)

客户端使用 curve25519 算法将服务器的公钥乘以客户端的私钥,生成32字节的结果称为 PreMasterSecret,结果如下:

df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624

然后客户端根据 PreMasterSecret 计算48字节的 MasterSecret

1
2
3
4
5
6
7
seed = "master secret" + client_random + server_random
a0 = seed
a1 = HMAC-SHA256(key=PreMasterSecret, data=a0)
a2 = HMAC-SHA256(key=PreMasterSecret, data=a1)
p1 = HMAC-SHA256(key=PreMasterSecret, data=a1 + seed)
p2 = HMAC-SHA256(key=PreMasterSecret, data=a2 + seed)
MasterSecret = p1[all 32 bytes] + p2[first 16 bytes]

利用 openssl生成 MasterSecret 的命令行示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
### set up our PreMasterSecret as a hex string
$ pmshex=df4a291baa1eb7cfa6934b29b474baad
$ pmshex=${pmshex}2697e29f1f920dcc77c8a0a088447624
### client random from Client Hello
$ echo -en '\x00\x01\x02\x03\x04\x05\x06\x07' > /tmp/c_rand
$ echo -en '\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' >> /tmp/c_rand
$ echo -en '\x10\x11\x12\x13\x14\x15\x16\x17' >> /tmp/c_rand
$ echo -en '\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' >> /tmp/c_rand
### server random from Server Hello
$ echo -en '\x70\x71\x72\x73\x74\x75\x76\x77' > /tmp/s_rand
$ echo -en '\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f' >> /tmp/s_rand
$ echo -en '\x80\x81\x82\x83\x84\x85\x86\x87' >> /tmp/s_rand
$ echo -en '\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f' >> /tmp/s_rand
### build the seed
$ echo -en 'master secret' > /tmp/seed
$ cat /tmp/c_rand /tmp/s_rand >> /tmp/seed
### a0 is the same as the seed
$ cat /tmp/seed > /tmp/a0
### a(n) is hmac-sha256(key=secret, data=a(n-1))
$ cat /tmp/a0 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$pmshex -binary > /tmp/a1
$ cat /tmp/a1 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$pmshex -binary > /tmp/a2
### p(n) is hmac-sha256(key=secret, data=a(n)+seed)
$ cat /tmp/a1 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$pmshex -binary > /tmp/p1
$ cat /tmp/a2 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$pmshex -binary > /tmp/p2
### first 48 bytes is MasterSecret
$ cat /tmp/p1 /tmp/p2 | head -c 48 > /tmp/mastersecret
$ hexdump /tmp/mastersecret

0000000 91 6a bf 9d a5 59 73 e1 36 14 ae 0a 3f 5d 3f 37
0000010 b0 23 ba 12 9a ee 02 cc 91 34 33 81 27 cd 70 49
0000020 78 1c 8e 19 fc 1e b2 a7 38 7a c0 6a e2 37 34 4c

得到:916abf9da55973e13614ae0a3f5d3f37b023ba129aee02cc9134338127cd7049781c8e19fc1eb2a7387ac06ae237344c

最后,我们利用 MasterSecret 生成用于通讯加密的 encryption keys(包括密钥,IV向量,mac key)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
seed = "key expansion" + server_random + client_random
a0 = seed
a1 = HMAC-SHA256(key=MasterSecret, data=a0)
a2 = HMAC-SHA256(key=MasterSecret, data=a1)
a3 = HMAC-SHA256(key=MasterSecret, data=a2)
a4 = ...
p1 = HMAC-SHA256(key=MasterSecret, data=a1 + seed)
p2 = HMAC-SHA256(key=MasterSecret, data=a2 + seed)
p3 = HMAC-SHA256(key=MasterSecret, data=a3 + seed)
p4 = ...
p = p1 + p2 + p3 + p4 ...
client write mac key = [first 20 bytes of p]
server write mac key = [next 20 bytes of p]
client write key = [next 16 bytes of p]
server write key = [next 16 bytes of p]
client write IV = [next 16 bytes of p]
server write IV = [next 16 bytes of p]

示例命令行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
### continued from above command line example
### set up our MasterSecret as a hex string
$ mshex=$(hexdump -ve '/1 "%02x"' /tmp/mastersecret)
### build the seed
$ echo -en 'key expansion' > /tmp/seed
$ cat /tmp/s_rand /tmp/c_rand >> /tmp/seed
### a0 is the same as the seed
$ cat /tmp/seed > /tmp/a0
### a(n) is hmac-sha256(key=secret, data=a(n-1))
$ cat /tmp/a0 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/a1
$ cat /tmp/a1 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/a2
$ cat /tmp/a2 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/a3
$ cat /tmp/a3 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/a4
### p(n) is hmac-sha256(key=secret, data=a(n)+seed)
$ cat /tmp/a1 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/p1
$ cat /tmp/a2 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/p2
$ cat /tmp/a3 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/p3
$ cat /tmp/a4 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/p4
### combine them into a single stream
$ cat /tmp/p1 /tmp/p2 /tmp/p3 /tmp/p4 > /tmp/p
$ dd if=/tmp/p of=/tmp/client_mac_key bs=1 skip=0 count=20
$ dd if=/tmp/p of=/tmp/server_mac_key bs=1 skip=20 count=20
$ dd if=/tmp/p of=/tmp/client_key bs=1 skip=40 count=16
$ dd if=/tmp/p of=/tmp/server_key bs=1 skip=56 count=16
$ dd if=/tmp/p of=/tmp/client_iv bs=1 skip=72 count=16
$ dd if=/tmp/p of=/tmp/server_iv bs=1 skip=88 count=16
$ hexdump /tmp/client_mac_key
0000000 1b 7d 11 7c 7d 5f 69 0b c2 63 ca e8 ef 60 af 0f
0000010 18 78 ac c2

$ hexdump /tmp/server_mac_key
0000000 2a d8 bd d8 c6 01 a6 17 12 6f 63 54 0e b2 09 06
0000010 f7 81 fa d2

$ hexdump /tmp/client_key
0000000 f6 56 d0 37 b1 73 ef 3e 11 16 9f 27 23 1a 84 b6

$ hexdump /tmp/server_key
0000000 75 2a 18 e7 a9 fc b7 cb cd d8 f9 8d d8 f7 69 eb

$ hexdump /tmp/client_iv
0000000 a0 d2 55 0c 92 38 ee bf ef 5c 32 25 1a bb 67 d6

$ hexdump /tmp/server_iv
0000000 43 45 28 db 49 37 d5 40 d3 93 13 5e 06 a1 1b b8

最终客户端得到

  • client MAC key: 1b7d117c7d5f690bc263cae8ef60af0f1878acc2
  • server MAC key: 2ad8bdd8c601a617126f63540eb20906f781fad2
  • client write key: f656d037b173ef3e11169f27231a84b6
  • server write key: 752a18e7a9fcb7cbcdd8f98dd8f769eb
  • client write IV: a0d2550c9238eebfef5c32251abb67d6
  • server write IV: 434528db4937d540d393135e06a11bb8

客户端启用加密通讯(Client Change Cipher Spec)

同服务端启用通讯加密

客户端表示它已经计算了共享加密密钥,并且来自客户端的所有后续消息将使用客户端写入的密钥进行加密。

在TLS的下一版本中,此消息类型已被删除,因为显得有点多余。

示例:14 03 03 00 01 01

报文结构:

记录 (Record)14 03 03 00 01 01

0x14:客户端启用加密通讯的标识符(ChangeCipherSpec record)

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x01:长度——接下来消息将占用1字节

0x01:客户端启用加密通讯

客户端握手完毕(Client Handshake Finished)

为了验证握手是否成功且未被篡改,客户端计算验证数据并使用客户端通讯密钥对其进行加密。

验证数据是根据所有握手消息的散列构建的,并验证握手过程的完整性。

示例:16 03 03 00 40 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 22 7b c9 ba 81 ef 30 f2 a8 a7 8f f1 df 50 84 4d 58 04 b7 ee b2 e2 14 c3 2b 68 92 ac a3 db 7b 78 07 7f dd 90 06 7c 51 6b ac b3 ba 90 de df 72 0f

报文结构:

记录标头 (Record Header)16 03 03 00 40

0x16:握手记录的标识符

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x40:长度——接下来握手消息将占用64字节

加密向量(Encryption IV)40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f

客户端发送用于解密密钥的初始IV向量

0x40 0x41 … 0x4f:IV向量

加密密文(Encrypted Data)22 7b c9 ba 81 ef 30 f2 a8 a7 8f f1 df 50 84 4d 58 04 b7 ee b2 e2 14 c3 2b 68 92 ac a3 db 7b 78 07 7f dd 90 06 7c 51 6b ac b3 ba 90 de df 72 0f

此数据使用客户端通讯密钥加密。它包含消息认证码(MAC)和填充,所以密文比解密的数据大。

可以用以下命令解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
### client key
$ hexkey=f656d037b173ef3e11169f27231a84b6
### IV for this record
$ hexiv=404142434445464748494a4b4c4d4e4f
### encrypted data
$ echo '22 7b c9 ba 81 ef 30 f2 a8 a7 8f f1 df 50 84 4d' > /tmp/msg1
$ echo '58 04 b7 ee b2 e2 14 c3 2b 68 92 ac a3 db 7b 78' >> /tmp/msg1
$ echo '07 7f dd 90 06 7c 51 6b ac b3 ba 90 de df 72 0f' >> /tmp/msg1
$ xxd -r -p /tmp/msg1 \
| openssl enc -d -nopad -aes-128-cbc -K $hexkey -iv $hexiv | hexdump

0000000 14 00 00 0c cf 91 96 26 f1 36 0c 53 6a aa d7 3a
0000010 a5 a0 3d 23 30 56 e4 ac 6e ba 7f d9 e5 31 7f ac
0000020 2d b5 b7 0e 0b 0b 0b 0b 0b 0b 0b 0b 0b 0b 0b 0b

The last 32 bytes contain a 20-byte MAC and padding to bring the data to a
multiple of 16 bytes. The 20-byte MAC can be reproduced as follows:

### from https://tools.ietf.org/html/rfc2246#section-6.2.3.1
$ sequence='0000000000000000'
$ rechdr='16 03 03'
$ datalen='00 10'
$ data='14 00 00 0c cf 91 96 26 f1 36 0c 53 6a aa d7 3a'
### from "Encryption Keys Calculation"
$ mackey=1b7d117c7d5f690bc263cae8ef60af0f1878acc2
$ echo $sequence $rechdr $datalen $data | xxd -r -p \
| openssl dgst -sha1 -mac HMAC -macopt hexkey:$mackey

a5a03d233056e4ac6eba7fd9e5317fac2db5b70e

将会得到明文:14 00 00 0c cf 91 96 26 f1 36 0c 53 6a aa d7 3a

明文的含义为:

握手标头 (Handshake Header)14 00 00 0c

0x14:握手完成标识符 (finished)

0x00 0x00 0x0c:长度——接下来发送的握手消息将占用12字节

验证消息(Verify Data)cf 91 96 26 f1 36 0c 53 6a aa d7 3a

0xcf 0x91 … 0x3a:用于验证的消息

验证消息是根据主密钥和在此之前的所有握手记录(类型为0x16)的有效载荷的散列构建的。

在此之前的所有握手消息的 SHA256 为 061dda04b3c2217ff73bd79b9cf88a2bb6ec505404aac8722db03ef417b54cb4 。

1
2
3
4
5
seed = "client finished" + SHA256(all handshake messages)
a0 = seed
a1 = HMAC-SHA256(key=MasterSecret, data=a0)
p1 = HMAC-SHA256(key=MasterSecret, data=a1 + seed)
verify_data = p1[first 12 bytes]

命令示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
### set up our MasterSecret as a hex string
$ mshex=$(hexdump -ve '/1 "%02x"' /tmp/mastersecret)
### build the seed
$ echo -en 'client finished' > /tmp/seed
### add SHA256(all_messages) to seed
$ echo -en '\x06\x1d\xda\x04\xb3\xc2\x21\x7f' >> /tmp/seed
$ echo -en '\xf7\x3b\xd7\x9b\x9c\xf8\x8a\x2b' >> /tmp/seed
$ echo -en '\xb6\xec\x50\x54\x04\xaa\xc8\x72' >> /tmp/seed
$ echo -en '\x2d\xb0\x3e\xf4\x17\xb5\x4c\xb4' >> /tmp/seed
### a0 is the same as the seed
$ cat /tmp/seed > /tmp/a0
### a(n) is hmac-sha256(key=secret, data=a(n-1))
$ cat /tmp/a0 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/a1
### p(n) is hmac-sha256(key=secret, data=a(n)+seed)
$ cat /tmp/a1 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/p1
$ head -c 12 /tmp/p1 > /tmp/verify_data
$ hexdump /tmp/verify_data

0000000 cf 91 96 26 f1 36 0c 53 6a aa d7 3a

服务端通讯密钥计算(Server Encryption Keys Calculation)

计算步骤和计算结果都与客户端通讯密钥计算相同

服务端启用加密通讯(Server Change Cipher Spec)

同客户端启用加密通讯

示例:14 03 03 00 01 01

服务端握手完毕(Client Handshake Finished)

同客户端握手完毕

示例:16 03 03 00 40 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 18 e0 75 31 7b 10 03 15 f6 08 1f cb f3 13 78 1a ac 73 ef e1 9f e2 5b a1 af 59 c2 0b e9 4f c0 1b da 2d 68 00 29 8b 73 a7 e8 49 d7 4b d4 94 cf 7d

报文结构:

记录标头 (Record Header)16 03 03 00 40

0x16:握手记录的标识符

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x40:长度——接下来握手消息将占用64字节

加密向量(Encryption IV)51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60

客户端发送用于解密密钥的初始IV向量

0x51 0x52 … 0x60:IV向量

加密密文(Encrypted Data)18 e0 75 31 7b 10 03 15 f6 08 1f cb f3 13 78 1a ac 73 ef e1 9f e2 5b a1 af 59 c2 0b e9 4f c0 1b da 2d 68 00 29 8b 73 a7 e8 49 d7 4b d4 94 cf 7d

解密可得

14 00 00 0c 84 4d 3c 10 74 6d d7 22 f9 2f 0c 7e

握手标头 (Handshake Header)14 00 00 0c

0x14:握手完成标识符 (finished)

0x00 0x00 0x0c:长度——接下来发送的握手消息将占用12字节

验证消息(Verify Data)84 4d 3c 10 74 6d d7 22 f9 2f 0c 7e

0x84 0x4d … 0x7e:用于验证的消息

在此之前的所有握手消息的 SHA256 为 b2017ba28d0e27f03ae327456b6ff00b4d5bbf0ef7cda83ce1029b521c3e7c35 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
### set up our MasterSecret as a hex string
$ mshex=$(hexdump -ve '/1 "%02x"' /tmp/mastersecret)
### build the seed
$ echo -en 'server finished' > /tmp/seed
### add SHA256(all_messages) to seed
$ echo -en '\xb2\x01\x7b\xa2\x8d\x0e\x27\xf0' >> /tmp/seed
$ echo -en '\x3a\xe3\x27\x45\x6b\x6f\xf0\x0b' >> /tmp/seed
$ echo -en '\x4d\x5b\xbf\x0e\xf7\xcd\xa8\x3c' >> /tmp/seed
$ echo -en '\xe1\x02\x9b\x52\x1c\x3e\x7c\x35' >> /tmp/seed
### a0 is the same as the seed
$ cat /tmp/seed > /tmp/a0
### a(n) is hmac-sha256(key=secret, data=a(n-1))
$ cat /tmp/a0 | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/a1
### p(n) is hmac-sha256(key=secret, data=a(n)+seed)
$ cat /tmp/a1 /tmp/seed | openssl dgst -sha256 \
-mac HMAC -macopt hexkey:$mshex -binary > /tmp/p1
$ head -c 12 /tmp/p1 > /tmp/verify_data
$ hexdump /tmp/verify_data

0000000 84 4d 3c 10 74 6d d7 22 f9 2f 0c 7e

双方正式进行加密通讯(Application Data)

示例,

客户端发送信息:”ping”:17 03 03 00 30 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 6c 42 1c 71 c4 2b 18 3b fa 06 19 5d 13 3d 0a 09 d0 0f c7 cb 4e 0f 5d 1c da 59 d1 47 ec 79 0c 99

报文结构:

记录标头 (Record Header)17 03 03 00 30

0x17:通讯标识符(Application Data)

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x30:长度——接下来握手消息将占用48字节

加密向量(Encryption IV): 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f

加密密文(Encrypted Data):6c 42 1c 71 c4 2b 18 3b fa 06 19 5d 13 3d 0a 09 d0 0f c7 cb 4e 0f 5d 1c da 59 d1 47 ec 79 0c 99

解密示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
### client key
$ hexkey=f656d037b173ef3e11169f27231a84b6
### IV for this record
$ hexiv=000102030405060708090a0b0c0d0e0f
### encrypted data
$ echo '6c 42 1c 71 c4 2b 18 3b fa 06 19 5d 13 3d 0a 09' > /tmp/msg1
$ echo 'd0 0f c7 cb 4e 0f 5d 1c da 59 d1 47 ec 79 0c 99' >> /tmp/msg1
$ xxd -r -p /tmp/msg1 \
| openssl enc -d -nopad -aes-128-cbc -K $hexkey -iv $hexiv | hexdump

0000000 70 69 6e 67 60 10 12 49 f7 4a 03 77 c9 ca cf 63
0000010 09 75 13 70 d8 0c fc aa 07 07 07 07 07 07 07 07

The last 28 bytes contain a 20-byte MAC and padding to bring the data to a
multiple of 16 bytes. The 20-byte MAC can be reproduced as follows:

### from https://tools.ietf.org/html/rfc2246#section-6.2.3.1
$ sequence='0000000000000001'
$ rechdr='17 03 03'
$ datalen='00 04'
$ data='70 69 6e 67'
### from "Encryption Keys Calculation"
$ mackey=1b7d117c7d5f690bc263cae8ef60af0f1878acc2
$ echo $sequence $rechdr $datalen $data | xxd -r -p \
| openssl dgst -sha1 -mac HMAC -macopt hexkey:$mackey

60101249f74a0377c9cacf6309751370d80cfcaa

解密得到:70 69 6e 67 60 10 12 49 f7 4a 03 77 c9 ca cf 63 09 75 13 70 d8 0c fc aa 07 07 07 07 07 07 07 07

70 69 6e 67:消息 “ping”(Application Data)

60 10 12 49 f7 4a 03 77 c9 ca cf 63 09 75 13 70 d8 0c fc aa:MAC

07 07 07 07 07 07 07 07 填充(padding)

服务端发送消息:”pong“:17 03 03 00 30 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 97 83 48 8a f5 fa 20 bf 7a 2e f6 9d eb b5 34 db 9f b0 7a 8c 27 21 de e5 40 9f 77 af 0c 3d de 56

报文结构:

记录标头 (Record Header)17 03 03 00 30

0x17:通讯标识符(Application Data)

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x30:长度——接下来握手消息将占用48字节

加密向量(Encryption IV): 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70

加密密文(Encrypted Data):97 83 48 8a f5 fa 20 bf 7a 2e f6 9d eb b5 34 db 9f b0 7a 8c 27 21 de e5 40 9f 77 af 0c 3d de 56

解密示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
### server key
$ hexkey=752a18e7a9fcb7cbcdd8f98dd8f769eb
### IV for this record
$ hexiv=6162636465666768696a6b6c6d6e6f70
### encrypted data
$ echo '97 83 48 8a f5 fa 20 bf 7a 2e f6 9d eb b5 34 db' > /tmp/msg1
$ echo '9f b0 7a 8c 27 21 de e5 40 9f 77 af 0c 3d de 56' >> /tmp/msg1
$ xxd -r -p /tmp/msg1 \
| openssl enc -d -nopad -aes-128-cbc -K $hexkey -iv $hexiv | hexdump

0000000 70 6f 6e 67 5a c7 99 dc cf dc 0f af 95 2b dc 91
0000010 18 af 20 0e e3 1c 51 05 07 07 07 07 07 07 07 07

The last 28 bytes contain a 20-byte MAC and padding to bring the data to a
multiple of 16 bytes. The 20-byte MAC can be reproduced as follows:

### from https://tools.ietf.org/html/rfc2246#section-6.2.3.1
$ sequence='0000000000000001'
$ rechdr='17 03 03'
$ datalen='00 04'
$ data='70 6f 6e 67'
### from "Encryption Keys Calculation"
$ mackey=2ad8bdd8c601a617126f63540eb20906f781fad2
$ echo $sequence $rechdr $datalen $data | xxd -r -p \
| openssl dgst -sha1 -mac HMAC -macopt hexkey:$mackey

5ac799dccfdc0faf952bdc9118af200ee31c5105

解密可得:70 6f 6e 67 5a c7 99 dc cf dc 0f af 95 2b dc 91 18 af 20 0e e3 1c 51 05 07 07 07 07 07 07 07 07

70 6f 6e 67:消息 “pong”(Application Data)

5a c7 99 dc cf dc 0f af 95 2b dc 91 18 af 20 0e e3 1c 51 05:MAC

07 07 07 07 07 07 07 07 填充(padding)

客服端关闭连接(Client Close Notify)

客户端将发出告警,表明它正在关闭连接。

示例:15 03 03 00 30 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 0d 83 f9 79 04 75 0d d8 fd 8a a1 30 21 86 32 63 4f d0 65 e4 62 83 79 b8 8b bf 9e fd 12 87 a6 2d

报文结构:

记录标头 (Record Header)15 03 03 00 30

0x15:告警记录标识符(alert record)

0x03 0x03 :协议是3.3版本, TLS 1.2;

0x00 0x30:长度——接下来握手消息将占用48字节

加密向量(Encryption IV): 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

加密密文(Encrypted Data):0d 83 f9 79 04 75 0d d8 fd 8a a1 30 21 86 32 63 4f d0 65 e4 62 83 79 b8 8b bf 9e fd 12 87 a6 2d

解密可得:01 00 92 79 9c ba 81 9f 31 07 44 c5 59 62 2b e4 2b ce 3d 6a 41 fb 09 09 09 09 09 09 09 09 09 09

其中:

0x01:告警等级为 1,表示 Warning

0x00:告警类型为 0,为关闭通知


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 643713081@qq.com

文章标题:TLS 1.2 协议(一)

文章字数:10.1k

本文作者:Van1sh

发布时间:2022-12-08, 21:10:00

最后更新:2023-01-31, 16:17:50

原始链接:http://jayxv.github.io/2022/12/08/TLS1.2协议分析(一)/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏