Java客户端中具有SNI的TLS

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

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

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

我和ftrotter在同一个项目上工作。

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

在ftrotter的要求下,我做了一些关于java,TLS和SNI主题的搜索,以及实现相当于基于命名的虚拟主机情况的其他方法,每个虚拟主机有一个证书。 这就是我提出的:

  • JSSE(Java安全套接字扩展)支持TLS,并且对TLS + SNI具有“部分支持”。 我不知道在这种情况下部分支持意味着什么。 我看到的评论表明,存在的支持不足以完成基于命名的虚拟主机,这基本上就是我们所需要的。

  • 我发现有一篇文章声称JSSE的JDK7版本支持TLS + SNI(日期为2008年11月20日),而且我发现了一个声称它不会发布的文章(日期为2009年2月27日)。 两者都不具有特别的权威性。

  • 一些致力于OpenJDK 7的人讨论了在2009年2月至3月期间向JSSE添加SNI支持的问题,包括发布源补丁。 (线程从这里开始: http : //www.mail-archive.com/security-dev@openjdk.java.net/msg00612.html )。 OpenJDK7将不会在2010年9月之前的任何时间发布。我不知道Java 7平台什么时候发布。

  • java.sun.com上没有任何实质内容,所以我真的不知道Sun的计划是什么。

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

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

总之,当前基于名称的虚拟主机的Java技术状态似乎是“无法做到”。 此外,还不清楚何时或是否会添加。

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

JavaSE 7在JSSE中具有SNI支持。

http://docs.oracle.com/javase/7/docs/technotes/guides/security/enhancements-7.html

注意,它似乎有问题,你可以在这里阅读:

SSL握手警报:自升级到Java 1.7.0以来unrecognized_name错误

也可以使用某些行修补SUN JDK(bootclasspath)以使服务器SNI正常工作。

类:sun.security.ssl.ServerHandshaker

添加字段

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

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

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

补丁方法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); } 

添加到类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 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()]); }