記一次 gradle 編譯過程中的 SSL handshake_failure

1. 背景:Android Studio中 Gradle 同步拉取library信息失敗

2022-12-14T17:13:14.916+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
2022-12-14T17:13:14.916+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436)
2022-12-14T17:13:14.916+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384)
2022-12-14T17:13:14.916+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
2022-12-14T17:13:14.916+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374)
2022-12-14T17:13:14.916+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.gradle.internal.resource.transport.http.HttpClientHelper.performHttpRequest(HttpClientHelper.java:141)
2022-12-14T17:13:14.917+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.gradle.internal.resource.transport.http.HttpClientHelper.performHttpRequest(HttpClientHelper.java:121)
2022-12-14T17:13:14.918+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.gradle.internal.resource.transport.http.HttpClientHelper.executeGetOrHead(HttpClientHelper.java:106)
2022-12-14T17:13:14.918+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   at org.gradle.internal.resource.transport.http.HttpClientHelper.performRequest(HttpClientHelper.java:97)
2022-12-14T17:13:14.919+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]   ... 50 more


Daemon worker: released lock on root.1
2022-12-14T17:13:14.860+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 
2022-12-14T17:13:14.862+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] FAILURE: Build failed with an exception.
2022-12-14T17:13:14.863+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 
2022-12-14T17:13:14.863+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] * What went wrong:
2022-12-14T17:13:14.864+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] Could not determine the dependencies of task ':app:compileJunoUatDebugKotlin'.
2022-12-14T17:13:14.867+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] > Could not resolve all files for configuration ':app:googleplayUatDebugRuntimeClasspath'.
2022-12-14T17:13:14.867+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]    > Could not download base-1.1.2-SNAPSHOT.aar (com.your.pkg:base:1.1.2-SNAPSHOT:20210628.100523-1)
2022-12-14T17:13:14.867+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]       > Could not get resource 'https://nexus3.***.io/repository/maven-mobile-snapshots/com/your/pkg/base/1.1.2-SNAPSHOT/base-1.1.2-20210628.100523-1.aar'.
2022-12-14T17:13:14.868+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]          > Could not HEAD 'https://nexus3.***.io/repository/maven-mobile-snapshots/com/your/pkg/base/1.1.2-SNAPSHOT/base-1.1.2-20210628.100523-1.aar'.
2022-12-14T17:13:14.868+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]             > Received fatal alert: handshake_failure
2022-12-14T17:13:14.868+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 
2022-12-14T17:13:14.868+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] * Try:
2022-12-14T17:13:14.868+0800 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter]  Run with --scan to get full insights.

2. 查看nexus服務(wù)器支持的tls 版本以及客戶端的設(shè)置

經(jīng)過在網(wǎng)上搜索,有一些線索厢拭。Https握手階段失敗佣蓉,最直接的想法??是 客戶端與服務(wù)器 TLS 版本協(xié)商失敗奕纫。重新看了下客戶端JDK的版本已經(jīng)是JDK11,再 分析 下 nexus 服務(wù)器上支持的協(xié)議糙及,看到并不存在它所提到的問題优床。

3. 工具分析

通過 openssl 命令 openssl s_client -connect nexus3.***.io:443 [-servername nexus3.***.io] (帶或不帶 參數(shù)servername)的結(jié)果來(lái)看, 服務(wù)器端是否支持 SNI,即它存在多臺(tái)虛擬主機(jī)烘豹,可以根據(jù)客戶端請(qǐng)求中不同的host瓜贾,將請(qǐng)求分發(fā)給不同的域名(虛擬主機(jī))來(lái)處理诺祸。

注意到 JDK 1.8中 參數(shù) jsse.enableSNIExtension 默認(rèn)值為 true携悯。
于是在AS 項(xiàng)目中附加了參數(shù) -Djsse.enableSNIExtension=trueorg.gradle.jvmargs中。操作完成后重試筷笨,發(fā)現(xiàn)本地編譯偶有成功憔鬼,但問題依舊存在。

可以使用openssl s_client和不使用-servername選項(xiàng):

without SNI

$ openssl s_client -connect host:port

use SNI

$ openssl s_client -connect host:port -servername host
如果你獲得兩個(gè)同名的不同證書胃夏,則表示支持并正確配置了 SNI轴或。
但是,如果返回的證書中的輸出不同仰禀,或者沒有SNI的調(diào)用無(wú)法建立SSL連接照雁,則表明需要SNI但沒有正確配置。解決此問題可能需要切換到專用 IP 地址答恶。

此時(shí)發(fā)現(xiàn) 不帶 -servername 的命令返回的結(jié)果確實(shí)是有問題的:

> openssl s_client -connect nexus3.***.io:443 -tlsextdebug

CONNECTED(00000006)
140704677139648:error:1404B410:SSL routines:ST_CONNECT:sslv3 alert handshake failure:/AppleInternal/Library/BuildRoots/810eba08-405a-11ed-86e9-6af958a02716/Library/Caches/com.apple.xbs/Sources/libressl/libressl-3.3/ssl/tls13_lib.c:129:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 287 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1671086879
    Timeout   : 7200 (sec)
    Verify return code: 0 

4. 和SRE一起解決問題

于是找到公司的SRE同事一起來(lái)看饺蚊,他建議斷開cloud flare萍诱,設(shè)置本地host為固定IP地址后再嘗試。果然Jenkins上的編譯成功了污呼≡7唬回頭再看看服務(wù)器 不帶 -servername 的返回,證書信息也有了燕酷。此刻真相大白了:上了cloud flare后 SNI的配置出現(xiàn)了問題籍凝!

5. 番外: regression ?!

又有一天看,其它業(yè)務(wù)組的同事也報(bào)出了相同的問題導(dǎo)致Jenkins上打包?? 出錯(cuò)苗缩。在升級(jí) gradle 版本到6.8后饵蒂,發(fā)現(xiàn)除了上面的錯(cuò)誤外,還額外有一條錯(cuò)誤信息是

[org.gradle.internal.buildevents.BuildExceptionReporter] > 
The server may not support the client's requested TLS protocol versions: (TLSv1.2, TLSv1.3). 
You may need to configure the client to allow other protocols to be used. 
See: https://docs.gradle.org/6.8/userguide/build_environment.html#gradle_system_properties

這無(wú)疑之中讓我想到除了在Jenkins 主機(jī)上抓網(wǎng)絡(luò)數(shù)據(jù)包外挤渐,是不是還有其它辦法可以看到更多HTTPS 握手階段出錯(cuò)的更多細(xì)節(jié)呢苹享?果然萬(wàn)能的SO給出類似問題的了一條很贊的回復(fù)[1], 在JVM中設(shè)置參數(shù)-Djavax.net.debug=all ,就可以調(diào)試 HTTP SSL/TLS 連接了浴麻。

在單獨(dú)指定tls 版本為 TLSv1.3后得问,再看Jenkins上詳細(xì)的log 輸出:

The server does not support the client's requested TLS protocol versions: (TLSv1.3). You may need to configure the client to allow other protocols to be used. See: https://docs.gradle.org/6.8/userguide/build_environment.html#gradle_system_properties
Received fatal alert: protocol_version
......
 [ERROR] [system.err] javax.net.ssl|DEBUG|24|Build operations Thread 2|2023-02-09 10:41:02.495 UTC|SSLSocketInputRecord.java:213|READ: TLSv1.2 alert, length = 2
 [ERROR] [system.err] javax.net.ssl|DEBUG|24|Build operations Thread 2|2023-02-09 10:41:02.495 UTC|SSLSocketInputRecord.java:458|Raw read (
 [ERROR] [system.err]   0000: 02 46                                              .F
 [ERROR] [system.err] )
 [ERROR] [system.err] javax.net.ssl|DEBUG|24|Build operations Thread 2|2023-02-09 10:41:02.495 UTC|SSLSocketInputRecord.java:249|READ: TLSv1.2 alert, length = 2
 [ERROR] [system.err] javax.net.ssl|DEBUG|24|Build operations Thread 2|2023-02-09 10:41:02.496 UTC|Alert.java:232|Received alert message (
 [ERROR] [system.err] "Alert": {
 [ERROR] [system.err]   "level"      : "fatal",
 [ERROR] [system.err]   "description": "protocol_version"
 [ERROR] [system.err] }
 [ERROR] [system.err] )
 [ERROR] [system.err] javax.net.ssl|ERROR|24|Build operations Thread 2|2023-02-09 10:41:02.497 UTC|TransportContext.java:313|Fatal (PROTOCOL_VERSION): 
 Received fatal alert: protocol_version

?? 至此為止看判斷是與服務(wù)端協(xié)商支持的tls 版本不一致導(dǎo)致的問題,將客戶端的tls 版本設(shè)置為TLSv1.2后软免,再次嘗試編譯宫纬,果然就成功了??。

6. Ref


  1. handshake_failure SO 鏈接 ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末膏萧,一起剝皮案震驚了整個(gè)濱河市漓骚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌榛泛,老刑警劉巖蝌蹂,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異曹锨,居然都是意外死亡孤个,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門沛简,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)齐鲤,“玉大人,你說我怎么就攤上這事椒楣「迹” “怎么了?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵捧灰,是天一觀的道長(zhǎng)淆九。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么炭庙? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任跪另,我火速辦了婚禮,結(jié)果婚禮上煤搜,老公的妹妹穿的比我還像新娘免绿。我一直安慰自己,他們只是感情好擦盾,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布嘲驾。 她就那樣靜靜地躺著,像睡著了一般迹卢。 火紅的嫁衣襯著肌膚如雪辽故。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天腐碱,我揣著相機(jī)與錄音誊垢,去河邊找鬼。 笑死症见,一個(gè)胖子當(dāng)著我的面吹牛喂走,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谋作,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼芋肠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了遵蚜?” 一聲冷哼從身側(cè)響起帖池,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吭净,沒想到半個(gè)月后睡汹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寂殉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年囚巴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片不撑。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡文兢,死狀恐怖晤斩,靈堂內(nèi)的尸體忽然破棺而出焕檬,到底是詐尸還是另有隱情,我是刑警寧澤澳泵,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布实愚,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腊敲。R本人自食惡果不足惜击喂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碰辅。 院中可真熱鬧懂昂,春花似錦、人聲如沸没宾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)循衰。三九已至铲敛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間会钝,已是汗流浹背伐蒋。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留迁酸,地道東北人先鱼。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像奸鬓,于是被迫代替她去往敵國(guó)和親型型。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容