예제 #1
0
        public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            var connected = false;

            if (cs.ConnectionType == ConnectionType.Tcp)
            {
                connected = await OpenTcpSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            else if (cs.ConnectionType == ConnectionType.Unix)
            {
                connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            if (!connected)
            {
                throw new MyCatException("Unable to connect to any of the specified MySQL hosts.");
            }

            var socketByteHandler = new SocketByteHandler(m_socket);

            m_payloadHandler = new StandardPayloadHandler(socketByteHandler);

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
            string authPluginName;

            if ((initialHandshake.ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
            {
                authPluginName = initialHandshake.AuthPluginName;
            }
            else
            {
                authPluginName = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.SecureConnection) == 0 ? "mysql_old_password" : "mysql_native_password";
            }
            if (authPluginName != "mysql_native_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }

            ServerVersion  = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId   = initialHandshake.ConnectionId;
            AuthPluginData = initialHandshake.AuthPluginData;
            if (cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) == 0)
            {
                cs = cs.WithUseCompression(false);
            }

            if (cs.SslMode != MyCatSslMode.None)
            {
                await InitSslAsync(initialHandshake.ProtocolCapabilities, cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            var response = HandshakeResponse41Packet.Create(initialHandshake, cs);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

            payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            OkPayload.Create(payload);

            if (cs.UseCompression)
            {
                m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
            }
        }
예제 #2
0
        private async Task InitSslAsync(ProtocolCapabilities serverCapabilities, ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            X509Certificate2 certificate;

            try
            {
                certificate = new X509Certificate2(cs.CertificateFile, cs.CertificatePassword);
            }
            catch (CryptographicException ex)
            {
                if (!File.Exists(cs.CertificateFile))
                {
                    throw new MyCatException("Cannot find SSL Certificate File", ex);
                }
                throw new MyCatException("Either the SSL Certificate Password is incorrect or the SSL Certificate File is invalid", ex);
            }

            Func <object, string, X509CertificateCollection, X509Certificate, string[], X509Certificate> localCertificateCb =
                (lcbSender, lcbTargetHost, lcbLocalCertificates, lcbRemoteCertificate, lcbAcceptableIssuers) => lcbLocalCertificates[0];

            Func <object, X509Certificate, X509Chain, SslPolicyErrors, bool> remoteCertificateCb =
                (rcbSender, rcbCertificate, rcbChain, rcbPolicyErrors) =>
            {
                switch (rcbPolicyErrors)
                {
                case SslPolicyErrors.None:
                    return(true);

                case SslPolicyErrors.RemoteCertificateNameMismatch:
                    return(cs.SslMode != MyCatSslMode.VerifyFull);

                default:
                    return(cs.SslMode == MyCatSslMode.Required);
                }
            };

            var sslStream = new SslStream(m_networkStream, false,
                                          new RemoteCertificateValidationCallback(remoteCertificateCb),
                                          new LocalCertificateSelectionCallback(localCertificateCb));
            var clientCertificates = new X509CertificateCollection {
                certificate
            };

            // SslProtocols.Tls1.2 throws an exception in Windows, see https://github.com/mysql-net/MyCatConnector/pull/101
            var sslProtocols = SslProtocols.Tls | SslProtocols.Tls11;

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                sslProtocols |= SslProtocols.Tls12;
            }

            var checkCertificateRevocation = cs.SslMode == MyCatSslMode.VerifyFull;

            var initSsl = new PayloadData(new ArraySegment <byte>(HandshakeResponse41Packet.InitSsl(serverCapabilities, cs)));

            await SendReplyAsync(initSsl, ioBehavior, cancellationToken).ConfigureAwait(false);

            try
            {
                if (ioBehavior == IOBehavior.Asynchronous)
                {
                    await sslStream.AuthenticateAsClientAsync(m_hostname, clientCertificates, sslProtocols, checkCertificateRevocation).ConfigureAwait(false);
                }
                else
                {
#if NETSTANDARD1_6
                    await sslStream.AuthenticateAsClientAsync(m_hostname, clientCertificates, sslProtocols, checkCertificateRevocation).ConfigureAwait(false);
#else
                    sslStream.AuthenticateAsClient(m_hostname, clientCertificates, sslProtocols, checkCertificateRevocation);
#endif
                }
                var sslByteHandler = new StreamByteHandler(sslStream);
                m_payloadHandler.ByteHandler = sslByteHandler;
            }
            catch (AuthenticationException ex)
            {
                ShutdownSocket();
                m_hostname = "";
                m_state    = State.Failed;
                throw new MyCatException("SSL Authentication Error", ex);
            }
        }