Grpc-java: gRPC Netty with TLS failing on Android API < 24

Created on 31 Aug 2020  路  6Comments  路  Source: grpc/grpc-java

What version of gRPC-Java are you using?

The current latest: 1.31.1, although it's probably present in earlier versions.

What is your environment?

Android

What did you expect to see?

Being able to use NettyChannelBuilder with TLS negotiation type on Android devices with API levels 16+.

What did you see instead?

The client crashes with the following error on Android devices under API 24:

java.lang.NoSuchMethodError: No virtual method setEndpointIdentificationAlgorithm(Ljava/lang/String;)V in class Ljavax/net/ssl/SSLParameters; or its super classes (declaration of 'javax.net.ssl.SSLParameters' appears in /system/framework/core-libart.jar)"

This is the offending call: https://github.com/grpc/grpc-java/blob/master/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java#L350

SSLParameters#setEndpointIdentificationAlgorithm is only available in Android 24+.

Steps to reproduce the bug

Create a client gRPC Netty client with a TLS connection and try connecting to a server. Example:

TestServiceGrpc.newStub(
    NettyChannelBuilder
        .forAddress(InetSocketAddress("0.0.0.0", 1234))
        .useTransportSecurity()
        .build()
)
docs

All 6 comments

We don't directly support Netty channels on Android devices (although looking now I'm not seeing this particularly well-documented anywhere...). If you need to run on pre-24 Android devices, we would recommend using a gRPC OkHttp or Cronet channel. That said, if there's a way to accomplish the same effect in io.grpc.netty.ProtocolNegotiators that would also be compatible with earlier versions of Android, I'd be happy to review a PR.

We need to both a gRPC client as a server, that's why we went with Netty for Android.

The simplest workaround I can think of is to catch and log the NoSuchMethodError, and I can open a PR with that change. But I don't fully grasp the consequences of skipping the call to SSLParameters#setEndpointIdentificationAlgorithm, and if there are alternative ways to achieve the same behaviour.

I did a bit of poking around and found this old issue on the OkHttp repo. It sounds from the docs like not calling setEndpointIndentificationAlgorithm leaves the code open to man-in-the-middle attacks, and that seems to be why gRPC with OkHttp does its own hostname verification.

I'm not an expert on these such vulnerabilities but, it sounds like if we were to change Netty to have a safe fallback behavior when setEndpointIdentificationAlgorithm throws a NoSuchMethodError, it would have to manually do the hostname verification. While I'm sure this is possible, my initial inclination is that the drawbacks of doing this (including code maintenance and security overhead) would outweigh the benefits (there are lots of developer quality-of-life improvements we will be able to make to our Android-specific code as the minimum supported API level slowly advances past 16, so this change would feel in some respects like going backwards).

It shouldn't be _too_ bad to use Netty for the server and OkHttp for the client on Android. Our gRPC OkHttp stack is pretty minimal, so any additional APK size should be pretty minor compared to the (perhaps substantial) hit you're already taking for bringing in Netty on the server side. It looks like you already have a PR doing this as a workaround - does that meet your needs here?

Hey @ericgribkoff,

I'm working with Sergio on this.

That's right, not calling setEndpointIdentificationAlgorithm would skip the host name validation. I tested it early today.

We're switching to OkHTTP since that's what you recommend on Android anyway. That channel doesn't call setEndpointIdentificationAlgorithm but presumably OkHTTP does because the host name is verified.

@gnarea Great, thanks for the update.

We're switching to OkHTTP since that's what you recommend on Android anyway. That channel doesn't call setEndpointIdentificationAlgorithm but presumably OkHTTP does because the host name is verified.

Correct, the OkHttp code was developed well before API 24, so hostname validation is done "manually" in the OkHttp code path itself.

Thanks for all the help. Might be worth adding this gotchas to the documentation. At least that client-side gRPC Netty is not working right now on Android API < 24.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

emaayan picture emaayan  路  8Comments

njovy picture njovy  路  5Comments

darewreck54 picture darewreck54  路  5Comments

nddipiazza picture nddipiazza  路  3Comments

nanil4568 picture nanil4568  路  5Comments