Java客户端中的TLS与SNI

10

目前,安全和信任工作组为NHIN Direct正在讨论传统SSL所创建的IP到域名映射问题。如果一个HISP(由NHIN Direct定义)想要为提供者托管数千个NHIN Direct“健康域”,那么为每个域购买IP将会导致“人为膨胀的成本”。

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

您能否为我提供有关Java客户端TLS+SNI支持的“最新技术”摘要?我需要一个Java实现者的观点。


这个问题很久了,但我没有找到更好的地方。当前(Java 14)参考文档位于:https://docs.oracle.com/en/java/javase/14/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-82B884DF-AA3D-4FE1-8991-9C3F14044C4F - Gustave
3个回答

8

1
如果您在服务器上遇到了无法忽略的“unrecognized_name”警报问题(JSSE客户端无法忽略),请参见http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7127374,您可以关闭发送SNI:jsse.enableSNIExtension=false。 - eckes
有什么办法可以关闭小程序的这个功能吗? - ivb
您可以在系统控制面板中添加(全局)系统属性,用于Applets和WebStart。JNLP文件不能指定不在安全白名单中的系统参数。(我认为该列表可以在某个地方进行修改,但那不是官方接口)。 - eckes
1
Oracle JSSE增强链接已失效 - 新链接为http://docs.oracle.com/javase/7/docs/technotes/guides/security/enhancements-7.html。 - mvanwely

7

您可以通过补丁方式为原始的Sun JDK (bootclasspath)添加一些代码行,以使服务器SNI功能正常运作。

类: sun.security.ssl.ServerHandshaker

添加字段

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

在客户端Hello报文中添加以下内容(使用Patch方法)。
    /* Use for SNI */
    this.serverNameExtension = (ServerNameExtension)mesg.extensions.get(ExtensionType.EXT_SERVER_NAME);

设置私钥和链的Patch方法(更改)

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

3

我正在与ftrotter一起开展同一项目。

请注意需要支持数千个域名的要求。我认为SAN证书不太适合有两个原因。首先,证书的大小将会变得巨大,这可能会导致性能问题。其次,这些域名会经常出现和消失,特别是在NHIN Direct早期阶段。每次域名出现或消失都必须更新证书的操作负担将是无法接受的,在我看来。

应ftrotter的请求,我对Java、TLS和SNI以及其他实现基于名称的虚拟主机情况的方法进行了搜索。每个虚拟主机使用一个证书。以下是我的研究结果:

JSSE(Java Secure Socket Extension)支持TLS,并对TLS + SNI提供“部分支持”。我不知道在这种情况下“部分支持”是什么意思。我看到的评论表明,现有的支持不足以进行基于名称的虚拟主机,这基本上是我们所需要的。
我找到了一篇文章声称JDK7版本的JSSE将支持TLS + SNI(日期为11/20/2008),还发现一篇声称它不会支持(日期为2/27/2009)。两者都不是特别权威。
一些在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的计划是什么。
显然有一种不同的方法可以实现基于名称的虚拟主机,这种方法似乎广泛兼容,使用每个托管服务器包含多个公共名称和多个主题alt名称的单个证书。请参见 http://wiki.cacert.org/VhostTaskForceServe different certs for same Tomcat application via connectors?
如果您有许多虚拟主机,采用这种方法会创建非常大的证书(由于所有这些CN和SAN)。 NHIN Direct最近的面对面会议上的一位人士谈到希望支持成千上万个虚拟主机。我猜这将破坏很多实现。此外,每次添加或删除虚拟主机时都必须更新证书听起来像是一个荒谬的操作负担。
总之,当前Java技术状态下基于名称的虚拟主机使用单独证书的情况似乎是“无法做到”。此外,目前还不清楚何时或是否会添加该功能。
有人同意或不同意吗? 有人知道OpenJDK项目是否有意为Java 6“回溯”SNI支持吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接