使用下划线“_”作为 SNI 服务器名称的一部分的 JVM 崩溃
JVM crashes using underline '_' as part of SNI server name
我正在为我的应用程序框架使用 Netty 4.1.14.Final
。我想实现当客户端使用 netty-tcnative-boringssl-static
.
请求时,服务器可以检查 SNI 信息
但是当我将 -servername
指定为 svc.v1
时,我的应用程序崩溃了一次,我收到了这条消息:
java: ../ssl/handshake_server.c:541: negotiate_version: Assertion `!ssl->s3->have_version' failed.
使用 OpenSSL 命令:
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
---
但是,如果我将 -servername
指定为 svc.v1
,并且不带下划线 _
。
,效果会很好
这是我的 Netty 服务器实现:
// 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);
}
})
版本:
网络 -> 4.1.14.Final
netty-tcnative-boringssl-static -> 2.0.5.Final
根据原始 RFC 952 和 RFC 1123 修改,主机名不允许包含下划线字符。以下内容来自 Hostname.
的 Wikipedia 页面
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.
我正在为我的应用程序框架使用 Netty 4.1.14.Final
。我想实现当客户端使用 netty-tcnative-boringssl-static
.
但是当我将 -servername
指定为 svc.v1
时,我的应用程序崩溃了一次,我收到了这条消息:
java: ../ssl/handshake_server.c:541: negotiate_version: Assertion `!ssl->s3->have_version' failed.
使用 OpenSSL 命令:
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
---
但是,如果我将 -servername
指定为 svc.v1
,并且不带下划线 _
。
// 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);
}
})
版本: 网络 -> 4.1.14.Final netty-tcnative-boringssl-static -> 2.0.5.Final
根据原始 RFC 952 和 RFC 1123 修改,主机名不允许包含下划线字符。以下内容来自 Hostname.
的 Wikipedia 页面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.