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

Mutual Authentication: Certificate chain removed when connecting to server in MAUI app but not Xamarin Forms #100602

Open
vsfeedback opened this issue Apr 2, 2024 · 24 comments
Assignees
Labels
area-System.Net.Http needs-author-action An issue or pull request that requires more info or actions from the author. no-recent-activity os-android
Milestone

Comments

@vsfeedback
Copy link

vsfeedback commented Apr 2, 2024

This issue has been moved from a ticket on Developer Community.


Hi,

When connecting to the server but running the code using Xamarin Forms, the server received the full certificate chain.
Using MAUI .Net 7 or 8.0, only the client certificate is sent to the server. Certificate chain is empty.
Same certificate and server are used.

In HttpWebRequest ServerCertificateValidationCallback, chain.ChainElements is empty.
Certificate received by the server is valid.

Does anyone knows how to fix this?

Here's a snippet on the client:

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);

req.ServerCertificateValidationCallback = ValidateServerCertificate;
req.ProtocolVersion = HttpVersion.Version11;
req.ClientCertificates = certificates;
req.Method = "GET";
req.Accept = "text/plain";
req.KeepAlive = false;
...

private static bool ValidateServerCertificate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
{

}

Original Comments

Feedback Bot on 2/12/2024, 05:46 PM:

(private comment, text removed)


Original Solutions

(no solutions)

@mattleibow mattleibow transferred this issue from dotnet/maui Apr 3, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Apr 3, 2024
@ManickaP
Copy link
Member

ManickaP commented Apr 8, 2024

I'm a bit confused, where is the chains missing? ServerCertificateValidationCallback is for server certificate. ClientCertificates is for sending client certificate to the server. So on which side is the problem?

Also if you're on .NET 7/8, why are you using HttpWebRequest instead of HttpClient? We do not recommend HttpWebRequest for any new development, it's there only for backward compat and easier transition from .NET Framework. It has limited set of features and doesn't get any new development.

@ManickaP ManickaP added the needs-author-action An issue or pull request that requires more info or actions from the author. label Apr 8, 2024
@NexusMobile
Copy link

The missing chains is at the server. Server receives only chain[0]. All the other certificates in the chain are not provided.
Using httpClient provides the same result at the server. Only the client cert is sent.
In the ValidateServerCertificate callback function, chain.ChainElement.Count = 0 that confirms chain is not sent.
This happen using Net6 and Net8 apps.

Using Xamarin Forms app with httpClient or HttpWebRequest both send the full chain of certificate to the server

@ManickaP
Copy link
Member

ManickaP commented Apr 9, 2024

Can you provide us with a repro code? Preferably for both sides? Also if you have a working code, could you share that as well?

Using httpClient provides the same result at the server. Only the client cert is sent.

You can use HttpClient in a server code, but it is still in the role of a client in some other communication with another server. So some of the description still confuses me.

@NexusMobile
Copy link

NexusMobile commented Apr 9, 2024

Hi,

Client code snippet:

/* ************ */
.
.
.

var httpClientHandler = new HttpClientHandler();

httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
httpClientHandler.SslProtocols = SslProtocols.Tls12;
httpClientHandler.ServerCertificateCustomValidationCallback = ValidateServerCertificate;

/* clientCert contains client CA certificates
httpClientHandler.ClientCertificates.Add(clientCert);

HttpClient httpClient = new HttpClient(httpClientHandler);

var username = "test@xxxx.com";
var password = "123456";

string encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
httpClient.DefaultRequestHeaders.Add("Accept", "text/plain");

httpClient.BaseAddress = new Uri("https://192.168.0.109:8443");

HttpResponseMessage response = await httpClient.GetAsync(****URL****);
var jsonResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{jsonResponse}\n");
.
.
.

private static bool ValidateServerCertificate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors  slPolicyErrors)
{
               if (chain != null)
                   Console.WriteLine("chain: {0}", chain.ChainElements.Count); 
               // Printed value is: [DOTNET] chain: 0
               // Same code running in Xamarin Froms, printed value is: chain: 4
               return true;
}

/* ************ */

At the server, we get the same result in ssl handshake function as above regarding certificate chain received from client:
Chain count of 0 and chain count of 4.

BTW, this is a mutual authentication SSL handshake using private CA

Does it help understand the issue?

Regards

@ManickaP
Copy link
Member

ManickaP commented Apr 9, 2024

So the problem is in provided server certificate chain do the validation callback and that it differs based on what platform you compile for? And you claim this difference is between Xamarin Forms and MAUI? Isn't Xamarin foundation of MAUI?

@simonrozsival do you know of any difference there?

@NexusMobile
Copy link

The problem is to provide certificate chain from the client to the server.
From the sample provided above the client does not send the certificate chain to the server.
It works using Xamarin Forms but not using MAUI net 8.0 on Android
I don't understand your last question: Isn't Xamarin foundation of MAUI?
How can I tell?
We are using VS 2022 17.9.5 testing on both platform.

@simonrozsival
Copy link
Member

@NexusMobile can you please try setting <UseNativeHttpHandler>false</UseNativeHttpHandler> in your csproj file and try again? I believe the support for client certificates in Android's native message handler is not working as expected (xamarin/xamarin-android#7274).

@NexusMobile
Copy link

false already in csproj file to fix httpClientHandler.ClientCertificates being null without it.

@NexusMobile
Copy link

While building project using Xamarin Forms it works fine without <UseNativeHttpHanlder>false<\UseNativeHttpHanlder>
Building a MAUI project with .Net8 using the setting above solve only httpClientHanlder.ClientCertificates not being null and have the client send his certificate (without the chain) to the server.

@simonrozsival
Copy link
Member

I see. I originally misread the issue and I thought the problem is with sending the client certificate to the server. The problem actually is that the server's certificate chain doesn't seem to be passed to the ServerCertificateValidationCallback on the client correctly.

Isn't Xamarin foundation of MAUI?

Xamarin.Forms and MAUI have different implementation of the networking layer. Xamarin.Forms uses BoringSSL or OpenSSL and MAUI/.NET 8 on Android uses Android's platform APIs.

@simonrozsival simonrozsival self-assigned this Apr 10, 2024
@simonrozsival simonrozsival added this to the 9.0.0 milestone Apr 10, 2024
@NexusMobile
Copy link

Unless mistaken this is my understanding too.
What would be the next step to get t his resolved?
Thanks again

@simonrozsival
Copy link
Member

simonrozsival commented Apr 10, 2024

@NexusMobile is the server's certificate self-signed? if it is, this would be a duplicate of #84202

The relevant part from the previous discussion:

My understanding of Android is that ChainElements on X509Chain are not populated unless the chain is valid. Contrast this with other operating systems where the chain elements is usually populated, even for partial or incomplete chains.

@NexusMobile
Copy link

@simonrozsival, Client and server certificates are self-signed by the same CA. For us the certification is valid.
When using Xamarin Forms, we validate the client certificate in code at the server.
I've read issue #84202 and I don't think this is the same issue.
Unless mistaken the server certificates is not involved yet at this point, only the client certificate is involved.

@ManickaP ManickaP added os-android and removed untriaged New issue has not been triaged by the area owner labels Apr 11, 2024
@NexusMobile
Copy link

Hi,
Do you need anything else from us?
This issue has tag needs-author-action
Regards

@simonrozsival
Copy link
Member

Unless mistaken the server certificates is not involved yet at this point, only the client certificate is involved.

I think there is still some confusion in this thread. In the client code in the ValidateServerCertificate, the second parameter certificate is the server's certificate sent to the client and the third parameter chain is the server's certificate chain, not the client's.

If I understand your situation correctly, you should include your CA's public key (and possibly also the public keys of the intermediate certifcates) in the client app using network_security_config.xml. Does the network config solve the issue for you?

@NexusMobile
Copy link

My mistake. You are absolutely right.

I've tried network_security_config.xml and I still get an empty chain.
I've confirm also using Wireshark the server's certificate and chain were sent to the app.

Thanks

@NexusMobile
Copy link

I've replaced the self-signed Certificate the server sends to the client with a public certificate and I get the same empty chain.
What would be the next step?

Is it possible to have access to the source code?

@simonrozsival
Copy link
Member

I've replaced the self-signed Certificate the server sends to the client with a public certificate and I get the same empty chain.

That seems like bug and it is different from the issue I shared previously. I need to be able to replicate the issue so I can diagnose it. Can you create a minimal repro in a new MAUI project and share that as a public github repo? Ideally make requests to a public website, such as https://microsoft.com or https://badssl.com (there are multiple subdomains for example with a self-signed certificate).

@NexusMobile
Copy link

I will look into this.
Where can I find "(there are multiple subdomains for example with a self-signed certificate)?
I have found only this one: https://self-signed.badssl.com/
And connecting the app to this site return the same empty chain.
Are there others I can try?

Also from our original post, the client's certificate sent to the server has his chain removed. The certificate's chain count should be 4 in our case but it returns 0.

Thanks

@simonrozsival
Copy link
Member

I will look into this.

Thanks!

I have found only this one: https://self-signed.badssl.com/

I think that is the most relevant one for your use case. The https://client.badssl.com/ should also be relevant for the other half of the problem you describe.

@Coccoliso-1963
Copy link

The CACertificate problem is extensive and has appeared since 17.8 and it concerns the certificates.
From version VS2022-17.8 an Android 13 application in net maui 7.0 no longer connects to a wcf application with certificate if compiled in release ( real device or emulator) but it works if in debug. At the time I rolled it back VS2022 to make it work. Now with vs 2022 17.9.6 in debug the exception throwed is is "not connected" and in release the app is killed at startup (real device or emulator ). The matter has not been resolved even in net maui 8.0, it's the same, no connection in debug or release in Android 13 or 14. The application was created as soon as net maui 7.0 was made available and it never gave any problems even with the auto update.. and it still works if I don't recompile it with VS2022 versions after 17.7.7. Several users use it in production..I feel slightly cheated.

@Coccoliso-1963
Copy link

` var bind = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
bind.MaxReceivedMessageSize = 2147483647;
bind.MaxBufferSize = 2147483647;
bind.ReaderQuotas.MaxArrayLength = 2147483647;
bind.SendTimeout = new TimeSpan(0, 5, 0);

            FEWCF.FEWCFClient _WS = new FEWCF.FEWCFClient(bind, new EndpointAddress(url));
            try
            {
                _WS.ClientCredentials.ClientCertificate.SetCertificate(_storelocation,
                                                                       _storename,
                                                                       X509FindType.FindByThumbprint,
                                                                       _Thumbprint);
            }
            catch
            {
            }

`
.. with StoreLocation System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser and StoreName System.Security.Cryptography.X509Certificates.StoreName.Root
All works until VS2022 17.7.7 then "null".

@simonrozsival
Copy link
Member

@Coccoliso-1963 would you mind opening a new issue so we can track these separately?

Copy link
Contributor

This issue has been automatically marked no-recent-activity because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove no-recent-activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Net.Http needs-author-action An issue or pull request that requires more info or actions from the author. no-recent-activity os-android
Projects
None yet
Development

No branches or pull requests

5 participants