File indexing completed on 2026-08-17 08:51:24
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CACHING_SHA2_PASSWORD_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CACHING_SHA2_PASSWORD_HPP
0010
0011 #include <boost/mysql/client_errc.hpp>
0012 #include <boost/mysql/error_code.hpp>
0013 #include <boost/mysql/string_view.hpp>
0014
0015 #include <boost/mysql/detail/next_action.hpp>
0016
0017 #include <boost/mysql/impl/internal/coroutine.hpp>
0018 #include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>
0019 #include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>
0020 #include <boost/mysql/impl/internal/protocol/static_buffer.hpp>
0021 #include <boost/mysql/impl/internal/sansio/auth_plugin_common.hpp>
0022 #include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>
0023 #include <boost/mysql/impl/internal/sansio/csha2p_encrypt_password.hpp>
0024
0025 #include <boost/asio/ssl/error.hpp>
0026 #include <boost/container/small_vector.hpp>
0027 #include <boost/core/span.hpp>
0028 #include <boost/system/result.hpp>
0029 #include <boost/system/system_category.hpp>
0030
0031 #include <array>
0032 #include <cstddef>
0033 #include <cstdint>
0034 #include <openssl/sha.h>
0035
0036
0037
0038
0039 namespace boost {
0040 namespace mysql {
0041 namespace detail {
0042
0043
0044 BOOST_INLINE_CONSTEXPR std::size_t csha2p_hash_size = 32;
0045 BOOST_INLINE_CONSTEXPR const char* csha2p_plugin_name = "caching_sha2_password";
0046 static_assert(csha2p_hash_size <= max_hash_size, "");
0047 static_assert(csha2p_hash_size == SHA256_DIGEST_LENGTH, "Buffer size mismatch");
0048
0049 inline void csha2p_hash_password_impl(
0050 string_view password,
0051 span<const std::uint8_t, scramble_size> scramble,
0052 span<std::uint8_t, csha2p_hash_size> output
0053 )
0054 {
0055
0056
0057 std::array<std::uint8_t, csha2p_hash_size> password_sha;
0058 SHA256(reinterpret_cast<const unsigned char*>(password.data()), password.size(), password_sha.data());
0059
0060
0061 std::array<std::uint8_t, csha2p_hash_size + scramble_size> buffer;
0062 SHA256(password_sha.data(), password_sha.size(), buffer.data());
0063 std::memcpy(buffer.data() + csha2p_hash_size, scramble.data(), scramble.size());
0064
0065
0066 std::array<std::uint8_t, csha2p_hash_size> salted_password;
0067 SHA256(buffer.data(), buffer.size(), salted_password.data());
0068
0069
0070 for (unsigned i = 0; i < csha2p_hash_size; ++i)
0071 {
0072 output[i] = salted_password[i] ^ password_sha[i];
0073 }
0074 }
0075
0076 inline static_buffer<max_hash_size> csha2p_hash_password(
0077 string_view password,
0078 span<const std::uint8_t, scramble_size> scramble
0079 )
0080 {
0081
0082 if (password.empty())
0083 return {};
0084
0085
0086 static_buffer<max_hash_size> res(csha2p_hash_size);
0087 csha2p_hash_password_impl(
0088 password,
0089 scramble,
0090 span<std::uint8_t, csha2p_hash_size>(res.data(), csha2p_hash_size)
0091 );
0092 return res;
0093 }
0094
0095 class csha2p_algo
0096 {
0097 int resume_point_{0};
0098
0099 static bool is_perform_full_auth(span<const std::uint8_t> server_data)
0100 {
0101 return server_data.size() == 1u && server_data[0] == 4;
0102 }
0103
0104 static bool is_fast_auth_ok(span<const std::uint8_t> server_data)
0105 {
0106 return server_data.size() == 1u && server_data[0] == 3;
0107 }
0108
0109 static next_action encrypt_password(
0110 connection_state_data& st,
0111 std::uint8_t& seqnum,
0112 string_view password,
0113 span<const std::uint8_t, scramble_size> scramble,
0114 span<const std::uint8_t> server_key
0115 )
0116 {
0117 container::small_vector<std::uint8_t, 512> buff;
0118 auto ec = csha2p_encrypt_password(password, scramble, server_key, buff, asio::error::ssl_category);
0119 if (ec)
0120 return ec;
0121 return st.write(
0122 string_eof{string_view(reinterpret_cast<const char*>(buff.data()), buff.size())},
0123 seqnum
0124 );
0125 }
0126
0127 public:
0128 csha2p_algo() = default;
0129
0130 next_action resume(
0131 connection_state_data& st,
0132 span<const std::uint8_t> server_data,
0133 string_view password,
0134 span<const std::uint8_t, scramble_size> scramble,
0135 bool secure_channel,
0136 std::uint8_t& seqnum
0137 )
0138 {
0139 switch (resume_point_)
0140 {
0141 case 0:
0142
0143
0144 if (is_perform_full_auth(server_data))
0145 {
0146 if (secure_channel)
0147 {
0148
0149 BOOST_MYSQL_YIELD(resume_point_, 1, st.write(string_null{password}, seqnum))
0150
0151
0152 return error_code(client_errc::bad_handshake_packet_type);
0153 }
0154 else
0155 {
0156
0157 BOOST_MYSQL_YIELD(resume_point_, 2, st.write(int1{2}, seqnum))
0158
0159
0160 BOOST_MYSQL_YIELD(
0161 resume_point_,
0162 3,
0163 encrypt_password(st, seqnum, password, scramble, server_data)
0164 )
0165
0166
0167 return error_code(client_errc::bad_handshake_packet_type);
0168 }
0169 }
0170 else if (is_fast_auth_ok(server_data))
0171 {
0172
0173 BOOST_MYSQL_YIELD(resume_point_, 4, st.read(seqnum))
0174 }
0175 else
0176 {
0177
0178
0179 return error_code(client_errc::bad_handshake_packet_type);
0180 }
0181 }
0182
0183
0184 return error_code(client_errc::bad_handshake_packet_type);
0185 }
0186 };
0187
0188 }
0189 }
0190 }
0191
0192 #endif