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); } }
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); } }