-
Notifications
You must be signed in to change notification settings - Fork 5.6k
[Android] Enable TlsContext/TlsSession on Android #131461
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
base: main
Are you sure you want to change the base?
Changes from all commits
6ebc14b
4488d55
fc62c10
0cd119e
cef39c2
c6a2c40
d68493e
550db57
8d771cc
49c7199
0ebc0cb
7a994d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Security.Cryptography.X509Certificates; | ||
|
|
||
| namespace System.Net.Security | ||
| { | ||
| public abstract partial class TlsSession | ||
| { | ||
| private bool _platformChainRejected; | ||
|
|
||
| partial void InitializePlatformSpecificSessionState() | ||
| { | ||
| // In wedge mode the options bag is shared with SslStream, which installs its own | ||
| // proxy in its constructor. Only supply one when the bag does not already have it, | ||
| // so SslStream's callback routing stays intact and its JavaProxy is not leaked. | ||
| _options.SslStreamProxy ??= new SslStream.JavaProxy(AcceptAndDeferPlatformValidation); | ||
| } | ||
|
|
||
| partial void SeedPlatformValidationErrors(ref SslPolicyErrors sslPolicyErrors) | ||
| { | ||
| if (_platformChainRejected) | ||
| { | ||
| sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; | ||
| } | ||
| } | ||
|
|
||
| // Invoked synchronously from Android's DotnetProxyTrustManager. Always accepts so | ||
| // the handshake progresses; the platform verdict (if respected) is recorded and | ||
| // surfaced later through AcceptWithDefaultValidation. The verdict is assigned rather | ||
| // than latched so a later validation (e.g. renegotiation with a different chain) is | ||
| // not tainted by an earlier rejection. | ||
| private SslStream.JavaProxy.RemoteCertificateValidationResult AcceptAndDeferPlatformValidation(IntPtr platformValidationError) | ||
|
Comment on lines
+28
to
+33
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remember that always accepting during handshake and only surfacing the result later did not work on Android and was causing all sorts of problem. That's the reason why we even needed the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you have specific examples? Maybe you can ping me privately. I'm open to what ever this needs. As I mentioned , the goal is to isolate TLS functionality here and make SslStream consumer of it. So in general it needs to do everything SslStream needs. I used my local setup with emulator and the CI Android pipeline for verification. But I can broaden that as needed. Also we may do follow-up fixes if/when need to. This is primarily for the completeness so we can start on the SslStream internal cleanup.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did little bit more digging @simonrozsival The fundamental problem is that the trust manager runs inside the PAL call on the caller's thread. To block it until the caller posts a verdict, the caller can't be the blocked thread, or it can never return from Handshake() to supply one. And since we can't know which frame carries the peer Certificate, we can't offload just that call — the session would have to drive all PAL interaction on a dedicated thread from the start. So it did work for SslStream with synchronous callback. But that is problematic in general as the validation may need to fetch intermediates or do other IO (like revocation check) so to do it right would should probably add some ways hot to support asynchronous validation in SslStream. @rzikm did some work for OpenSSL but that still have some caveats. And this goes possibly beyond handshake: with TLS 1.3 post-handshake auth the peer certificate arrives during application data, so the trust manager can fire inside Read/Write/RequestClientCertificate as well. So every PAL entry point becomes a cross-thread handoff, with the worker JNI-attached for the session's lifetime. I'm not sure what would be good way out of this and I'm open to suggestions. |
||
| { | ||
| bool rejected = platformValidationError != IntPtr.Zero && ShouldRespectPlatformValidation(); | ||
| _platformChainRejected = rejected; | ||
|
|
||
| if (rejected && NetEventSource.Log.IsEnabled()) | ||
| { | ||
| string? validationError = Interop.AndroidCrypto.GetPlatformValidationError(platformValidationError); | ||
| NetEventSource.Error(this, $"The Android platform trust manager rejected the remote certificate chain: {validationError}"); | ||
| } | ||
|
|
||
| return new SslStream.JavaProxy.RemoteCertificateValidationResult | ||
| { | ||
| IsValid = true, | ||
| SslPolicyErrors = SslPolicyErrors.None, | ||
| ChainStatus = default, | ||
| AlertToken = default, | ||
| }; | ||
| } | ||
|
|
||
| private bool ShouldRespectPlatformValidation() | ||
| { | ||
| return _options.CertificateChainPolicy is not null | ||
| ? _options.CertificateChainPolicy.TrustMode != X509ChainTrustMode.CustomRootTrust | ||
| : _options.CertificateContext?.Trust is null; | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.