Uploaded image for project: 'MariaDB Connector/C'
  1. MariaDB Connector/C
  2. CONC-527

Connect error "SEC_E_ALGORITHM_MISMATCH" from Windows to Ubuntu server

Details

    Description

      The MariaDB connector on Windows seems unable to connect to a MariaDB server running on Ubuntu. Although the error (coming from MS Secure Channel) suggests a cipher mismatch, inspection of the ciphers supported on both sides shows 14 ciphers in common, one of which was selected by the server in the Server Hello.

      The MySQL connector/C connects fine from Windows to the same MariaDB.

      Inspection of the packets using Wireshark did not show an obvious problem. The Client Hello and Server Hello seemed ok (to a non-TLS expert). Stepping through the MariaDB Connector code on the Windows side also didn't show any obvious problem.

      I've reached the limits of the debugging that I can do in this context. Are there other errors which MS will put into the "SEC_E_ALGORITHM_MISMATCH" return code? Are there any other known problems with MariaDB Connector/C on Windows? Any other ideas?

      Wireshark files and (example self-signed) certificates are available.

      To replicate:
      (1) Have MariaDB 10.5.8 running on Ubuntu 20.04
      In the config file have three lines
      ssl-ca=/path/to/rootCA2.crt
      ssl-cert=/path/to/sqlserver2.crt
      ssl-key=/path/to/sqlserver2.key
      add new user as
      CREATE USER 'testuser'@'%' IDENTIFIED BY 'ChangeMe' REQUIRE X509;

      (2) On Windows, use the command
      "C:\Program Files\MariaDB 10.5\bin\mysql.exe" --ssl-cert=C:\Path\to\sqlclient2.crt --ssl-ca=C:\Path\to\rootCA2.crt --ssl-key=C:\Path\to\sqlclient2.key --user=testuser -pChangeMe --host=<ubuntu_hostname> --protocol=tcp --port=3306 --default-character-set=utf8

      This should give the error
      ERROR 2026 (HY000): SSL connection error: no cipher match. Error 0x80090331(SEC_E_ALGORITHM_MISMATCH)

      Apologies if there is anything wrong with these settings, but I feel I have tried as many permutations as I can think of.

      Thanks.

      Attachments

        1. image-2021-09-25-18-55-02-471.png
          image-2021-09-25-18-55-02-471.png
          263 kB
        2. rootCA2.crt
          1 kB
        3. sqlclient2.crt
          1 kB
        4. sqlclient2.key
          2 kB
        5. sqlserver2.crt
          1 kB
        6. sqlserver2.key
          2 kB
        7. wsl2_handshake_bad.pcap
          4 kB

        Issue Links

          Activity

            wlad Vladislav Vaintroub added a comment - - edited

            There appears to be some kind of bug in openssl. According to google, Ubuntu made the decision to compile with non-default settings for openssl, to make it appear more secure.
            https://github.com/Ensembl/ensembl-rest/issues/427 discusses one bug, but I'm not sure we're tripping over it. It looks like openssl itself is more lax about the strict requirements it imposes on client certificates, with SECLEVEL=2, than other SSL implementations are.

            The workaround

            Now, for all people who deal with that problem Ubuntu 20.04, this is one workaround

            • use parameter ssl-cipher=DEFAULT:@SECLEVEL=1 for the server, or
            • change /etc/ssl/openssl.cnf to add CipherString = DEFAULT:@SECLEVEL=1

            There are some variations on CipherString workaround, a popular discussion in https://askubuntu.com/questions/1233186/ubuntu-20-04-how-to-set-lower-ssl-security-level.

            This has something with the client certificate, and how it was created, but I frankly have no idea what that exactly can be.

            wlad Vladislav Vaintroub added a comment - - edited There appears to be some kind of bug in openssl. According to google, Ubuntu made the decision to compile with non-default settings for openssl, to make it appear more secure. https://github.com/Ensembl/ensembl-rest/issues/427 discusses one bug, but I'm not sure we're tripping over it. It looks like openssl itself is more lax about the strict requirements it imposes on client certificates, with SECLEVEL=2, than other SSL implementations are. The workaround Now, for all people who deal with that problem Ubuntu 20.04, this is one workaround use parameter ssl-cipher=DEFAULT:@SECLEVEL=1 for the server, or change /etc/ssl/openssl.cnf to add CipherString = DEFAULT:@SECLEVEL=1 There are some variations on CipherString workaround, a popular discussion in https://askubuntu.com/questions/1233186/ubuntu-20-04-how-to-set-lower-ssl-security-level . This has something with the client certificate, and how it was created, but I frankly have no idea what that exactly can be.
            wlad Vladislav Vaintroub added a comment - - edited

            I studied it a little bit more, and looked how other implementations may load private keys and certificates in PEM format and use them in Schannel TLS handshake

            Particularly interesting info is in the dotnet bug https://github.com/dotnet/runtime/issues/23749
            It turns out, that

            One has to use persistent key (stored in the container), rather than ephemeral(in-memory only) , for schannel. This is because a AcquireCredentialsHandle() talks to another process (LSASS.exe), and it does not marshal private key in the communication. Which is definitely Windows issue, but it had been there forever, and until it is solved, if at all, workaround is to use named key containers. To link client certificate with private key, dotnet sets CERT_KEY_PROV_INFO_PROP_ID , which includes persistent key container name.

            What .NET does, in many cases, but mostly prominently for self-signed SSL certificates, is to use unique name for key container, and then remove the whole container if it is no longer needed.
            The AcquireCredentialsHandle behavior and LSASS is extremely sparsely document, in PFXImportCertStore documentation (of all things), when discussing ephemeral pfx flag PKCS12_NO_PERSIST_KEY.

            So, ephemeral keys should not work, but they did so far for us in majority of cases.
            Maybe it is a legacy behavior and current process is doing some parts of handshake them rather than LSASS. Ephemeral keys did not work then georg was trying TLSv1.3 . See MS Q&A discussion , where Gary Nebbett even makes the correct suggestion, but was not able to explain why persistent keys worked, and ephemeral did not.

            I tried whatever .NET is doing, named key container, and CERT_KEY_PROV_INFO_PROP_ID, and with that, I can create a connection to OpenSSL-based server. Schannel will no longer be using sha1 for signature (this is what disturbed OpenSSL at security level !=0 ), but something more sophisticated, sha256 based.

            So this should be the way to go, seems we'd need to implement what this commenter calls "perphemeral" private keys, i.e persistent, with cleanup, unless abnormal termination, or directory %AppData%\Roaming\Microsoft\Crypto\RSA will grow with persistent keys that nobody will use.

            wlad Vladislav Vaintroub added a comment - - edited I studied it a little bit more, and looked how other implementations may load private keys and certificates in PEM format and use them in Schannel TLS handshake Particularly interesting info is in the dotnet bug https://github.com/dotnet/runtime/issues/23749 It turns out, that One has to use persistent key (stored in the container), rather than ephemeral(in-memory only) , for schannel. This is because a AcquireCredentialsHandle() talks to another process (LSASS.exe), and it does not marshal private key in the communication. Which is definitely Windows issue, but it had been there forever, and until it is solved, if at all, workaround is to use named key containers. To link client certificate with private key, dotnet sets CERT_KEY_PROV_INFO_PROP_ID , which includes persistent key container name. What .NET does, in many cases, but mostly prominently for self-signed SSL certificates, is to use unique name for key container, and then remove the whole container if it is no longer needed. The AcquireCredentialsHandle behavior and LSASS is extremely sparsely document, in PFXImportCertStore documentation (of all things), when discussing ephemeral pfx flag PKCS12_NO_PERSIST_KEY. So, ephemeral keys should not work, but they did so far for us in majority of cases. Maybe it is a legacy behavior and current process is doing some parts of handshake them rather than LSASS. Ephemeral keys did not work then georg was trying TLSv1.3 . See MS Q&A discussion , where Gary Nebbett even makes the correct suggestion, but was not able to explain why persistent keys worked, and ephemeral did not. I tried whatever .NET is doing, named key container, and CERT_KEY_PROV_INFO_PROP_ID, and with that, I can create a connection to OpenSSL-based server. Schannel will no longer be using sha1 for signature (this is what disturbed OpenSSL at security level !=0 ), but something more sophisticated, sha256 based. So this should be the way to go, seems we'd need to implement what this commenter calls "perphemeral" private keys, i.e persistent, with cleanup, unless abnormal termination, or directory %AppData%\Roaming\Microsoft\Crypto\RSA will grow with persistent keys that nobody will use.

            wlad, if a key can be automatically cleaned after the connection is established, then it should be very safe to delete all keys that are older than, say, 24 hours. Automatically, from the connector, why should the user know and do something about this?

            serg Sergei Golubchik added a comment - wlad , if a key can be automatically cleaned after the connection is established, then it should be very safe to delete all keys that are older than, say, 24 hours. Automatically, from the connector, why should the user know and do something about this?
            wlad Vladislav Vaintroub added a comment - - edited

            the user does not need to do anything. We clean up everything after AcquireCredentialsHandle. If process is killed or crashes during this time, something will remain, but let's assume it won't happen often.

            We should not be cleaning up keys that do not belong to our application, even if they reside in the same %AppData%\Roaming\Microsoft\Crypto\RSA directory. There is no documented way to find out from file name whether it belongs to our application or not (although at least , currently, one can run "strings" again a file, and the container name will show up in plaintext)

            The Windows model for key provider is this - you load key once into container, then use container name instead of always reading the key file. We are not using it, but someone else might.

            wlad Vladislav Vaintroub added a comment - - edited the user does not need to do anything. We clean up everything after AcquireCredentialsHandle. If process is killed or crashes during this time, something will remain, but let's assume it won't happen often. We should not be cleaning up keys that do not belong to our application, even if they reside in the same %AppData%\Roaming\Microsoft\Crypto\RSA directory. There is no documented way to find out from file name whether it belongs to our application or not (although at least , currently, one can run "strings" again a file, and the container name will show up in plaintext) The Windows model for key provider is this - you load key once into container, then use container name instead of always reading the key file. We are not using it, but someone else might.

            Right. I mean to clear up keys that belong to our application that were left after the process was killed or crashed. It is based on the assumption that we can somehow tell our keys from all others, e.g. by a specific naming pattern. If it is not possible — then we cannot do it.

            serg Sergei Golubchik added a comment - Right. I mean to clear up keys that belong to our application that were left after the process was killed or crashed. It is based on the assumption that we can somehow tell our keys from all others, e.g. by a specific naming pattern. If it is not possible — then we cannot do it.

            People

              wlad Vladislav Vaintroub
              mwbaxter Martin Baxter
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.