Skip to content

Commit a5784d2

Browse files
committed
WL11685: SHA256_MEMORY authentication
1 parent 5d99db8 commit a5784d2

File tree

13 files changed

+443
-51
lines changed

13 files changed

+443
-51
lines changed

cdk/extra/process_launcher/process_launcher.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,6 @@
2828
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2929
*/
3030

31-
This program is free software; you can redistribute it and/or modify
32-
it under the terms of the GNU General Public License as published by
33-
the Free Software Foundation; version 2 of the License.
34-
35-
This program is distributed in the hope that it will be useful,
36-
but WITHOUT ANY WARRANTY; without even the implied warranty of
37-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38-
GNU General Public License for more details.
39-
40-
You should have received a copy of the GNU General Public License
41-
along with this program; if not, write to the Free Software
42-
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
43-
4431
#ifndef _PROCESS_LAUNCHER_H_
4532
#define _PROCESS_LAUNCHER_H_
4633

cdk/include/mysql/cdk/data_source.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ class Protocol_options
141141
DEFAULT,
142142
PLAIN,
143143
MYSQL41,
144-
EXTERNAL
144+
EXTERNAL,
145+
SHA256_MEMORY
145146
};
146147

147148
virtual auth_method_t auth_method() const = 0;

cdk/include/mysql/cdk/mysqlx/session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ class Session
640640

641641
// Authentication (cdk::protocol::mysqlx::Auth_processor)
642642
void authenticate(const Options &options, bool secure = false);
643+
void do_authenticate(const Options &options, int auth_method, bool secure);
643644
void auth_ok(bytes data);
644645
void auth_continue(bytes data);
645646
void auth_fail(bytes data);

cdk/mysqlx/CMakeLists.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,20 @@ ADD_DEFINITIONS(-DSIZEOF_LONG=${SIZEOF_LONG} -DSIZEOF_LONG_LONG=${SIZEOF_LONG_LO
3636
# TODO: Fix compile warnings in auth_mysql41.cc
3737

3838
if(WIN32)
39-
set_property(SOURCE auth_mysql41.cc
39+
set_property(SOURCE auth_hash.cc
4040
PROPERTY COMPILE_FLAGS "/W3"
4141
)
4242
endif()
4343

4444

45-
ADD_LIBRARY(${target_mysqlx} OBJECT session.cc result.cc auth_mysql41.cc)
45+
ADD_LIBRARY(${target_mysqlx} OBJECT
46+
session.cc
47+
result.cc
48+
auth_hash.cc
49+
)
4650
ADD_COVERAGE(${target_mysqlx})
4751

48-
# Note: File auth_mysql41.cc uses SSL code.
52+
# Note: File auth_mysql41.cc and auth_sha256.cc uses SSL code.
4953

5054
add_ssl(${target_mysqlx})
5155

cdk/mysqlx/auth_mysql41.cc renamed to cdk/mysqlx/auth_hash.cc

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2929
*/
3030

31-
#include "auth_mysql41.h"
31+
#include "auth_hash.h"
3232
#include <stdint.h>
3333
#include <stdexcept>
3434
#include <string.h> // memset
@@ -58,6 +58,7 @@
5858
#define PVERSION41_CHAR '*'
5959
#define SCRAMBLE_LENGTH 20
6060
#define SHA1_HASH_SIZE 20
61+
#define SHA256_HASH_SIZE 32
6162

6263
#if defined( WITH_SSL_YASSL)
6364
using namespace TaoCrypt;
@@ -77,6 +78,9 @@ class SHA
7778
}
7879

7980
public:
81+
82+
enum { DIGEST_SIZE = SHA1_HASH_SIZE }; // in Bytes
83+
8084
SHA()
8185
{
8286
init();
@@ -92,6 +96,40 @@ class SHA
9296
SHA1_Final(hash, &m_sha);
9397
init();
9498
}
99+
100+
size_t getDigestSize() const {return SHA1_HASH_SIZE; }
101+
};
102+
103+
class SHA256
104+
{
105+
SHA256_CTX m_sha;
106+
107+
void init()
108+
{
109+
SHA256_Init(&m_sha);
110+
}
111+
112+
public:
113+
114+
enum { DIGEST_SIZE = SHA256_HASH_SIZE }; // in Bytes
115+
116+
SHA256()
117+
{
118+
init();
119+
}
120+
121+
void Update(byte* data, length_t length)
122+
{
123+
SHA256_Update(&m_sha, data, length);
124+
}
125+
126+
void Final(byte* hash)
127+
{
128+
SHA256_Final(hash, &m_sha);
129+
init();
130+
}
131+
132+
size_t getDigestSize() const {return SHA256_HASH_SIZE; }
95133
};
96134
#endif
97135

@@ -106,37 +144,47 @@ static void my_crypt(uint8_t *to, const uint8_t *s1, const uint8_t *s2, size_t l
106144

107145

108146

147+
template<class SHA_Crypt>
109148
static std::string scramble(const std::string &scramble_data, const std::string &password)
110149
{
111-
class SHA sha1;
150+
SHA_Crypt sha;
112151

113152
if (scramble_data.length() != SCRAMBLE_LENGTH)
114153
throw std::invalid_argument("Password scramble data is invalid");
115154

116-
byte hash_stage1[SHA1_HASH_SIZE];
117-
byte hash_stage2[SHA1_HASH_SIZE];
118-
byte result_buf[SHA1_HASH_SIZE+1];
155+
byte hash_stage1[SHA_Crypt::DIGEST_SIZE];
156+
byte hash_stage2[SHA_Crypt::DIGEST_SIZE];
157+
byte result_buf[SHA_Crypt::DIGEST_SIZE+1];
119158

120159
memset(result_buf, 0, sizeof(result_buf));
121160

122161
/* Two stage SHA1 hash of the pwd */
123162
/* Stage 1: hash pwd */
124-
sha1.Update((byte*)password.data(), (length_t)password.length());
125-
sha1.Final(hash_stage1);
163+
sha.Update((byte*)password.data(), (length_t)password.length());
164+
sha.Final(hash_stage1);
126165

127166
/* Stage 2 : hash first stage's output. */
128-
sha1.Update(hash_stage1, SHA1_HASH_SIZE);
129-
sha1.Final(hash_stage2);
167+
sha.Update(hash_stage1, sha.getDigestSize());
168+
sha.Final(hash_stage2);
130169

131170
/* create crypt string as sha1(message, hash_stage2) */;
132-
sha1.Update((byte*)scramble_data.data(), (length_t)scramble_data.length());
133-
sha1.Update(hash_stage2, SHA1_HASH_SIZE);
134-
sha1.Final(result_buf);
135-
result_buf[SHA1_HASH_SIZE] = '\0';
171+
/* MYSQL41 and SHA256_PASSWORD have different behaviors here! Bug? */
172+
if (sha.getDigestSize() == SHA1_HASH_SIZE)
173+
{
174+
sha.Update((byte*)scramble_data.data(), (length_t)scramble_data.length());
175+
sha.Update(hash_stage2, sha.getDigestSize());
176+
}
177+
else
178+
{
179+
sha.Update(hash_stage2, sha.getDigestSize());
180+
sha.Update((byte*)scramble_data.data(), (length_t)scramble_data.length());
181+
}
182+
sha.Final(result_buf);
183+
result_buf[sha.getDigestSize()] = '\0';
136184

137-
my_crypt(result_buf, result_buf, hash_stage1, SCRAMBLE_LENGTH);
185+
my_crypt(result_buf, result_buf, hash_stage1, sha.getDigestSize());
138186

139-
return std::string((char*)result_buf, SCRAMBLE_LENGTH);
187+
return std::string((char*)result_buf, sha.getDigestSize());
140188
}
141189

142190
static char *octet2hex(char *to, const char *str, size_t len)
@@ -153,8 +201,9 @@ static char *octet2hex(char *to, const char *str, size_t len)
153201
return to;
154202
}
155203

204+
// MYSQL41 specific
156205

157-
static std::string get_password_from_salt(const std::string &hash_stage2)
206+
static std::string get_password_from_salt_mysql41(const std::string &hash_stage2)
158207
{
159208
std::string result(2*SHA1_HASH_SIZE + 1, '\0');
160209

@@ -168,18 +217,19 @@ static std::string get_password_from_salt(const std::string &hash_stage2)
168217
}
169218

170219

171-
std::string mysqlx::build_mysql41_authentication_response(const std::string &salt_data,
172-
const std::string &user,
173-
const std::string &password,
174-
const std::string &schema)
220+
std::string mysqlx::build_mysql41_authentication_response(
221+
const std::string &salt_data,
222+
const std::string &user,
223+
const std::string &password,
224+
const std::string &schema)
175225
{
176226
std::string data;
177227
std::string password_hash;
178228

179229
if (password.length())
180230
{
181-
password_hash = scramble(salt_data, password);
182-
password_hash = get_password_from_salt(password_hash);
231+
password_hash = scramble<class SHA>(salt_data, password);
232+
password_hash = get_password_from_salt_mysql41(password_hash);
183233
}
184234

185235
data.append(schema).push_back('\0'); // authz
@@ -188,3 +238,38 @@ std::string mysqlx::build_mysql41_authentication_response(const std::string &sal
188238

189239
return data;
190240
}
241+
242+
// SHA256_MEMORY specific
243+
244+
static std::string get_password_from_salt_sha256(const std::string &hash_stage2)
245+
{
246+
std::string result(2*SHA256_HASH_SIZE +1 , '\0');
247+
248+
if (hash_stage2.length() != SHA256_HASH_SIZE)
249+
throw std::invalid_argument("Wrong size of binary hash password");
250+
251+
octet2hex(&result[0], &hash_stage2[0], SHA256_HASH_SIZE);
252+
253+
return result;
254+
}
255+
256+
std::string mysqlx::build_sha256_authentication_response(
257+
const std::string &salt_data,
258+
const std::string &user,
259+
const std::string &password,
260+
const std::string &schema)
261+
{
262+
std::string password_hash;
263+
std::string data;
264+
265+
password_hash = scramble<class SHA256>(salt_data, password);
266+
password_hash = get_password_from_salt_sha256(password_hash);
267+
//REMOVE ending \0
268+
password_hash.pop_back();
269+
270+
data.append(schema).push_back('\0'); // authz
271+
data.append(user).push_back('\0'); // authc
272+
data.append(password_hash); // pass
273+
274+
return data;
275+
}

cdk/mysqlx/auth_mysql41.h renamed to cdk/mysqlx/auth_hash.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,17 @@
3636

3737
namespace mysqlx
3838
{
39-
std::string build_mysql41_authentication_response(const std::string &salt_data,
40-
const std::string &user,
41-
const std::string &password,
42-
const std::string &schema);
39+
std::string build_mysql41_authentication_response(
40+
const std::string &salt_data,
41+
const std::string &user,
42+
const std::string &password,
43+
const std::string &schema);
44+
45+
std::string build_sha256_authentication_response(
46+
const std::string &salt_data,
47+
const std::string &user,
48+
const std::string &password,
49+
const std::string &schema);
4350
}
4451

4552
#endif

cdk/mysqlx/delayed_op.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Proto_delayed_op
9595
op = start();
9696

9797
if (op)
98-
op->wait();
98+
op->wait();
9999
else
100100
THROW("Invalid delayed operation.");
101101
}

0 commit comments

Comments
 (0)