最近碰到一些 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。 orm
继续 Google 一把找了同类受害者,他已经搞明白了缘由,见参考[2] server
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. ip
解决办法也很简单,先用 JDK6 提供的 keytool 将 .p12 格式的证书转换为 .jks 格式。再用 JDK8 提供的 keytool 将刚生成的 .jks 证书转换为 .p12 格式。转换命令以下: ssl
.p12 -> .jks ci
/JDK6/keytool -importkeystore -destkeystore apns.jks -srckeystore apns_jdk6.p12 -srcstoretype PKCS12 get
.jks -> .p12
/JDK8/keytool -importkeystore -srckeystore apns.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore apns_jdk8.p12
参考
[1] liuxian233. Android 6.0 HTTPS链接ssl3_get_server_key_exchange:BAD_DH_P_LENGTH错误问题
[2] szediwy. Apple Push Notification with Java
[3] ASHISH PARAB. APPLE PUSH NOTIFICATION SERVICE CERTIFICATE ISSUE WITH JDK 7