Skip to content
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

[Android] Resolve Android-specific active issues in System.Net.Security and System.Security.Cryptography #104352

Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ private static bool DetermineBinaryFormatterSupport()
{
return false;
}

Assembly assembly = typeof(System.Runtime.Serialization.Formatters.Binary.BinaryFormatter).Assembly;
AssemblyName name = assembly.GetName();
Version assemblyVersion = name.Version;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

using Xunit;
using Xunit.Abstractions;
using Microsoft.DotNet.XUnitExtensions;

namespace System.Net.Security.Tests
{
Expand Down Expand Up @@ -40,9 +41,13 @@ public void Dispose()
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(false, false)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task CertificateSelectionCallback_DelayedCertificate_OK(bool delayCertificate, bool sendClientCertificate)
{
if (delayCertificate && OperatingSystem.IsAndroid())
{
throw new SkipTestException("Android does not support delayed certificate selection.");
}

X509Certificate? remoteCertificate = null;

(SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ public async Task DefaultConnect_EndToEnd_Ok(string host)
[Theory]
[InlineData(true)]
[InlineData(false)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public Task ConnectWithRevocation_WithCallback(bool checkRevocation)
{
X509RevocationMode mode = checkRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
Expand Down Expand Up @@ -266,9 +265,13 @@ private async Task ConnectWithRevocation_WithCallback_Core(

if (offlineContext.HasValue)
{
// on android we need to include the root certificate in the certifiate context
X509Certificate2[] additionalCertificates = OperatingSystem.IsAndroid()
? [issuerCert, rootCert]
: [issuerCert];
serverOpts.ServerCertificateContext = SslStreamCertificateContext.Create(
serverCert,
new X509Certificate2Collection(issuerCert),
new X509Certificate2Collection(additionalCertificates),
offlineContext.GetValueOrDefault());

if (revocationMode == X509RevocationMode.Offline)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public async Task ServerAsyncAuthenticate_EachSupportedProtocol_Success(SslProto

[Theory]
[MemberData(nameof(ProtocolMismatchData))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task ServerAsyncAuthenticate_MismatchProtocols_Fails(
SslProtocols clientProtocol,
SslProtocols serverProtocol)
Expand All @@ -60,7 +59,16 @@ public async Task ServerAsyncAuthenticate_MismatchProtocols_Fails(
});

Assert.NotNull(e);
Assert.IsType<AuthenticationException>(e);

if (OperatingSystem.IsAndroid() && (PlatformDetection.IsX64Process || PlatformDetection.IsX86Process))
{
// On Android running on x64 or x86 the server side sometimes throws IOException instead of AuthenticationException
Assert.True(typeof(IOException) == e.GetType() || typeof(AuthenticationException) == e.GetType(), $"Unexpected exception type: {e.GetType()}");
simonrozsival marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
Assert.IsType<AuthenticationException>(e);
}
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ public async Task SslStream_StreamToStream_Alpn_Success(SslProtocols protocol, L
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task SslStream_StreamToStream_Alpn_NonMatchingProtocols_Fail()
{
(SslStream clientStream, SslStream serverStream) = TestHelper.GetConnectedSslStreams();
Expand All @@ -155,7 +154,8 @@ public async Task SslStream_StreamToStream_Alpn_NonMatchingProtocols_Fail()
};

// Test ALPN failure only on platforms that supports ALPN.
if (BackendSupportsAlpn)
// On Android, protocol mismatch won't cause an exception, even though it supports ALPN.
if (BackendSupportsAlpn && !OperatingSystem.IsAndroid())
{
Task t1 = Assert.ThrowsAsync<AuthenticationException>(() => clientStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions));
await Assert.ThrowsAsync<AuthenticationException>(() => serverStream.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions).WaitAsync(TestConfiguration.PassingTestTimeout));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -695,10 +695,15 @@ public async Task SslStream_NestedAuth_Throws()
[InlineData(false, true)]
[InlineData(false, false)]
[InlineData(true, true)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task SslStream_TargetHostName_Succeeds(bool useEmptyName, bool useCallback)
{
string targetName = useEmptyName ? string.Empty : Guid.NewGuid().ToString("N");
if (PlatformDetection.IsAndroid && !useEmptyName)
simonrozsival marked this conversation as resolved.
Show resolved Hide resolved
{
// Android does not allow single-word hostnames other than "localhost"
targetName = "localhost";
}

int count = 0;

(Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams();
Expand Down Expand Up @@ -751,12 +756,16 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
}
}

[Theory]
[ConditionalTheory]
[InlineData(true)]
[InlineData(false)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task SslStream_ServerUntrustedCaWithCustomTrust_OK(bool usePartialChain)
{
if (usePartialChain && OperatingSystem.IsAndroid())
{
throw new SkipTestException("Android does not support partial chain validation.");
}

int split = Random.Shared.Next(0, _certificates.serverChain.Count - 1);

var clientOptions = new SslClientAuthenticationOptions() { TargetHost = "localhost" };
Expand Down Expand Up @@ -854,8 +863,8 @@ private async Task SslStream_ClientSendsChain_Core(SslClientAuthenticationOption
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/73862", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Android, "It is not possible to add the intermediate certificates to the trust store on Android at runtime.")]
public async Task SslStream_ClientCertificate_SendsChain()
{
// macOS ignores CertificateAuthority
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public class SslStreamSniTest
{
[Theory]
[MemberData(nameof(HostNameData))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task SslStream_ClientSendsSNIServerReceives_Ok(string hostName)
{
using X509Certificate serverCert = Configuration.Certificates.GetSelfSignedServerCertificate();
Expand Down Expand Up @@ -237,7 +236,6 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task UnencodedHostName_ValidatesCertificate()
{
string rawHostname = "räksmörgås.josefsson.org";
Expand Down Expand Up @@ -284,7 +282,7 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
[InlineData("www-.volal.cz")]
[InlineData("www-.colorhexa.com")]
[InlineData("xn--www-7m0a.thegratuit.com")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
[SkipOnPlatform(TestPlatforms.Android, "Safe invalid IDN hostnames are not supported on Android")]
public async Task SslStream_SafeInvalidIdn_Success(string name)
{
(SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams();
Expand Down Expand Up @@ -369,6 +367,16 @@ private async Task WithVirtualConnection(Func<SslStream, SslStream, Task> server

public static IEnumerable<object[]> HostNameData()
{
if (OperatingSystem.IsAndroid())
{
yield return new object[] { "localhost" };
yield return new object[] { "dot.net" };
// max allowed hostname length is 63
yield return new object[] { $"{new string('a', 59)}.net" };
yield return new object[] { "\u017C\u00F3\u0142\u0107g\u0119\u015Bl\u0105ja\u017A\u0144.\u7EA2\u70E7.\u7167\u308A\u713C\u304D" };
yield break;
}

yield return new object[] { "a" };
yield return new object[] { "test" };
// max allowed hostname length is 63
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ namespace System.Net.Security.Tests
public class TransportContextTest
{
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/68206", TestPlatforms.Android)]
public async Task TransportContext_ConnectToServerWithSsl_GetExpectedChannelBindings()
{
(Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams();
Expand Down Expand Up @@ -50,6 +49,10 @@ private static void CheckTransportContext(TransportContext context)
{
Assert.True(cbt2 == null, "ChannelBindingKind.Unique token data is not expected on OSX platform.");
}
else if (OperatingSystem.IsAndroid())
simonrozsival marked this conversation as resolved.
Show resolved Hide resolved
{
Assert.True(cbt2 == null, "ChannelBindingKind.Unique token data is not expected on Android platform.");
}
else
{
Assert.True(cbt2 != null, "ChannelBindingKind.Unique token data should be returned.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,6 @@ public static void BuildChainForSelfSignedSha3Certificate()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/100224", typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid), nameof(PlatformDetection.IsArmOrArm64Process))]
public static void BuildChainForSelfSignedCertificate_WithSha256RsaSignature()
{
using (ChainHolder chainHolder = new ChainHolder())
Expand All @@ -1284,12 +1283,22 @@ public static void BuildChainForSelfSignedCertificate_WithSha256RsaSignature()
// minimum be marked UntrustedRoot.

Assert.False(chain.Build(cert));
AssertExtensions.HasFlag(X509ChainStatusFlags.UntrustedRoot, chain.AllStatusFlags());

if (PlatformDetection.IsAndroid)
{
// Android always validates trust as part of building a path,
// so violations comes back as PartialChain with no elements
Assert.Equal(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
Assert.Equal(0, chain.ChainElements.Count);
}
else
{
AssertExtensions.HasFlag(X509ChainStatusFlags.UntrustedRoot, chain.AllStatusFlags());
}
}
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/100224", typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid), nameof(PlatformDetection.IsArmOrArm64Process))]
public static void BuildChainForSelfSignedCertificate_WithUnknownOidSignature()
{
using (ChainHolder chainHolder = new ChainHolder())
Expand All @@ -1311,6 +1320,12 @@ public static void BuildChainForSelfSignedCertificate_WithUnknownOidSignature()
Assert.False(chain.Build(cert));
AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
}
else if (PlatformDetection.IsAndroid)
{
Assert.False(chain.Build(cert));
AssertExtensions.HasFlag(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
Assert.Equal(0, chain.ChainElements.Count);
}
else if (PlatformDetection.IsOpenSslSupported)
{
Assert.False(chain.Build(cert));
Expand Down
3 changes: 2 additions & 1 deletion src/tasks/AndroidAppBuilder/Templates/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
<uses-permission a:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission a:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application a:label="%PackageName%"
a:largeHeap="true">
a:largeHeap="true"
a:usesCleartextTraffic="true">
<activity a:name="net.dot.MainActivity" a:exported="true">
<intent-filter>
<category a:name="android.intent.category.LAUNCHER"/>
Expand Down
Loading