Skip to content

Cannot connect to AWS RDS Aurora 3 (Mysql8) using SslCa=<file> and SslMode=VerifyCA #1462

Closed
@frivard-coveo

Description

@frivard-coveo

Software versions
MySqlConnector version: 2.3.5
Server type (MySQL, MariaDB, Aurora, etc.) and version: Aurora MySQL 3.04.0 (Compatible with MySQL 8.0.28)
.NET version: 8.0
(Optional) ORM NuGet packages and versions:

Describe the bug
Following our industry's leading security practices, I tried to upgrade from SslMode=Required to SslMode=VerifyCA. To do that I downloaded the AWS RDS "CA Bundle" at https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem (see doc) .

Unfortunately it did not work, it gives the exception The remote certificate was rejected by the provided RemoteCertificateValidationCallback

After a lot of debugging, I tried one more thing : instead of passing the SslCa file, I imported it into the Windows Trusted Root Certificate Store. And it worked; proofing that the CA bundle is valid and sufficient. That is a good confirmation, but is not a portable solution.

See the additional context for the rest of the info.

Exception

MySqlConnector.MySqlException (0x80004005): SSL Authentication Error  ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
    at System.Net.Security.SslStream.SendAuthResetSignal(ReadOnlySpan`1 alert, ExceptionDispatchInfo exception)
    at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
    at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
    at MySqlConnector.Core.ServerSession.InitSslAsync(ProtocolCapabilities serverCapabilities, ConnectionSettings cs, MySqlConnection connection, SslProtocols sslProtocols, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 1434
    at MySqlConnector.Core.ServerSession.InitSslAsync(ProtocolCapabilities serverCapabilities, ConnectionSettings cs, MySqlConnection connection, SslProtocols sslProtocols, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 1472
    at MySqlConnector.Core.ServerSession.ConnectAsync(ConnectionSettings cs, MySqlConnection connection, Int64 startingTimestamp, ILoadBalancer loadBalancer, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 523
    at MySqlConnector.Core.ConnectionPool.ConnectSessionAsync(MySqlConnection connection, Action`4 logMessage, Int64 startingTimestamp, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ConnectionPool.cs:line 428
    at MySqlConnector.Core.ConnectionPool.ConnectSessionAsync(MySqlConnection connection, Action`4 logMessage, Int64 startingTimestamp, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ConnectionPool.cs:line 433
    at MySqlConnector.Core.ConnectionPool.GetSessionAsync(MySqlConnection connection, Int64 startingTimestamp, Int32 timeoutMilliseconds, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ConnectionPool.cs:line 111
    at MySqlConnector.Core.ConnectionPool.GetSessionAsync(MySqlConnection connection, Int64 startingTimestamp, Int32 timeoutMilliseconds, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ConnectionPool.cs:line 144
    at MySqlConnector.MySqlConnection.CreateSessionAsync(ConnectionPool pool, Int64 startingTimestamp, Activity activity, Nullable`1 ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlConnection.cs:line 919
    at MySqlConnector.MySqlConnection.OpenAsync(Nullable`1 ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlConnection.cs:line 419

Code sample

        var builder = new MySqlConnectionStringBuilder
        {
            Server = _mySqlConfig.Host,
            Port = _mySqlConfig.Port,
            Password = _mySqlConfig.Password,
            UserID = _mySqlConfig.Username,
            AllowLoadLocalInfile = true,
            AllowUserVariables = true,
            DefaultCommandTimeout = (uint)_mySqlConfig.CommandTimeout.TotalSeconds,
            SslMode = MySqlSslMode.VerifyCA,
            SslCa = _mySqlConfig.CACertificateFile,
            ConnectionTimeout = 999
        };

MySqlConnection connection = new MySqlConnection(builder.ToString());
await connection.OpenAsync(cancellationToken);

Expected behavior
I expect that the certificate present by AWS is validated by the CA bundle provided by AWS. It should be possible to do that via the SslCa option.

Additional context

The certificate chain presented by the AWS RDS server looks like (actual hostname redacted because... security...)

[Subject]  C=US, S=Washington, L=Seattle, O=Amazon.com, OU=RDS, CN=***redacted***.us-east-1.rds.amazonaws.com
[Issuer]  L=Seattle, CN=Amazon RDS us-east-1 Subordinate CA RSA2048 G1.A.10, S=WA, OU=Amazon RDS, O="Amazon Web Services, Inc.", C=US
[Serial Number]  00D7BEC99EA6A9A9F3E233BF8BDC696F97
[Not Before]  2024-03-15 9:37:26
[Not After]  2025-03-15 9:37:26
[Thumbprint]  424B43DAA5E6431865CB20664410539CC6A4F852


[Subject]  L=Seattle, CN=Amazon RDS us-east-1 Subordinate CA RSA2048 G1.A.10, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Issuer]  L=Seattle, CN=Amazon RDS us-east-1 Root CA RSA2048 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Serial Number]  06EAB8D792ADBF818DF67EA9308A42CB
[Not Before]  2022-12-27 18:10:35
[Not After]  2032-12-27 19:10:35
[Thumbprint]  1D719047BFF523AE530227C8B5D57FACB87D8A7B

and the CA Bundle for us-east-1 looks like (the full global bundle is has 131 certs instead of 5, but we only care about 1 here):

[Subject]  CN=Amazon RDS Root 2019 CA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", S=Washington, L=Seattle, C=US
[Issuer]  CN=Amazon RDS Root 2019 CA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", S=Washington, L=Seattle, C=US
[Serial Number]  00C73467369250AE75
[Not Before]  2019-08-22 13:08:50
[Not After]  2024-08-22 13:08:50
[Thumbprint]  D40DDB29E3750DFFA671C3140BBF5F478D1C8096


[Subject]  CN=Amazon RDS us-east-1 2019 CA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", L=Seattle, S=Washington, C=US
[Issuer]  CN=Amazon RDS Root 2019 CA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", S=Washington, L=Seattle, C=US
[Serial Number]  2555
[Not Before]  2019-09-19 14:16:53
[Not After]  2024-08-22 13:08:50
[Thumbprint]  F0ED823ED14447BAB557FDF3E4927466988C1C78


[Subject]  L=Seattle, CN=Amazon RDS us-east-1 Root CA RSA2048 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Issuer]  L=Seattle, CN=Amazon RDS us-east-1 Root CA RSA2048 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Serial Number]  00F55231F162B663393E199B68E16819F5
[Not Before]  2021-05-25 18:34:57
[Not After]  2061-05-25 19:34:57
[Thumbprint]  2FA77EF894D983BA9D37AD699C84AB0F657BE1C8


[Subject]  L=Seattle, CN=Amazon RDS us-east-1 Root CA RSA4096 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Issuer]  L=Seattle, CN=Amazon RDS us-east-1 Root CA RSA4096 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Serial Number]  6911DA12AA9A717376D1EF33649B660C
[Not Before]  2021-05-25 18:38:35
[Not After]  2121-05-25 19:38:35
[Thumbprint]  9DA6FA7FD2EC09C569A400D876B01B0C12759A96


[Subject]  L=Seattle, CN=Amazon RDS us-east-1 Root CA ECC384 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Issuer]  L=Seattle, CN=Amazon RDS us-east-1 Root CA ECC384 G1, S=WA, OU=Amazon RDS, O=""Amazon Web Services, Inc."", C=US
[Serial Number]  00F025124F1524F984CD5451696BD38760
[Not Before]  2021-05-25 18:41:55
[Not After]  2121-05-25 19:41:55
[Thumbprint]  24A97B91CBE86911190576C35C36AAB4FA7B25DE

However, in the custom certificate validation code around https://github.com/mysql-net/MySqlConnector/blob/master/src/MySqlConnector/Core/ServerSession.cs#L1390
, we have variable caCertificateChain built with the 5 root certificates in ExtraStore (see https://github.com/mysql-net/MySqlConnector/blob/master/src/MySqlConnector/Core/ServerSession.cs#L1368). This is okay.
But at line 1390, the callback receives as rcbCertificate only the base certificate (thumbprint 424B43DAA5E6431865CB20664410539CC6A4F852), issued by "Subordinate CA", and the other variable rcbChain contains both the base server certificate and the subordinate certificate.

Later at line 1398 when doing caCertificateChain.Build((X509Certificate2) rcbCertificate) we are attempting to verify the base certificate, but the chain is missing the subordinate, so it will always fail.

I am no expert on the .NET X509Chain API, but I would think that we must start with rcbChain.ChainElements.Last(), verify that one, and then work our way back the input chain until we hit the leaf.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions