Trust additional CAs and make use of the Android certificate store in a net6 MAUI solution

Viewed 439
System.Net.WebException: 
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.'

This is an error that occurs in my VS2022 solution when working with a self signed certificate and Android.

The case is the following:
It is an android app that runs on an local network, with a local https backend service. A certificate has been issued for this service by the domain admin. However, the domain is not an official CA (Certificate Authority). You then have to manually install a CA, via settings.

Part of the solution
What I did to solve this is adding the CA certificates to the Android device (via Settings > Security -> Encryption & Credentials -> Install a Certificate).

The web browser, in the android app, can now successfully access the https site, without warnings.

I still need help with
However the CA store is not accessible via the app unless it is configured via network-security-config: https://developer.android.com/training/articles/security-config#TrustingAdditionalCas

This is something that can be done in the Xamarin days like:

But in MAUI I'm a bit lost, I don't see the right resources, mipmap, etc.

I would like to solve this issue with a one-liner like this:

[assembly: Application(UsesCleartextTraffic = true)]

...which can also be configured via the via network-security-config.

Is there a one-liner or can someone help me out configuring my network-security-config to get the CA store available in a MAUI solution?

3 Answers

After this suggestion of Gerald, "So you can still add a xml folder under Resources (under the Android folder that is)", I finally got it!

enter image description here

Add a network_security_config.xml file, under the Android folder, with:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
        <!-- Trust preinstalled CAs -->
        <certificates src="system" />
        <!-- Additionaly trusted user added CAs -->
        <certificates src="user"/>
    </trust-anchors>
    </base-config>
</network-security-config>

And in your AndroidManifest.xml add the: android:networkSecurityConfig="@xml/network_security_config" attribute to your Application node.
So, add it to the already existing node, don't add a new one (or else you'll get strange errors):

enter image description here

And the trust anchor exception is gone, but I'm still curious if there is another way - without the network-security-config. ;-)

PS Don't forget to add the CA certificates to the Android device, as stated in the original question.

OK so I see a couple of things here and not sure what you're after exactly so let me go over it one by one.

Let's start with: if you can, please avoid using clear text traffic! ;)

UseClearTextTraffic Attribute

Then, the easy one, you want the [assembly: Application(UsesCleartextTraffic = true)] oneliner. You can totally still do that and actually you can now that throughout the whole project I think. But it makes the most sense in Android.

Notice how the attribute says assembly so it works for the whole assembly anyway and it doesn't really matter where you put it. That is how it typically works. However, in .NET MAUI there is already a [Application] attribute above the MainApplication, so open that and modify it like below.

namespace MauiAndroidClearText;

[Application(UsesCleartextTraffic = true)]
public class MainApplication : MauiApplication
{
   // Your code
}

Network Security Config

Basically your separate Android project is now under the Platforms\Android folder. Everything you put there, even if it's not there by default, will still behave as it was in a separate Android project.

So you can still add a xml folder under Resources (under the Android folder that is), then add the network_security_config.xml file with:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain> <!-- Debug port -->
    <domain includeSubdomains="true">xamarin.com</domain>
  </domain-config>
</network-security-config>

And in your AndroidManifest.xml add the android:networkSecurityConfig="@xml/network_security_config" attribute to your Application node.

See a full sample here: https://github.com/jfversluis/MauiAndroidClearText

How you asked how you could trust a self signed root certificate (self signed CA) without needed to install in the device, I will share the code.

I am using a MAUI project that use .NET 6.

In the MAUI project, in platform/android/resources/raw, you have to copy your ca.crt certificate. It can have .crt or .pem extension. In my case, I use .crt.

The raw folder is not created by default, so you have to create this folder.

In platform/android/resources, you have to create the folder xml, so you will have platform/android/resources/xml folder. In this folder, add a new xml file, with this name: network_security_config.xml.

This file set the certificates in which you want to trust.

The code of this file is:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config>
    <!--NOTA: el subdominio es necesario porque si no no se podrĂ¡ instalar-->
    <domain includeSubdomains="true">192.168.1.200</domain>
    <trust-anchors>
      <certificates src="@raw/ca"/>
    </trust-anchors>
  </domain-config>
</network-security-config>

The certificate is ca, with no extension, if not, it will give an error when you try to compile.

You have to include a subdomain, in my case, the IP of the server, because I am not inside a domain. If you don't set this, when you try to debug it doesn't start, gives problems.

You have to edit the file AndroidManifest.xml, this exists. The code of my file is this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"
               android:networkSecurityConfig="@xml/network_security_config"></application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

You only need to add android:networkSecurityConfig="@xml/network_security_config" in the application entry. This tells that you will config the network security.

That's all, you can build the project and then the application will include the CA in the trusted certificates, so you don't need to install the certificate in the device.

You can also see the following documentation for more information:

https://developer.android.com/training/articles/security-config

If you have some question, tell me and I will try tohelp.

Related