【问题标题】:how to force OkHttp on Android 11 to send ssl client cert auth with TLS 1.3如何强制 Android 11 上的 OkHttp 使用 TLS 1.3 发送 ssl 客户端证书身份验证
【发布时间】:2021-09-08 20:51:12
【问题描述】:

我们需要对只接受 TLS 1.3 连接的服务器执行基于证书的客户端身份验证。 服务器使用 Apache 2 和 HTTP 1.1,并配置为允许客户端证书身份验证但不强制执行,因为某些资源需要客户端身份验证,而其他资源不需要。

我们在 Android 11 上使用 OkHttp 4.9.1 来执行调用,并且我们遵循关于如何执行客户端身份验证的标准文档:https://github.com/square/okhttp/tree/master/okhttp-tls

但是服务器回复:403 (auth renegotiation not allowed)

这符合 TLS 1.3 规范,该规范不允许身份验证重新协商,除非在初始握手期间达成一致。

到目前为止,我们已经调试了连接,并在 OkHttp 中调试了 RealConnection 类,它实际上执行了握手,而无需协商客户端证书。

到目前为止,我们的研究表明这可能是由于服务器使用了 OPTIONAL ssl 客户端身份验证,但这不是我们可以改变的,所以......

  1. 我们可以在 OkHttp 初始化期间传递任何其他选项来强制它使用客户端证书执行初始握手吗?
  2. 如果 OkHttp 不是一个可行的选项,是否有任何其他 HTTP 客户端实现可以让我们在初始握手期间强制进行此类身份验证?

【问题讨论】:

  • 除了 OkHttp 之外,您是否尝试过任何其他 HTTP 客户端?通常默认的 Java(=android) 实现具有更广泛的兼容性(即使它缺少配置选项和 OkHttp 的灵活性)
  • 具有正确密钥库和信任管理器的 URLConnection 给出了完全相同的 403 错误,并且我们不希望标准 URLConnection 可以为此目的进行充分配置,而且我们已经在使用 OkHttp

标签: android authentication ssl okhttp


【解决方案1】:

使用其构建器创建一个 HandshakeCertificates 对象。您将需要您的私钥、客户端证书和客户端的任何中间体。

客户端还需要一个根证书才能让您的服务器信任它。如果您愿意,构建器具有使用内置证书颁发机构的功能。

  private OkHttpClient buildClient(
      HeldCertificate heldCertificate, X509Certificate... intermediates) {
    HandshakeCertificates.Builder builder = new HandshakeCertificates.Builder()
        .addTrustedCertificate(serverRootCa.certificate());

    if (heldCertificate != null) {
      builder.heldCertificate(heldCertificate, intermediates);
    }

    HandshakeCertificates handshakeCertificates = builder.build();
    return clientTestRule.newClientBuilder()
        .sslSocketFactory(
            handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager())
        .build();
  }

https://github.com/square/okhttp/blob/1ce86f35a9d957bae711fb81cec60abe9f43dda0/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.java#L126

【讨论】:

  • thnaks 但设置 socketFactory 和 trustManager 本质上与我提到的教程相同,并且正如预期的那样它没有解决
【解决方案2】:

从客户端的角度来看,可选的客户端证书身份验证与必需的客户端证书身份验证没有什么不同。客户端看到的只是一个 CertificateRequest,作为响应,它将发送一些证书(叶和链),这也可能是一个空的证书列表。由服务器决定这是否可以接受,即可选只是意味着服务器接受客户端发送一个空的证书列表。

因此问题不是可选或必需的客户端证书,而是服务器在初始 TLS 握手中根本没有请求证书,并且可能仅在访问特定路径时请求证书(请求的路径只能在之后看到最初的握手)。对于 Apache,如果在服务器全局配置中没有请求客户端证书,而是在特定路径的 .htaccess 文件中请求客户端证书,则通常会出现这种情况。解决方法是在域级别移动需求,而不仅仅是路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    • 2016-07-09
    • 2015-07-29
    相关资源
    最近更新 更多