代码之家  ›  专栏  ›  技术社区  ›  ftrotter mario

在Java客户端中使用SNI的TLS

  •  8
  • ftrotter mario  · 技术社区  · 14 年前

    正在讨论 security and trust working group for NHIN Direct regarding the IP-to-domain mapping problem that is created with traditional SSL . 如果一个hisp(由nhin direct定义)想要为提供者托管数千个nhin direct“健康域”,那么必须为每个域购买一个IP将是“人为夸大的成本”。

    因为apache和openssl最近发布了支持sni扩展的tls,所以可以使用sni来解决这个问题。 在服务器端 . 但是,如果我们决定 允许 NH间接传输层的服务器实现,以支持TLS+SNI,那么我们必须 要求 所有客户都支持SNI。默认情况下,基于openssl的客户机应该这样做,并且如果给定的编程语言ssl实现不支持sni,则可以始终使用stunnel来实现一个支持tls+sni的客户机来代理。看来,使用OpenJDK的本机Java应用程序还不支持SNI,但我不能从该项目中得到一个直接答案。我知道有OpenSSL的Java库可用,但我不知道这是否被认为是可行的。

    你能给我一个“最先进的”总结TLS+SNI支持Java客户端的地方吗?我需要一个Java实现者的观点。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Community kfsone    7 年前

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

    注意支持的要求 数千 领域的。我不认为sans会因为两个原因来切芥末。首先,证书的大小将变得巨大,这可能至少会导致性能问题。第二,这些领域将频繁出现和消失,特别是在NHIN Direct的早期。IMHO,每次域出现或消失时都必须更新证书的操作负担是不可接受的。

    在Frter的请求下,我在Java、TLS和SNI的主题上进行了一些搜索,以及其他方法来实现一个基于虚拟主机的情况,每个虚拟主机有一个证书。我想到的是:

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

    • 我发现有一篇文章声称JSSE的JDK7版本 支持tls+sni(2008年11月20日),我发现有一个声明不会(2009年2月27日)。两者都不是特别权威的。

    • 一些开发OpenJDK7的人在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/VhostTaskForce Serve different certs for same Tomcat application via connectors?

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

    综上所述,当前基于Java的虚拟主机的状态,每个虚拟主机具有不同证书的虚拟主机似乎是“不能做”。此外,还不清楚何时或是否添加。

    有人同意或不同意吗?有没有人知道OpenJDK项目有没有打算为Java 6“后退”SNI支持?

        2
  •  8
  •   eckes    7 年前
        3
  •  6
  •   SkateScout    12 年前

    也可以使用orig-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);
    

    修补方法设置privatekey和chain(更改)

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