MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
client_authentication.cc
1 /* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 // First include (the generated) my_config.h, to get correct platform defines.
17 #include "my_config.h"
18 
19 #if defined(HAVE_OPENSSL)
20 #include "crypt_genhash_impl.h"
21 #include "mysql/client_authentication.h"
22 #include "m_ctype.h"
23 #include "sql_common.h"
24 #include "errmsg.h"
25 #include "sql_string.h"
26 
27 #include <string.h>
28 #include <stdarg.h>
29 #if !defined(HAVE_YASSL)
30 #include <openssl/rsa.h>
31 #include <openssl/pem.h>
32 #include <openssl/err.h>
33 #if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C)
34 #include <openssl/applink.c>
35 #endif
36 #endif
38 
39 #define MAX_CIPHER_LENGTH 1024
40 
41 #if !defined(HAVE_YASSL)
42 mysql_mutex_t g_public_key_mutex;
43 #endif
44 
45 int sha256_password_init(char *a, size_t b, int c, va_list d)
46 {
47 #if !defined(HAVE_YASSL)
48  mysql_mutex_init(0,&g_public_key_mutex, MY_MUTEX_INIT_SLOW);
49 #endif
50  return 0;
51 }
52 
53 int sha256_password_deinit(void)
54 {
55 #if !defined(HAVE_YASSL)
56  mysql_mutex_destroy(&g_public_key_mutex);
57 #endif
58  return 0;
59 }
60 
61 
62 #if !defined(HAVE_YASSL)
63 
71 RSA *rsa_init(MYSQL *mysql)
72 {
73  static RSA *g_public_key= NULL;
74  RSA *key= NULL;
75 
76  mysql_mutex_lock(&g_public_key_mutex);
77  key= g_public_key;
78  mysql_mutex_unlock(&g_public_key_mutex);
79 
80  if (key != NULL)
81  return key;
82 
83  FILE *pub_key_file= NULL;
84 
85  if (mysql->options.extension != NULL &&
86  mysql->options.extension->server_public_key_path != NULL &&
87  mysql->options.extension->server_public_key_path != '\0')
88  {
89  pub_key_file= fopen(mysql->options.extension->server_public_key_path,
90  "r");
91  }
92  /* No public key is used; return 0 without errors to indicate this. */
93  else
94  return 0;
95 
96  if (pub_key_file == NULL)
97  {
98  /*
99  If a key path was submitted but no key located then we print an error
100  message. Else we just report that there is no public key.
101  */
102  fprintf(stderr,"Can't locate server public key '%s'\n",
103  mysql->options.extension->server_public_key_path);
104 
105  return 0;
106  }
107 
108  mysql_mutex_lock(&g_public_key_mutex);
109  key= g_public_key= PEM_read_RSA_PUBKEY(pub_key_file, 0, 0, 0);
110  mysql_mutex_unlock(&g_public_key_mutex);
111  fclose(pub_key_file);
112  if (g_public_key == NULL)
113  {
114  ERR_clear_error();
115  fprintf(stderr, "Public key is not in PEM format: '%s'\n",
116  mysql->options.extension->server_public_key_path);
117  return 0;
118  }
119 
120  return key;
121 }
122 #endif // !defined(HAVE_YASSL)
123 
135 extern "C"
136 int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
137 {
138  bool uses_password= mysql->passwd[0] != 0;
139 #if !defined(HAVE_YASSL)
140  unsigned char encrypted_password[MAX_CIPHER_LENGTH];
141  static char request_public_key= '\1';
142  RSA *public_key= NULL;
143  bool got_public_key_from_server= false;
144 #endif
145  bool connection_is_secure= false;
146  unsigned char scramble_pkt[20];
147  unsigned char *pkt;
148 
149 
150  DBUG_ENTER("sha256_password_auth_client");
151 
152  /*
153  Get the scramble from the server because we need it when sending encrypted
154  password.
155  */
156  if (vio->read_packet(vio, &pkt) != SCRAMBLE_LENGTH)
157  {
158  DBUG_PRINT("info",("Scramble is not of correct length."));
159  DBUG_RETURN(CR_ERROR);
160  }
161  /*
162  Copy the scramble to the stack or it will be lost on the next use of the
163  net buffer.
164  */
165  memcpy(scramble_pkt, pkt, SCRAMBLE_LENGTH);
166 
167  if (mysql_get_ssl_cipher(mysql) != NULL)
168  connection_is_secure= true;
169 
170  /* If connection isn't secure attempt to get the RSA public key file */
171  if (!connection_is_secure)
172  {
173  #if !defined(HAVE_YASSL)
174  public_key= rsa_init(mysql);
175 #endif
176  }
177 
178  if (!uses_password)
179  {
180  /* We're not using a password */
181  static const unsigned char zero_byte= '\0';
182  if (vio->write_packet(vio, (const unsigned char *) &zero_byte, 1))
183  DBUG_RETURN(CR_ERROR);
184  }
185  else
186  {
187  /* Password is a 0-terminated byte array ('\0' character included) */
188  unsigned int passwd_len= strlen(mysql->passwd) + 1;
189  if (!connection_is_secure)
190  {
191 #if !defined(HAVE_YASSL)
192  /*
193  If no public key; request one from the server.
194  */
195  if (public_key == NULL)
196  {
197  if (vio->write_packet(vio, (const unsigned char *) &request_public_key,
198  1))
199  DBUG_RETURN(CR_ERROR);
200 
201  int pkt_len= 0;
202  unsigned char *pkt;
203  if ((pkt_len= vio->read_packet(vio, &pkt)) == -1)
204  DBUG_RETURN(CR_ERROR);
205  BIO* bio= BIO_new_mem_buf(pkt, pkt_len);
206  public_key= PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
207  BIO_free(bio);
208  if (public_key == 0)
209  {
210  ERR_clear_error();
211  DBUG_RETURN(CR_ERROR);
212  }
213  got_public_key_from_server= true;
214  }
215 
216  /* Obfuscate the plain text password with the session scramble */
217  xor_string(mysql->passwd, strlen(mysql->passwd), (char *) scramble_pkt,
218  SCRAMBLE_LENGTH);
219  /* Encrypt the password and send it to the server */
220  int cipher_length= RSA_size(public_key);
221  /*
222  When using RSA_PKCS1_OAEP_PADDING the password length must be less
223  than RSA_size(rsa) - 41.
224  */
225  if (passwd_len + 41 >= (unsigned) cipher_length)
226  {
227  /* password message is to long */
228  DBUG_RETURN(CR_ERROR);
229  }
230  RSA_public_encrypt(passwd_len, (unsigned char *) mysql->passwd,
231  encrypted_password,
232  public_key, RSA_PKCS1_OAEP_PADDING);
233  if (got_public_key_from_server)
234  RSA_free(public_key);
235 
236  if (vio->write_packet(vio, (uchar*) encrypted_password, cipher_length))
237  DBUG_RETURN(CR_ERROR);
238 #else
239  set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_ERR, unknown_sqlstate,
240  ER(CR_AUTH_PLUGIN_ERR), "sha256_password",
241  "Authentication requires SSL encryption");
242  DBUG_RETURN(CR_ERROR); // If no openssl support
243 #endif
244  }
245  else
246  {
247  /* The vio is encrypted already; just send the plain text passwd */
248  if (vio->write_packet(vio, (uchar*) mysql->passwd, passwd_len))
249  DBUG_RETURN(CR_ERROR);
250  }
251 
252  memset(mysql->passwd, 0, passwd_len);
253  }
254 
255  DBUG_RETURN(CR_OK);
256 }
257 
258 #endif