Skip to content

Commit 937f74e

Browse files
committed
Log in directly with caching_sha2_password. Fixes #1562
If the server allows 'caching_sha2_password' in the initial handshake packet, then use that authentication method directly, saving a roundtrip.
1 parent 20a73ed commit 937f74e

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,11 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
528528
if (m_supportsConnectionAttributes && cs.ConnectionAttributes is null)
529529
cs.ConnectionAttributes = CreateConnectionAttributes(cs.ApplicationName);
530530

531+
// send a caching_sha2_password response if the server advertised support in the initial handshake
532+
var useCachingSha2 = initialHandshake.AuthPluginName == "caching_sha2_password";
533+
531534
var password = GetPassword(cs, connection);
532-
using (var handshakeResponsePayload = HandshakeResponse41Payload.Create(initialHandshake, cs, password, m_compressionMethod, connection.ZstandardPlugin?.CompressionLevel, m_characterSet, m_supportsConnectionAttributes ? cs.ConnectionAttributes : null))
535+
using (var handshakeResponsePayload = HandshakeResponse41Payload.Create(initialHandshake, cs, password, useCachingSha2, m_compressionMethod, connection.ZstandardPlugin?.CompressionLevel, m_characterSet, m_supportsConnectionAttributes ? cs.ConnectionAttributes : null))
533536
await SendReplyAsync(handshakeResponsePayload, ioBehavior, cancellationToken).ConfigureAwait(false);
534537
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
535538

@@ -539,6 +542,26 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
539542
payload = await SwitchAuthenticationAsync(cs, password, payload, ioBehavior, cancellationToken).ConfigureAwait(false);
540543
}
541544

545+
// check if caching_sha2_password response was sent
546+
if (useCachingSha2 && payload.HeaderByte == CachingSha2ServerResponsePayload.Signature)
547+
{
548+
// process a successful response, or fall back to sending the password if the server doesn't have it
549+
var cachingSha2ServerResponsePayload = CachingSha2ServerResponsePayload.Create(payload.Span);
550+
if (cachingSha2ServerResponsePayload.Succeeded)
551+
{
552+
payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
553+
}
554+
else if (!m_isSecureConnection && password.Length != 0)
555+
{
556+
var publicKey = await GetRsaPublicKeyAsync(m_currentAuthenticationMethod, cs, ioBehavior, cancellationToken).ConfigureAwait(false);
557+
payload = await SendEncryptedPasswordAsync(AuthPluginData, publicKey, password, ioBehavior, cancellationToken).ConfigureAwait(false);
558+
}
559+
else
560+
{
561+
payload = await SendClearPasswordAsync(password, ioBehavior, cancellationToken).ConfigureAwait(false);
562+
}
563+
}
564+
542565
var ok = OkPayload.Create(payload.Span, this);
543566

544567
if (m_sslPolicyErrors != SslPolicyErrors.None)

src/MySqlConnector/Protocol/Payloads/HandshakeResponse41Payload.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using MySqlConnector.Core;
22
using MySqlConnector.Protocol.Serialization;
3+
using MySqlConnector.Utilities;
34

45
namespace MySqlConnector.Protocol.Payloads;
56

@@ -55,20 +56,22 @@ private static ByteBufferWriter CreateCapabilitiesPayload(ProtocolCapabilities s
5556
public static PayloadData CreateWithSsl(ProtocolCapabilities serverCapabilities, ConnectionSettings cs, CompressionMethod compressionMethod, CharacterSet characterSet) =>
5657
CreateCapabilitiesPayload(serverCapabilities, cs, compressionMethod, characterSet, ProtocolCapabilities.Ssl).ToPayloadData();
5758

58-
public static PayloadData Create(InitialHandshakePayload handshake, ConnectionSettings cs, string password, CompressionMethod compressionMethod, int? compressionLevel, CharacterSet characterSet, byte[]? connectionAttributes)
59+
public static PayloadData Create(InitialHandshakePayload handshake, ConnectionSettings cs, string password, bool useCachingSha2, CompressionMethod compressionMethod, int? compressionLevel, CharacterSet characterSet, byte[]? connectionAttributes)
5960
{
6061
// TODO: verify server capabilities
6162
var writer = CreateCapabilitiesPayload(handshake.ProtocolCapabilities, cs, compressionMethod, characterSet);
6263
writer.WriteNullTerminatedString(cs.UserID);
63-
var authenticationResponse = AuthenticationUtility.CreateAuthenticationResponse(handshake.AuthPluginData, password);
64+
65+
var authenticationResponse = useCachingSha2 ? AuthenticationUtility.CreateScrambleResponse(Utility.TrimZeroByte(handshake.AuthPluginData.AsSpan()), password) :
66+
AuthenticationUtility.CreateAuthenticationResponse(handshake.AuthPluginData, password);
6467
writer.Write((byte) authenticationResponse.Length);
6568
writer.Write(authenticationResponse);
6669

6770
if (!string.IsNullOrWhiteSpace(cs.Database))
6871
writer.WriteNullTerminatedString(cs.Database);
6972

7073
if ((handshake.ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
71-
writer.Write("mysql_native_password\0"u8);
74+
writer.Write(useCachingSha2 ? "caching_sha2_password\0"u8 : "mysql_native_password\0"u8);
7275

7376
if (connectionAttributes is not null)
7477
writer.Write(connectionAttributes);

0 commit comments

Comments
 (0)