Skip to content

okhttp: use new APIs for configuring TLS whenever possible (Android Q+) #6912

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

voidzcy
Copy link
Contributor

@voidzcy voidzcy commented Apr 8, 2020

Use Android Q+'s new APIs for configuring TLS whenever possible. The new APIs are

Calling the hidden methods SSLSocket#setAlpnProtocols(...) and SSLSocket#getAlpnProtocol() in Android R throws an UnsupportedAppUsage exception in internal version of Android R (annotated on Android's Conscrypt). This PR migrates to invoke new public APIs for configuring Conscrypt whenever possible. Only fall back to invoke the old reflective APIs in when new APIs are not available (and for work around Conscrypt's bug as mentioned in #6912 (comment)).

There is also a new API for enabling SNI on SSLParameters introduced from Android 24. It requires constructing SNIHostName (also introduced from API 24). This PR also migrates to use that whenever possible.

I tested code execution for configuring Conscrypt under different environments:
(Note SSLSockets#setUseSessionTickets(...) is only supported for com.android.org.conscrypt sockets).

Android API version Play Service App-bundled Conscrypt Socket type Enable session tickets Enable SNI Configure ALPN
R Yes No "com.google.android.gms.org.conscrypt" Old API New API Both due to Conscrypt bug
R No No "com.android.org.conscrypt" New API New API New API
R No Yes "org.conscrypt" Old API New API Both due to Conscrypt bug
27 Yes No "com.google.android.gms.org.conscrypt Old API New API Old API
27 No No "com.android.org.conscrypt" Old API New API Old API
27 No Yes "org.conscrypt" Old API New API Old API

@voidzcy voidzcy force-pushed the bugfix/okhttp_config_tls_with_public_apis_on_android_r branch from c47f4dd to f035d6e Compare April 8, 2020 19:00
@voidzcy voidzcy force-pushed the bugfix/okhttp_config_tls_with_public_apis_on_android_r branch from f035d6e to aa9b7ec Compare April 8, 2020 19:01
@voidzcy voidzcy force-pushed the bugfix/okhttp_config_tls_with_public_apis_on_android_r branch from b005895 to 0e6e2d0 Compare April 8, 2020 20:16
@voidzcy voidzcy marked this pull request as ready for review April 14, 2020 18:56
@voidzcy voidzcy requested review from ericgribkoff and ejona86 April 14, 2020 18:57
Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

com.google.android.gms.org.conscrypt on R should support the new API. I'm concerned to hear it doesn't. We should probably discuss, since there may be something that invalidated your test.

@ejona86
Copy link
Member

ejona86 commented Apr 14, 2020

Note: we'd ideally not do this work in the Android Platform and instead use JdkAlpnPlatform. We should be thinking about swapping to the new SNI APIs as well.

@ejona86
Copy link
Member

ejona86 commented Apr 15, 2020

With some testing @voidzcy confirmed that Conscrypt was truly not throwing UnsupportedOperationException for getApplicationProtocols and also failing to do ALPN. On investigating, it appears it is simply because Conscrypt ignores the ALPN SSLParameters on Android: google/conscrypt#832 .

This feels like it will be a thorn in our side for a good while. We will want to figure out a workaround if we can. From the code it looks like we can getSSLParamaters after calling setSSLParameters to see if the ALPN configuration is still present.

sslSocket.setSSLParameters(sslParams);
// Check protocol configuration through SSLParameters succeeds. If not, fall back to
// configure with the old reflective method.
// Workaround for Conscrypt issue: https://github.com/google/conscrypt/issues/832
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written, this is not working around Conscrypt. This is checking whether the API is supported in a Conscrypt-compatible way. For this to be a workaround we would need to do the does-GET_APPLICATION_PROTOCOL-throw check before this, or we would need to say "we aren't checking getApplicationProtocol as a Conscrypt workaround".

Copy link
Contributor Author

@voidzcy voidzcy Apr 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you are really referring to SSLParameters#getApplicationProtocols() instead of SSLSocket#getApplicationProtocol() here. The former never throw (we aren't doing the latter during configuration). The getApplicationProtocols() check really is to see if protocols configured on SSLParameters are propagated to SSLSocket, which is only because Conscrypt on Android does this incorrectly. Normally we wouldn't need to do this. Isn't this a workaround?

I agree now it looks more like checking whether the API is supported in a Conscrypt-compatible way due to using duck-type method calls. After changing to normal Method and only do this when APIs are available, it would be clearer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was referring to SSLSocket.getApplicationProtocol().

An API was added in Java 9 and Android API 27 to configure ALPN. But that API is implemented by multiple implementations. So we can't assume that if the API is there that it works. I was suggesting to use SSLSocket.getApplicationProtocol() before any negotiation has occurred to see if ALPN is supported in this fashion. If the method throws UnsupportedOperationException then the implementation does not support that API and we should try other APIs. That is the way we decided to handle it in Netty.

Copy link
Contributor Author

@voidzcy voidzcy Apr 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That was what we used to find the Conscrypt bug. Due to that bug, even the invocation of SSLSocket.getApplicationProtocol() before any negotiation has occurred does not throw UnsupportedOperationException, ALPN is still not configured correctly. Here, we are working around that bug. Consequently, this check also helps us verifying the SSLSocket is configured with ALPN, isn't it? So do we still need the does-GET_APPLICATION_PROTOCOL-throw check?

@voidzcy
Copy link
Contributor Author

voidzcy commented Apr 15, 2020

Addressed all the comments and tested locally with different Conscrypt settings. PTAL. Thanks.

voidzcy added 2 commits April 15, 2020 12:33
…). It cannot be verified now as we are using reflections loaded statically.
@voidzcy voidzcy requested a review from ejona86 April 16, 2020 16:58
Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@voidzcy voidzcy merged commit 5803dfd into grpc:master Apr 17, 2020
voidzcy added a commit to voidzcy/grpc-java that referenced this pull request Apr 20, 2020
voidzcy added a commit to voidzcy/grpc-java that referenced this pull request Apr 21, 2020
voidzcy added a commit that referenced this pull request Apr 21, 2020
…#6959)

* Revert "okhttp: Skip enabling SNI and session ticket for fake/test host names (#6949)"

This reverts commit eb8e314.

* Revert "okhttp: use new APIs for configuring TLS whenever possible (Android Q+) (#6912)"

This reverts commit 5803dfd.
dfawley pushed a commit to dfawley/grpc-java that referenced this pull request Jan 15, 2021
…+) (grpc#6912)

Use new APIs for configuring TLS in Android environment. Starting from Android 29, there is a new set of public APIs for configuring ALPN (and starting from Android 24, there is API for enabling SNI). This change migrates to use these new APIs whenever possible. Only fallback to call the old hidden APIs if new ones do not exist (or do not work).
dfawley pushed a commit to dfawley/grpc-java that referenced this pull request Jan 15, 2021
…grpc#6959)

* Revert "okhttp: Skip enabling SNI and session ticket for fake/test host names (grpc#6949)"

This reverts commit eb8e314.

* Revert "okhttp: use new APIs for configuring TLS whenever possible (Android Q+) (grpc#6912)"

This reverts commit 5803dfd.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants