CryptographicException in Classic ASP with MySQL TLS

335 Views Asked by At

I am facing this issue when I am trying to invoke a COM Visible c# class in classic ASP Page which tries to execute one MySQL query against database.(Here MySQL is on TLS).

Here in my case one of the classic asp page, we create instance of SomeUser class and then call SetId method on that which will try to create MySQL connection and fails with this stacktrace. Just for complete clarity, here SomeUser class is COMVisible.

Classic ASP code snippet

dim dummy: set dummy= new SomeUser
dim dummyObj: set dummyObj= dummy.obj

dummyObj.SetId(ID)

Exception

System.Security.Cryptography.CryptographicException: The system cannot find the file specified. 
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) 
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromFile(String fileName, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx) at System.Security.Cryptography.X509Certificates.X509Utils.LoadCertFromFile(String fileName, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle pCertCtx) 
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags) 
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password) at MySql.Data.MySqlClient.NativeDriver.GetClientCertificates() 
at MySql.Data.MySqlClient.NativeDriver.StartSSL() at MySql.Data.MySqlClient.NativeDriver.Open() at MySql.Data.MySqlClient.Driver.Open() 
at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings) at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection() 
at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection() at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver() at MySql.Data.MySqlClient.MySqlPool.GetConnection() 
at MySql.Data.MySqlClient.MySqlConnection.Open() at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) 
at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior) 
at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable) at Some.Other.Namespace.Execute(MySqlConnection connection, String sql, DataTable table, DataParameter[] dataParameters) at Some.Other.Namespace.Execute(MySqlConnection connection, String sql, DataParameter[] dataParameters) at Some.Other.Namespace.Execute(String sql, DataParameter[] dataParameters) 
at SomeNamespace.SomeDc.GetData(UInt32 Id) at 
SomeNamespace.User.GetData(UInt32 ID) at SomeNameSpace.SomeUser.SetId(Int32 Id)

Similar question on Stack Overflow on this.

In my case, this solution(Setting Load User Profile to true) work for ASPX pages only but not in this case.

One more point I would like to highlight w3wp.exe is running in Default App Pool with ApplicationPoolIdentity.

I have tried many things so far but no luck. Any point in the right direction will be of great help.

Things I have tried so far.

  • Setting Load User Profile to true for all the application pools.
  • Changing Application Pool Identity to Network Service, Local System and others present in IIS.
  • Changing Application Pool Identity to a custom account(I used an administrator account to try this)
1

There are 1 best solutions below

4
On BEST ANSWER

I don't have any clue about ASP, so I don't understand what you have tried.

However, the exception log seems to tell what is going wrong. The ASP / COM application is trying to load a client certificate when connecting to the MySQL server, but can't find the respective file. This may be due to permissions, or may simply happen because that file does not exist.

Please note that this is a not-so-common problem which may keep you from finding solutions fast. Problems with certificates usually are due to server certificates not being trusted, revoked or outdated. But in this case, the COM part is trying to load a client certificate so that it can prove its identity to the server.

The way to solve the problem depends upon circumstances:

  • If you are in control of the MySQL server, you can configure it so that it does not request client certificates. Then the COM code doesn't need to load a client certificate any more, and you can change the COM object's behavior accordingly. However, turning off client authentication at the server may be insecure.

  • You seem to be in control of the COM code, so you could revisit it and look where it tries to load the MySQL client certificate. Check out which file it tries to load, and check whether you have that file on the file system. If it isn't there, and if working without client certificates is not an option, you'll have to generate the client certificate.
    I don't know how the COM object works, though. Even if you don't find a place where it tries to load a client certificate explicitly, it may evaluate some MySQL client configuration files which tell it to use a (certain) client certificate when connecting to the server. Such files may have names like mysql.ini, my.ini, my.cnf or the like.

For clarification: The above paragraphs are about MySQL client certificates for the MySQL TLS connection. This has nothing to do with web server certificates.

If you need MySQL client authentication, you should test step by step:

  1. Generate an appropriate MySQL client certificate.
  2. Put that client certificate along with the private key onto the machine where your COM application runs.
  3. Log onto that machine and install the native MySQL client there (it is available for Windows).
  4. On that machine, try to establish an encrypted connection to your MySQL server with client authentication, using the native MySQL client and using your client certificate.
    If this does not work, there probably is no chance that it works from within your COM object, so you'll need to solve that first.
  5. In the last step, try your ASP application / COM object again. Make sure that it has sufficient permissions to read the certificate and the private key, and that both exist at the expected place.

If connection with the native client succeeds, but the COM object still can't connect, I may have an additional idea of how to debug the situation. In that case, just drop a comment; I'll eventually amend this answer then.