SqlClient: Android - cannot connect to SQL Server Express 2019 using any casual SqlClient version (v2.1.4, v4.1.0, v5Preview)

Describe the bug

Edit: please use the test application version added in the latest comment in this issue (more functions, less hardcoded)

Introduction:

  • there is no issue on Windows
  • on Windows, you should be seeing this with the sample app:
    • image
    • run as image

This is a continuation of this issue: https://github.com/dotnet/SqlClient/issues/1656 There, only Android 9 and higher can communicate with a SQL Server 2012 with latest patch and a valid certificate from DigiCert. The message in SqlException is always the same for both of these issues: (A connection was successfully established with the server, but then an error occurred during the pre-login handshake.)


In this issue, I have set up a local SQL Server Express 2019 instance and opened it to the local network (port 1433). TCP/IP connection is enabled and a SQL account for authentication is set.

These versions of SQL Server API from C# fail to communicate to the instance from Android (.NET MAUI):

  • Microsoft.Data.SqlClient 2.1.4 (EF Core 6.0.6)
  • Microsoft.Data.SqlClient 5.0.0-preview2.22096.2 (EF Core 7.0.0-preview.5.22302.2)
  • Microsoft.Data.SqlClient 4.1.0
  • Microsoft.Data.SqlClient 2.0.0
  • Microsoft.Data.SqlClient 5.0.0-preview3.22168.1
  • System.Data.SqlClient 4.8.3

Result of the test: No Android verison can communicate with the SQL Server Express 2019 instance properly after connection

  • all SqlClient versions have the same result on all Android versions when trying to communicate with the SQL Server 2019 instance -> “…pre-login handshake failed…” SqlException of Class 20 (A connection was successfully established with the server, but then an error occurred during the pre-login handshake.) The Android devices do in fact connect to the server, because if they did not, I would have received a different SqlException.
  • using TrustServerCertificate=true; and/or Encrypt=false; does not help solving the error

Test project:

About the test project:

  • note: watch the Debug Output window or place a breakpoint or execute step-by-step with debugger to observe the results (Label UI controls (which are supposed to show the text result) in MAUI are bugged and do not show on Android)
  • it executes a DB call using the list of SqlClients listed above

Here a detailed look into a separate test of Microsoft.Data.SqlClient 2.1.4 (EF Core 6.0.6 = current) alone:

The following are results (debug output from Visual Studio) with internal errors on Android versions 5,6,8,9,11,12 for attempted communication with SQL Server Express 2019 (all fail with the same error “pre-login handshake…”) for EF COre 6.0.6 (using SqlClient 2.1.4 internally)

  • Android 5 emulator:

    • no internal exception shown
  • Android 6 emulator:

    • no internal exception shown
  • Android 8 emulator:

    • this happens for SQL Server 2012 as well
    •   [System.err] 	at com.android.org.conscrypt.OpenSSLEngineImpl.beginHandshakeInternal(OpenSSLEngineImpl.java:335)
        [System.err] 	at com.android.org.conscrypt.OpenSSLEngineImpl.beginHandshake(OpenSSLEngineImpl.java:325)
        [System.err] 	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
        [System.err] 	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:30)
        [System.err] 	at android.view.View.performClick(View.java:6256)
        [System.err] 	at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
        [System.err] 	at android.view.View$PerformClick.run(View.java:24701)
        [System.err] 	at android.os.Handler.handleCallback(Handler.java:789)
        [System.err] 	at android.os.Handler.dispatchMessage(Handler.java:98)
        [System.err] 	at android.os.Looper.loop(Looper.java:164)
        [System.err] 	at android.app.ActivityThread.main(ActivityThread.java:6541)
        [System.err] 	at java.lang.reflect.Method.invoke(Native Method)
        [System.err] 	at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        [System.err] 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)```
      
      
  • Android 9 emulator:

    • no internal exception shown
  • Android 11 emulator:

    • this does not happen for SQL Server 2012
    • this happens with Encrypt=false and TrustServerCertificate=true
    • [System.err] 	at com.android.org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:362)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1134)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1089)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
      [System.err] 	at com.android.org.conscrypt.Java8EngineWrapper.unwrap(Java8EngineWrapper.java:237)
      [System.err] 	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
      [System.err] 	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:30)
      [System.err] 	at android.view.View.performClick(View.java:7448)
      [System.err] 	at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
      [System.err] 	at android.view.View.performClickInternal(View.java:7425)
      [System.err] 	at android.view.View.access$3600(View.java:810)
      [System.err] 	at android.view.View$PerformClick.run(View.java:28305)
      [System.err] 	at android.os.Handler.handleCallback(Handler.java:938)
      [System.err] 	at android.os.Handler.dispatchMessage(Handler.java:99)
      [System.err] 	at android.os.Looper.loop(Looper.java:223)
      [System.err] 	at android.app.ActivityThread.main(ActivityThread.java:7656)
      [System.err] 	at java.lang.reflect.Method.invoke(Native Method)
      [System.err] 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
      [System.err] 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
      [System.err] Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
      [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:677)
      [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:554)
      [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:510)
      [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:428)
      [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:371)
      [System.err] 	at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:102)
      [System.err] 	at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:106)
      [System.err] 	at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:250)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1644)
      [System.err] 	at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)
      [System.err] 	at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:568)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataHeap(ConscryptEngine.java:1115)
      [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1087)
      [System.err] 	... 18 more
      [System.err] Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
      [System.err] 	... 32 more```
      
      
  • Android 12 emulator:

    •     [System.err] 	at com.android.org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:363)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1134)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1089)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
          [System.err] 	at com.android.org.conscrypt.Java8EngineWrapper.unwrap(Java8EngineWrapper.java:237)
          [System.err] 	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method)
          [System.err] 	at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:30)
          [System.err] 	at android.view.View.performClick(View.java:7441)
          [System.err] 	at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
          [System.err] 	at android.view.View.performClickInternal(View.java:7418)
          [System.err] 	at android.view.View.access$3700(View.java:835)
          [System.err] 	at android.view.View$PerformClick.run(View.java:28676)
          [System.err] 	at android.os.Handler.handleCallback(Handler.java:938)
          [System.err] 	at android.os.Handler.dispatchMessage(Handler.java:99)
          [System.err] 	at android.os.Looper.loopOnce(Looper.java:201)
          [System.err] 	at android.os.Looper.loop(Looper.java:288)
          [System.err] 	at android.app.ActivityThread.main(ActivityThread.java:7839)
          [System.err] 	at java.lang.reflect.Method.invoke(Native Method)
          [System.err] 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
          [System.err] 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
          [System.err] Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
          [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:672)
          [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:549)
          [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:505)
          [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:425)
          [System.err] 	at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:368)
          [System.err] 	at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:102)
          [System.err] 	at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:106)
          [System.err] 	at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:255)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1638)
          [System.err] 	at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)
          [System.err] 	at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:569)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataHeap(ConscryptEngine.java:1115)
          [System.err] 	at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1087)
          [System.err] 	... 19 more
          [System.err] Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
          [System.err] 	... 33 more```
      
      
  • Android 12 device - [System.err] javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. [System.err] at com.android.org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:363) [System.err] at com.android.org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1134) [System.err] at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1089) [System.err] at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876) [System.err] at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747) [System.err] at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712) [System.err] at com.android.org.conscrypt.Java8EngineWrapper.unwrap(Java8EngineWrapper.java:237) [System.err] at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.n_onClick(Native Method) [System.err] at crc64fcf28c0e24b4cc31.ButtonHandler_ButtonClickListener.onClick(ButtonHandler_ButtonClickListener.java:30) [System.err] at android.view.View.performClick(View.java:7451) [System.err] at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194) [System.err] at android.view.View.performClickInternal(View.java:7425) [System.err] at android.view.View.access$3700(View.java:842) [System.err] at android.view.View$PerformClick.run(View.java:28690) [System.err] at android.os.Handler.handleCallback(Handler.java:938) [System.err] at android.os.Handler.dispatchMessage(Handler.java:99) [System.err] at android.os.Looper.loopOnce(Looper.java:346) [System.err] at android.os.Looper.loop(Looper.java:475) [System.err] at android.app.ActivityThread.main(ActivityThread.java:7889) [System.err] at java.lang.reflect.Method.invoke(Native Method) [System.err] at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) [System.err] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1009) [System.err] Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. [System.err] at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:672) [System.err] at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:549) [System.err] at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:505) [System.err] at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:425) [System.err] at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:368) [System.err] at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:102) [System.err] at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:106) [System.err] at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:255) [System.err] at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1638) [System.err] at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method) [System.err] at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:569) [System.err] at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095) [System.err] at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataHeap(ConscryptEngine.java:1115) [System.err] at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1087) [System.err] ... 19 more [System.err] Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. [System.err] ... 33 more

To reproduce

  • have a working SQL Server Express 2019 instance exposed to the network (this tutorial will do: https://www.youtube.com/watch?v=xNmIdFjXzl4)
    • set up a SQL Server Express 2019
    • open port 1433 on firewall
    • configure the SQL Server Express instance to allow SQL authentication
    • enable an account on the instance (e.g. sa)
    • configure the instance to allow TCP/IP connection on port 1433
  • be able to run the MAUI application
    • download latest VS 2022 Preview (because MAUI can only be used in VS 2022 Preview)
    • add the MAUI part in Visual Studio Installer
      • image
    • install some Android emulators (default settings are OK) via Visual Studio -> image
      • or use physical device - after connecting via USB and enabling USB debugging, you should be able to see and use it as follows:
        • image

Note:

  • the connection strings which are hardcoded into the sample app, have the following properties:
    • Database Ordinace devRemin
    • SQL account name sa
    • SQL account password sa
    • a table called USER in the default dbo schema
      • the EF test projects require that it has some columns but you can skip using the EF Core projects because they use SqlClient anyways
        • the other projects simply select number of rows from the USER table (could have selected something from a dummy table or be doing SELECT 'Hello World') the current version simply executes SELECT LEN('Hello World')

Note dotnet/maui#2:

  • the Constants.LocalNetworkConnectionString string has a hardcoded private IP of 192.168.0.234
    • this IP will probably be different in every local network
    • the correct IP can be obtained via running the command line command ipconfig on the host machine running the SQL Express (this example requires that the Android device and the machine hosting the SQL Server are in the same local network so that private IP can be used (or you can share your SQL Server Express to the internet and use a public IP address in fact but I did not do that)
      • look for IPv4 Address entry in the output of the ipconfig command, that’s the private/local IP address

Expected behavior

Android can communicate with the SQL Server Express.

Further technical details

.NET target: .NET 6.0 (dotnet --version: 6.0.400-preview.22301.10) SQL Server version: SQL Server Express 2019 Operating system: Windows 10 21H1

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 38 (10 by maintainers)

Most upvoted comments

Hi, I managed to get it working on the android emulator running Android 21 with Sql Server 2019 and M.D.SqlClient 5.0 GA.

After I generated the self signed certs and installing them on both the sql server and android emulator by following the instructions from @stegl83 on creating the self signed certificate here and installing certs i.e. installing pfx file on the my local sql server and the crt file onto the android device by copying it using adb push <path_to_self_signed_crt_not_pfx> /sdcard/download/ directory and on the device, going into settings and installing the certificate.

Go into Settings > Security > Encryptions & credentials > Install a certificate > CA Certificate install_cert_on_android Select Install Anyway and locate your certificate in your Downloads folder install_cert_on_android_2 Once installed, the notification will give you warning that there’s a CA installed from an unknown third party, which means your self-signed cert was installed successfully install_cert_on_android_3

Since my android emulator and the sql server were both on the same machine. I found this article on the MAUI documentation and use the 10.0.2.2 ip address instead of my machine’s hostname and adding the following to the network_security_config.xml in addition to the previous instructions on the MAUI side.

    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">10.0.2.2</domain>
    </domain-config>

Now boot up your app, and connect to 10.0.2.2,1433 or whichever port you chose for your Sql Server and it should get passed the connection.Open()

and the connection string I used is: Data Source=tcp:10.0.2.2,1433;Database=Northwind;uid=sa;pwd=***;encrypt=false;Connection Timeout = 30;TrustServerCertificate=true;

note: don’t use trusted_connection=true; in the connection string as it’ll override the uid and pwd as I tested it and resulted in a System.Data.Security.Native unable to load dll error with a stack trace identical to this.

As soon as I removed the self-signed cert from either end i.e. android or sql server, the error 35 returns. I recall reading that the Azure Sql Server doesn’t run into this issue, which I’m going to guess is because it’s the url i.e. *.database.windows.net might already have proper ssl certificate issued by an official CA installed on the server and the client automatically trusts the certificate, so it doesn’t this setup.

Let me know if this works for you.

There are good news about the issue: dotnet/runtime#77386 has been merged. Maybe we have a solution in .NET 8.

I followed that post while ago, the bad thing is that we have to wait 10 months, Right? xD

Yeah, right. But better than never get it because its moved to the “backlog” AKA recycle bin. I’m waiting for the first preview of .NET 8 for MAUI …

There are good news about the issue: https://github.com/dotnet/runtime/pull/77386 has been merged.

Maybe we have a solution in .NET 8.

We still have no solution to make it works without a cert right now, right?

Yes, that is correct for a local/on-prem SQL Server. I believe it works for an Azure SQL Database without manually trusting the self-signed certificate on the device because the certificate comes from a trusted certificate authority. My assumption is that implementation to Trust Server Certificate is overwritten by the OS security levels on the device, but further investigation is required.

I’m closing this issue as it’s an issue caused by the runtime and is fixed when a new version of .NET is released.

There are good news about the issue: dotnet/runtime#77386 has been merged.

Maybe we have a solution in .NET 8.

I followed that post while ago, the bad thing is that we have to wait 10 months, Right? xD

i know the security of “direct” communicate with SQL Server Database. but we just “connect” locally, and no security issues here with small team like me. and too expensive with Restfull API, because we are not big team or corporate. so maybe someone can fixed this bug? please

Hi @janseris,

we spend a LOT of hours to get this working.

You have to use certificates, without them there is no connection possible.
This is our way to achieve the successful connection:

Setup the Device and Server

  1. create a selfsigned Cert, consider this:
    • the Flag “CA:TRUE” must be set
    • set the commonName to the ServerName like this: [PCName].[Domain].local
    • Build a CRT-File and a PFX
  2. install the CRT-File on the device and the PFX on the Server (we have installed the cert in the Store “Computer/own Cert” and make a copy to "trustworthy root… " (in german it was “Vertrauenswürdige Stammzertifizierungsstellen”)
  3. Set Permission -> “Manage Private Keys” see Link below (2)
  4. you can now select the cert in the certicate-Tab in SQL Configuration Mgr (SQL-Network config -> Right click on Protocols)
  5. restart SqlService

Setup the MAUI-App (You have to explicitly allow User Certificates)

  1. AndroidManifest (in application-tag): android:networkSecurityConfig=“@xml/network_security_config

  2. include “network_security_config.xml” in project network_security_config.zip

  3. ConnectionString like this: Data Source=[PCName].[Domain].local; … ;Trust Server Certificate=True

Give a Try.

Links: (1) https://codekabinett.com/rdumps.php?Lang=2&targetDoc=create-install-ssl-tls-certificate-sql-server (2) https://stackoverflow.com/questions/36830411/how-can-i-give-sql-server-permission-to-read-my-ssl-key

We still have no solution to make it works without a cert right now, right?

From a brief look at how the TrustServerCertificate connection parameter is used, it seems like it’s only referenced when encrypt parameter is set to true or mandatory during the enabling of ssl, and will require more investigation in the MDS.SNI to figure out how it works.

The SSL/TLS moment is here during SQL Server login process. This part of the connection is always encrypted even when Encrypt=false. Otherwise, plaintext login and password would be sent over the network because SQL Server communication is not encrypted by default. AFAIK what we are talking all the time about here is that the SSL problem is in the login process because everything fails at this moment (the Encrypt true /false option isn’t used at all because the actual data transfers aren’t even initiated when login fails because of Android errors)

Managed to solve it with cert and IP address. How?

  1. Create a cert with powershell for your IP address: New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname ‘192.168.0.15’,‘localhost’ -KeySpec KeyExchange -FriendlyName ‘192.168.0.15’ -NotAfter (Get-Date).AddMonths(240) (Will work with any IP address of your sql server later).

  2. Set your cert in SQL Server Configuration manager.

  3. Export that certificate as Base-64 encoded X.509 (.CER) file.

  4. Import that cer in Platforms\Android\Resources\raw folder (if it does not exist create it).

  5. In Platforms\Android\xml folder create nsc.xml (for me was not working if I name it network_security_config.xml) with content: (change the data ofc IP and domain names and @raw/certname mine was called razvoj1.cer in \Platforms\Android\Resources\raw folder and my SQL server IP was 192.168.0.15 )

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
	<base-config cleartextTrafficPermitted="true">
		<trust-anchors>
			<certificates src="system" />
			<certificates src="user" />
			<certificates src="@raw/razvoj1"/>
		</trust-anchors>
	</base-config>
    <domain-config cleartextTrafficPermitted="true">
		<domain includeSubdomains="true">localhost</domain>
		<domain includeSubdomains="true">192.168.0.15,1433</domain>
		<domain includeSubdomains="true">192.168.0.15</domain>
        <domain includeSubdomains="true">RAZVOJ1</domain>
		<domain includeSubdomains="true">RAZVOJ1.localhost</domain>
		<trust-anchors>
			<certificates src="system" />
			<certificates src="user" />
			<certificates src="@raw/razvoj1"/>
		</trust-anchors>
    </domain-config>
</network-security-config>
  1. In AndroidManifest add android:usesCleartextTraffic=“true” and android:networkSecurityConfig = “@xml/nsc” to application tag :
<?xml version="1.0" encoding="utf-8"?>
<manifest android:targetSandboxVersion="1" xmlns:android="http://schemas.android.com/apk/res/android">
	<application android:allowBackup="true" 
				 android:icon="@mipmap/appicon" 
				 android:roundIcon="@mipmap/appicon_round"
				 android:usesCleartextTraffic="true"
			         android:networkSecurityConfig="@xml/nsc"
				 android:supportsRtl="true"></application>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission android:name="android.permission.INTERNET" />
</manifest>
  1. Use this connection string: string connectionString = @“Server=192.168.0.15,1433;Database=YOURDB;User Id=sa;Password=YOURPASS;Persist Security Info=True;Encrypt=True;TrustServerCertificate=True”;

  2. You should be able to open SQLConnection with Microsoft.Data.SQLClient 5.0.0 and .net 7 MAUI

I’m glad that I could help you. It’s annoying that we have so much effort for securing a connection in private network. Not only to spend a lot of hours to get this running, as far as there is no easier solution, we had additional effort for maintaining certificates on server and devices in each production environment we set up.

The next step is to find if its possible to rollout a certificate by MDM (Android Enterprise).

btw. there are very similar issues with SSL in SMTP, WebSocket and gRPC to this one also for MAUI Android. Mainly affecting older Android versions, sometimes precisely matching the Android versions in this issue -> 8.1 and lower vs 9.0 and higher

SMTP: https://github.com/dotnet/maui/issues/9587 probably related and matching Android versions, too gRPC: https://github.com/xamarin/xamarin-android/issues/7274 not sure if directly related WebSocket: https://github.com/dotnet/runtime/issues/83118 with very familiar error

java.lang.IllegalStateException: Handshake has already been started W System.err: at com.android.org.conscrypt.OpenSSLEngineImpl.beginHandshakeInternal(OpenSSLEngineImpl.java:335)

Thanks @janseris for your thorough analysis. I’m currently investigating dotnet/maui#1412 and it seems like a similar issue. I’m able to reproduce the connection failure issue using Sql Server 2019 express edition, and my .NET6 MAUI app running with MDS v5.0 on the Android Emulator running Android 12.1. Also did some digging and saw the issue also mentioned here https://github.com/dotnet/maui/issues/3522 that the project needs to set it’s SSL/TLS Implementation to Native TLS 1.2+ ; however, in .NET6’s MAUI project, the option no longer exists and I read there was a mention that TLS 1.2 is enabled by default https://techcommunity.microsoft.com/t5/app-development/enable-tls-1-2-on-net-maui-app-on-android/m-p/3267534 . In the same issue, someone also mentioned that it worked on AzureSqlServer, but only local/on-prem instances of SqlServer seems to run into the issue which makes me suspect, it might be a configuration issue, but I’ll have to dig deeper to figure out the root cause.

@janseris Hi thank you, Let’s face it, we will now provide a solution with the RESTFULL API.