Java 客户端中带有 SNI 的 TLS

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2804551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:01:13  来源:igfitidea点击:

TLS with SNI in Java clients

javaclient-sidessl

提问by ftrotter

There is an ongoing discussion on the security and trust working group for NHIN Directregarding the IP-to-domain mapping problem that is created with traditional SSL. If an HISP (as defined by NHIN Direct) wants to host thousands of NHIN Direct "Health Domains" for providers, then it will an "artificially inflated cost" to have to purchase an IP for each of those domains.

NHIN Direct安全和信任工作组正在进行有关使用传统 SSL 创建的 IP 到域映射问题的讨论。如果 HISP(由 NHIN Direct 定义)想要为提供商托管数千个 NHIN Direct“健康域”,那么必须为每个域购买 IP 将是“人为夸大的成本”。

Because Apache and OpenSSL have recently released TLS with support for the SNI extension, it is possible to use SNI as a solution to this problem on the server side. However, if we decide that we will allowserver implementations of the NHINDirect transport layer to support TLS+SNI, then we must requirethat all clients support SNI too. OpenSSL based clients should do this by default and one could always us stunnel to implement an TLS+SNI aware client to proxy if your given programming language SSL implementation does not support SNI. It appears that native Java applications using OpenJDK do not yet support SNI, but I cannot get a straight answer out of that project. I know that there are OpenSSL Java libraries available but I have no idea if that would be considered viable.

因为 Apache 和 OpenSSL 最近发布了支持 SNI 扩展的 TLS,所以可以在服务器端使用 SNI 作为这个问题的解决方案。但是,如果我们决定允许NHINDirect 传输层的服务器实现支持 TLS+SNI,那么我们必须要求所有客户端也支持 SNI。默认情况下,基于 OpenSSL 的客户端应执行此操作,如果您给定的编程语言 SSL 实现不支持 SNI,则始终可以使用 stunnel 实现 TLS+SNI 感知客户端进行代理。似乎使用 OpenJDK 的本机 Java 应用程序尚不支持 SNI,但我无法从该项目中直接得到答案。我知道有可用的 OpenSSL Java 库,但我不知道这是否可行。

Can you give me a "state of the art" summary of where TLS+SNI support is for Java clients? I need a Java implementers perspective on this.

你能给我一个关于 Java 客户端的 TLS+SNI 支持的“最新技术”摘要吗?我需要一个 Java 实现者的观点。

采纳答案by user337533

I'm working on the same project as ftrotter.

我正在和 ftrotter 做同一个项目。

Note the requirement of support for thousandsof domains. I don't think that SANs are going to cut the mustard for two reasons. First, the size of the certificate is going to get enormous, which will likely cause performance problems at a minimum. Second, these domains are going to come and go frequently, particularly in the early days of NHIN Direct. The operational burden of having to update the certificate every time a domain comes or goes, is going to be unacceptable, IMHO.

请注意支持数千个域的要求。我认为 SAN 不会削减芥末的原因有两个。首先,证书的大小将变得巨大,这可能至少会导致性能问题。其次,这些域会频繁地来来去去,尤其是在 NHIN Direct 的早​​期。恕我直言,每次域出现或离开时都必须更新证书的操作负担将是不可接受的。

At ftrotter's request, I did some googling around on the subject of java, TLS and SNI, and other ways to implement what amounts to a named-based virtual hosting situation, with one certificate per virtual host. Here's what I've come up with:

应 ftrotter 的要求,我对 Java、TLS 和 SNI 以及其他实现基于命名的虚拟主机情况的方法进行了一些搜索,每个虚拟主机有一个证书。这是我想出的:

  • JSSE (Java Secure Socket Extension) supports TLS, and has "partial support" for TLS+SNI. I have no idea what partial support means in this context. The commentary I'm seeing indicates that the support that exists is not adequate for doing named-based virtual hosts, which is basically what we need.

  • I've found one article that claims the JDK7 version of JSSE willsupport TLS+SNI (dated 11/20/2008), and I've found one that claims it won't (dated 2/27/2009). Neither is particularly authoritative.

  • Some of the folks working on OpenJDK 7 discussed the issues around adding SNI support to JSSE back in Feb-Mar 2009, including posting a source patch. (thread starts here: http://www.mail-archive.com/[email protected]/msg00612.html). OpenJDK7 isn't going to be released any time before about September 2010. I have no idea when the Java 7 platform will be released.

  • There is nothing substantive on java.sun.com at all, so I really don't know what Sun's plans are at all.

  • There is apparently a different way to accomplish name-based virtual hosts which is apparently widely compatible, using a single certificate per hosting server which contains multiple common names and multiple subject alt names. See http://wiki.cacert.org/VhostTaskForceand Serve different certs for same Tomcat application via connectors?

  • JSSE(Java Secure Socket Extension)支持TLS,对TLS+SNI有“部分支持”。我不知道在这种情况下部分支持意味着什么。我看到的评论表明现有的支持不足以进行基于命名的虚拟主机,这基本上是我们所需要的。

  • 我发现一篇文章声称 JSSE 的 JDK7 版本支持 TLS+SNI(日期为 11/20/2008),我发现一篇文章声称它不会(日期为 2/27/2009)。两者都不是特别权威。

  • 一些在 OpenJDK 7 上工作的人在 2009 年 2 月至 3 月讨论了有关向 JSSE 添加 SNI 支持的问题,包括发布源补丁。(线程从这里开始:http: //www.mail-archive.com/[email protected]/msg00612.html)。OpenJDK7 不会在大约 2010 年 9 月之前发布。我不知道 Java 7 平台何时发布。

  • java.sun.com上根本没有什么实质性的东西,所以我真的完全不知道Sun的计划是什么。

  • 显然有一种不同的方式来完成基于名称的虚拟主机,它显然是广泛兼容的,每个托管服务器使用一个证书,其中包含多个通用名称和多个主题替代名称。请参阅http://wiki.cacert.org/VhostTaskForce通过连接器为同一 Tomcat 应用程序提供不同的证书?

This approach would create really large certificates (due to all those CNs and SANs) if you have lots of virtual hosts. One of the folks at NHIN Direct's recent face-to-face meeting was talking about wanting to support thousandsof virtual hosts. My guess is that this will break a lot of implementations. In addition, having to update the certificate each time you add or remove a virtual host sounds like a ridiculous operational burden.

如果您有很多虚拟主机,这种方法将创建非常大的证书(由于所有这些 CN 和 SAN)。在 NHIN Direct 最近的面对面会议上,其中一位成员正在谈论要支持数千个虚拟主机。我的猜测是这会破坏很多实现。此外,每次添加或删除虚拟主机时都必须更新证书听起来像是一种荒谬的操作负担。

In summary, the current Java state of the art for name-based virtual hosting with separate certificates per virtual host appears to be "no can do". In addition, it's not clear when or if it will be added.

总之,对于每个虚拟主机具有单独证书的基于名称的虚拟主机的当前 Java 技术状态似乎是“无能为力”。此外,尚不清楚何时或是否会添加它。

Does anyone agree or disagree? Does anyone know if the OpenJDK project has any intention of "backporting" SNI support for Java 6?

有人同意或不同意吗?有谁知道 OpenJDK 项目是否有意“向后移植”对 Java 6 的 SNI 支持?

回答by eckes

回答by SkateScout

it is also possible to patch with some lines the orig Sun JDK (bootclasspath) to get Server SNI working.

也可以用一些行修补 orig Sun JDK (bootclasspath) 以使服务器 SNI 工作。

Class: sun.security.ssl.ServerHandshaker

类:sun.security.ssl.ServerHandshaker

Add Field

添加字段

    /** Use for SNI */
    private ServerNameExtension serverNameExtension = null;

Patch Method clientHello (add these lines)

补丁方法 clientHello(添加这些行)

    /* Use for SNI */
    this.serverNameExtension = (ServerNameExtension)mesg.extensions.get(ExtensionType.EXT_SERVER_NAME);

Patch Method setupPrivateKeyAndChain (change)

补丁方法 setupPrivateKeyAndChain(更改)

    if (this.conn != null) { alias = km.chooseServerAlias(algorithm      , null, this.conn);
    } else                 { alias = km.chooseEngineServerAlias(algorithm, null, this.engine); }

to

    final Principal[] principals = (this.serverNameExtension == null) ? null : this.serverNameExtension.getHostnamePrincipals();
    if (this.conn != null) { alias = km.chooseServerAlias(algorithm      , principals, this.conn);
    } else                 { alias = km.chooseEngineServerAlias(algorithm, principals, this.engine); }

Add to Class sun.security.ssl.ServerNameExtension

添加到类 sun.security.ssl.ServerNameExtension

static final class ServerNamePrincipal implements Principal {
    private final String name;
    ServerNamePrincipal(final String name) { this.name = name; }
    @Override public String getName() { return this.name; }
    @Override public String toString() { return this.name; }
}

public Principal[] getHostnamePrincipals() {
    final List<Principal> principals = new LinkedList<>();
    for(final ServerName name : this.names) {
        if(name.type == NAME_HOST_NAME) { principals.add(new ServerNamePrincipal(name.hostname)); }
    }
    return principals.toArray(new Principal[principals.size()]);
}