-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
Both go1.12 and go.1.15 occur the same bug which described as follows.
I read the codes of the master branch, the problem is also existed.
When I use grpc-go build a http server which eanble ssl/tls protocol, the browser visit the grpc service normally.
But I use grpc-java as a client to visit the grpc service, the exception information:
io.grpc.StatusRuntimeException: UNAVAILABLE: Failed ALPN negotiation: Unable to find compatible protocol
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:262)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:243)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:156)
at bini.server.serverpb.AdminGrpc$AdminBlockingStub.databases(AdminGrpc.java:1667)
at com.inspur.znbase.rpc.AdminClient.main(AdminClient.java:72)
The reason is: the SSL/TLS of grpc-java will checked the alpnprotocol after the handshake success. But the message which sends back by grpc-go missing the alpnprotocol.
check codes of class ClientTlsHandler of io.grpc.netty.ProtocolNegotitators.java file:
@Override
protected void userEventTriggered0(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof SslHandshakeCompletionEvent) {
SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
if (handshakeEvent.isSuccess()) {
SslHandler handler = ctx.pipeline().get(SslHandler.class);
// The check code
if (sslContext.applicationProtocolNegotiator().protocols()
.contains(handler.applicationProtocol())) {
// Successfully negotiated the protocol.
logSslEngineDetails(Level.FINER, ctx, "TLS negotiation succeeded.", null);
propagateTlsComplete(ctx, handler.engine().getSession());
} else {
Exception ex =
unavailableException("Failed ALPN negotiation: Unable to find compatible protocol");
logSslEngineDetails(Level.FINE, ctx, "TLS negotiation failed.", ex);
ctx.fireExceptionCaught(ex);
}
} else {
ctx.fireExceptionCaught(handshakeEvent.cause());
}
} else {
super.userEventTriggered0(ctx, evt);
}
}
The codes of the method "doFullHandshake" of go sdk's source file: "crypto/tls/handshake_server.go":
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
if c.config.ClientAuth == NoClientCert {
// No need to keep a full record of the handshake if client
// certificates won't be used.
hs.finishedHash.discardHandshakeBuffer()
}
so add the codes to the method "doFullHandshake" of go sdk's source file: "crypto/tls/handshake_server.go:
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
// fix grpc-java openssl check
if len(hs.clientHello.alpnProtocols) > 0 {
hs.hello.alpnProtocol = hs.clientHello.alpnProtocols[0]
}
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
if c.config.ClientAuth == NoClientCert {
// No need to keep a full record of the handshake if client
// certificates won't be used.
hs.finishedHash.discardHandshakeBuffer()
}