最近碰到一些 SSL 的小問題,特記錄下。

我們有個 Java 實現的 SSL TCP 服務端,為客戶端(PC、Android 和 iOS)提供 SSL 接入連線服務。最近有使用者反饋其手機上 App 不能正常連線登入,別人手機上都可以。經過單獨回訪調查該使用者使用的手機作業系統是 Android 6.0,經搜尋瞭解了 Android 6.0 之後 Google 使用了自家的 BoringSSL 替換了原來的 OpenSSL,懷疑是這裡在搗鬼。

繼續搜尋類似問題解決方案,在參考[1] 中找到答案:

SSL/TLS握手過程中,假如選中了諸如 TLS_DHE_RSA_WITH_AES_128_CBC_SHA 這樣使用 deffie-hellman 金鑰的 cipher,那麼在 deffie-hellman 金鑰交換過程中會使用的一個P引數(prime number),伺服器側提供的 P 引數在 JDK8 之前都只用了 768bit 的長度,小於 1024bit 存在安全漏洞可導致 logjam attack,會被最新本版的瀏覽器和 BoringSSL 拒絕。

明瞭了原因後我們只好把 JDK 從 6 升級到了 8,順利解決 Android6.0 SSL 握手失敗問題。但解決完這個後,沒多久又發現 APNS iOS 推送又不可用了,和蘋果推送伺服器建立 SSL 連線失敗,無法推送訊息。唯一的變化就是升級到了 JDK8 自然就將懷疑目標對準了 JDK8。

繼續 Google 一把找了同類受害者,他已經搞明白了原因,見參考[2]

The problem was the exported keystore (in PKCS12 format) contained the private key as well as the production certificate and the development certificate for push notifications. Java can use keystores in the PKCS12 format. But Java 6 and Java 8 did not read-in the keystore the same way. It looks like Java 6 read in the production certificate for the private key and Java 8 read in the development certificate.

解決辦法也很簡單,先用 JDK6 提供的 keytool 將 .p12 格式的證書轉換為 .jks 格式。再用 JDK8 提供的 keytool 將剛生成的 .jks 證書轉換為 .p12 格式。轉換命令如下:

.p12 -> .jks
/JDK6/keytool -importkeystore -destkeystore apns.jks -srckeystore apns_jdk6.p12 -srcstoretype PKCS12

.jks -> .p12
/JDK8/keytool -importkeystore -srckeystore apns.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore apns_jdk8.p12

參考

寫點文字,畫點畫兒,「瞬息之間」一切都變了。覺得不錯,掃描二維碼關注。
這裡寫圖片描述