jdk7 调用 https url 握手_失败

问题描述

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 维护版本)应该已经在 J​​DK 7 上激活了 TLSv1.2。不知道为什么你自己有这个代码。

https://github.com/square/okhttp/blob/parent-3.12.12/okhttp/src/main/java/okhttp3/internal/platform/Platform.java#L298

  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);
    }
  }

您可以使用类似于 https://github.com/square/okhttp/blob/master/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt

的代码启用帧日志记录 ,

正如另一个答案所指出的,如果使用 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();