问题描述
jdk1.7.0_79 和 okhttp 3.8 调用 https url 失败
import (
"os"
"golang.org/x/sys/unix"
)
func main() {
// do stuff with piped input
pid := os.Getpid()
pgid,err := unix.Getpgid(pid)
if err != nil {
log.Fatalf("Could not get process group id for pid: %v\n",pid)
}
processGroup,err := os.FindProcess(pgid)
if err != nil {
log.Fatalf("Could not find process for pid: %v\n",pgid)
}
processGroup.Signal(os.Interrupt)
}
写入和读取TLSv1为什么还是handshake_failure,如果使用jdk8就可以了,握手信息如下
syscall
客户端和服务器都使用 TLSv1.2
因此尝试将 jdk7 默认 tls 更改为 TLSv1.2 在此 doc 中遵循以下方法
main,WRITE: TLSv1 Handshake,length = 148
main,READ: TLSv1 Alert,length = 2
main,RECV TLSv1 ALERT: fatal,handshake_failure
main,called closeSocket()
main,handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
main,called close()
main,called closeInternal(true)
但这次仍然是handshake_failure 调试信息是
main,WRITE: TLSv1.2 Handshake,length = 170
main,READ: TLSv1.2 Handshake,length = 93
main,length = 5516
这次 write 使用 TLSv1.2 但 recv 仍然使用 TLSv1。 为什么会这样?如何让客户端和服务器都使用 TLSV1.2?
解决方法
OkHttp 3.12.12(JDK 7 的 3.x 维护版本)应该已经在 JDK 7 上激活了 TLSv1.2。不知道为什么你自己有这个代码。
public SSLContext getSSLContext() {
String jvmVersion = System.getProperty("java.specification.version");
if ("1.7".equals(jvmVersion)) {
try {
// JDK 1.7 (public version) only support > TLSv1 with named protocols
return SSLContext.getInstance("TLSv1.2");
} catch (NoSuchAlgorithmException e) {
// fallback to TLS
}
}
try {
return SSLContext.getInstance("TLS");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No TLS provider",e);
}
}
的代码启用帧日志记录
,
正如另一个答案所指出的,如果使用 Java 7
,您至少需要 OkHttp 3.12.12 来支持 TLSv1.2。
但您还必须考虑服务器中启用的必须与 OkHttp 兼容的密码套件。
默认情况下,OkHttp 使用 17 个“已批准”密码套件的列表,您可以在此处查看 https://github.com/square/okhttp/blob/okhttp_3.12.x/okhttp/src/main/java/okhttp3/ConnectionSpec.java(请参阅 APPROVED_CIPHER_SUITES
)
但是在这 17 个中,de JDK 1.7 只支持 5 个:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
因此,如果服务器不接受任何此类密码套件,您将收到握手失败错误。
如果服务器接受一些 Java 7 支持的密码套件,但不在 OkHttp 的 APPROVED_CIPHER_SUITES
列表中,您可以创建自己的 ConnectionSpec
并在 OkHttpClient.Builder
.例如,假设服务器接受 Java 7 支持的以下密码套件:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
您可以执行以下操作将它们添加到 OkHttp 支持的密码套件列表中:
// Create a list of cipher suites based on the default approved list by OkHttp
List<CipherSuite> cipherSuites = new ArrayList<CipherSuite>(ConnectionSpec.MODERN_TLS.cipherSuites());
// Add another cipher suites suported by Java 7
cipherSuites.add(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
cipherSuites.add(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);
// Build a connection spec based on the default overridding the cipher suites.
ConnectionSpec COMPATIBLE_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
.build();
// Build a client specifying our own connection spec
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Util.immutableList(COMPATIBLE_SPEC))
.build();