tls为什么要分为两层协议(HTTPS温故知新四)
Go语言中文网,致力于每日分享编码、开源等知识,欢迎关注我,会有意想不到的收获!
这是 直观感受 TLS 握手流程 最后一部分。
十. 直观感受 TLS 1.3 会话恢复这一章,笔者用 wireshark 抓取 TLS 1.3 会话恢复中的数据包,让读者直观感受一下 TLS 1.3 会话恢复流程。
1. PSK 会话恢复
这是 TLS 1.3 会话恢复的完整流程。
上面这 4 个扩展是 TLS 1.3 PSK 会话恢复中 ClientHello 必须配置的。psk_key_exchange_modes、pre_shared_key、key_share、supported_versions。
上面这 3 个扩展是 TLS 1.3 PSK 会话恢复中 ServerHello 必须配置的。pre_shared_key、key_share、supported_versions。
一旦 PSK 校验完成,Server 就不需要再次发送证书了,直接回应 ChangeCipherSpec、Encrypted Extensions、Finished 即可完成会话恢复。
2. 0-RTT
截止到笔者写这篇文章为止,当前主流浏览器对 TLS 1.3 的支持度如下图。
Google Chrome Canary 最新 74.0.3702.0 还不能支持 0-RTT 模式,Firefox Nightly 最新 67.0a1 可以支持 0-RTT 模式(在 about:config 中 security.tls.enable_0rtt_data 设置为 true),Safari 最新的 12.0.3 (14606.4.5) 还不能支持 0-RTT 模式。所以笔者只能用 Firefox Nightly 抓取 0-RTT 的包。
当然 OpenSSL 最新版 1.1.1a 的 Client 是支持发送 early_data 的,也就是支持 0-RTT 的,用它来调试 TLS 1.3 0-RTT 也更加方便。
先来看看支持 0-RTT 的 Firefox Nightly 抓到的包是怎么样的。
可以发现整个会话恢复过程满足了 0-RTT 的条件,所以 0-RTT 开启成功。
在用 OpenSSL 的 Client 来测试测试 0-RTT。
先将必要参数导出来,比如协商的密钥和 session 信息。
$ openssl s_client -connect halfrost.com:443 -tls1_3 -keylogfile=/Users/ydz/Documents/sslkeylog.log -sess_out=/Users/ydz/Documents/tls13.sess
输出如下:
CONNECTED(00000006) depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify error:num=20:unable to get local issuer certificate --- Certificate chain 0 s:CN = halfrost.com i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 i:O = Digital Signature Trust Co., CN = DST Root CA X3 2 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 i:O = Digital Signature Trust Co., CN = DST Root CA X3 --- Server certificate -----BEGIN CERTIFICATE----- MIIEljCCA36gAwIBAgISA9VdA6rPN6mIzBxEPL/3iAICMA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTAyMTAwMTQxMjJaFw0x OTA1MTEwMTQxMjJaMBcxFTATBgNVBAMTDGhhbGZyb3N0LmNvbTBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABA7sYzIwq29BkT1mQ2TSZRPe34BlnuqN65xoLY A87M8 PpblV0IvNyj4ZdcgiSmSZffocVF6wzck6TmsQ/j2/sujggJyMIICbjAOBgNVHQ8B Af8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB /wQCMAAwHQYDVR0OBBYEFOD4YIpf PkD1Jvy eayPn0csEi/MB8GA1UdIwQYMBaA FKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAuBggrBgEFBQcw AYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAvBggrBgEFBQcw AoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8wKQYDVR0RBCIw IIIMaGFsZnJv\ghfhjghjjbmd3cuaGFsZnJvc3QuY29tMEwGA1UdIARFMEMwCAYG Z4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMu bGV0c2VuY3J5cHQub3JnMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDvAHUA4mlLribo 6UAJ6IYbtjuD1D7n/nSI 6SPKJMBnd3x2/4AAAFo1UfZTgAABAMARjBEAiAsXJLC A5uO2R926Dba3fZpV/zvzG9tCPVtTKAeso5bAwIgMXoLRtLqhG5bEcXIpGXJcrd0 6S8tbUdS9YRAIWpMX1oAdgApPFGWVMg5ZbqqUPxYB9S3b79Yeily3KTDDPTlRUf0 eAAAAWjVR9lQAAAEAwBHMEUCIHv6NJ9MWMiL AHxU8ilL3APMmPkUcc03SjBiDaW Vm6JAiEA5YF/XHKuYH0S0 mqfB YdT0FIey9wFQObkR4/Qvzla4wDQYJKoZIhvcN AQELBQADggEBAHU7a EgzdhrsyD 2ch7AGD1n1TjDfdxkEjmoitN0Tjh4q3jP/IK 7FPs0LBsDRusmtJVK3gZQc9cTEy/om86VQtcnV0LhK83GnFUIuLTEzeTZmnz6Qbs 3KznprZH0DRUbfpmZsDNIfBEOUOXiBR4DpLd3tPVfRkQowmO6o39vM4UOGlB0zIA g977q97IT6wS9BCEiGmuF0HSjpLfiPhTy9bpl2VGcJVpIy2TS d4 JWRI7K5BFSz ncGDzHJ zGsx4wS dxuiwaS9hw4c0FG2V4kMFnA orAa/oTnfwFlRIehTbDBO rN TNtjm4yh63M9gInoQEI1REl2EkGcWug6Ijs= -----END CERTIFICATE----- subject=CN = halfrost.com issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 --- No client certificate CA names sent Peer signing digest: SHA256 Peer signature type: ECDSA Server Temp Key: X25519, 253 bits --- SSL handshake has read 3912 bytes and written 316 bytes Verification error: unable to get local issuer certificate --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Server public key is 256 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 20 (unable to get local issuer certificate) --- --- Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_AES_256_GCM_SHA384 Session-ID: DECE5063ABC2D1162A5E767C55083FDFFA6A86B64082FE3AD990A213AE Session-ID-ctx: Resumption PSK: EACCC93ACB3DC420DF5027BEC576EE130D11BF546463034C1BB92B54806057E0C9F5C3DB557AD10D425E PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 86400 (seconds) TLS session ticket: 0000 - 0b 8d e5 44 b2 62 71 9d-f9 0a ec da f0 d0 6a 0b ...D.bq.......j. 0010 - 97 5d 63 21 ea 1e 8a 69-01 52 a9 0a 19 bf 5c a3 .]c!...i.R....\. 0020 - 67 45 a3 a0 28 65 ea 9c-c8 d4 cf df 5d c5 5a be gE..(e......].Z. 0030 - 32 45 0d 1e af f7 32 67-4a d8 66 cb b6 cb c8 0e 2E....QgJ.f..... 0040 - 6b b8 53 a8 d2 d4 4b 7b-cc a6 cb 52 39 61 20 6d k.S...K{...R9a m 0050 - 75 f8 cb 43 11 1d 58 a2-de 2b 74 b0 ca 70 a2 9c u..C..X.. t..p.. 0060 - 85 6b 1a 00 9a f1 bd 9b-8c b4 5a 41 aa 4b 64 5d .k........ZA.Kd] 0070 - 5a 48 23 a6 10 49 4f 61-c9 57 74 f4 56 50 83 1a ZH#..IOa.Wt.VP.. 0080 - 1b 74 6c ea 09 99 42 f5-d6 3c 6d 4f 5b 98 ca b3 .tl...B..<mO.... 0090 - c7 72 56 5c 6c 67 71 77-8d 68 f7 54 e5 e3 7b d3 .rV\lgqw.h.T..{. 00a0 - 24 ff 42 0c 3f 12 27 42-7f 9e 0a 4c c2 79 60 45 $.B.?.'B...L.y`E 00b0 - 2d 77 a2 c8 2f f5 85 34-fa ce 79 ee 0b ea 00 c1 -w../..4..y..... 00c0 - 74 33 f0 6c af 7a 1a 55-f8 35 bd 5e 49 66 6f 06 t3.l.z.U.5.^Ifo. 00d0 - c6 38 ed a6 82 e2 c8 77-99 b7 34 9a 4a 9a 31 40 .8.....w..4.J.1@ 00e0 - f1 93 a0 94 7f 1e 8d e0-54 29 dc e3 6f 5c 93 21 ........T)..o\.! Start Time: 1549886406 Timeout : 7200 (sec) Verify return code: 20 (unable to get local issuer certificate) Extended master secret: no Max Early Data: 16384 --- read R BLOCK --- Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_AES_256_GCM_SHA384 Session-ID: B7E28DE5DF2C95F2E3DE43732E4F9A45A8943ED3856B73CAB5E7260E7 Session-ID-ctx: Resumption PSK: BF2BA2304BEB2B948F7BF6617D0KDRNFB9CD5466DEC1EB9697D2543B7BB913BC7854359D7F5DF7559D67 PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 86400 (seconds) TLS session ticket: 0000 - 0b 8d e5 44 b2 62 71 9d-f9 0a ec da f0 d0 6a 0b ...D.bq.......j. 0010 - b4 9f cc 17 63 9a 70 c8-63 f8 2e c4 9f d4 a1 f8 ....c.p.c....... 0020 - 22 34 22 03 d0 f9 78 66-a0 d4 2f 62 53 d3 d8 e3 "4"...xf../bS... 0030 - 55 2c a5 7c 0b 19 b3 fc-77 55 8c de 0b 2d 00 bd U,.|....wUL..-.. 0040 - b8 fa 2e 00 30 78 c8 dc-35 14 d3 61 f0 69 38 59 ...%0x..5..a.i8Y 0050 - ee 2a 75 7e 50 34 3f e3-25 04 71 1c 6e c9 c8 20 .*u~P4?.%.q.n.. 0060 - d7 4e 44 b3 69 56 50 23-38 c2 f1 1e ac 10 a7 ff .ND.iVP#8....... 0070 - 96 cf fe ff 4d 07 7e 08-2d 37 49 78 ab 1d 78 6e ....M.~.-7Ix..xn 0080 - 62 4b 99 e7 37 03 3e a2-89 de 61 48 a1 c5 77 18 bK..7.>...aH..w. 0090 - 6f 1c 95 8a 0d 1d 17 68-88 8a 01 5b f0 dc ea 06 o......h...[.... 00a0 - 98 dc 7e 94 f8 ef 4a 72-ff ba e5 03 07 c7 3d d0 ..~...Jr......=. 00b0 - c8 91 a6 ae 9a df 92 25-05 63 77 03 b0 bc b4 ab .......%.c...... 00c0 - 36 cb 0f 8c 5d ec 58 65-7c 97 2a 30 57 4a 96 b9 6...].Xe|.*0WJ.. 00d0 - 60 21 12 76 77 4c 6d 0d-12 0c 50 cc f5 da 54 4e `!.vwLm...P...TN 00e0 - 4b 27 5f 1b dd 11 b1 8d-7f e0 37 43 34 a3 88 34 K'_.......7C4..4 Start Time: 1549886406 Timeout : 7200 (sec) Verify return code: 20 (unable to get local issuer certificate) Extended master secret: no Max Early Data: 16384 --- read R BLOCK
接下来在复用刚刚的连接,命令如下:
$ openssl s_client -connect halfrost.com:443 -tls1_3 -keylogfile=/Users/ydz/Documents/sslkeylog.log -sess_in=/Users/ydz/Documents/tls13.sess -early_data=/Users/ydz/Documents/req.txt
req.txt 里面只是简单的写一个 GET 请求:
GET / HTTP/1.1 HOST: halfrost.com Early-Data: 657567765
执行 s_client 以后,输出如下:
CONNECTED(00000006) --- Server certificate -----BEGIN CERTIFICATE----- MIIElzCCA3 gAwIBAgISA604VEs 7Wwch5cNQDshC4t MA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODEyMDgxMzQzMzhaFw0x OTAzMDgxMzQzMzhaMBcxFTATBgNVBAMTDGhhbGZyb3N0LmNvbTBZMBMGByqGSM49 AgEGCCqGSM49AwEHA0IABA7sYzIwq29BkT1mQ2TSZRPe34BlnuqN65xoLY A87M8 PpblV0IvNyj4ZdcgiSmSZffocVF6wzck6TmsQ/j2/sujggJzMIICbzAOBgNVHQ8B Af8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB /wQCMAAwHQYDVR0OBBYEFOD4YIpf PkD1Jvy eayPn0csEi/MB8GA1UdIwQYMBaA FKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAuBggrBgEFBQcw AYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAvBggrBgEFBQcw AoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8wKQYDVR0RBCIw IIIMaGFsZnJvc3QuY29tghB3d3cuaGFsZnJvc3QuY29tMEwGA1UdIARFMEMwCAYG Z4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMu bGV0c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHUA4mlLribo 73qkwe6lN9vZWu1dJV8 Q41cFLGYMJhDD56x7QIgL V6g1CQst9UDXobdkAEnjah KiJWihr/Qn3plzgzjiIAdwApPFGWVMg5ZbqqUPxYB9S3b79Yeily3KTDDPTlRUf0 eAAAAWeORhq2AAAEAwBIMEYCIQD1Mf1GtmegyTqIu0S3Q4afNDt0srIFyrtROtn0 jQAV1gIhAJwXIGyMj87kjHtRc/mHJOOCZRSUvoasvWrytCv2dPwXMA0GCSqGSIb3 DQEBCwUAA4IBAQB3sC7jKVGHR8MnAOWnECO/V5Z4oBqbahogwyhOSrbxuutijhyk 8kb3A73Q Ey150Y hlNUQStmG9JBGg9pyLG2Yug9p5L13a6VrNaL1VQ1Dq6YgS5 5J8ElsalUgr 9jvTJesdYzfXPdsc8IK67tBXhukqc0/cT3I1QHNwAVru/AKWrkne H4AcadSeLGe5he2X9OV3JJg gb/vE90UaVmqwUuSGMzluyBXPMuznTa/ 7 31vWV Q8aWE32X E5qHSyeLU808mZHYjvKHvuDnNNu6I0KlNcVJf1s0jOQOjgo7hIP/OR4 OlW6ywk07IupV4w07xykP1/tWBsSCviXECcZ -----END CERTIFICATE----- subject=CN = halfrost.com issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 --- No client certificate CA names sent Server Temp Key: X25519, 253 bits --- SSL handshake has read 245 bytes and written 649 bytes Verification error: unable to get local issuer certificate --- Reused, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Server public key is 256 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was accepted Verify return code: 20 (unable to get local issuer certificate) ---
从输出中可以看到 Early data was accepted。这个时候转到 wireshark,看抓到的包是怎么样的。
可以看到 Client 在 ClientHello 之后,就立即发送了 Application Data。
在 wireshark 中首选项,把下图中的勾去掉。
配置生效以后,可以看到 Application Data 里面的请求了。
普通的 GET 请求中 header 中带了 Early-Data 的值。这个值就会传给 Server 处理了。
十一. TLS 1.3 的状态机TLS 1.3 相对 TLS 1.2 握手流程发生了巨大的变化,所以状态机也发生了巨大的变化。下面放 2 张状态流转图,最为总结,对应的也是本篇文章的精华。
START <---- Send ClientHello | | Recv HelloRetryRequest [K_send = early data] | | v | / WAIT_SH ---- | | Recv ServerHello | | K_recv = handshake Can | V send | WAIT_EE early | | Recv EncryptedExtensions data | -------- -------- | Using | | Using certificate | PSK | v | | WAIT_CERT_CR | | Recv | | Recv CertificateRequest | | Certificate | v | | | WAIT_CERT | | | | Recv Certificate | | v v | | WAIT_CV | | | Recv CertificateVerify | > WAIT_FINISHED < | | Recv Finished \ | [Send EndOfEarlyData] | K_send = handshake | [Send Certificate [ CertificateVerify]] Can send | Send Finished app data --> | K_send = K_recv = application after here v CONNECTED
这图是 Client 在握手流程上的状态机。如果读者还不清楚中间的某个步骤,可以对照上文中的内容查缺补漏。
START <----- Recv ClientHello | | Send HelloRetryRequest v | RECVD_CH ---- | Select parameters v NEGOTIATED | Send ServerHello | K_send = handshake | Send EncryptedExtensions | [Send CertificateRequest] Can send | [Send Certificate CertificateVerify] app data | Send Finished after --> | K_send = application here -------- -------- No 0-RTT | | 0-RTT | | K_recv = handshake | | K_recv = early data [Skip decrypt errors] | ------> WAIT_EOED - | | Recv | | Recv EndOfEarlyData | | early data | | K_recv = handshake | ------------ | | | > WAIT_FLIGHT2 <-------- | -------- -------- No auth | | Client auth | | | v | WAIT_CERT | Recv | | Recv Certificate | empty | v | Certificate | WAIT_CV | | | Recv | v | CertificateVerify -> WAIT_FINISHED <--- | Recv Finished | K_recv = application v CONNECTED
这图是 Server 在握手流程上的状态机。如果读者还不清楚中间的某个步骤,可以对照上文中的内容查缺补漏。读者能理解透上面这 2 张状态机,TLS 1.3 也就掌握透彻了。
全文完。
- Reference:
- RFC 8466
- TLS1.3 draft-28
GitHub Repo:Halfrost-Field
Follow: halfrost · GitHub
Source: https://halfrost.com/HTTPS_handshake/
本文作者:于德志 (@halfrost),原创授权发布
,
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com