Search code examples
javaopensslnettysniboringssl

JVM crashes using underline '_' as part of SNI server name


I'm using Netty 4.1.14.Final for my application's framework. I want to implement that the server can check the SNI information when the clients request using netty-tcnative-boringssl-static.

But my application crashes once as I specify the -servername as svc.v1, and I got this message:

java: ../ssl/handshake_server.c:541: negotiate_version: Assertion `!ssl->s3->have_version' failed.

with the OpenSSL command:

openssl s_client -cert service.crt -key service.key -CAfile root_ca.pem -connect 127.0.0.1:8080 -servername svc.v1_1
CONNECTED(00000003)
write:errno=0
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 210 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1532336403
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
---

However, it works well if I specify the -servername as svc.v1, without the underline _.

Here is my Netty server implementation:
// define ssl provider
private static final SslProvider SSL_PROVIDER = SslProvider.OPENSSL;

// factory method for creating ssl context
public SslContext serverCtx(InputStream certificate, InputStream privateKey) {
        try {
            return SslContextBuilder.forServer(certificate, privateKey)
                                    .sslProvider(SSL_PROVIDER)                                         
                                    .clientAuth(ClientAuth.REQUIRE)
                               .trustManager(TwoWayTrustManagerFactory.INSTANCE)
                                    .build();
        } catch (Exception e) {
            throw new RuntimeException("failed to create ssl context", e);
        }
}

// SNI Matcher implementation
@Slf4j
public class MySNIMatcher extends SNIMatcher {

    private final byte[] hostIdentifier;

    public MySNIMatcher(Identifier hostIdentifier) {
        super(0);
        this.hostIdentifier = hostIdentifier.idDistKey().getBytes(StandardCharsets.US_ASCII);
    }

    @Override
    public boolean matches(SNIServerName sniServerName) {
        return Arrays.equals(sniServerName.getEncoded(), hostIdentifier);
    }
}

// Netty bootstrap
bootstrap.childHandler(new ChannelInitializer<Channel>() {
    @Override
    protected void initChannel(Channel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        if (conf.logEnable())
            pipeline.addLast("logging", new LoggingHandler());

        if (conf.sslEnable()) {
            // conf.sslCtx() will actually use serverCtx() to create context
            SSLEngine engine = conf.sslCtx().newEngine(ch.alloc());
            SSLParameters s = engine.getSSLParameters();
            s.setSNIMatchers(new MySNIMatcher(...));
            s.setEndpointIdentificationAlgorithm("HTTPS");
            engine.setSSLParameters(s);
            pipeline.addLast("ssl", new SslHandler(engine, true));
        }

        codec(pipeline);

        int idleTimeout = (int) TimeUnit.MILLISECONDS.toSeconds(conf.idleTimeout());
        if (0 < idleTimeout)
            pipeline.addLast("idle", new IdleStateHandler(0, 0, idleTimeout));

        pipeline.addLast("handler", handler);
    }                  
})

Version: netty -> 4.1.14.Final netty-tcnative-boringssl-static -> 2.0.5.Final


Solution

  • Hostnames are not allowed to contain an underscore character, per the original RFC 952, and modified by RFC 1123. The following is from the Wikipedia page for Hostname.

    The Internet standards (Requests for Comments) for protocols mandate that component hostname labels may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner), the digits '0' through '9', and the minus sign ('-'). The original specification of hostnames in RFC 952, mandated that labels could not start with a digit or with a minus sign, and must not end with a minus sign. However, a subsequent specification (RFC 1123) permitted hostname labels to start with digits. No other symbols, punctuation characters, or white space are permitted.