Skip to content

Authentication #1696

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Authentication #1696

wants to merge 1 commit into from

Conversation

rusher
Copy link
Contributor

@rusher rusher commented Apr 16, 2025

Description

authentication has been revamp. this is a simplification of #1694, without new authentication plugin addition, since it's already a big change.

Current implementation was requiring authentication switch plugins data to begin with iAuthMoreData, but that's only required for "caching_sha2_password" and "sha256_password" plugins.
Additionally, now permits multi-authentication (in mariadb: https://mariadb.com/kb/en/create-user/#identified-viawith-authentication_plugin / mysql: https://dev.mysql.com/doc/refman/8.0/en/multifactor-authentication.html)

goal is to add MariaDB main authentication plugins (like parsec, PAM, GSSAPI, ...) based on plugin like this

Checklist

  • Code compiles correctly
  • Created tests which fail without the change (if possible)
  • All tests passing
  • Extended the README / documentation, if necessary
  • Added myself / the copyright holder to the AUTHORS file

Summary by CodeRabbit

  • New Features

    • Introduced a pluggable authentication system supporting multiple MySQL and MariaDB authentication methods, including native password, caching_sha2_password, cleartext, old password, sha256_password, and client_ed25519.
    • Added detailed documentation describing the available authentication plugins and their usage.
  • Bug Fixes

    • Improved error handling and authentication flow to prevent infinite loops and ensure immediate error reporting on authentication failure.
  • Refactor

    • Centralized authentication handling behind a unified plugin interface for greater modularity and extensibility.
  • Tests

    • Enhanced and expanded authentication tests, including new scenarios for multi-step authentication processes.

Copy link

coderabbitai bot commented Apr 16, 2025

Walkthrough

This set of changes introduces a modular authentication plugin system to the Go MySQL driver. The authentication logic is refactored to use a generic plugin interface, allowing multiple authentication methods to be implemented as separate plugins. Each plugin encapsulates its own protocol, including native password, caching SHA2, cleartext, old password, SHA256, and Ed25519 authentication. The driver now maintains a global plugin registry, and authentication flows are managed through this registry and the plugin interface. Extensive cryptographic and protocol-specific logic is moved from the core authentication code into the respective plugins. Tests are updated to use the new plugin-based interface.

Changes

File(s) Change Summary
README.md Added a new section describing the authentication plugin system and listing supported plugins.
auth.go Refactored to remove direct authentication logic; introduced generic plugin-based authentication handling and helper for parsing auth switch data. Removed all legacy cryptographic and plugin-specific code.
auth_plugin.go Introduced the AuthPlugin interface, a simple plugin registry, and global plugin registration functions.
auth_mysql_native.go Added implementation of the mysql_native_password plugin with SHA1-based password scrambling.
auth_caching_sha2.go Added implementation of the caching_sha2_password plugin supporting fast and full authentication with SHA256 and RSA encryption.
auth_cleartext.go Added implementation of the mysql_clear_password plugin for cleartext password authentication.
auth_old_password.go Added implementation of the mysql_old_password plugin using the legacy pre-4.1 password hashing scheme.
auth_sha256.go Added implementation of the sha256_password plugin with RSA encryption and SHA256 hashing.
auth_ed25519.go Added implementation of the client_ed25519 plugin using Ed25519 signatures.
auth_test.go Refactored tests to use plugin instances and the new plugin interface. Added tests for multi-step authentication switch flows.
connector.go Changed authentication to use plugin registry and plugin interface. Removed fallback to default plugin. Introduced authMaximumSwitch constant.
driver.go Added a global plugin registry.
packets.go Removed the readAuthResult method, as authentication result handling is now managed by plugins.
const.go Removed constants related to caching SHA2 authentication states, as this logic is now internal to the plugin.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant Connector
    participant mysqlConn
    participant PluginRegistry
    participant AuthPlugin
    participant Server

    App->>Connector: Connect()
    Connector->>mysqlConn: initiate connection
    mysqlConn->>PluginRegistry: GetPlugin(plugin_name)
    PluginRegistry-->>mysqlConn: AuthPlugin instance
    mysqlConn->>AuthPlugin: InitAuth(authData, config)
    AuthPlugin-->>mysqlConn: auth response
    mysqlConn->>Server: send auth response
    loop (up to max switches)
        Server-->>mysqlConn: auth result / switch request
        alt OK or ERR
            mysqlConn-->>Connector: authentication success/failure
        else Auth Switch
            mysqlConn->>PluginRegistry: GetPlugin(new_plugin_name)
            PluginRegistry-->>mysqlConn: AuthPlugin instance
            mysqlConn->>AuthPlugin: continuationAuth(packet, authData, conn)
            AuthPlugin-->>mysqlConn: next auth response
            mysqlConn->>Server: send next auth response
        end
    end
Loading

Suggested reviewers

  • methane

Poem

In the warren of code, plugins now hop,
Each with a secret, a key, or a lock.
Native and cleartext, Ed25519 too,
Old and new passwords, all hopping through.
The registry garden keeps every bun,
Securely authenticating, one by one.
🐇✨ The driver now dances—authentication is fun!

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
driver.go (1)

42-44: Global plugin registry introduction
This new variable and initialization appear well-structured for the upcoming plugin-based authentication system. Ensure the globalPluginRegistry registration and usage is thread-safe, especially if plugin registrations can occur at runtime.

README.md (1)

540-546: Use consistent list style per markdownlint
Static analysis flags these lines for inconsistent unordered list style. Switch from dashes to asterisks to comply with the configured Markdown style guidelines.

Apply the following diff to update the list style:

- - `mysql_native_password` - The default MySQL authentication method
- - `caching_sha2_password` - Default authentication method in MySQL 8.0+
- - `mysql_clear_password` - Cleartext authentication (requires `allowCleartextPasswords=true`)
- - `mysql_old_password` - Old MySQL authentication (requires `allowOldPasswords=true`)
- - `sha256_password` - SHA256 authentication
- - `client_ed25519` - MariaDB Ed25519 authentication
+ * `mysql_native_password` - The default MySQL authentication method
+ * `caching_sha2_password` - Default authentication method in MySQL 8.0+
+ * `mysql_clear_password` - Cleartext authentication (requires `allowCleartextPasswords=true`)
+ * `mysql_old_password` - Old MySQL authentication (requires `allowOldPasswords=true`)
+ * `sha256_password` - SHA256 authentication
+ * `client_ed25519` - MariaDB Ed25519 authentication
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

541-541: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


542-542: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


543-543: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


544-544: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


545-545: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


546-546: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

auth_ed25519.go (1)

29-63: Ed25519 authentication logic appears correct.
The scalar clamping, base multiplication, uniform hashing, and final combined signature steps reflect standard Ed25519 signing internals. Error handling for scalar creation is handled properly. One optional consideration is whether to sanitize (zero) sensitive intermediate data in memory once done, if there's concern about side-channel leaks in ephemeral memory. Overall, the plugin method is well-structured.

auth_caching_sha2.go (1)

67-74: Use descriptive constants for magic numbers.
The sub-switch values 3 and 4 can be replaced by clearly named constants to enhance maintainability and code clarity.

auth_sha256.go (1)

107-131: RSA-OAEP with SHA1.
While this aligns with MySQL's required method, note that SHA1 is considered weaker cryptographically. Keep it for compatibility, or consider offering a stronger alternative if not constrained by server support.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 879eb11 and 5dd643c.

📒 Files selected for processing (16)
  • AUTHORS (1 hunks)
  • README.md (1 hunks)
  • auth.go (2 hunks)
  • auth_caching_sha2.go (1 hunks)
  • auth_cleartext.go (1 hunks)
  • auth_ed25519.go (1 hunks)
  • auth_mysql_native.go (1 hunks)
  • auth_old_password.go (1 hunks)
  • auth_plugin.go (1 hunks)
  • auth_sha256.go (1 hunks)
  • auth_test.go (53 hunks)
  • connector.go (2 hunks)
  • const.go (0 hunks)
  • driver.go (1 hunks)
  • driver_test.go (4 hunks)
  • packets.go (0 hunks)
💤 Files with no reviewable changes (2)
  • const.go
  • packets.go
🧰 Additional context used
🧬 Code Graph Analysis (9)
driver.go (1)
auth_plugin.go (1)
  • NewPluginRegistry (42-47)
auth_cleartext.go (3)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrCleartextPassword (23-23)
auth_plugin.go (1)
dsn.go (1)
  • Config (37-84)
auth_old_password.go (3)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrOldPassword (25-25)
auth_mysql_native.go (3)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrNativePassword (24-24)
auth_sha256.go (3)
auth_plugin.go (2)
  • AuthPlugin (12-26)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrMalformPkt (21-21)
auth_test.go (2)
auth_old_password.go (1)
  • OldPasswordPlugin (12-12)
auth_mysql_native.go (1)
  • NativePasswordPlugin (14-16)
auth_caching_sha2.go (3)
auth_plugin.go (2)
  • AuthPlugin (12-26)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrMalformPkt (21-21)
auth.go (2)
auth_plugin.go (1)
  • AuthPlugin (12-26)
errors.go (1)
  • ErrMalformPkt (21-21)
🪛 markdownlint-cli2 (0.17.2)
README.md

541-541: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


542-542: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


543-543: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


544-544: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


545-545: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


546-546: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

🔇 Additional comments (96)
AUTHORS (1)

40-40: No concerns found with this addition
Adding the new author entry in alphabetical order is correct and maintains consistency with the file’s structure.

README.md (1)

537-539: Good addition of the new authentication section
Introducing a dedicated subsection clarifies how the new pluggable authentication system works. The explanation gives a clear overview for end users.

connector.go (4)

147-150: Appropriate plugin existence check
Returning an error if the plugin is missing is a good defensive approach. Make sure any dynamic plugin loading is handled before this point to avoid unexpected failures for known custom plugins.


153-156: Plugin-driven auth initialization
Delegating InitAuth to the plugin fosters modularity. The cleanup after error is correct.


164-165: Bounded authentication flow
Passing authMaximumSwitch and reusing the same plugin instance ensures a controlled multi-step authentication without fallback confusion.


21-23:

✅ Verification successful

Reasonable limit on plugin switch attempts
Using a constant for the maximum number of authentication plugin switches keeps the logic maintainable. Confirm that the limit of 5 attempts aligns with all supported multi-factor authentication scenarios.


🏁 Script executed:

#!/bin/bash
# Description: Check references to authMaximumSwitch across the codebase to ensure it is not exceeded or bypassed during multi-factor auth flows.
rg -A 5 "authMaximumSwitch"

Length of output: 876


Verification Confirmed: Consistent and Intentional Limit

The constant authMaximumSwitch is set to 5 in connector.go and is referenced both in the authentication flow (mc.handleAuthResult) and in generating the error message ("maximum of %d authentication switch reached") in auth.go. The grep output confirms that the limit is applied consistently across the multi-factor authentication logic.

  • The constant is declared and used in a way that prevents exceeding the intended number of switch attempts.
  • There’s no evidence from the codebase that the limit is bypassed or that additional scenarios require a higher count.

If later multi-factor authentication scenarios demand a different limit, please update the constant accordingly.

driver_test.go (3)

1633-1658: Improved collation test to handle server overrides - good approach.

The added code correctly handles cases where the server overrides the default collation based on character_set_collations. This makes the test more robust against different server configurations by:

  1. Fetching the server's character set collations mapping
  2. Parsing it into a usable dictionary structure
  3. Checking if the expected collation's charset has a server-mandated override
  4. Using the overridden value for comparison when necessary

1721-1721: Updated timezone test locations for broader coverage.

Changed test timezones from "US/Central", "US/Pacific" to "America/New_York", "Asia/Hong_Kong" which provides more global timezone coverage and uses IANA standard timezone names.


3577-3585: Good addition of performance_schema availability check.

This change adds an important check to verify the performance_schema is enabled before attempting to query connection attributes. This prevents test failures when running against MySQL servers with performance_schema disabled.

auth_cleartext.go (4)

11-23: Good implementation of the cleartext password plugin.

The ClearPasswordPlugin is well-structured and properly embeds SimpleAuth. The comments clearly document the security implications of cleartext authentication and when it should be used (TLS/SSL, Unix sockets, PAM).


25-27: Appropriate plugin registration in init.

The plugin correctly registers itself with the global plugin registry during package initialization, allowing the driver to discover it without manual registration.


29-31: Plugin identification method.

The GetPluginName method correctly returns "mysql_clear_password" which matches MySQL's internal plugin name.


33-46: Well-implemented authentication initialization.

The InitAuth method has good security practices:

  1. It checks if cleartext passwords are allowed in the configuration
  2. Returns an appropriate error if not allowed
  3. Correctly appends a null terminator to the password as required by the protocol

The null termination handling is particularly important for external authentication systems that need access to the original password.

auth_mysql_native.go (5)

13-16: Proper implementation of native password plugin.

The plugin structure is clean and correctly embeds SimpleAuth for shared functionality.


18-20: Self-registration pattern is consistent.

The plugin registers itself in init, matching the pattern used in other authentication plugins.


22-24: Plugin name matches MySQL's internal name.

The GetPluginName method correctly returns "mysql_native_password" in accordance with MySQL's naming.


26-34: Security check in initialization method.

InitAuth properly checks configuration settings before proceeding:

  1. Verifies AllowNativePasswords configuration flag
  2. Handles empty passwords correctly
  3. Calls scramblePassword with the correct portion of authData (first 20 bytes)

36-64: Accurate implementation of MySQL 4.1+ password hashing.

The scramblePassword function correctly implements the MySQL 4.1+ native password hashing algorithm:

  1. Properly handles empty passwords
  2. Calculates the SHA1 hash of the password (stage1)
  3. Creates a SHA1 hash of the stage1 hash
  4. Creates a SHA1 hash of the scramble + stage1 hash
  5. XORs the scramble hash with stage1 to produce the authentication token

The implementation follows the MySQL protocol specification precisely.

auth_plugin.go (4)

11-26: Well-designed plugin interface for authentication.

The AuthPlugin interface is cleanly defined with three essential methods:

  1. GetPluginName - Identifies the plugin
  2. InitAuth - Handles initial authentication
  3. ContinuationAuth - Manages subsequent authentication steps

The interface provides enough flexibility for different authentication mechanisms while maintaining a consistent API. The documentation for each method clearly explains parameters and purpose.


28-34: Good base implementation with SimpleAuth.

The SimpleAuth struct provides a sensible default implementation for ContinuationAuth, making it easier to implement simple plugins by embedding this struct. This avoids code duplication for plugins that don't need multi-step authentication.


36-58: Clean implementation of plugin registry.

The PluginRegistry implementation is straightforward and effective:

  1. Uses a map to store plugins by name
  2. Provides methods to register and retrieve plugins
  3. Has a proper constructor (NewPluginRegistry)
  4. Returns a boolean status with GetPlugin to safely handle missing plugins

This design allows for efficient plugin lookup while avoiding panics for unavailable plugins.


60-63: Global registry access with RegisterAuthPlugin.

This helper function simplifies plugin registration by accessing the global registry, following a common pattern in Go libraries. This makes it easy for both built-in and external plugins to register themselves.

auth_ed25519.go (4)

1-8: License and package header look good.
No issues found in the licensing block or package declaration.


16-19: Struct definition is straightforward.
Embedding SimpleAuth aligns with the plugin-based design. No immediate concerns.


21-23: Plugin registration is correct.
RegisterAuthPlugin invocation follows the new authentication system’s pattern.


25-27: Plugin name retrieval is fine.
The function name and return value match plugin naming conventions.

auth_test.go (41)

53-55: Initiating OldPasswordPlugin in test.
Constructing the plugin directly is acceptable for targeted testing. No issues.


122-122: Invocation of handleAuthResult.
Looks consistent with new multi-step auth approach.


137-138: Retrieving plugin from registry and calling InitAuth.
This is correct and aligns with the plugin-based design.


179-186: Setting up plugin and verifying handshake response flow.
Combining registry lookup with InitAuth is correct. The subsequent writeHandshakeResponsePacket call properly handles the returned bytes.


236-237: Caching SHA2 plugin retrieval and initialization.
Implementation follows the same pattern as other plugins. No issues.


289-290: Secure plugin initialization.
Reading from registry and calling InitAuth is consistent.


346-347: Cleartext password plugin retrieval and InitAuth check.
This test ensures errors are returned when not allowed. Logic is fine.


364-365: Acquiring plugin instance and retrieving auth response.
Matches the plugin design. Good coverage for empty password.


391-391: handleAuthResult usage.
Consistent approach to finalizing authentication.


407-408: Same pattern for plugin acquisition and initialization.
Design is uniform—straightforward test validation.


511-511: InitAuth with native password plugin in test.
Implementation is correct, verifying empty password logic.


553-553: sha256_password plugin test.
Empty password scenario is covered. Appropriately tested.


602-602: SHA256 password plugin retrieval & initialization.
No issues—standard plugin usage.


631-631: handleAuthResult for RSA scenario.
Ensures RSA logic is properly tested.


652-652: SHA256 plugin with custom pubKey.
Test coverage is thorough, ensuring plugin handles configured RSA key.


685-685: sha256_password plugin with secure connection.
Test ensures fallback to sending decrypted password over TLS. Implementation is correct.


714-714: handleAuthResult final check.
Standard multi-step auth logic, no issues.


741-741: Auth switch with &NativePasswordPlugin{}.
Matches plugin-based approach. No concerns.


773-773: handleAuthResult with empty password.
Trivial test scenario is validated.


807-807: Multi-step RSA-based handshake switch.
Test ensures partial hush vs. final hush approach. No issues.


849-849: Authorization switch with provided pubKey.
Flow is consistent with the plugin’s logic.


889-889: handleAuthResult for secure SHA256.
Ensures it sends cleartext password if TLS is verified. Good coverage.


913-913: Invalid plugin switch for cleartext password.
Expects error. Aligned with new plugin design.


935-935: handleAuthResult with explicit plugin object.
Demonstrates multi-auth switch for cleartext password.


959-959: Empty password old auth test.
Ensures correct fallback or error.


979-979: Disallow old password scenario.
Tests the config-based restriction. Good coverage.


1001-1001: Handling native password switch with non-empty password.
Ensures the scramble is created properly.


1029-1029: Empty password with native password switch.
Covered scenario; no issues.


1047-1047: handleAuthResult for old password not allowed.
Correctly returns ErrOldPassword. Test logic is fine.


1062-1062: handleAuthResult for old password with OldAuthSwitch request.
Same approach, verifying it fails.


1084-1084: Allowed old passwords.
Ensures scramble logic is tested.


1109-1109: Handling OldAuthSwitch with allowed old passwords.
Test confirms fallback is correct.


1132-1132: Handling old password with empty credentials.
Test ensures short-circuit for empty password.


1155-1155: Confirm empty old password switch.
No issues. Good coverage for an edge case.


1180-1180: Auth switch for sha256 with empty plugin data.
Verifies no crash or unexpected errors.


1211-1211: RSA-based pub key response.
Ensures correctness of encryption step.


1243-1243: RSA-based key scenario with custom pubKey.
Ensures no break with user-provided key.


1275-1275: Secure connection usage.
Checks fallback to sending password in cleartext over TLS.


1315-1319: Verifying Ed25519 client output.
Checks 64-byte response correctness, ensuring the derived signature matches expectations. Logic is correct.


1335-1370: TestMultiAuthSimpleSwitch.
Demonstrates multi-step switch from caching_sha2_password to mysql_clear_password. Asserts the correct handshake sequence is written.


1372-1413: TestMultiAuthSwitch.
Similar multi-step example, now adding RSA pub key steps before switching to cleartext. Thorough test coverage of multi-factor flow.

auth_old_password.go (6)

1-8: License and package declaration.
No concerns with the added header.


11-16: Plugin struct registration.
Embedding SimpleAuth and registering under mysql_old_password is consistent with the new system.


18-20: Plugin name retrieval.
Matches the typical plugin naming pattern. No issues.


22-33: InitAuth method for old password.
Properly checks AllowOldPasswords config flag. The scrambleOldPassword call is restricted to the first 8 bytes of the server scramble, matching MySQL’s old approach. This is correct for pre-4.1 style.


35-55: scrambleOldPassword implementation.
The code matches the historical MySQL algorithm, including skipping tabs/spaces and performing an insecure hash-based scramble. The approach is intentionally insecure but historically compatible. No immediate issues beyond inherent weakness of the scheme.


57-109: myRnd and pwHash logic.
Implements the legacy MySQL random generator and two-component hashing precisely. This is correct for old-style password scrambling.

auth_caching_sha2.go (12)

19-24: Clean separation of the plugin struct.
Embedding AuthPlugin in CachingSha2PasswordPlugin aligns well with the new plugin-based approach, making the design modular and maintainable.


26-28: Automatic plugin registration.
Registering the plugin in the init() function ensures it is discovered without additional user code, improving developer experience.


30-32: Correct and consistent plugin name.
Returning "caching_sha2_password" matches MySQL’s official plugin name and fulfills the AuthPlugin interface requirement.


34-42: Clear initial scramble implementation.
Delegating the scrambling logic to scrambleSHA256Password keeps the implementation focused and maintainable.


55-57: Empty packet handling.
It's good to error on an empty authentication response packet. Confirm there's no valid scenario in which the server sends an empty packet mid-auth.


59-62: iERR case verification.
Returning (packet, nil) for iERR relies on higher-level logic to recognize an error packet. Double-check that the caller properly treats it as an error and does not inadvertently proceed.


63-66: Fast auth success scenario.
This path indicates an immediate indication of success and proceeds to mc.readPacket(). Ensure this matches MySQL's spec for cached credentials with zero extended data.


75-127: Validate cleartext sending logic.
When TLS or a Unix socket is used, the password is sent in cleartext. Verify if you need to respect AllowCleartextPasswords or similar flags to avoid unexpected exposures.


129-131: Clear error for unknown state.
Throwing an error on unrecognized state ensures robust error handling and quicker debugging.


133-135: Unexpected packet length fallback.
Raising an error for mismatched lengths prevents subtle protocol mishandling.


136-139: Failsafe for invalid packet types.
Rejecting unknown packet types maintains stability, ensuring the driver doesn’t silently ignore server anomalies.


141-176: MySQL 8+ scramble algorithm.
The three-step SHA256-based hashing followed by XOR is consistent with caching_sha2_password specification.

auth_sha256.go (5)

20-22: Struct embedding for sha256_password plugin.
Adhering to the same plugin pattern keeps authentication logic uniform across plugins.


24-26: Init-based plugin registration.
Similar to the other plugins, this ensures the plugin is discovered and available at runtime.


28-30: Accurate plugin naming.
"sha256_password" properly identifies the authentication method for MySQL and matches server expectations.


32-62: Comprehensive InitAuth logic.
Handles empty passwords, TLS-based cleartext, RSA encryption fallback, and public key requests. Confirm any relevant AllowCleartextPasswords or usage constraints are enforced as needed.


64-105: ContinuationAuth multi-step support.
The switch statement properly handles OK, error, or public-key retrieval. Double-check iERR handling to ensure the caller interprets the error scenario correctly.

auth.go (6)

12-12: Introducing the bytes import.
Used to parse and locate the plugin name from null-terminated data, which is appropriate within packet parsing logic.


59-65: Guard against infinite re-auth loops.
Limiting remainingSwitch avoids potential recursion issues in multi-factor or repeated authentication switch scenarios.


67-79: Delegation to ContinuationAuth.
Continuing the authentication flow via the plugin maintains modular design. Ensure the returned packet is consistently valid for follow-up logic.


80-85: Direct handling of OK/ERR.
Returning the result or error packet as-is is concise. Validate that a server error via iERR is recognized upstream.


86-104: Auth switch recursion with new plugin.
Efficiently fetches next plugin from the registry and re-invokes auth logic, decrementing remainingSwitch. This structure elegantly supports multi-step authentication.


110-132: Plugin name extraction.
Automatically falls back to mysql_old_password if only a single byte remains, preserving legacy compatibility. Good approach for older server versions.

@coveralls
Copy link

coveralls commented Apr 19, 2025

Coverage Status

coverage: 82.753% (-0.08%) from 82.833%
when pulling ad292aa on rusher:authentication
into 7da50ff on go-sql-driver:master.

@methane
Copy link
Member

methane commented Apr 19, 2025

Make "test stability improvement." PR first.
I did it by myself.

driver.go Outdated
dials map[string]DialContextFunc
dialsLock sync.RWMutex
dials map[string]DialContextFunc
globalPluginRegistry = NewPluginRegistry()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
globalPluginRegistry = NewPluginRegistry()
pluginRegistry = NewPluginRegistry()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cannot do since that's the name of the struct

@methane
Copy link
Member

methane commented Apr 21, 2025

Maybe, its time to use internal package.

Current implementation was requiring authentication plugin that are have multiple step to begin with iAuthMoreData, but that's only required for "caching_sha2_password" and "sha256_password" plugins.
Additionally, now permits multi-authentication (in mariadb: https://mariadb.com/kb/en/create-user/#identified-viawith-authentication_plugin / mysql: https://dev.mysql.com/doc/refman/8.0/en/multifactor-authentication.html)

goal is to add MariaDB main authentication plugins (like parsec, PAM, GSSAPI, ...)
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
README.md (1)

537-547: Documentation looks great, consider using consistent list style

The new Authentication Plugin System section provides clear documentation of the supported authentication methods. However, the unordered list uses dash (-) markers instead of asterisks (*) which is inconsistent with the rest of the document.

-The driver implements a pluggable authentication system that supports various authentication methods used by MySQL and MariaDB servers. The built-in authentication plugins include:
-
-- `mysql_native_password` - The default MySQL authentication method
-- `caching_sha2_password` - Default authentication method in MySQL 8.0+
-- `mysql_clear_password` - Cleartext authentication (requires `allowCleartextPasswords=true`)
-- `mysql_old_password` - Old MySQL authentication (requires `allowOldPasswords=true`)
-- `sha256_password` - SHA256 authentication
-- `client_ed25519` - MariaDB Ed25519 authentication
+The driver implements a pluggable authentication system that supports various authentication methods used by MySQL and MariaDB servers. The built-in authentication plugins include:
+
+* `mysql_native_password` - The default MySQL authentication method
+* `caching_sha2_password` - Default authentication method in MySQL 8.0+
+* `mysql_clear_password` - Cleartext authentication (requires `allowCleartextPasswords=true`)
+* `mysql_old_password` - Old MySQL authentication (requires `allowOldPasswords=true`)
+* `sha256_password` - SHA256 authentication
+* `client_ed25519` - MariaDB Ed25519 authentication
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

541-541: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


542-542: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


543-543: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


544-544: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


545-545: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


546-546: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

auth_old_password.go (2)

11-12: Add missing documentation for SimpleAuth embedding.

The OldPasswordPlugin embeds SimpleAuth, but there's no documentation explaining what SimpleAuth provides. Consider adding a comment to clarify the inheritance relationship and available functionality.


83-108: Consider adding security warning for production use.

While the implementation correctly follows the legacy protocol, it would be helpful to add a comment warning that this hashing algorithm is cryptographically weak by modern standards and should only be used for backward compatibility.

 // Generate binary hash from byte string using insecure pre 4.1 method
+// WARNING: This algorithm is cryptographically weak by modern standards
+// and should only be used for backward compatibility with legacy systems.
 func pwHash(password []byte) (result [2]uint32) {
auth_caching_sha2.go (1)

149-176: Consider using crypto/subtle for constant-time operations.

Since this is a cryptographic function, consider using crypto/subtle package's constant-time functions for operations involving sensitive data to avoid potential timing side-channel attacks.

 // XOR the first hash with the third hash
 for i := range message1 {
-    message1[i] ^= message2[i]
+    message1[i] = message1[i] ^ message2[i] // Use XOR operator explicitly for clarity
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5dd643c and ad292aa.

📒 Files selected for processing (14)
  • README.md (1 hunks)
  • auth.go (2 hunks)
  • auth_caching_sha2.go (1 hunks)
  • auth_cleartext.go (1 hunks)
  • auth_ed25519.go (1 hunks)
  • auth_mysql_native.go (1 hunks)
  • auth_old_password.go (1 hunks)
  • auth_plugin.go (1 hunks)
  • auth_sha256.go (1 hunks)
  • auth_test.go (53 hunks)
  • connector.go (2 hunks)
  • const.go (0 hunks)
  • driver.go (1 hunks)
  • packets.go (0 hunks)
💤 Files with no reviewable changes (2)
  • packets.go
  • const.go
✅ Files skipped from review due to trivial changes (1)
  • auth_mysql_native.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • driver.go
  • connector.go
  • auth_cleartext.go
  • auth_plugin.go
🧰 Additional context used
🧬 Code Graph Analysis (5)
auth_caching_sha2.go (3)
auth_plugin.go (2)
  • AuthPlugin (12-26)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrMalformPkt (21-21)
auth_ed25519.go (2)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
auth_test.go (2)
auth_old_password.go (1)
  • OldPasswordPlugin (12-12)
auth_mysql_native.go (1)
  • NativePasswordPlugin (14-16)
auth.go (2)
auth_plugin.go (1)
  • AuthPlugin (12-26)
errors.go (1)
  • ErrMalformPkt (21-21)
auth_sha256.go (3)
auth_plugin.go (2)
  • AuthPlugin (12-26)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrMalformPkt (21-21)
🪛 markdownlint-cli2 (0.17.2)
README.md

541-541: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


542-542: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


543-543: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


544-544: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


545-545: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


546-546: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

⏰ Context from checks skipped due to timeout of 90000ms (16)
  • GitHub Check: test (windows-latest, 1.24, 8.4)
  • GitHub Check: test (windows-latest, 1.24, mariadb-11.1)
  • GitHub Check: test (windows-latest, 1.24, mariadb-11.4)
  • GitHub Check: test (windows-latest, 1.24, 5.7)
  • GitHub Check: test (windows-latest, 1.24, 8.0)
  • GitHub Check: test (windows-latest, 1.24, mariadb-10.5)
  • GitHub Check: test (windows-latest, 1.24, 9.0)
  • GitHub Check: test (windows-latest, 1.24, mariadb-10.11)
  • GitHub Check: test (windows-latest, 1.24, mariadb-10.6)
  • GitHub Check: test (windows-latest, 1.24, mariadb-11.2)
  • GitHub Check: test (macos-latest, 1.24, 8.0)
  • GitHub Check: test (ubuntu-latest, 1.24, mariadb-11.2)
  • GitHub Check: test (macos-latest, 1.24, 9.0)
  • GitHub Check: test (macos-latest, 1.24, mariadb-11.2)
  • GitHub Check: test (macos-latest, 1.24, mariadb-10.6)
  • GitHub Check: test (macos-latest, 1.24, mariadb-10.5)
🔇 Additional comments (15)
auth_test.go (4)

1335-1370: Well-designed test for simple authentication switch flow

This test effectively verifies the multi-authentication support by testing a scenario where authentication switches from SHA256 password to cleartext password. The test checks both the beginning and end of the authentication data, confirming that the protocol flows correctly through multiple authentication methods.


1372-1413: Comprehensive test for complex multi-authentication flow

This test covers a more complex scenario with multiple authentication switches including public key retrieval, demonstrating the robustness of the new plugin-based authentication system. The verification checks both the prefix and suffix of the response data, ensuring the correct sequence of authentication packets.


53-56: Good refactoring of old password testing to use plugin architecture

The test was correctly refactored to use the new plugin-based approach, instantiating the OldPasswordPlugin and using its method instead of a global function.


122-124: Updated interface for handleAuthResult with proper recursion limit

The signature change for handleAuthResult now includes the remaining switch count (5) to prevent infinite loops during authentication. This is a good security practice.

auth_ed25519.go (2)

29-64: Strong cryptographic implementation of Ed25519 authentication

The Ed25519 authentication implementation is secure and follows cryptographic best practices:

  1. It derives keys using SHA-512 hashing
  2. Properly implements scalar clamping
  3. Uses the edwards25519 library for cryptographic operations
  4. Has appropriate error handling at each step

The implementation is attributed to the MariaDB server source and follows the Go style guidelines.


16-23: Clean plugin architecture with proper registration

The plugin follows the established plugin architecture pattern, embedding SimpleAuth and registering itself during initialization.

auth.go (2)

80-129: Improved authentication flow with plugin-based approach

The new handleAuthResult method implements a more modular and extensible authentication flow:

  1. It sets a limit on authentication switches to prevent infinite loops
  2. Properly delegates to the authentication plugin for continuation
  3. Handles standard MySQL protocol responses (OK, ERR, EOF)
  4. Manages authentication switches by retrieving the appropriate plugin
  5. Uses recursion with a decremented counter for subsequent authentication steps

This approach improves maintainability and makes it easier to add new authentication methods.


131-153: Well-designed helper for authentication switch parsing

The new parseAuthSwitchData method correctly extracts plugin name and authentication data from packets, with special handling for the old authentication protocol. The method makes a copy of the authentication data to prevent unintended modifications.

auth_old_password.go (2)

22-33: Good implementation with proper error handling.

The method handles configuration checks and empty password cases correctly. The reference to a known issue with a GitHub link provides helpful context for future maintainers.


35-55: Implementation follows the legacy protocol correctly.

The scramble implementation properly follows the pre-4.1 MySQL protocol. The method correctly limits the scramble to 8 bytes and uses the legacy hashing and XOR operations.

auth_caching_sha2.go (4)

54-57: Error handling improvement for empty packet.

Good error handling with context using the wrapped error pattern for better diagnostic information.


59-138: Well-structured authentication flow with proper error handling.

The implementation correctly handles all the authentication paths with proper error messages and comprehensive packet validation. The code is readable and well-organized with clear comments explaining each step of the process.


76-81:

✅ Verification successful

Verify error handling when sending cleartext password.

Ensure the error handling correctly propagates errors when sending cleartext passwords. Currently, you're wrapping the error with additional context, which is good, but verify this interaction with the actual connection implementation.


🏁 Script executed:

#!/bin/bash
# Check how writeAuthSwitchPacket handles errors in other places
grep -rn "writeAuthSwitchPacket" --include="*.go" .

Length of output: 479


Cleartext password error handling is correct

The writeAuthSwitchPacket method returns any underlying write errors directly, and your fmt.Errorf("failed to send cleartext password: %w", err) wrapper cleanly adds context while propagating the error. No further changes are needed here.


22-24:

❌ Incorrect review comment

Fix inconsistent struct definition.

The CachingSha2PasswordPlugin embeds AuthPlugin which appears to be an interface, not a struct. Compare with other plugins that embed SimpleAuth or properly implement the interface. This might lead to unexpected behavior if AuthPlugin doesn't have default implementations.


🏁 Script executed:

#!/bin/bash
# Verify the definition of AuthPlugin interface and SimpleAuth
grep -rn "type AuthPlugin" --include="*.go" .
grep -rn "type SimpleAuth" --include="*.go" .

Length of output: 188


🏁 Script executed:

#!/bin/bash
# List other AuthPlugin implementations to compare struct embedding patterns
grep -R "type .*Plugin struct" -n --include="*.go" .

Length of output: 430


🏁 Script executed:

#!/bin/bash
# Inspect constructors for password plugins to see how they initialize embedded fields
grep -R "func New.*PasswordPlugin" -n --include="*.go" -A5 -B5 .

Length of output: 66


Ignore inconsistent struct definition warning

Embedding the AuthPlugin interface in CachingSha2PasswordPlugin is intentional and matches the pattern used by other password plugins:

  • auth_cleartext.go:21 type ClearPasswordPlugin struct{ AuthPlugin }
  • auth_ed25519.go:17 type ClientEd25519Plugin struct{ AuthPlugin }
  • auth_mysql_native.go:14 type NativePasswordPlugin struct{ AuthPlugin }
  • auth_sha256.go:22 type Sha256PasswordPlugin struct{ AuthPlugin }

No changes are needed here.

Likely an incorrect or invalid review comment.

auth_sha256.go (1)

107-130: Strong implementation with good security practices.

The password encryption implementation properly XORs the password with the auth seed to prevent replay attacks and uses RSA-OAEP with SHA1, which is more secure than PKCS#1 v1.5 padding. Consider using a more modern hash function like SHA-256 instead of SHA-1 in the future, though this might be constrained by protocol requirements.

Comment on lines +89 to +93
// Send encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pub.(*rsa.PublicKey))
if err != nil {
return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add type assertion error checking.

The type assertion pub.(*rsa.PublicKey) on line 90 doesn't check if the assertion succeeded. If the server returns an unexpected key type, this could panic. Add error checking for the type assertion.

 // Send encrypted password
-enc, err := encryptPassword(mc.cfg.Passwd, authData, pub.(*rsa.PublicKey))
+pubKey, ok := pub.(*rsa.PublicKey)
+if !ok {
+    return nil, fmt.Errorf("server sent an invalid public key type: %T", pub)
+}
+enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
 if err != nil {
     return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Send encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pub.(*rsa.PublicKey))
if err != nil {
return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
}
// Send encrypted password
pubKey, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("server sent an invalid public key type: %T", pub)
}
enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
if err != nil {
return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
}

Comment on lines +70 to +105
func (p *Sha256PasswordPlugin) continuationAuth(packet []byte, authData []byte, mc *mysqlConn) ([]byte, error) {

switch packet[0] {
case iOK, iERR, iEOF:
return packet, nil

case iAuthMoreData:
// Parse public key from PEM format
block, rest := pem.Decode(packet[1:])
if block == nil {
return nil, fmt.Errorf("invalid PEM data in auth response: %q", rest)
}

// Parse the public key
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}

// Send encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pub.(*rsa.PublicKey))
if err != nil {
return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
}

// Send the encrypted password
if err = mc.writeAuthSwitchPacket(enc); err != nil {
return nil, fmt.Errorf("failed to send encrypted password: %w", err)
}

return mc.readPacket()

default:
return nil, fmt.Errorf("%w: unexpected packet type %d", ErrMalformPkt, packet[0])
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing check for packet length before accessing.

There's no check for packet length before accessing packet[0] on line 72. If the server returns an empty packet, this will cause a panic. Add a length check similar to what you implemented in auth_caching_sha2.go.

+if len(packet) == 0 {
+    return nil, fmt.Errorf("%w: empty auth response packet", ErrMalformPkt)
+}

 switch packet[0] {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (p *Sha256PasswordPlugin) continuationAuth(packet []byte, authData []byte, mc *mysqlConn) ([]byte, error) {
switch packet[0] {
case iOK, iERR, iEOF:
return packet, nil
case iAuthMoreData:
// Parse public key from PEM format
block, rest := pem.Decode(packet[1:])
if block == nil {
return nil, fmt.Errorf("invalid PEM data in auth response: %q", rest)
}
// Parse the public key
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
// Send encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pub.(*rsa.PublicKey))
if err != nil {
return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
}
// Send the encrypted password
if err = mc.writeAuthSwitchPacket(enc); err != nil {
return nil, fmt.Errorf("failed to send encrypted password: %w", err)
}
return mc.readPacket()
default:
return nil, fmt.Errorf("%w: unexpected packet type %d", ErrMalformPkt, packet[0])
}
}
func (p *Sha256PasswordPlugin) continuationAuth(packet []byte, authData []byte, mc *mysqlConn) ([]byte, error) {
// Ensure we have at least one byte before inspecting packet[0]
if len(packet) == 0 {
return nil, fmt.Errorf("%w: empty auth response packet", ErrMalformPkt)
}
switch packet[0] {
case iOK, iERR, iEOF:
return packet, nil
case iAuthMoreData:
// Parse public key from PEM format
block, rest := pem.Decode(packet[1:])
if block == nil {
return nil, fmt.Errorf("invalid PEM data in auth response: %q", rest)
}
// Parse the public key
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
// Send encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pub.(*rsa.PublicKey))
if err != nil {
return nil, fmt.Errorf("failed to encrypt password with server key: %w", err)
}
// Send the encrypted password
if err = mc.writeAuthSwitchPacket(enc); err != nil {
return nil, fmt.Errorf("failed to send encrypted password: %w", err)
}
return mc.readPacket()
default:
return nil, fmt.Errorf("%w: unexpected packet type %d", ErrMalformPkt, packet[0])
}
}

@rusher
Copy link
Contributor Author

rusher commented Apr 22, 2025

rebase on current master, and corrected the point above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants