chenpengcong / blog

14 stars 3 forks source link

TLS-PSK协议分析 #33

Open chenpengcong opened 3 years ago

chenpengcong commented 3 years ago

本文通过一个演示例子讲解基于PSK( Pre-Shared Key,预共享密钥)的TLS(Transport Layer Security)协议是如何加密及计算MAC的,对于想要实现TLS-PSK Server及client的读者应该有所帮助。

在演示例子中,客户端与服务端使用TLS1.2及PSK-AES128-CBC-SHA256密码套件进行交互,客户端发送"hi server\n",服务端响应"hi client\n",然后正常终止连接

准备工作

  1. 运行tcpdump,将后续捕获到的TLS数据保存到文件
  2. 使用openssl client与openssl server建立TLS-PSK连接
  3. 使用Wireshark解析TLS数据

运行tcpdump,将后续捕获到的TLS数据保存到文件

抓取本地4433端口流量并保存到tls_psk.pcap文件

$ tcpdump port 4433 -i lo -w tls_psk.pcap

这里抓取的端口要与TLS server监听的端口一致

使用openssl client与openssl server建立TLS-PSK连接

使用openssl server启动一个TLS server

$ openssl s_server -cipher PSK-AES128-CBC-SHA256 -tls1_2 -nocert -no_ticket -psk_identity my_psk_id -psk 000102030405060708090A0B0C0D0E0F

-nocert表示不使用证书,这是PSK与PKI(Public Key Infrastructure)的一个区别

-no_ticket用于disable session ticket,session ticket可以优化握手效率,但会复杂化首次握手的流程,所以不启用

默认监听4433端口

使用openssl client与server建立TLS连接

$ openssl s_client -cipher PSK-AES128-CBC-SHA256 -tls1_2 -psk_identity my_psk_id -psk 000102030405060708090A0B0C0D0E0F

使用Wireshark解析TLS数据

运行Wireshark,打开tls_psk.cap文件,为了Wireshark能够解析密文,还需要配置Pre-Shared Key,点击编辑 -> 首选项 -> Protocols -> TLS,在Pre-Shared Key中输入密钥值000102030405060708090A0B0C0D0E0F

在TLS配置页面可以顺便选择TLS debug file,该功能会将Wireshark解析TLS的一些过程数据比如master secret,key block等保存到文件中,方便我们比对计算结果排查问题,非常有用

最终得到TLS数据如下

Client Hello

16 03 01 00 7d 01 00 00 79 03 03 36 9e 43 08 87 60 b8 b1 e0 61 cd d8 1f 4b ab 5e e1 38 08 c2 d9 d5 50 9d 92 61 3e af 62 55 f6 be 00 00 04 00 ae 00 ff 01 00 00 4c 00 00 00 0e 00 0c 00 00 09 6c 6f 63 61 6c 68 6f 73 74 00 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 2a 00 28 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 03 03 03 01 03 02 04 02 05 02 06 02

Server Hello

16 03 03 00 59 02 00 00 55 03 03 c5 b4 a2 ca 4e fb 20 21 74 75 fc 9f 91 78 38 ee 47 30 74 8f 8e d9 e4 56 a9 bf 94 0d 55 eb cb 22 20 9e e6 cb c2 77 ad db 29 05 52 eb ce 60 81 fa 71 43 63 5b 9b c9 31 84 f0 88 09 dc d0 21 8a ff 48 00 ae 00 00 0d ff 01 00 01 00 00 16 00 00 00 17 00 00

Server Hello Done

16 03 03 00 04 0e 00 00 00

Client Key Exchange

16 03 03 00 0f 10 00 00 0b 00 09 6d 79 5f 70 73 6b 5f 69 64

Client Change Cipher Spec

14 03 03 00 01 01

Client Finished

16 03 03 00 50 98 9c 70 7f 7b b2 d1 9d 38 70 c1 b0 81 8d 60 97 07 cd 28 0b 61 64 bf ae 46 08 22 90 34 56 82 3a 5e b4 4a e0 51 bd df 9b 34 44 92 67 1b 6c 22 44 60 92 03 e8 d4 f7 09 12 37 56 30 b7 ae 1f 7b 67 58 d5 72 ce 4e 36 89 a6 5a 90 d3 15 2f 53 1a 6c

Server Change Cipher Spec

14 03 03 00 01 01

Server Finished

16 03 03 00 50 41 54 6e f1 7a 2a 3f 1d 0f 26 29 95 7f ba 0a f2 d8 4b 4a 9a c5 b3 b4 71 2e ef 70 fa 39 17 5e cc 90 9f 33 16 c2 e3 ad 4a 3c 95 f1 fe 90 cd cc a1 98 d8 7c 0a b4 d6 50 3a fa 6a 16 f5 6e ff 06 77 a7 f4 66 db d2 fb b4 be cf 8d 7b c8 7c 78 78 71

Client Application Data

17 03 03 00 40 19 77 d0 be 1f b4 83 f9 53 6d 8c f5 06 05 b3 10 e9 98 68 ed bf 30 93 e1 74 cc 22 3a 3b 31 a3 93 26 e2 0c 1c c3 c8 eb d9 f6 ec 11 5a b5 a1 bd 65 7c 28 e4 5b 0d c5 08 65 b7 f3 4a 93 91 83 8a 3a

Server Application Data

17 03 03 00 40 07 80 69 09 82 fd c3 7f 28 18 81 ad 78 4b 78 45 12 fb 47 ca 97 60 a2 50 65 32 97 d4 9e 2c 65 48 2a e3 f3 2b 3b d1 82 6c 30 e1 e8 45 46 32 e0 ca b0 40 96 26 98 fc 4f db d4 c2 33 23 10 a8 6c f3

Alert(Client Close Notify)

15 03 03 00 40 4f aa 08 0c ec c9 19 a0 87 e5 8d f8 69 49 70 54 ac bf 46 58 d5 76 18 1e 22 77 57 1b 86 9d 03 c5 b5 4d 7b 2b a1 e8 29 00 07 23 41 be e6 ad c0 23 61 ec b6 d3 83 dd 0f ed 06 43 c5 03 c9 89 4c ac

消息数据的每个字节含义在wireshark中已提示得很清晰,就不一一解释了,本文演示例子抓包的数据文件可以点击tls_psk.pcap下载,方便跟着文章一步一步计算

这里重点关注加解密这一块,接下来将还原Finished,Application Data及Alert消息的密文构造过程

从Client Hello及Server Hello消息可知

并且协商使用了下面这两个扩展(extension)

这两个扩展要重点关注,他们改变了RFC5246中定义的TLS1.2协议的默认行为

首先计算master secret,要特别注意的是例子中使用了extended master secret extension,要参考rfc7627#section-4而非RFC5246,rfc7627定义如下

master_secret = PRF(pre_master_secret, "extended master secret", 
              session_hash)[0..47];

session_hash定义在RFC7627#section-3

When a full TLS handshake takes place, we define

​ session_hash = Hash(handshake_messages)

where "handshake_messages" refers to all handshake messages sent or received, starting at the ClientHello up to and including the ClientKeyExchange message, including the type and length fields of the handshake messages. This is the concatenation of all the exchanged Handshake structures, as defined in Section 7.4 of [RFC5246].

For TLS 1.2, the "Hash" function is the one defined in Section 7.4.9 of [RFC5246] for the Finished message computation. For all previous versions of TLS, the "Hash" function computes the concatenation of MD5 and SHA1.

PSK的premaster secret定义在RFC4279#section-2

The premaster secret is formed as follows: if the PSK is N octets long, concatenate a uint16 with the value N, N zero octets, a second uint16 with the value N, and the PSK itself.

PRF(Pseudorandom Function)定义在RFC5246#section-5

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
                       HMAC_hash(secret, A(2) + seed) +
                       HMAC_hash(secret, A(3) + seed) + ...
where + indicates concatenation.
A() is defined as:
  A(0) = seed
  A(i) = HMAC_hash(secret, A(i-1))

针对密码套件PSK-AES128-CBC-SHA256,PRF使用的hash算法为SHA256,在RFC5487#section-3.1中描述

CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xAE}; CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF}; CipherSuite TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0}; CipherSuite TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1};

The above four cipher suites are the same as the corresponding cipher suites in RFC 4279 and RFC 4785 (with names ending in "_SHA" in place of "_SHA256" or "_SHA384"), except for the hash and PRF algorithms, as explained below.

o For cipher suites with names ending in "_SHA256":

​ * The MAC is HMAC [RFC2104] with SHA-256 as the hash function.

​ * When negotiated in a version of TLS prior to 1.2, the PRF from that version is used; otherwise, the PRF is the TLS PRF [RFC5246] with SHA-256 as the hash function.

有了规范依据后,接下来代入实际数据进行计算

###### 计算premaster secret ######
premaster secret  = 0010 + 00000000000000000000000000000000 + 0010 + 000102030405060708090A0B0C0D0E0F = 0010000000000000000000000000000000000010000102030405060708090A0B0C0D0E0F

###### 计算sessIon_hash(handshake_messages) ######
handshake_messages是client hello ~ ClientKeyExchange之间所有content type为handshake(0x16)的消息的拼接,在上述例子即client hello, server hello, server hello done, client key exchange 这4个消息,change cipher spec的content type不是handshake因此不包含,需要注意这里拼接的每个handshake message不包含record layer headers,即最开始的ContentType,ProtocolVersion及length这几个参数

handshake_messages = client hello + server hello + sever hello done + client key exchange = 010000790303369e43088760b8b1e061cdd81f4bab5ee13808c2d9d5509d92613eaf6255f6be00000400ae00ff0100004c0000000e000c0000096c6f63616c686f7374002300000016000000170000000d002a0028040305030603080708080809080a080b080408050806040105010601030303010302040205020602020000550303c5b4a2ca4efb20217475fc9f917838ee4730748f8ed9e456a9bf940d55ebcb22209ee6cbc277addb290552ebce6081fa7143635b9bc93184f08809dcd0218aff4800ae00000dff0100010000160000001700000e0000001000000b00096d795f70736b5f6964

session_hash = SHA256(handshake_messages) = d08e6ed25877545d37396ff946bc0c2c9a99b74732ec025bce300814a42e0ff7

###### 计算master secret ######
A(0) = seed = "extended master secret" + session_hash = 657874656E646564206D617374657220736563726574d08e6ed25877545d37396ff946bc0c2c9a99b74732ec025bce300814a42e0ff7              
A(1) = HMAC_SHA256(pre_master_secret, A(0)) = ad934828a4ed92206f0c1697ec010458eac51f2fa632a534e35b210bc5804e20
A(2) = HMAC_SHA256(pre_master_secret, A(1)) = ee7461a8253437d4bce063e2aded9cc4d5b654025dbaf671d504fbf7814b7637

HMAC_SHA256(pre_master_secret, A(1) + seed) = 499404bc28ade1b35d0a7a4a946e7c0459b15531e1dd5aa208f2752361afb96b
HMAC_SHA256(pre_master_secret, A(2) + seed) = f5b8b08057b01bd1b9b8dc862490f9336e8ad8a69804ae05b35d340c611b6518

master secret = PRF(pre_master_secret, seed)[0..47] = P_hash(pre_master_secret, seed)[0..47] = HMAC_SHA256(pre_master_secret, A(1) + seed)[all 32 bytes] + HMAC_SHA256(pre_master_secret, A(2) + seed)[0..15]

至此可得到48字节的master secret = 499404bc28ade1b35d0a7a4a946e7c0459b15531e1dd5aa208f2752361afb96bf5b8b08057b01bd1b9b8dc862490f933

接下来计算client/server的write key及mac key,需要先生成key block,定义在RFC5246#section-6.3

key_block = PRF(SecurityParameters.master_secret,
                "key expansion",
                SecurityParameters.server_random +
                SecurityParameters.client_random);

until enough output has been generated.  Then, the key_block is partitioned as follows:

client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]

根据RFC5246#appendix-C

                      Key      IV   Block
Cipher        Type    Material  Size  Size
------------  ------  --------  ----  -----
NULL          Stream      0       0    N/A
RC4_128       Stream     16       0    N/A
3DES_EDE_CBC  Block      24       8      8
AES_128_CBC   Block      16      16     16
AES_256_CBC   Block      32      16     16

MAC       Algorithm    mac_length  mac_key_length
--------  -----------  ----------  --------------
NULL      N/A              0             0
MD5       HMAC-MD5        16            16
SHA       HMAC-SHA1       20            20
SHA256    HMAC-SHA256     32            32

Key Material
  The number of bytes from the key_block that are used for generating the write keys.

可知PSK-AES128-CBC-SHA256密码套件的enc_key_length为16字节,mac_key_length为32字节

因此key_block至少需要 2 32 + 2 16 = 96字节,P_hash需要迭代3次生成96字节数据

###### 计算key block ######

A(0) = seed = "key expansion", server_random + client_random = 6B657920657870616E73696F6Ec5b4a2ca4efb20217475fc9f917838ee4730748f8ed9e456a9bf940d55ebcb22369e43088760b8b1e061cdd81f4bab5ee13808c2d9d5509d92613eaf6255f6be
A(1) = HMAC_SHA256(master_secret, A(0)) = 2974a1366b2acfae12ae915c5e22cff27c68c19135a0e9d4c4c60c9530690861
A(2) = HMAC_SHA256(master_secret, A(1)) = 309cc823366446903ffd3e6147f1fd3f44a991685def09fc51feeee88ad468a3
A(3) = HMAC_SHA256(master_secret, A(2)) = 5783e391ea9f845fe698a4a48a9846700ffb64c60b72fd408d09c68f3929513a

HMAC_hash(master_secret, A(1) + seed) = 
1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
HMAC_hash(master_secret, A(2) + seed) = 
af14436461232f2786d91eaf9ea2465e20cb7f7ea796fd9a3cbeac872f3a5276
HMAC_hash(master_secret, A(3) + seed) = 
2b492656fc20fc2b103fc49e707bd65826203fabe4fe7aa49f18e4d66a5189fc

key_block = PRF(master_secret, seed) = P_SHA256(master_secret, seed) = HMAC_SHA256(master_secret, A(1) + seed) + HMAC_SHA256(master_secret, A(2) + seed) + HMAC_SHA256(master_secret, A(3) + seed)

得到key_block = 1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1af14436461232f2786d91eaf9ea2465e20cb7f7ea796fd9a3cbeac872f3a52762b492656fc20fc2b103fc49e707bd65826203fabe4fe7aa49f18e4d66a5189fc

client_write_MAC_key[32] = 1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
server_write_MAC_key[32] = af14436461232f2786d91eaf9ea2465e20cb7f7ea796fd9a3cbeac872f3a5276
client_write_key[16] = 2b492656fc20fc2b103fc49e707bd658
server_write_key[16] = 26203fabe4fe7aa49f18e4d66a5189fc

到这里,用于加密及计算MAC的密钥已经得到了

接下来解析finished message,还是先介绍理论依据,根据RFC5246#section-7.4.9,Finished message定义如下,包含了12字节的verify_data

struct {
  opaque verify_data[verify_data_length];
} Finished;

verify_data
  PRF(master_secret, finished_label, Hash(handshake_messages))
  [0..verify_data_length-1];

finished_label
  For Finished messages sent by the client, the string "client finished".  For Finished messages sent by the server, the string "server finished".

Any cipher suite which does not explicitly specify verify_data_length has a verify_data_length equal to 12

the Hash MUST be the Hash used as the basis for the PRF

All of the data from all messages in this handshake (not including any HelloRequest messages) up to, but not including, this message.  This is only data visible at the handshake layer and does not include record layer headers.

接下来介绍TLS-PSK是如何对消息进行MAC的计算及加密的,需要特别注意的是上述例子client与server协商使用了encrypt-then-mac extension,MAC的计算需要参考RFC7366#section-3

Once the use of encrypt-then-MAC has been negotiated, processing of TLS/DTLS packets switches from the standard:

encrypt( data || MAC || pad )

to the new:

encrypt( data || pad ) || MAC

with the MAC covering the entire packet up to the start of the MAC value.
for TLS 1.1 and greater with an explicit IV is:

MAC(MAC_write_key, seq_num +
    TLSCipherText.type +
    TLSCipherText.version +
    TLSCipherText.length +
    IV +
    ENC(content + padding + padding_length));

The overall TLS packet is then:
struct {
       ContentType type;
       ProtocolVersion version;
       uint16 length;
       GenericBlockCipher fragment;
       opaque MAC;
} TLSCiphertext;

sequence number见RFC5246#section-6.1

sequence number Each connection state contains a sequence number, which is maintained separately for read and write states. The sequence number MUST be set to zero whenever a connection state is made the active state. Sequence numbers are of type uint64 and may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS implementation would need to wrap a sequence number, it must renegotiate instead. A sequence number is incremented after each record: specifically, the first record transmitted under a particular connection state MUST use sequence number 0.

个人理解简单来说就是一个8字节的值,初始值为0,client及server针对接收和发送消息都维护自己的两个sequence number,每次接收消息后read sequence number + 1,每次发送消息后write sequence number+1

而加密规则还是需要参考RFC5246#section-6.2.3,要注意GenericBlockCipher中的MAC计算以RFC7366规范为准

struct {
  ContentType type;
  ProtocolVersion version;
  uint16 length;
  select (SecurityParameters.cipher_type) {
      case stream: GenericStreamCipher;
      case block:  GenericBlockCipher;
      case aead:   GenericAEADCipher;
  } fragment;
} TLSCiphertext;

struct {
    opaque IV[SecurityParameters.record_iv_length];
    block-ciphered struct {
        opaque content[TLSCompressed.length];
        opaque MAC[SecurityParameters.mac_length];
        uint8 padding[GenericBlockCipher.padding_length];
        uint8 padding_length;
  };
} GenericBlockCipher;

接下来代入具体数值还原client finished message

###### 计算verify data ######

handshake_messages = client hello + client hello + server hello + server hello done + client key exchange = 
010000790303369e43088760b8b1e061cdd81f4bab5ee13808c2d9d5509d92613eaf6255f6be00000400ae00ff0100004c0000000e000c0000096c6f63616c686f7374002300000016000000170000000d002a0028040305030603080708080809080a080b080408050806040105010601030303010302040205020602020000550303c5b4a2ca4efb20217475fc9f917838ee4730748f8ed9e456a9bf940d55ebcb22209ee6cbc277addb290552ebce6081fa7143635b9bc93184f08809dcd0218aff4800ae00000dff0100010000160000001700000e0000001000000b00096d795f70736b5f6964

SHA256(handshake_messages) = d08e6ed25877545d37396ff946bc0c2c9a99b74732ec025bce300814a42e0ff7

A(0) = seed = "client finished" + SHA256(handshake_messages) = 636C69656E742066696E6973686564d08e6ed25877545d37396ff946bc0c2c9a99b74732ec025bce300814a42e0ff7
A(1) = HMAC_SHA256(master_secret, A(0)) = 44486e65f5bec93fa356cb38d09e0186bf7e5d9176f2021a79239ac1762e2158

HMAC_SHA256(master_secret, A(1) + seed) = b776a81f5cb028809bf74714e1bda48063764d61b56b8ef6c9a1186958f18092

verify_data = PRF(master_secret, seed)[0..11] = P_SHA256(master_secret, seed)[0..11] = HMAC_SHA256(master_secret, A(1) + seed)[0..11] = b776a81f5cb028809bf74714

###### 校验MAC ######

client finisded message
16 03 03 00 50 98 9c 70 7f 7b b2 d1 9d 38 70 c1 b0 81 8d 60 97 07 cd 28 0b 61 64 bf ae 46 08 22 90 34 56 82 3a 5e b4 4a e0 51 bd df 9b 34 44 92 67 1b 6c 22 44 60 92 03 e8 d4 f7 09 12 37 56 30 b7 ae 1f 7b 67 58 d5 72 ce 4e 36 89 a6 5a 90 d3 15 2f 53 1a 6c 

由引用的规范说明可知finished message的fragment由IV,block-ciphered text,MAC三部分组成,因此其中密文部分组成如下
iv: 989c707f7bb2d19d3870c1b0818d6097
block-ciphered text: 07cd280b6164bfae460822903456823a5eb44ae051bddf9b344492671b6c2244
mac: 609203e8d4f70912375630b7ae1f7b6758d572ce4e3689a65a90d3152f531a6c

MAC_write_key = client_write_MAC_key = 1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
TLSCipherText.seq_num = 0000000000000000
TLSCipherText.type = 16
TLSCipherText.version = 0303
TLSCipherText.length = 0050 - 0020 = 0030 # 这里要特别注意要先减掉MAC的长度
ENC(content + padding + padding_length) = 07cd280b6164bfae460822903456823a5eb44ae051bddf9b344492671b6c2244

MAC(MAC_write_key, seq_num +
 TLSCipherText.type +
 TLSCipherText.version +
 TLSCipherText.length +
 IV +
 ENC(content + padding + padding_length)) = 609203e8d4f70912375630b7ae1f7b6758d572ce4e3689a65a90d3152f531a6c

$ echo "00000000000000001603030030989c707f7bb2d19d3870c1b0818d609707cd280b6164bfae460822903456823a5eb44ae051bddf9b344492671b6c2244" | xxd -r -p | openssl dgst -sha256 -mac hmac -macopt hexkey:1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
结果:609203e8d4f70912375630b7ae1f7b6758d572ce4e3689a65a90d3152f531a6c

得到的MAC与实际抓包数据一致

###### 解密block-ciphered text ######

client_write_key = 2b492656fc20fc2b103fc49e707bd658
block-ciphered text = 07cd280b6164bfae460822903456823a5eb44ae051bddf9b344492671b6c2244
iv = 989c707f7bb2d19d3870c1b0818d6097

$ echo "07cd280b6164bfae460822903456823a5eb44ae051bddf9b344492671b6c2244" | xxd -r -p | openssl aes-128-cbc -d -K 2b492656fc20fc2b103fc49e707bd658 -iv 989c707f7bb2d19d3870c1b0818d6097 -nopad | xxd -p
结果:1400000cb776a81f5cb028809bf747140f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f

14 - handshake type:finished
00000c - length
b776a81f5cb028809bf74714 - verify data
0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f - padding[padding_length] + padding_length

解密后得到的verify_data与前面计算结果一致

Server finished message的解析过程类似,理论层面不再赘述,直接代入具体数值计算

###### 计算verify data ######
handshake_messages = client hello + client hello + server hello + server hello done + client key exchange + client finished = 010000790303369e43088760b8b1e061cdd81f4bab5ee13808c2d9d5509d92613eaf6255f6be00000400ae00ff0100004c0000000e000c0000096c6f63616c686f7374002300000016000000170000000d002a0028040305030603080708080809080a080b080408050806040105010601030303010302040205020602020000550303c5b4a2ca4efb20217475fc9f917838ee4730748f8ed9e456a9bf940d55ebcb22209ee6cbc277addb290552ebce6081fa7143635b9bc93184f08809dcd0218aff4800ae00000dff0100010000160000001700000e0000001000000b00096d795f70736b5f69641400000cb776a81f5cb028809bf74714

要特别注意上面拼接的client finished是加密前的消息体:1400000cb776a81f5cb028809bf74714

A(0) = seed = "server finished" + SHA256(handshake_messages) = 7365727665722066696e6973686564f9387601c17d5a57310b1828cf9b4a7df5e0933e8e89b92ef50f89f7c992a61b
A(1) = HMAC_SHA256(master_secret, A(0)) = bb74f4bb302f4772c8c3392daa762cac19ec98646eff3af80c8cdbff062dc923

HMAC_SHA256(master_secret, A(1) + seed) = ae30c192dbcd56cbcc927f0576b392cfbfb2a25d0745be165cfb0610fc69bc2f

verify_data = PRF(master_secret, seed)[0..11] = P_SHA256(master_secret, seed)[0..11] = HMAC_SHA256(master_secret, A(1) + seed)[0..11] = ae30c192dbcd56cbcc927f05

###### 校验MAC ######
16 03 03 00 50 41 54 6e f1 7a 2a 3f 1d 0f 26 29 95 7f ba 0a f2 d8 4b 4a 9a c5 b3 b4 71 2e ef 70 fa 39 17 5e cc 90 9f 33 16 c2 e3 ad 4a 3c 95 f1 fe 90 cd cc a1 98 d8 7c 0a b4 d6 50 3a fa 6a 16 f5 6e ff 06 77 a7 f4 66 db d2 fb b4 be cf 8d 7b c8 7c 78 78 71 

iv: 41546ef17a2a3f1d0f2629957fba0af2
block-ciphered text: d84b4a9ac5b3b4712eef70fa39175ecc909f3316c2e3ad4a3c95f1fe90cdcca1
mac: 98d87c0ab4d6503afa6a16f56eff0677a7f466dbd2fbb4becf8d7bc87c787871

MAC_write_key = server_write_MAC_key = af14436461232f2786d91eaf9ea2465e20cb7f7ea796fd9a3cbeac872f3a5276
TLSCipherText.seq_num = 0000000000000000
TLSCipherText.type = 16
TLSCipherText.version = 0303
TLSCipherText.length = 0050 - 0020 = 0030 # 减掉MAC的长度
ENC(content + padding + padding_length) = d84b4a9ac5b3b4712eef70fa39175ecc909f3316c2e3ad4a3c95f1fe90cdcca1

MAC(MAC_write_key, seq_num +
 TLSCipherText.type +
 TLSCipherText.version +
 TLSCipherText.length +
 IV +
 ENC(content + padding + padding_length)) = 98d87c0ab4d6503afa6a16f56eff0677a7f466dbd2fbb4becf8d7bc87c787871

$ echo "0000000000000000160303003041546ef17a2a3f1d0f2629957fba0af2d84b4a9ac5b3b4712eef70fa39175ecc909f3316c2e3ad4a3c95f1fe90cdcca1" | xxd -r -p | openssl dgst -sha256 -mac hmac -macopt hexkey:af14436461232f2786d91eaf9ea2465e20cb7f7ea796fd9a3cbeac872f3a5276
结果:98d87c0ab4d6503afa6a16f56eff0677a7f466dbd2fbb4becf8d7bc87c787871

得到的MAC与实际抓包数据一致

###### 解密block-ciphered text ######
server_write_key = 26203fabe4fe7aa49f18e4d66a5189fc
block-ciphered text = d84b4a9ac5b3b4712eef70fa39175ecc909f3316c2e3ad4a3c95f1fe90cdcca1
iv = 41546ef17a2a3f1d0f2629957fba0af2

$ echo "d84b4a9ac5b3b4712eef70fa39175ecc909f3316c2e3ad4a3c95f1fe90cdcca1" | xxd -r -p | openssl aes-128-cbc -d -nopad -K 26203fabe4fe7aa49f18e4d66a5189fc -iv 41546ef17a2a3f1d0f2629957fba0af2  | xxd -p
结果:1400000cae30c192dbcd56cbcc927f050f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f

14 - handshake type:finished
00000c - length
ae30c192dbcd56cbcc927f05 - verify data
0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f - padding[padding_length] + padding_length

解密后得到的verify_data与前面计算结果一致

client application data及server application data的加密及MAC计算与Finished也是一样的,这里只演示client application data的计算

###### 校验MAC ######
Client Application Data

17 03 03 00 40 19 77 d0 be 1f b4 83 f9 53 6d 8c f5 06 05 b3 10 e9 98 68 ed bf 30 93 e1 74 cc 22 3a 3b 31 a3 93 26 e2 0c 1c c3 c8 eb d9 f6 ec 11 5a b5 a1 bd 65 7c 28 e4 5b 0d c5 08 65 b7 f3 4a 93 91 83 8a 3a 

iv:1977d0be1fb483f9536d8cf50605b310
block-ciphered text:e99868edbf3093e174cc223a3b31a393
mac:26e20c1cc3c8ebd9f6ec115ab5a1bd657c28e45b0dc50865b7f34a9391838a3a

MAC_write_key = client_write_MAC_key = 1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
TLSCipherText.seq_num = 0000000000000001
TLSCipherText.type = 17
TLSCipherText.version = 0303
TLSCipherText.length = 0040 - 0020 = 0020 # 减掉MAC的长度
ENC(content + padding + padding_length) = e99868edbf3093e174cc223a3b31a393

MAC(MAC_write_key, seq_num +
 TLSCipherText.type +
 TLSCipherText.version +
 TLSCipherText.length +
 IV +
 ENC(content + padding + padding_length)) = 26e20c1cc3c8ebd9f6ec115ab5a1bd657c28e45b0dc50865b7f34a9391838a3a

$ echo "000000000000000117030300201977d0be1fb483f9536d8cf50605b310e99868edbf3093e174cc223a3b31a393" | xxd -r -p | openssl dgst -mac hmac -sha256 -macopt hexkey:1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
结果:26e20c1cc3c8ebd9f6ec115ab5a1bd657c28e45b0dc50865b7f34a9391838a3a

得到的MAC与实际抓包数据一致

###### 解密block-ciphered text ######
client_write_key = 2b492656fc20fc2b103fc49e707bd658
block-ciphered text = e99868edbf3093e174cc223a3b31a393
IV = 1977d0be1fb483f9536d8cf50605b310

$ echo "e99868edbf3093e174cc223a3b31a393" | xxd -r -p | openssl enc -aes-128-cbc -d -nopad -K 2b492656fc20fc2b103fc49e707bd658 -iv 1977d0be1fb483f9536d8cf50605b310 | xxd -p
结果:6869207365727665720a050505050505

6869207365727665720a - hi server\n
050505050505 - padding[padding_length] + padding_length

得到client发送的明文是"hi server\n"

解密Alert(Client Close Notify)

###### 校验MAC ######
15 03 03 00 40 4f aa 08 0c ec c9 19 a0 87 e5 8d f8 69 49 70 54 ac bf 46 58 d5 76 18 1e 22 77 57 1b 86 9d 03 c5 b5 4d 7b 2b a1 e8 29 00 07 23 41 be e6 ad c0 23 61 ec b6 d3 83 dd 0f ed 06 43 c5 03 c9 89 4c ac 

iv:4faa080cecc919a087e58df869497054
block-ciphered text:acbf4658d576181e2277571b869d03c5
mac:b54d7b2ba1e82900072341bee6adc02361ecb6d383dd0fed0643c503c9894cac

MAC_write_key = client_write_MAC_key = 1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
TLSCipherText.seq_num = 0000000000000002
TLSCipherText.type = 15
TLSCipherText.version = 0303
TLSCipherText.length = 0040 - 0020 = 0020 # 减掉MAC的长度
ENC(content + padding + padding_length) = acbf4658d576181e2277571b869d03c5

MAC(MAC_write_key, seq_num +
 TLSCipherText.type +
 TLSCipherText.version +
 TLSCipherText.length +
 IV +
 ENC(content + padding + padding_length)) = b54d7b2ba1e82900072341bee6adc02361ecb6d383dd0fed0643c503c9894cac

$ echo "000000000000000215030300204faa080cecc919a087e58df869497054acbf4658d576181e2277571b869d03c5" | xxd -r -p | openssl dgst -mac hmac -sha256 -macopt hexkey:1ae8a34eaeee0c7a2023ebdc307427736ca15a69f76e933f10f7bdd6c7ea4ac1
结果:b54d7b2ba1e82900072341bee6adc02361ecb6d383dd0fed0643c503c9894cac

得到的MAC与实际抓包数据一致

###### 解密block-ciphered text ######
client_write_key = 2b492656fc20fc2b103fc49e707bd658
block-ciphered text = acbf4658d576181e2277571b869d03c5
IV = 4faa080cecc919a087e58df869497054

$ echo "acbf4658d576181e2277571b869d03c5" | xxd -r -p | openssl enc -aes-128-cbc -d -nopad -K 2b492656fc20fc2b103fc49e707bd658 -iv 4faa080cecc919a087e58df869497054 | xxd -p
结果:01000d0d0d0d0d0d0d0d0d0d0d0d0d0d

01 - level: Warning
00 - description: close notify
0d0d0d0d0d0d0d0d0d0d0d0d0d0d - padding[padding_length] + padding_length