1 简介

1.1 常用排查思路

在客户端访问 HTTPS 服务器时关于 TLS 的相关问题常见有:密码套件协商失败、证书过期等。定位手段可以使用如下命令:

1
2
curl -vk https://www.example.com
strace openssl s_client -tlsextdebug -connect www.example.com:443

通过 OpenSSL 命令可以看到访问的更多信息。

另外为了查看 TLS 握手过程,可以通过 tcpdump、wireshark 等工具进行抓包。

1.2 常用工具

在发现 密码套件协商失败或者TLS握手中某些扩展参数协商失败(椭圆曲线选择),可以通过 工具扫描查看服务器支持的密码套件和椭圆曲线等。

  • nmap

安装nmap工具:首先需要在Linux系统上安装nmap工具。可以通过包管理器(如apt、yum等)进行安装,或者从官方网站下载并编译安装。
运行nmap扫描:使用以下命令运行nmap扫描,以获取目标服务器支持的TLS协议和密码套件信息:

1
nmap --script ssl-enum-ciphers -p 443 <目标IP地址>

image.png

2 问题处理

2.1 问题现象

本次出现的问题是WAF产品在接入一家客户的网站后,访问网站出现响应码502的情况,查看WAF的日志显示如下:

1
SSL_do_handshake() failed(SSL:error:0A000132:SSL routines::bad ecpoint) while SSL handshaking to upstream, client:xx.xx.xx.xx, server: xxx.xxx.xxx.xxx, request: "GET / HTTP/1.1", upstream: "https://xxx.xxx.xxx.xxx",

根据日志可知,是WAF在回源访问源站时 TLS 握手发生错误,导致无法访问源站,所以返回给客户端502的响应码。

在ubuntu22.04上使用curl直接访问网站报错如下:
image.png

2.2 问题分析

客户网站的情况是必须使用HTTPS访问,并且同时支持国密和非国密的访问,因为是接入WAF后访问报错,首先尝试了在不经过WAF的情况下直接访问客户的网站,发现使用浏览器可以正常访问,但是在linux 系统上使用curl访问同样报错 “curl: (35) error:0A000132:SSL routines::bad ecpoint”,与WAF上的日志报错一样。

根据以上报错怀疑是在 TLS 握手过程中使用的椭圆曲线相关问题,导致握手失败,下边分别在使用浏览器访问源站(成功访问)和 使用curl命令访问(失败访问)进行抓包查看:

  • curl访问
    image.png

通过查看数据包,可以确定,服务器响应了 Server Hello 和 Server key Exchange 说明 密码套件 协商成功,然后根据报错情况,也可以确定 不是服务器证书问题。

image.png
根据Server key exchange 数据包可知,此次服务器选择的是 x448 椭圆曲线。

  • 浏览器访问

image.png

image.png

通过抓取浏览器访问成功的情况,可以看到协商的密码套件为“TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)”,与上边curl访问时协商的密码套件是一样的,根据 Server Key Exchange 数据包可可知,服务器选择的 x25519 椭圆曲线。

2.3 Server Key Exchange 消息

这里介绍下 上边的 Server Key Exchange 消息,此消息在TLS握手过程中不是必须的,是在如果证书包含的 信息 不足以进行密钥交换,才会发送该消息。

  • 下列的密码套件,服务器会发送 Server Key Exchange 子消息。
    1
    2
    3
    4
    DHE_DSS
    DHE_RSA
    ECDHE_ECDSA
    ECDHE_RSA
    上述密码套件都是使用临时 DH/ECDHE 密码协商算法,客户端每次连接服务器的时候,服务器会发送动态 DH 信息(DH 参数和 DH 公钥),这些信息不存在证书中,需要通过 Server Key Exchange 消息传递,传递的 DH 信息需要使用服务器的私钥进行签名,该私钥和证书中包含的服务器公钥是一对。

2.4 问题排查过程

综上所述,可知,成功与失败访问协商的密码套件是一样的,都是 “TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)”,但选择椭圆曲线不同,成功访问时选择的 x25519 椭圆曲线,失败访问时选择的 x448 椭圆曲线。
因为选择的椭圆曲线不同,尝试升级 curl 命令,看更高版本中是否存在问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(base)  baihl@192# curl --version
curl 8.7.1 (x86_64-apple-darwin23.0) libcurl/8.7.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.12 nghttp2/1.61.0
Release-Date: 2024-03-27

(base) baihl@192 # curl -I https://xxx.xxx.xxx.xxx
HTTP/1.1 200 Connection established

HTTP/1.1 200
Server: nginx/1.22.0
Date: Sat, 28 Sep 2024 05:41:21 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Language: zh-CN
Expires: Sat, 28 Sep 2024 05:46:21 GMT
Cache-Control: max-age=300

使用 curl 8.7.1 版本 可以成功访问,访问出错的版本为 curl 7.81.0,OpenSSL/3.0.2,WAF 采用的 Tongsuo 8.4.0(为支持国密),是基于 OpenSSL 3.0.3,同样存在问题。

到此问题解决方法:就是升级 使用 LibreSSL/3.3.6 替换 OpenSSL,但是无法支持国密

2.4.1 指定椭圆曲线参数

根据上边可知,问题原因为 椭圆曲线问题,可以对比 LibreSSL/3.3.6 与 OpenSSL 3.0.3 ,查看为什么选择 x448 椭圆曲线时失败?
image.png
根据出错时访问的 Client Hello 数据包可知,客户端支持 x448,x25519 但是最终服务器选择了 x448 椭圆曲线,导致报错,所以可以通过强制指定椭圆曲线为 x25519 进行访问,这里使用 openssl 命令的 -curves 进行指定椭圆曲线:(访问成功)

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
(base) root@baihl-node:/home/mac-workspace# echo "GET / HTTP/1.1" | openssl s_client -connect xxx.xxx.xxx.xxx:443 -curves X25519
CONNECTED(00000003)
depth=2 C = CN, O = China Financial Certification Authority, CN = CFCA EV ROOT
verify return:1
depth=1 C = CN, O = China Financial Certification Authority, CN = CFCA OV OCA
verify return:1
depth=0 C = CN, ST = \E4\BA\91\E5\8D\97\E7\9C\81, L = \E6\98\86\E6\98\8E\E5\B8\82, O = \E4\BA\91\E5\8D\97\E7\9C\81\E5\95\86\E5\8A\A1\E5\8E\85\EF\BC\88\E4\BA\91\E5\8D\97\E7\9C\81\E4\BA\BA\E6\B0\91\E6\94\BF\E5\BA\9C\E5\8F\A3\E5\B2\B8\E5\8A\9E\E5\85\AC\E5\AE\A4\EF\BC\89, CN = swt.yn.gov.cn
verify return:1
---
Certificate chain
0 s:C = CN, ST = \E4\BA\91\E5\8D\97\E7\9C\81, L = \E6\98\86\E6\98\8E\E5\B8\82, O = \E4\BA\91\E5\8D\97\E7\9C\81\E5\95\86\E5\8A\A1\E5\8E\85\EF\BC\88\E4\BA\91\E5\8D\97\E7\9C\81\E4\BA\BA\E6\B0\91\E6\94\BF\E5\BA\9C\E5\8F\A3\E5\B2\B8\E5\8A\9E\E5\85\AC\E5\AE\A4\EF\BC\89, CN = swt.yn.gov.cn
i:C = CN, O = China Financial Certification Authority, CN = CFCA OV OCA
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Mar 23 07:00:16 2024 GMT; NotAfter: Dec 29 07:43:04 2024 GMT
1 s:C = CN, O = China Financial Certification Authority, CN = CFCA OV OCA
i:C = CN, O = China Financial Certification Authority, CN = CFCA EV ROOT
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Mar 25 02:02:56 2015 GMT; NotAfter: Dec 25 02:02:56 2029 GMT
2 s:C = CN, O = China Financial Certification Authority, CN = CFCA EV ROOT
i:C = CN, O = China Financial Certification Authority, CN = CFCA EV ROOT
a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA256
v:NotBefore: Aug 8 03:07:01 2012 GMT; NotAfter: Dec 31 03:07:01 2029 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIHCzCCBfOgAwIBAgIQIBUB/zRdykl8LUhd+qJ6wjANBgkqhkiG9w0BAQsFADBV
MQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmlj
YXRpb24gQXV0aG9yaXR5MRQwEgYDVQQDDAtDRkNBIE9WIE9DQTAeFw0yNDAzMjMw
NzAwMTZaFw0yNDEyMjkwNzQzMDRaMIGUMQswCQYDVQQGEwJDTjESMBAGA1UECAwJ
5LqR5Y2X55yBMRIwEAYDVQQHDAnmmIbmmI7luIIxRTBDBgNVBAoMPOS6keWNl+ec
geWVhuWKoeWOhe+8iOS6keWNl+ecgeS6uuawkeaUv+W6nOWPo+WyuOWKnuWFrOWu
pO+8iTEWMBQGA1UEAwwNc3d0LnluLmdvdi5jbjCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAIzk5OjyQJAuhyNinQjlRi80x+/nNjyDXP/kph6Irn+01aan
KFElMtv2HGY+jikJqbKcyc61IDYAPqJUbjPOw+L8wigaiJuz+E2wPjN6Bj3UuMn7
2WsoRAQfRqPJ8AcYxqPwz3oEDXwWDlUSkn0KDbgy//0bpSx1skesItDhxH0EnFGu
CRHzLZ1eAikMAfiWNgCWaeMKSn55g5IQQJj2KBRTWMrsoez/o7EqkxbF3YVcw7VA
gQTqy+4rCeDqr5N/FzJWj3nJrGo5Fd70b5Me2AdLZd9wYJREyQpgNWGV8HWTkEPQ
WKS4mAUvCYjhEkxV8pZm5WYCFPfchVyOZ04IPVsCAwEAAaOCA5UwggORMAwGA1Ud
EwEB/wQCMAAwbAYIKwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vb2Nz
cC5jZmNhLmNvbS5jbi9vY3NwMDIGCCsGAQUFBzAChiZodHRwOi8vZ3RjLmNmY2Eu
Y29tLmNuL292b2NhL292b2NhLmNlcjAnBgNVHREEIDAegg1zd3QueW4uZ292LmNu
gg1mdHoueW4uZ292LmNuMA4GA1UdDwEB/wQEAwIFoDAdBgNVHQ4EFgQU5uDv9qad
7oBmTr0RLnxpC3bYu8YwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMIIB
8wYKKwYBBAHWeQIEAgSCAeMEggHfAd0AdQDatr9rP7W2Ip+bwrtca+hwkXFsu1GE
hTS9pD0wSNf7qwAAAY5qHDRnAAAEAwBGMEQCIBa5Y5f2NR20fmEQkbOY1U8a5xqn
iKKnxnbEfV6k+xmgAiAWKzlHOCBmQlXCqCndY+L2Q2g1raN1XykEAMmYFGmLcQB1
AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8vOzew1FIWUZxH7WbAAABjmocNJIAAAQDAEYw
RAIgFoEv/kMB3M0YJOVq5rgOPcWz0lmqF1my8Ht6HtLo/TcCIHu1O6555hs9jQ55
4xN1EqOy6b8EhgOg5wLHrdOBNXMSAHYASLDja9qmRzQP5WoC+p0w6xxSActW3SyB
2bu/qznYhHMAAAGOahw1AwAABAMARzBFAiEA2nnlIoAKu3GngTs1ojdbA0rngbPx
ghs2e8Y5uISKTIMCIACAsdQLa1YueL7XLoKxXMsN+P1aYfLyik9bZeQy0LgAAHUA
dv+IPwq2+5VRwmHM9Ye6NLSkzbsp3GhCCp/mZ0xaOnQAAAGOahw2mwAABAMARjBE
AiA64pC2p0UfJxoW1f14mos+akU15XlaZvfDljU7A1A2CAIgAgCz/P08MOV1zIq6
4QBzqIxov/UChhPw1qMrIob3sh4wHwYDVR0jBBgwFoAUZrPv+1SVh+mspZZWruZ9
7TrQQ9EwRgYDVR0gBD8wPTA7BgZngQwBAgIwMTAvBggrBgEFBQcCARYjaHR0cDov
L3d3dy5jZmNhLmNvbS5jbi91cy91cy0xMi5odG0wPAYDVR0fBDUwMzAxoC+gLYYr
aHR0cDovL2NybC5jZmNhLmNvbS5jbi9PVk9DQS9SU0EvYWxsQ1JMLmNybDANBgkq
hkiG9w0BAQsFAAOCAQEAcXN3mqH7skNKNnWvv6nx4FscX8Zd0C82T/6z6TqMrwxT
pE7DB5ntcnDFjG7n7ZQqYzNlQpHqghCpEJ6RXlOSnQMZcO7WXFVhuc6UY1UOvArQ
hCTwqbfo/Rwa9zliRMX0OK+s6+H+wsdey9MlRMeBgeXqMZzF6bmv6dXXMnnXdoeE
l+6FhzLt7lyFi5MbEvdXjyQ5g8uL8nfhw81nbou0ecW48h4GtqMtutmN4runjhyU
3U34BFEdvIY9JVsgwKUX/xzhQqXaNkM8M0EQ5WEsN70UBSWKUifkRlhYZsud8BnE
QRWtQVhkkoBe7r1Ji5Rs+kaVrW6EpIdVQtyeTiaPEg==
-----END CERTIFICATE-----
subject=C = CN, ST = \E4\BA\91\E5\8D\97\E7\9C\81, L = \E6\98\86\E6\98\8E\E5\B8\82, O = \E4\BA\91\E5\8D\97\E7\9C\81\E5\95\86\E5\8A\A1\E5\8E\85\EF\BC\88\E4\BA\91\E5\8D\97\E7\9C\81\E4\BA\BA\E6\B0\91\E6\94\BF\E5\BA\9C\E5\8F\A3\E5\B2\B8\E5\8A\9E\E5\85\AC\E5\AE\A4\EF\BC\89, CN = swt.yn.gov.cn
issuer=C = CN, O = China Financial Certification Authority, CN = CFCA OV OCA
---
No client certificate CA names sent
Peer signing digest: SHA512
Peer signature type: RSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 5307 bytes and written 394 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: CFCBF4605F86B54CE80DE2CEE38276E557E8402439DBE3CF7A8FC09CB3D18AFA
Session-ID-ctx:
Master-Key: D75FF264BF4E1AD3FE61581CC0CC3FD66190F3AB55D642AC416506D1FA6231B6FFF46FD0CD58EEAD59C050EF17BFBC38
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 33 b5 98 dc d9 3d 77 de-b0 85 59 3b a4 92 c7 ab 3....=w...Y;....
0010 - ad 6d 5a 57 67 37 60 f2-e3 f8 7b ab ed 6a 73 6c .mZWg7`...{..jsl
0020 - 5d 8e 29 e8 20 50 3c 9b-54 6c d8 e2 85 5b e3 3d ].). P<.Tl...[.=
0030 - 5d 79 eb 27 17 df f7 fb-39 6e ac 09 2e dc 61 16 ]y.'....9n....a.
0040 - fe 5a 52 e8 d0 36 cb 08-34 0d 74 62 0a e9 37 39 .ZR..6..4.tb..79
0050 - dd c9 82 24 ff df 83 39-00 81 65 03 61 ae 15 7b ...$...9..e.a..{
0060 - 49 05 47 c3 d4 85 ed 1a-3f ca eb 4c bb de 62 60 I.G.....?..L..b`
0070 - 15 7b 20 52 6e fd 65 aa-ce 65 56 65 51 2e b4 f0 .{ Rn.e..eVeQ...
0080 - dc 58 00 dd 81 97 89 13-9b b3 8c 04 38 92 bd c6 .X..........8...
0090 - e6 c5 7a 29 39 37 51 f3-7e d8 eb 25 a8 51 6a 00 ..z)97Q.~..%.Qj.
00a0 - 16 a3 fa 99 57 04 8e ab-d5 00 2b 2d ca 85 d3 aa ....W.....+-....
00b0 - 00 a2 8c 10 5c 47 1c 18-0a 26 4f 59 1e b2 ae 0d ....\G...&OY....

Start Time: 1727505319
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes
---
DONE

2.4.2 更新OpenSSL

尝试更新OpenSSL,使用 OpenSSL 3.3.2

1
2
3
(base) root@baihl-node:/home/source_pkt/curl-8.10.1/output# ./bin/curl --version
curl 8.10.1 (aarch64-unknown-linux-gnu) libcurl/8.10.1 OpenSSL/3.3.2 zlib/1.2.11
Release-Date: 2024-09-18

访问依然报错:
image.png

2.4.3 使用 LibreSSL

尝试使用 libressl-3.7.2

1
2
3
(base) root@baihl-node:/home/source_pkt/curl-8.10.1/output# ./bin/curl --version
curl 8.10.1 (aarch64-unknown-linux-gnu) libcurl/8.10.1 LibreSSL/3.7.2 zlib/1.2.11
Release-Date: 2024-09-18

访问成功:
image.png

2.5 解决方法

因为此次WAF底层采用的Nginx,所以临时解决方法为,在Nginx中配置不使用 ECDHE 类的密码套件,回源配置如下:

1
proxy_ssl_ciphers HIGH:!aNULL:!MD5:!ADH:!RC4:!ECDHE;

上边反向代理配置中禁止 ECDHE 相关密码套件,则在TSL握手过程中也不会用到 椭圆曲线,可以避免以上问题。

解决问题的另一种方法就是使用 LibreSSL/3.7.2 替换 Tongsuo,但是无法支持国密了,当前无法使用此方式解决。