Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ find_package(MySQL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(AWSSDK 1.11.774 EXACT REQUIRED COMPONENTS s3-crt)

# minimysql_server needs OpenSSL::SSL for boost::asio::ssl (server-side TLS
# listener). OpenSSL::Crypto is used by several other targets as well and
# was previously picked up transitively via AWS SDK; make the dependency
# explicit now that we also need the SSL half of OpenSSL.
find_package(OpenSSL REQUIRED)

# various utility files
set(util_source_files
src/util/bnf_parser_helpers.hpp
Expand Down Expand Up @@ -615,9 +621,11 @@ set(minimysql_source_files
src/minimysql/connection_context.cpp
src/minimysql/network_io_operations_fwd.hpp
src/minimysql/network_io_operations.hpp
src/minimysql/network_io_operations.cpp
src/minimysql/network_service.hpp
src/minimysql/network_service.cpp
src/minimysql/ssl_acceptor_context_fwd.hpp
src/minimysql/ssl_acceptor_context.hpp
src/minimysql/ssl_acceptor_context.cpp
src/minimysql/sample_event_collection.hpp
src/minimysql/sample_event_collection.cpp

Expand All @@ -631,6 +639,7 @@ target_link_libraries(minimysql_server
PRIVATE
binlog_server_compiler_flags
Boost::headers Boost::asio
OpenSSL::SSL
OpenSSL::Crypto
)

Expand Down
528 changes: 516 additions & 12 deletions src/minimysql/caching_sha2_password_authenticator.cpp

Large diffs are not rendered by default.

113 changes: 112 additions & 1 deletion src/minimysql/caching_sha2_password_authenticator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,127 @@
#ifndef MINIMYSQL_CACHING_SHA2_PASSWORD_AUTHENTICATOR_HPP
#define MINIMYSQL_CACHING_SHA2_PASSWORD_AUTHENTICATOR_HPP

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

#include "minimysql/network_io_operations_fwd.hpp"

namespace minimysql {

class auth_packet_encoder {
public:
auth_packet_encoder() = default;
virtual ~auth_packet_encoder() = default;

auth_packet_encoder(const auth_packet_encoder &) = delete;
auth_packet_encoder(auth_packet_encoder &&) = delete;
auth_packet_encoder &operator=(const auth_packet_encoder &) = delete;
auth_packet_encoder &operator=(auth_packet_encoder &&) = delete;

[[nodiscard]] virtual network_buffer_type
encode_single_byte(std::uint8_t payload_byte) = 0;
[[nodiscard]] virtual network_buffer_type
encode_raw(std::string_view payload) = 0;
[[nodiscard]] virtual network_buffer_type
encode_auth_method_data(std::string_view payload) = 0;
virtual void
validate_incoming_sequence(const network_buffer_type &payload) = 0;
[[nodiscard]] virtual std::string_view
frame_payload(const network_buffer_type &payload) const = 0;
};

enum class authentication_state : std::uint8_t {
in_progress,
succeeded,
failed,
};

class caching_sha2_password_authenticator {
public:
static constexpr std::string_view plugin_name{"caching_sha2_password"};

static std::string scramble(std::string_view password, std::string_view salt);
explicit caching_sha2_password_authenticator(
std::string_view password,
std::string_view server_rsa_public_key_path = {},
std::string_view server_rsa_private_key_path = {});
~caching_sha2_password_authenticator();

caching_sha2_password_authenticator(
const caching_sha2_password_authenticator &) = delete;
caching_sha2_password_authenticator &
operator=(const caching_sha2_password_authenticator &) = delete;
caching_sha2_password_authenticator(
caching_sha2_password_authenticator &&) noexcept = default;
caching_sha2_password_authenticator &
operator=(caching_sha2_password_authenticator &&) noexcept = default;

[[nodiscard]] static bool
needs_auth_method_switch(std::string_view client_plugin) noexcept;

[[nodiscard]] static std::string
generate_auth_switch_plugin_data(std::string_view salt);

void begin_authentication(std::string_view expected_username,
std::string_view client_username,
std::string_view client_auth_data,
std::string_view salt, bool secure_transport,
auth_packet_encoder &encoder);

[[nodiscard]] authentication_state state() const noexcept;

[[nodiscard]] bool expects_client_input() const noexcept;

[[nodiscard]] std::vector<network_buffer_type> take_outbound_frames();

authentication_state submit_client_frame(const network_buffer_type &frame,
auth_packet_encoder &encoder);

[[nodiscard]] static std::string scramble(std::string_view password,
std::string_view salt);

private:
struct rsa_key_pair;

[[nodiscard]] std::string_view get_rsa_public_key_pem() const noexcept;
[[nodiscard]] std::size_t get_rsa_cipher_length() const noexcept;
[[nodiscard]] static bool
check_public_key_request(std::string_view payload) noexcept;
[[nodiscard]] std::string
decrypt_rsa_password(std::string_view encrypted_password,
std::string_view salt) const;

void enqueue_perform_full_authentication(auth_packet_encoder &encoder);
void enqueue_public_key(auth_packet_encoder &encoder);
void enqueue_fast_auth_success(auth_packet_encoder &encoder);
[[nodiscard]] authentication_state
verify_encrypted_password(std::string_view encrypted_password);
[[nodiscard]] authentication_state
verify_cleartext_password(std::string_view password_payload);

[[nodiscard]] bool verify_greeting_scramble(
std::string_view expected_username, std::string_view client_username,
std::string_view client_auth_data, std::string_view salt) const;

std::string password_;
std::string expected_username_;
std::string client_username_;
std::string salt_;
bool secure_transport_{false};
std::unique_ptr<rsa_key_pair> rsa_keys_;

enum class phase : std::uint8_t {
idle,
awaiting_full_auth_response,
awaiting_encrypted_password,
succeeded,
failed,
};
phase phase_{phase::idle};
std::vector<network_buffer_type> outbound_frames_;
};

} // namespace minimysql
Expand Down
Loading
Loading