Skip to content

crypto/tls: missing alpnprotocol field's value of the message which SSL/TLS protocol's handshake phase sends back. #45918

@lynnyuan-arch

Description

@lynnyuan-arch

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions