Commit bec1d903 authored by Sergei Golubchik's avatar Sergei Golubchik

Do the partial merge of WL#5602 correctly:

  Remove unused code (that should not have been merged)
  Add protocol extension (that should have been merged)
  Fix bugs (see pack.c)
parent 6ae5f0ef
/* defines and prototypes for using crypt_genhash_impl.cc */
#ifndef CRYPT_HASHGEN_IMPL_H
#define CRYPT_HASHGEN_IMPL_H
#define ROUNDS_DEFAULT 5000
#define ROUNDS_MIN 1000
#define ROUNDS_MAX 999999999
#define MIXCHARS 32
#define CRYPT_SALT_LENGTH 20
#define CRYPT_MAGIC_LENGTH 3
#define CRYPT_PARAM_LENGTH 13
#define SHA256_HASH_LENGTH 43
#define CRYPT_MAX_PASSWORD_SIZE (CRYPT_SALT_LENGTH + \
SHA256_HASH_LENGTH + \
CRYPT_MAGIC_LENGTH + \
CRYPT_PARAM_LENGTH)
int extract_user_salt(char **salt_begin,
char **salt_end);
C_MODE_START
char *
my_crypt_genhash(char *ctbuffer,
size_t ctbufflen,
const char *plaintext,
int plaintext_len,
const char *switchsalt,
const char **params);
void generate_user_salt(char *buffer, int buffer_len);
void xor_string(char *to, int to_len, char *pattern, int pattern_len);
C_MODE_END
#endif
#ifndef CLIENT_AUTHENTICATION_H
#define CLIENT_AUTHENTICATION_H
#include "mysql.h"
#include "mysql/client_plugin.h"
C_MODE_START
int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
int sha256_password_init(char *, size_t, int, va_list);
int sha256_password_deinit(void);
C_MODE_END
#endif
......@@ -265,11 +265,11 @@ enum enum_server_command
CLIENT_REMEMBER_OPTIONS | \
CLIENT_PROGRESS | \
CLIENT_PLUGIN_AUTH | \
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
CLIENT_CONNECT_ATTRS)
/*
To be added later:
CLIENT_CONNECT_ATTRS, CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA,
CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS
*/
......@@ -641,7 +641,9 @@ void my_thread_end(void);
#ifdef MY_GLOBAL_INCLUDED
ulong STDCALL net_field_length(uchar **packet);
my_ulonglong net_field_length_ll(uchar **packet);
my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len);
uchar *net_store_length(uchar *pkg, ulonglong length);
uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length);
#endif
#ifdef __cplusplus
......
......@@ -24,8 +24,6 @@ void my_make_scrambled_password_323(char *to, const char *password,
size_t pass_len);
void my_make_scrambled_password(char *to, const char *password,
size_t pass_len);
void my_make_scrambled_password_sha1(char *to, const char *password,
size_t pass_len);
void hash_password(ulong *result, const char *password, uint password_len);
......
......@@ -35,7 +35,6 @@ struct st_mysql_options_extention {
char *default_auth;
char *ssl_crl; /* PEM CRL file */
char *ssl_crlpath; /* PEM directory of CRL-s? */
char *server_public_key_path;
void (*report_progress)(const MYSQL *mysql,
unsigned int stage,
unsigned int max_stage,
......
......@@ -337,7 +337,6 @@ SET(CLIENT_SOURCES
../sql-common/mysql_async.c
../sql-common/my_time.c
../sql-common/client_plugin.c
../sql-common/client_authentication.cc
../sql/net_serv.cc
../sql-common/pack.c
../sql/password.c
......
......@@ -35,6 +35,7 @@ extern char * mysql_unix_port;
CLIENT_MULTI_RESULTS | \
CLIENT_PS_MULTI_RESULTS | \
CLIENT_PLUGIN_AUTH | \
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
CLIENT_CONNECT_ATTRS)
sig_handler my_pipe_sig_handler(int sig);
......
......@@ -26,7 +26,6 @@ ENDIF()
# must be compiled with "-fvisibility=hidden"
IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
SET_SOURCE_FILES_PROPERTIES(
crypt_genhash_impl.cc
my_aes.cc
my_md5.cc
my_sha1.cc
......@@ -35,7 +34,6 @@ IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
ENDIF()
SET(MYSYS_SSL_SOURCES
crypt_genhash_impl.cc
my_aes.cc
my_sha1.cc
my_sha2.cc
......
/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */
/* We always should include my_global first */
#include <my_global.h>
#ifdef HAVE_OPENSSL
#ifdef HAVE_YASSL
#include <sha.hpp>
#include <openssl/ssl.h>
#else
#include <openssl/sha.h>
#include <openssl/rand.h>
#endif
#include "crypt_genhash_impl.h"
#include <string.h>
#ifndef HAVE_YASSL
#define DIGEST_CTX SHA256_CTX
#define DIGESTInit SHA256_Init
#define DIGESTUpdate SHA256_Update
#define DIGESTFinal SHA256_Final
#define DIGEST_LEN SHA256_DIGEST_LENGTH
#else
#define DIGEST_CTX TaoCrypt::SHA256
#define DIGEST_LEN 32
void DIGESTInit(DIGEST_CTX *ctx)
{
ctx->Init();
}
void DIGESTUpdate(DIGEST_CTX *ctx, const void *plaintext, int len)
{
ctx->Update((const TaoCrypt::byte *)plaintext, len);
}
void DIGESTFinal(void *txt, DIGEST_CTX *ctx)
{
ctx->Final((TaoCrypt::byte *)txt);
}
#endif // HAVE_YASSL
static const char crypt_alg_magic[] = "$5";
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
/**
Size-bounded string copying and concatenation
This is a replacement for STRLCPY(3)
*/
size_t
strlcat(char *dst, const char *src, size_t siz)
{
char *d= dst;
const char *s= src;
size_t n= siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen= d - dst;
n= siz - dlen;
if (n == 0)
return(dlen + siz);
while (*s != '\0')
{
if (n != 1)
{
*d++= *s;
n--;
}
s++;
}
*d= '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1;
static unsigned char b64t[] = /* 0 ... 63 => ascii - 64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
#define b64_from_24bit(B2, B1, B0, N) \
{ \
uint32 w = ((B2) << 16) | ((B1) << 8) | (B0); \
int n = (N); \
while (--n >= 0 && ctbufflen > 0) { \
*p++ = b64t[w & 0x3f]; \
w >>= 6; \
ctbufflen--; \
} \
}
#define ROUNDS "rounds="
#define ROUNDSLEN (sizeof (ROUNDS) - 1)
/**
Get the integer value after rounds= where ever it occurs in the string.
if the last char after the int is a , or $ that is fine anything else is an
error.
*/
static uint32 getrounds(const char *s)
{
const char *r;
const char *p;
char *e;
long val;
if (s == NULL)
return (0);
if ((r = strstr(s, ROUNDS)) == NULL)
{
return (0);
}
if (strncmp(r, ROUNDS, ROUNDSLEN) != 0)
{
return (0);
}
p= r + ROUNDSLEN;
errno= 0;
val= strtol(p, &e, 10);
/*
An error occurred or there is non-numeric stuff at the end
which isn't one of the crypt(3c) special chars ',' or '$'
*/
if (errno != 0 || val < 0 || !(*e == '\0' || *e == ',' || *e == '$'))
{
return (0);
}
return ((uint32) val);
}
/**
Finds the interval which envelopes the user salt in a crypt password
The crypt format is assumed to be $a$bbbb$cccccc\0 and the salt is found
by counting the delimiters and marking begin and end.
@param salt_being[in] Pointer to start of crypt passwd
@param salt_being[out] Pointer to first byte of the salt
@param salt_end[in] Pointer to the last byte in passwd
@param salt_end[out] Pointer to the byte immediatly following the salt ($)
@return The size of the salt identified
*/
int extract_user_salt(char **salt_begin,
char **salt_end)
{
char *it= *salt_begin;
int delimiter_count= 0;
while(it != *salt_end)
{
if (*it == '$')
{
++delimiter_count;
if (delimiter_count == 2)
{
*salt_begin= it + 1;
}
if (delimiter_count == 3)
break;
}
++it;
}
*salt_end= it;
return *salt_end - *salt_begin;
}
const char *sha256_find_digest(char *pass)
{
int sz= strlen(pass);
return pass + sz - SHA256_HASH_LENGTH;
}
/*
* Portions of the below code come from crypt_bsdmd5.so (bsdmd5.c) :
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
*
*/
/*
* The below code implements the specification from:
*
* From http://people.redhat.com/drepper/SHA-crypt.txt
*
* Portions of the code taken from inspired by or verified against the
* source in the above document which is licensed as:
*
* "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>."
*/
/*
Due to a Solaris namespace bug DS is a reserved word. To work around this
DS is undefined.
*/
#undef DS
/* ARGSUSED4 */
extern "C"
char *
my_crypt_genhash(char *ctbuffer,
size_t ctbufflen,
const char *plaintext,
int plaintext_len,
const char *switchsalt,
const char **params)
{
int salt_len, i;
char *salt;
unsigned char A[DIGEST_LEN];
unsigned char B[DIGEST_LEN];
unsigned char DP[DIGEST_LEN];
unsigned char DS[DIGEST_LEN];
DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS;
int rounds = ROUNDS_DEFAULT;
int srounds = 0;
bool custom_rounds= false;
char *p;
char *P, *Pp;
char *S, *Sp;
/* Refine the salt */
salt = (char *)switchsalt;
/* skip our magic string */
if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0)
{
salt += crypt_alg_magic_len + 1;
}
srounds = getrounds(salt);
if (srounds != 0) {
rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
custom_rounds= true;
p = strchr(salt, '$');
if (p != NULL)
salt = p + 1;
}
salt_len = MIN(strcspn(salt, "$"), CRYPT_SALT_LENGTH);
//plaintext_len = strlen(plaintext);
/* 1. */
DIGESTInit(&ctxA);
/* 2. The password first, since that is what is most unknown */
DIGESTUpdate(&ctxA, plaintext, plaintext_len);
/* 3. Then the raw salt */
DIGESTUpdate(&ctxA, salt, salt_len);
/* 4. - 8. */
DIGESTInit(&ctxB);
DIGESTUpdate(&ctxB, plaintext, plaintext_len);
DIGESTUpdate(&ctxB, salt, salt_len);
DIGESTUpdate(&ctxB, plaintext, plaintext_len);
DIGESTFinal(B, &ctxB);
/* 9. - 10. */
for (i= plaintext_len; i > MIXCHARS; i -= MIXCHARS)
DIGESTUpdate(&ctxA, B, MIXCHARS);
DIGESTUpdate(&ctxA, B, i);
/* 11. */
for (i= plaintext_len; i > 0; i >>= 1) {
if ((i & 1) != 0)
{
DIGESTUpdate(&ctxA, B, MIXCHARS);
}
else
{
DIGESTUpdate(&ctxA, plaintext, plaintext_len);
}
}
/* 12. */
DIGESTFinal(A, &ctxA);
/* 13. - 15. */
DIGESTInit(&ctxDP);
for (i= 0; i < plaintext_len; i++)
DIGESTUpdate(&ctxDP, plaintext, plaintext_len);
DIGESTFinal(DP, &ctxDP);
/* 16. */
Pp= P= (char *)alloca(plaintext_len);
for (i= plaintext_len; i >= MIXCHARS; i -= MIXCHARS)
{
Pp= (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS;
}
(void) memcpy(Pp, DP, i);
/* 17. - 19. */
DIGESTInit(&ctxDS);
for (i= 0; i < 16 + (uint8)A[0]; i++)
DIGESTUpdate(&ctxDS, salt, salt_len);
DIGESTFinal(DS, &ctxDS);
/* 20. */
Sp= S= (char *)alloca(salt_len);
for (i= salt_len; i >= MIXCHARS; i -= MIXCHARS)
{
Sp= (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS;
}
(void) memcpy(Sp, DS, i);
/* 21. */
for (i= 0; i < rounds; i++)
{
DIGESTInit(&ctxC);
if ((i & 1) != 0)
{
DIGESTUpdate(&ctxC, P, plaintext_len);
}
else
{
if (i == 0)
DIGESTUpdate(&ctxC, A, MIXCHARS);
else
DIGESTUpdate(&ctxC, DP, MIXCHARS);
}
if (i % 3 != 0) {
DIGESTUpdate(&ctxC, S, salt_len);
}
if (i % 7 != 0) {
DIGESTUpdate(&ctxC, P, plaintext_len);
}
if ((i & 1) != 0)
{
if (i == 0)
DIGESTUpdate(&ctxC, A, MIXCHARS);
else
DIGESTUpdate(&ctxC, DP, MIXCHARS);
}
else
{
DIGESTUpdate(&ctxC, P, plaintext_len);
}
DIGESTFinal(DP, &ctxC);
}
/* 22. Now make the output string */
if (custom_rounds)
{
(void) snprintf(ctbuffer, ctbufflen,
"%s$rounds=%zu$", crypt_alg_magic, (size_t)rounds);
}
else
{
(void) snprintf(ctbuffer, ctbufflen,
"%s$", crypt_alg_magic);
}
(void) strncat(ctbuffer, (const char *)salt, salt_len);
(void) strlcat(ctbuffer, "$", ctbufflen);
p= ctbuffer + strlen(ctbuffer);
ctbufflen -= strlen(ctbuffer);
b64_from_24bit(DP[ 0], DP[10], DP[20], 4);
b64_from_24bit(DP[21], DP[ 1], DP[11], 4);
b64_from_24bit(DP[12], DP[22], DP[ 2], 4);
b64_from_24bit(DP[ 3], DP[13], DP[23], 4);
b64_from_24bit(DP[24], DP[ 4], DP[14], 4);
b64_from_24bit(DP[15], DP[25], DP[ 5], 4);
b64_from_24bit(DP[ 6], DP[16], DP[26], 4);
b64_from_24bit(DP[27], DP[ 7], DP[17], 4);
b64_from_24bit(DP[18], DP[28], DP[ 8], 4);
b64_from_24bit(DP[ 9], DP[19], DP[29], 4);
b64_from_24bit(0, DP[31], DP[30], 3);
*p= '\0';
(void) memset(A, 0, sizeof (A));
(void) memset(B, 0, sizeof (B));
(void) memset(DP, 0, sizeof (DP));
(void) memset(DS, 0, sizeof (DS));
return (ctbuffer);
}
/**
Generate a random string using ASCII characters but avoid seperator character.
Stdlib rand and srand are used to produce pseudo random numbers between
with about 7 bit worth of entropty between 1-127.
*/
extern "C"
void generate_user_salt(char *buffer, int buffer_len)
{
char *end= buffer + buffer_len - 1;
#ifdef HAVE_YASSL
yaSSL::RAND_bytes((unsigned char *) buffer, buffer_len);
#else
RAND_bytes((unsigned char *) buffer, buffer_len);
#endif
/* Sequence must be a legal UTF8 string */
for (; buffer < end; buffer++)
{
*buffer &= 0x7f;
if (*buffer == '\0' || *buffer == '$')
*buffer= *buffer + 1;
}
/* Make sure the buffer is terminated properly */
*end= '\0';
}
void xor_string(char *to, int to_len, char *pattern, int pattern_len)
{
int loop= 0;
while(loop <= to_len)
{
*(to + loop) ^= *(pattern + loop % pattern_len);
++loop;
}
}
#endif // HAVE_OPENSSL
......@@ -2477,6 +2477,29 @@ typedef struct {
int last_read_packet_len; /**< the length of the last *read* packet */
} MCPVIO_EXT;
/*
Write 1-8 bytes of string length header infromation to dest depending on
value of src_len, then copy src_len bytes from src to dest.
@param dest Destination buffer of size src_len+8
@param dest_end One byte past the end of the dest buffer
@param src Source buff of size src_len
@param src_end One byte past the end of the src buffer
@return pointer dest+src_len+header size or NULL if
*/
static uchar *write_length_encoded_string4(uchar *dst, size_t dst_len,
const uchar *src, size_t src_len)
{
uchar *to= safe_net_store_length(dst, dst_len, src_len);
if (to == NULL)
return NULL;
memcpy(to, src, src_len);
return to + src_len;
}
/**
sends a COM_CHANGE_USER command with a caller provided payload
......@@ -2578,7 +2601,7 @@ error:
1 charset number
23 reserved (always 0)
n user name, \0-terminated
n plugin auth data (e.g. scramble), length (1 byte) coded
n plugin auth data (e.g. scramble), length encoded
n database name, \0-terminated
(if CLIENT_CONNECT_WITH_DB is set in the capabilities)
n client auth plugin name - \0-terminated string,
......@@ -2736,10 +2759,20 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
{
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
end= (char*)write_length_encoded_string4((uchar*)end,
buff_size, data, data_len);
else
{
if (data_len > 255)
goto error;
*end++= data_len;
memcpy(end, data, data_len);
end+= data_len;
}
if (end == NULL)
goto error;
}
else
{
DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
......
/* Copyright (c) 2012, Oracle and/or its affiliates.
Copyright (c) 2013, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */
#include <my_global.h>
#if defined(HAVE_OPENSSL)
#include "crypt_genhash_impl.h"
#include "mysql/client_authentication.h"
#include "m_ctype.h"
#include "sql_common.h"
#include "errmsg.h"
#include "m_string.h"
#include <string.h>
#if !defined(HAVE_YASSL)
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C)
#include <openssl/applink.c>
#endif
#endif
#include "mysql/service_my_plugin_log.h"
#define MAX_CIPHER_LENGTH 1024
#if !defined(HAVE_YASSL)
mysql_mutex_t g_public_key_mutex;
#endif
int sha256_password_init(char *a, size_t b, int c, va_list d)
{
#if !defined(HAVE_YASSL)
mysql_mutex_init(0,&g_public_key_mutex, MY_MUTEX_INIT_SLOW);
#endif
return 0;
}
int sha256_password_deinit(void)
{
#if !defined(HAVE_YASSL)
mysql_mutex_destroy(&g_public_key_mutex);
#endif
return 0;
}
#if !defined(HAVE_YASSL)
/**
Reads and parse RSA public key data from a file.
@param mysql connection handle with file path data
@return Pointer to the RSA public key storage buffer
*/
RSA *rsa_init(MYSQL *mysql)
{
static RSA *g_public_key= NULL;
RSA *key= NULL;
mysql_mutex_lock(&g_public_key_mutex);
key= g_public_key;
mysql_mutex_unlock(&g_public_key_mutex);
if (key != NULL)
return key;
FILE *pub_key_file= NULL;
if (mysql->options.extension != NULL &&
mysql->options.extension->server_public_key_path != NULL &&
mysql->options.extension->server_public_key_path != '\0')
{
pub_key_file= fopen(mysql->options.extension->server_public_key_path,
"r");
}
/* No public key is used; return 0 without errors to indicate this. */
else
return 0;
if (pub_key_file == NULL)
{
/*
If a key path was submitted but no key located then we print an error
message. Else we just report that there is no public key.
*/
fprintf(stderr,"Can't locate server public key '%s'\n",
mysql->options.extension->server_public_key_path);
return 0;
}
mysql_mutex_lock(&g_public_key_mutex);
key= g_public_key= PEM_read_RSA_PUBKEY(pub_key_file, 0, 0, 0);
mysql_mutex_unlock(&g_public_key_mutex);
fclose(pub_key_file);
if (g_public_key == NULL)
{
fprintf(stderr, "Public key is not in PEM format: '%s'\n",
mysql->options.extension->server_public_key_path);
return 0;
}
return key;
}
#endif // !defined(HAVE_YASSL)
/**
Authenticate the client using the RSA or TLS and a SHA256 salted password.
@param vio Provides plugin access to communication channel
@param mysql Client connection handler
@return Error status
@retval CR_ERROR An error occurred.
@retval CR_OK Authentication succeeded.
*/
extern "C"
int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
{
bool uses_password= mysql->passwd[0] != 0;
#if !defined(HAVE_YASSL)
unsigned char encrypted_password[MAX_CIPHER_LENGTH];
static char request_public_key= '\1';
RSA *public_key= NULL;
bool got_public_key_from_server= false;
#endif
bool connection_is_secure= false;
unsigned char scramble_pkt[20];
unsigned char *pkt;
DBUG_ENTER("sha256_password_auth_client");
/*
Get the scramble from the server because we need it when sending encrypted
password.
*/
if (vio->read_packet(vio, &pkt) != SCRAMBLE_LENGTH)
{
DBUG_PRINT("info",("Scramble is not of correct length."));
DBUG_RETURN(CR_ERROR);
}
/*
Copy the scramble to the stack or it will be lost on the next use of the
net buffer.
*/
memcpy(scramble_pkt, pkt, SCRAMBLE_LENGTH);
if (mysql_get_ssl_cipher(mysql) != NULL)
connection_is_secure= true;
/* If connection isn't secure attempt to get the RSA public key file */
if (!connection_is_secure)
{
#if !defined(HAVE_YASSL)
public_key= rsa_init(mysql);
#endif
}
if (!uses_password)
{
/* We're not using a password */
static const unsigned char zero_byte= '\0';
if (vio->write_packet(vio, (const unsigned char *) &zero_byte, 1))
DBUG_RETURN(CR_ERROR);
}
else
{
/* Password is a 0-terminated byte array ('\0' character included) */
unsigned int passwd_len= strlen(mysql->passwd) + 1;
if (!connection_is_secure)
{
#if !defined(HAVE_YASSL)
/*
If no public key; request one from the server.
*/
if (public_key == NULL)
{
if (vio->write_packet(vio, (const unsigned char *) &request_public_key,
1))
DBUG_RETURN(CR_ERROR);
int pkt_len= 0;
unsigned char *pkt;
if ((pkt_len= vio->read_packet(vio, &pkt)) == -1)
DBUG_RETURN(CR_ERROR);
BIO* bio= BIO_new_mem_buf(pkt, pkt_len);
public_key= PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
BIO_free(bio);
if (public_key == 0)
DBUG_RETURN(CR_ERROR);
got_public_key_from_server= true;
}
/* Obfuscate the plain text password with the session scramble */
xor_string(mysql->passwd, strlen(mysql->passwd), (char *) scramble_pkt,
SCRAMBLE_LENGTH);
/* Encrypt the password and send it to the server */
int cipher_length= RSA_size(public_key);
/*
When using RSA_PKCS1_OAEP_PADDING the password length must be less
than RSA_size(rsa) - 41.
*/
if (passwd_len + 41 >= (unsigned) cipher_length)
{
/* password message is to long */
DBUG_RETURN(CR_ERROR);
}
RSA_public_encrypt(passwd_len, (unsigned char *) mysql->passwd,
encrypted_password,
public_key, RSA_PKCS1_OAEP_PADDING);
if (got_public_key_from_server)
RSA_free(public_key);
if (vio->write_packet(vio, (uchar*) encrypted_password, cipher_length))
DBUG_RETURN(CR_ERROR);
#else
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_ERR, unknown_sqlstate,
ER(CR_AUTH_PLUGIN_ERR), "sha256_password",
"Authentication requires SSL encryption");
DBUG_RETURN(CR_ERROR); // If no openssl support
#endif
}
else
{
/* The vio is encrypted already; just send the plain text passwd */
if (vio->write_packet(vio, (uchar*) mysql->passwd, passwd_len))
DBUG_RETURN(CR_ERROR);
}
memset(mysql->passwd, 0, passwd_len);
}
DBUG_RETURN(CR_OK);
}
#endif
......@@ -48,7 +48,7 @@ ulong STDCALL net_field_length(uchar **packet)
/* The same as above but returns longlong */
my_ulonglong net_field_length_ll(uchar **packet)
{
reg1 uchar *pos= *packet;
uchar *pos= *packet;
if (*pos < 251)
{
(*packet)++;
......@@ -69,12 +69,47 @@ my_ulonglong net_field_length_ll(uchar **packet)
(*packet)+=4;
return (my_ulonglong) uint3korr(pos+1);
}
DBUG_ASSERT(*pos == 254);
(*packet)+=9; /* Must be 254 when here */
#ifdef NO_CLIENT_LONGLONG
return (my_ulonglong) uint4korr(pos+1);
#else
return (my_ulonglong) uint8korr(pos+1);
#endif
}
my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len)
{
uchar *pos= *packet;
if (packet_len < 1)
goto err;
if (*pos < 251)
{
(*packet)++;
return (my_ulonglong) *pos;
}
if (*pos == 251)
{
(*packet)++;
return (my_ulonglong) NULL_LENGTH;
}
if (*pos == 252)
{
if (packet_len < 3)
goto err;
(*packet)+=3;
return (my_ulonglong) uint2korr(pos+1);
}
if (*pos == 253)
{
if (packet_len < 4)
goto err;
(*packet)+=4;
return (my_ulonglong) uint3korr(pos+1);
}
if (packet_len < 9 || *pos != 254)
goto err;
(*packet)+=9;
return (my_ulonglong) uint8korr(pos+1);
err:
*packet = NULL;
return 0;
}
/*
......@@ -82,38 +117,69 @@ my_ulonglong net_field_length_ll(uchar **packet)
SYNOPSIS
net_store_length()
pkg Store the packed integer here
packet Store the packed integer here
length integers to store
NOTES
This is mostly used to store lengths of strings.
We have to cast the result for the LL() becasue of a bug in Forte CC
compiler.
RETURN
Position in 'pkg' after the packed length
Position in 'packet' after the packed length
*/
uchar *net_store_length(uchar *packet, ulonglong length)
{
if (length < (ulonglong) 251LL)
if (length < 251)
{
*packet= (uchar) length;
return packet+1;
}
/* 251 is reserved for NULL */
if (length < 65536)
{
*packet++=252;
int2store(packet, (uint) length);
return packet+2;
}
if (length < 16777216)
{
*packet++=253;
int3store(packet, (ulong) length);
return packet+3;
}
*packet++=254;
int8store(packet,length);
return packet+8;
}
uchar *safe_net_store_length(uchar *packet, size_t packet_len, ulonglong length)
{
if (length < 251)
{
*packet=(uchar) length;
if (packet_len < 1)
return NULL;
*packet= (uchar) length;
return packet+1;
}
/* 251 is reserved for NULL */
if (length < (ulonglong) 65536LL)
if (length < 65536)
{
if (packet_len < 3)
return NULL;
*packet++=252;
int2store(packet,(uint) length);
int2store(packet, (uint) length);
return packet+2;
}
if (length < (ulonglong) 16777216LL)
if (length < 16777216)
{
if (packet_len < 4)
return NULL;
*packet++=253;
int3store(packet,(ulong) length);
int3store(packet, (ulong) length);
return packet+3;
}
if (packet_len < 9)
return NULL;
*packet++=254;
int8store(packet,length);
return packet+8;
......
......@@ -34,6 +34,7 @@
CLIENT_PROTOCOL_41 | \
CLIENT_SECURE_CONNECTION | \
CLIENT_PLUGIN_AUTH | \
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
CLIENT_CONNECT_ATTRS)
#define read_user_name(A) {}
......
......@@ -2171,129 +2171,28 @@ void Item_func_trim::print(String *str, enum_query_type query_type)
/* Item_func_password */
/**
Helper function for calculating a new password. Used in
Item_func_password::fix_length_and_dec() for const parameters and in
Item_func_password::val_str_ascii() for non-const parameters.
@param str The plain text password which should be digested
@param buffer a pointer to the buffer where the digest will be stored.
@note The buffer must be of at least CRYPT_MAX_PASSWORD_SIZE size.
@return Size of the password.
*/
static int calculate_password(String *str, char *buffer)
{
DBUG_ASSERT(str);
if (str->length() == 0) // PASSWORD('') returns ''
return 0;
int buffer_len= 0;
THD *thd= current_thd;
int old_passwords= 0;
if (thd)
old_passwords= thd->variables.old_passwords;
#if defined(HAVE_OPENSSL)
if (old_passwords == 2)
{
my_make_scrambled_password(buffer, str->ptr(),
str->length());
buffer_len= (int) strlen(buffer) + 1;
}
else
#endif
if (old_passwords == 0)
{
my_make_scrambled_password_sha1(buffer, str->ptr(),
str->length());
buffer_len= SCRAMBLED_PASSWORD_CHAR_LENGTH;
}
else
if (old_passwords == 1)
{
my_make_scrambled_password_323(buffer, str->ptr(),
str->length());
buffer_len= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
return buffer_len;
}
/* Item_func_password */
void Item_func_password::fix_length_and_dec()
{
maybe_null= false; // PASSWORD() never returns NULL
if (args[0]->const_item())
{
String str;
String *res= args[0]->val_str(&str);
if (!args[0]->null_value)
{
m_hashed_password_buffer_len=
calculate_password(res, m_hashed_password_buffer);
fix_length_and_charset(m_hashed_password_buffer_len, default_charset());
m_recalculate_password= false;
return;
}
}
m_recalculate_password= true;
fix_length_and_charset(CRYPT_MAX_PASSWORD_SIZE, default_charset());
}
String *Item_func_password::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(str);
if (args[0]->null_value)
res= make_empty_result();
/* we treat NULLs as equal to empty string when calling the plugin */
check_password_policy(res);
null_value= 0;
if (args[0]->null_value) // PASSWORD(NULL) returns ''
return res;
if (m_recalculate_password)
m_hashed_password_buffer_len= calculate_password(res,
m_hashed_password_buffer);
if (m_hashed_password_buffer_len == 0)
if (args[0]->null_value || res->length() == 0)
return make_empty_result();
str->set(m_hashed_password_buffer, m_hashed_password_buffer_len,
default_charset());
my_make_scrambled_password(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
return str;
}
char *Item_func_password::
create_password_hash_buffer(THD *thd, const char *password, size_t pass_len)
char *Item_func_password::alloc(THD *thd, const char *password, size_t pass_len)
{
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff)
{
String *password_str= new (thd->mem_root)String(password, thd->variables.
character_set_client);
check_password_policy(password_str);
char *buff= NULL;
if (thd->variables.old_passwords == 0)
{
/* Allocate memory for the password scramble and one extra byte for \0 */
buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH + 1);
my_make_scrambled_password_sha1(buff, password, pass_len);
}
#if defined(HAVE_OPENSSL)
else
{
/* Allocate memory for the password scramble and one extra byte for \0 */
buff= (char *) thd->alloc(CRYPT_MAX_PASSWORD_SIZE + 1);
my_make_scrambled_password(buff, password, pass_len);
}
#endif
return buff;
}
......
......@@ -21,8 +21,6 @@
/* This file defines all string functions */
#include "crypt_genhash_impl.h"
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
......@@ -394,21 +392,16 @@ public:
class Item_func_password :public Item_str_ascii_func
{
char m_hashed_password_buffer[CRYPT_MAX_PASSWORD_SIZE + 1];
unsigned int m_hashed_password_buffer_len;
bool m_recalculate_password;
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
public:
Item_func_password(Item *a) :Item_str_ascii_func(a)
Item_func_password(Item *a) :Item_str_ascii_func(a) {}
String *val_str_ascii(String *str);
void fix_length_and_dec()
{
m_hashed_password_buffer_len= 0;
m_recalculate_password= false;
fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH, default_charset());
}
String *val_str_ascii(String *str);
void fix_length_and_dec();
const char *func_name() const { return "password"; }
static char *alloc(THD *thd, const char *password, size_t pass_len);
static char *create_password_hash_buffer(THD *thd, const char *password,
size_t pass_len);
};
......
......@@ -67,7 +67,6 @@
#include <mysql.h>
#include <my_rnd.h>
#include <sha1.h>
#include <crypt_genhash_impl.h>
/************ MySQL 3.23-4.0 authentication routines: untouched ***********/
......@@ -280,14 +279,13 @@ void make_password_from_salt_323(char *to, const ulong *salt)
**************** MySQL 4.1.1 authentication routines *************
*/
/*
Generate string of printable random characters of requested length
SYNOPSIS
create_random_string()
to OUT buffer for generation; must be at least length+1 bytes
/**
Generate string of printable random characters of requested length.
@param to[out] Buffer for generation; must be at least length+1 bytes
long; result string is always null-terminated
length IN how many random characters to put in buffer
rand_st INOUT structure used for number generation
length[in] How many random characters to put in buffer
rand_st Structure used for number generation
*/
void create_random_string(char *to, uint length,
......@@ -374,23 +372,6 @@ my_crypt(char *to, const uchar *s1, const uchar *s2, uint len)
}
#if defined(HAVE_OPENSSL)
void my_make_scrambled_password(char *to, const char *password,
size_t pass_len)
{
char salt[CRYPT_SALT_LENGTH + 1];
generate_user_salt(salt, CRYPT_SALT_LENGTH + 1);
my_crypt_genhash(to,
CRYPT_MAX_PASSWORD_SIZE,
password,
pass_len,
salt,
0);
}
#endif
/**
Compute two stage SHA1 hash of the password :
......@@ -422,13 +403,13 @@ void compute_two_stage_sha1_hash(const char *password, size_t pass_len,
The result of this function is used as return value from PASSWORD() and
is stored in the database.
SYNOPSIS
my_make_scrambled_password_sha1()
my_make_scrambled_password()
buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
password IN password string
pass_len IN length of password string
*/
void my_make_scrambled_password_sha1(char *to, const char *password,
void my_make_scrambled_password(char *to, const char *password,
size_t pass_len)
{
uint8 hash_stage2[SHA1_HASH_SIZE];
......@@ -455,7 +436,7 @@ void my_make_scrambled_password_sha1(char *to, const char *password,
void make_scrambled_password(char *to, const char *password)
{
my_make_scrambled_password_sha1(to, password, strlen(password));
my_make_scrambled_password(to, password, strlen(password));
}
......@@ -500,7 +481,7 @@ scramble(char *to, const char *message, const char *password)
null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE
long (if not, something fishy is going on).
SYNOPSIS
check_scramble_sha1()
check_scramble()
scramble clients' reply, presumably produced by scramble()
message original random string, previously sent to client
(presumably second argument of scramble()), must be
......@@ -514,7 +495,7 @@ scramble(char *to, const char *message, const char *password)
*/
my_bool
check_scramble_sha1(const uchar *scramble_arg, const char *message,
check_scramble(const uchar *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
uint8 buf[SHA1_HASH_SIZE];
......@@ -532,13 +513,6 @@ check_scramble_sha1(const uchar *scramble_arg, const char *message,
return test(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE));
}
my_bool
check_scramble(const uchar *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
return check_scramble_sha1(scramble_arg, message, hash_stage2);
}
/*
Convert scrambled password from asciiz hex string to binary form.
......@@ -567,3 +541,4 @@ void make_password_from_salt(char *to, const uint8 *hash_stage2)
*to++= PVERSION41_CHAR;
octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
}
......@@ -11419,13 +11419,20 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
*passwd > 127 and become 2**32-127+ after casting to uint.
*/
uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
(uchar)(*passwd++) : strlen(passwd);
uint passwd_len;
if (!(thd->client_capabilities & CLIENT_SECURE_CONNECTION))
passwd_len= strlen(passwd);
else if (!(thd->client_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA))
passwd_len= (uchar)(*passwd++);
else
passwd_len= safe_net_field_length_ll((uchar**)&passwd,
net->read_pos + pkt_len - (uchar*)passwd);
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
db + passwd_len + 1 : 0;
if (passwd + passwd_len + test(db) > (char *)net->read_pos + pkt_len)
if (passwd == NULL ||
passwd + passwd_len + test(db) > (char *)net->read_pos + pkt_len)
return packet_error;
/* strlen() can't be easily deleted without changing protocol */
......
......@@ -9753,7 +9753,7 @@ function_call_conflict:
| PASSWORD '(' expr ')'
{
Item* i1;
if (thd->variables.old_passwords == 1)
if (thd->variables.old_passwords)
i1= new (thd->mem_root) Item_func_old_password($3);
else
i1= new (thd->mem_root) Item_func_password($3);
......@@ -14789,18 +14789,10 @@ text_or_password:
TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')'
{
if ($3.length == 0)
$$= $3.str;
else
switch (thd->variables.old_passwords) {
case 1: $$= Item_func_old_password::
alloc(thd, $3.str, $3.length);
break;
case 0:
case 2: $$= Item_func_password::
create_password_hash_buffer(thd, $3.str, $3.length);
break;
}
$$= $3.length ? thd->variables.old_passwords ?
Item_func_old_password::alloc(thd, $3.str, $3.length) :
Item_func_password::alloc(thd, $3.str, $3.length) :
$3.str;
if ($$ == NULL)
MYSQL_YYABORT;
}
......@@ -15400,7 +15392,7 @@ grant_user:
(char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff == NULL)
MYSQL_YYABORT;
my_make_scrambled_password_sha1(buff, $4.str, $4.length);
my_make_scrambled_password(buff, $4.str, $4.length);
$1->password.str= buff;
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment