1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
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, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    Without limiting anything contained in the foregoing, this file,
15    which is part of C Driver for MySQL (Connector/C), is also subject to the
16    Universal FOSS Exception, version 1.0, a copy of which can be found at
17    http://oss.oracle.com/licenses/universal-foss-exception.
18 
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License, version 2.0, for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
27 
28 // First include (the generated) my_config.h, to get correct platform defines.
29 #include "my_config.h"
30 
31 #if defined(HAVE_OPENSSL)
32 #include "crypt_genhash_impl.h"
33 #include "mysql/client_authentication.h"
34 #include "m_ctype.h"
35 #include "sql_common.h"
36 #include "errmsg.h"
37 #include "sql_string.h"
38 
39 #include <string.h>
40 #include <stdarg.h>
41 #include <openssl/rsa.h>
42 #include <openssl/pem.h>
43 #include <openssl/err.h>
44 #include <openssl/sha.h>
45 #if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C)
46 #include <openssl/applink.c>
47 #endif
48 #include "mysql/plugin.h"
49 
50 #define MAX_CIPHER_LENGTH 1024
51 
52 #define SHA2_SCRAMBLE_LENGTH SHA256_DIGEST_LENGTH
53 
54 mysql_mutex_t g_public_key_mutex;
55 
sha256_password_init(char * a,size_t b,int c,va_list d)56 int sha256_password_init(char *a, size_t b, int c, va_list d)
57 {
58   mysql_mutex_init(0,&g_public_key_mutex, MY_MUTEX_INIT_SLOW);
59   return 0;
60 }
61 
sha256_password_deinit(void)62 int sha256_password_deinit(void)
63 {
64   mysql_mutex_destroy(&g_public_key_mutex);
65   return 0;
66 }
67 
68 
69 /**
70   Reads and parse RSA public key data from a file.
71 
72   @param mysql connection handle with file path data
73 
74   @return Pointer to the RSA public key storage buffer
75 */
76 
rsa_init(MYSQL * mysql)77 RSA *rsa_init(MYSQL *mysql)
78 {
79   static RSA *g_public_key= NULL;
80   RSA *key= NULL;
81 
82   mysql_mutex_lock(&g_public_key_mutex);
83   key= g_public_key;
84   mysql_mutex_unlock(&g_public_key_mutex);
85 
86   if (key != NULL)
87     return key;
88 
89   FILE *pub_key_file= NULL;
90 
91   if (mysql->options.extension != NULL &&
92       mysql->options.extension->server_public_key_path != NULL &&
93       mysql->options.extension->server_public_key_path[0] != '\0')
94   {
95     pub_key_file= fopen(mysql->options.extension->server_public_key_path,
96                         "r");
97   }
98   /* No public key is used; return 0 without errors to indicate this. */
99   else
100     return 0;
101 
102   if (pub_key_file == NULL)
103   {
104     /*
105       If a key path was submitted but no key located then we print an error
106       message. Else we just report that there is no public key.
107     */
108     my_message_local(WARNING_LEVEL, "Can't locate server public key '%s'",
109                      mysql->options.extension->server_public_key_path);
110 
111     return 0;
112   }
113 
114   mysql_mutex_lock(&g_public_key_mutex);
115   key= g_public_key= PEM_read_RSA_PUBKEY(pub_key_file, 0, 0, 0);
116   mysql_mutex_unlock(&g_public_key_mutex);
117   fclose(pub_key_file);
118   if (g_public_key == NULL)
119   {
120     ERR_clear_error();
121     my_message_local(WARNING_LEVEL, "Public key is not in PEM format: '%s'",
122                      mysql->options.extension->server_public_key_path);
123     return 0;
124   }
125 
126   return key;
127 }
128 
129 /**
130   Authenticate the client using the RSA or TLS and a SHA256 salted password.
131 
132   @param vio Provides plugin access to communication channel
133   @param mysql Client connection handler
134 
135   @return Error status
136     @retval CR_ERROR An error occurred.
137     @retval CR_OK Authentication succeeded.
138 */
139 
140 extern "C"
sha256_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)141 int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
142 {
143   bool uses_password= mysql->passwd[0] != 0;
144   unsigned char encrypted_password[MAX_CIPHER_LENGTH];
145   static char request_public_key= '\1';
146   RSA *public_key= NULL;
147   bool got_public_key_from_server= false;
148   bool connection_is_secure= false;
149   unsigned char scramble_pkt[20];
150   unsigned char *pkt;
151 
152 
153   DBUG_ENTER("sha256_password_auth_client");
154 
155   /*
156     Get the scramble from the server because we need it when sending encrypted
157     password.
158   */
159   if (vio->read_packet(vio, &pkt) != SCRAMBLE_LENGTH + 1)
160   {
161     DBUG_PRINT("info",("Scramble is not of correct length."));
162     DBUG_RETURN(CR_ERROR);
163   }
164   if (pkt[SCRAMBLE_LENGTH] != '\0')
165   {
166     DBUG_PRINT("info",("Missing protocol token in scramble data."));
167     DBUG_RETURN(CR_ERROR);
168   }
169   /*
170     Copy the scramble to the stack or it will be lost on the next use of the
171     net buffer.
172   */
173   memcpy(scramble_pkt, pkt, SCRAMBLE_LENGTH);
174 
175   if (mysql_get_ssl_cipher(mysql) != NULL)
176     connection_is_secure= true;
177 
178   /* If connection isn't secure attempt to get the RSA public key file */
179   if (!connection_is_secure)
180   {
181     public_key= rsa_init(mysql);
182   }
183 
184   if (!uses_password)
185   {
186     /* We're not using a password */
187     static const unsigned char zero_byte= '\0';
188     if (vio->write_packet(vio, &zero_byte, 1))
189       DBUG_RETURN(CR_ERROR);
190   }
191   else
192   {
193     /* Password is a 0-terminated byte array ('\0' character included) */
194     unsigned int passwd_len= static_cast<unsigned int>(strlen(mysql->passwd) + 1);
195     if (!connection_is_secure)
196     {
197       /*
198         If no public key; request one from the server.
199       */
200       if (public_key == NULL)
201       {
202         if (vio->write_packet(vio, (const unsigned char *) &request_public_key,
203                               1))
204           DBUG_RETURN(CR_ERROR);
205 
206         int pkt_len= 0;
207         unsigned char *pkt;
208         if ((pkt_len= vio->read_packet(vio, &pkt)) == -1)
209           DBUG_RETURN(CR_ERROR);
210         BIO* bio= BIO_new_mem_buf(pkt, pkt_len);
211         public_key= PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
212         BIO_free(bio);
213         if (public_key == 0)
214         {
215           ERR_clear_error();
216           DBUG_RETURN(CR_ERROR);
217         }
218         got_public_key_from_server= true;
219       }
220 
221       /*
222         An arbitrary limitation based on the assumption that passwords
223         larger than e.g. 15 symbols don't contribute to security.
224         Note also that it's furter restricted to RSA_size() - 41 down
225         below, so this leaves 471 bytes of possible RSA key sizes which
226         should be reasonably future-proof.
227         We avoid heap allocation for speed reasons.
228       */
229       char passwd_scramble[512];
230 
231       if (passwd_len > sizeof(passwd_scramble))
232       {
233         /* password too long for the buffer */
234         if (got_public_key_from_server)
235           RSA_free(public_key);
236         DBUG_RETURN(CR_ERROR);
237       }
238       memmove(passwd_scramble, mysql->passwd, passwd_len);
239 
240       /* Obfuscate the plain text password with the session scramble */
241       xor_string(passwd_scramble, passwd_len - 1, (char *) scramble_pkt,
242                  SCRAMBLE_LENGTH);
243       /* Encrypt the password and send it to the server */
244       int cipher_length= RSA_size(public_key);
245       /*
246         When using RSA_PKCS1_OAEP_PADDING the password length must be less
247         than RSA_size(rsa) - 41.
248       */
249       if (passwd_len + 41 >= (unsigned) cipher_length)
250       {
251         /* password message is to long */
252         if (got_public_key_from_server)
253           RSA_free(public_key);
254         DBUG_RETURN(CR_ERROR);
255       }
256       RSA_public_encrypt(passwd_len, (unsigned char *) passwd_scramble,
257                          encrypted_password,
258                          public_key, RSA_PKCS1_OAEP_PADDING);
259       if (got_public_key_from_server)
260         RSA_free(public_key);
261 
262       if (vio->write_packet(vio, (uchar*) encrypted_password, cipher_length))
263         DBUG_RETURN(CR_ERROR);
264     }
265     else
266     {
267       /* The vio is encrypted already; just send the plain text passwd */
268       if (vio->write_packet(vio, (uchar*) mysql->passwd, passwd_len))
269         DBUG_RETURN(CR_ERROR);
270     }
271   }
272 
273   DBUG_RETURN(CR_OK);
274 }
275 
276 /* caching_sha2_password */
277 
caching_sha2_password_init(char *,size_t,int,va_list)278 int caching_sha2_password_init(char *, size_t, int, va_list)
279 {
280   return 0;
281 }
282 
caching_sha2_password_deinit(void)283 int caching_sha2_password_deinit(void)
284 {
285   return 0;
286 }
287 
is_secure_transport(MYSQL * mysql)288 static bool is_secure_transport(MYSQL *mysql)
289 {
290   if (!mysql || !mysql->net.vio)
291     return false;
292   switch (mysql->net.vio->type)
293   {
294     case VIO_TYPE_SSL:
295     {
296       if (mysql_get_ssl_cipher(mysql) == NULL)
297         return false;
298     }
299    // Fall through
300    case VIO_TYPE_SHARED_MEMORY:
301    // Fall through
302    case VIO_TYPE_SOCKET:
303      return true;
304    default:
305      return false;
306   }
307   return false;
308 }
309 
310 /**
311   Authenticate the client using the RSA or TLS and a SHA2 salted password.
312 
313   @param vio Provides plugin access to communication channel
314   @param mysql Client connection handler
315 
316   @return Error status
317     @retval CR_ERROR An error occurred.
318     @retval CR_OK Authentication succeeded.
319 */
320 
321 static char request_public_key= '\2';
322 static char fast_auth_success= '\3';
323 static char perform_full_authentication= '\4';
324 
caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)325 int caching_sha2_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
326 {
327   bool uses_password= mysql->passwd[0] != 0;
328   unsigned char encrypted_password[MAX_CIPHER_LENGTH];
329   RSA *public_key= NULL;
330   bool got_public_key_from_server= false;
331   bool connection_is_secure= false;
332   unsigned char scramble_pkt[20];
333   unsigned char *pkt;
334 
335   DBUG_ENTER("caching_sha2_password_auth_client");
336 
337   /*
338     Get the scramble from the server because we need it when sending encrypted
339     password.
340   */
341   if (vio->read_packet(vio, &pkt) != SCRAMBLE_LENGTH + 1)
342   {
343     DBUG_PRINT("info", ("Scramble is not of correct length."));
344     DBUG_RETURN(CR_ERROR);
345   }
346 
347   if (pkt[SCRAMBLE_LENGTH] != '\0')
348   {
349     DBUG_PRINT("info", ("Missing protocol token in scramble data."));
350     DBUG_RETURN(CR_ERROR);
351   }
352 
353   /*
354     Copy the scramble to the stack or it will be lost on the next use of the
355     net buffer.
356   */
357   memcpy(scramble_pkt, pkt, SCRAMBLE_LENGTH);
358 
359   connection_is_secure= is_secure_transport(mysql);
360 
361   if (!uses_password)
362   {
363     /* We're not using a password */
364     static const unsigned char zero_byte= '\0';
365     if (vio->write_packet(vio, &zero_byte, 1))
366       DBUG_RETURN(CR_ERROR);
367     DBUG_RETURN(CR_OK);
368   }
369   else
370   {
371     /* Password is a 0-terminated byte array ('\0' character included) */
372     unsigned int passwd_len=
373       static_cast<unsigned int>(strlen(mysql->passwd) + 1);
374     int pkt_len= 0;
375     {
376       /* First try with SHA2 scramble */
377       unsigned char sha2_scramble[SHA2_SCRAMBLE_LENGTH];
378       if (generate_sha256_scramble(sha2_scramble, SHA2_SCRAMBLE_LENGTH,
379                                    mysql->passwd, passwd_len - 1,
380                                    (char *)scramble_pkt, SCRAMBLE_LENGTH))
381       {
382         set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_ERR, unknown_sqlstate,
383                                  ER(CR_AUTH_PLUGIN_ERR),
384                                  "caching_sha2_password",
385                                  "Failed to generate scramble");
386         DBUG_RETURN(CR_ERROR);
387       }
388 
389       if (vio->write_packet(vio, sha2_scramble, SHA2_SCRAMBLE_LENGTH))
390         DBUG_RETURN(CR_ERROR);
391 
392       if ((pkt_len= vio->read_packet(vio, &pkt)) == -1)
393         DBUG_RETURN(CR_ERROR);
394 
395       if (pkt_len == 1 && *pkt == fast_auth_success)
396         DBUG_RETURN(CR_OK);
397 
398       /* An OK packet would follow */
399     }
400 
401     if (pkt_len != 1 || *pkt != perform_full_authentication)
402     {
403       DBUG_PRINT("info", ("Unexpected reply from server."));
404       DBUG_RETURN(CR_ERROR);
405     }
406 
407     if (!connection_is_secure)
408     {
409       /* If connection isn't secure attempt to get the RSA public key file */
410       public_key= rsa_init(mysql);
411 
412       if (public_key == NULL && mysql->options.extension &&
413           mysql->options.extension->get_server_public_key)
414       {
415         // If no public key; request one from the server.
416         if (vio->write_packet(vio, (const unsigned char *)&request_public_key,
417                               1))
418           DBUG_RETURN(CR_ERROR);
419 
420         if ((pkt_len= vio->read_packet(vio, &pkt)) <= 0)
421           DBUG_RETURN(CR_ERROR);
422         BIO *bio= BIO_new_mem_buf(pkt, pkt_len);
423         public_key= PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
424         BIO_free(bio);
425         if (public_key == 0)
426         {
427           ERR_clear_error();
428           DBUG_PRINT("info", ("Failed to parse public key"));
429           DBUG_RETURN(CR_ERROR);
430         }
431         got_public_key_from_server= true;
432       }
433 
434       if (public_key)
435       {
436         /*
437           An arbitrary limitation based on the assumption that passwords
438           larger than e.g. 15 symbols don't contribute to security.
439           Note also that it's further restricted to RSA_size() - 11 down
440           below, so this leaves 471 bytes of possible RSA key sizes which
441           should be reasonably future-proof.
442           We avoid heap allocation for speed reasons.
443         */
444         char passwd_scramble[512];
445 
446         if (passwd_len > sizeof(passwd_scramble))
447         {
448           /* password too long for the buffer */
449           if (got_public_key_from_server) RSA_free(public_key);
450           DBUG_PRINT("info", ("Password is too long."));
451           DBUG_RETURN(CR_ERROR);
452         }
453         memmove(passwd_scramble, mysql->passwd, passwd_len);
454 
455         /* Obfuscate the plain text password with the session scramble */
456         xor_string(passwd_scramble, passwd_len - 1, (char *)scramble_pkt,
457                    SCRAMBLE_LENGTH);
458         /* Encrypt the password and send it to the server */
459         int cipher_length= RSA_size(public_key);
460         /*
461           When using RSA_PKCS1_OAEP_PADDING the password length must be less
462           than RSA_size(rsa) - 41.
463         */
464         if (passwd_len + 41 >= (unsigned)cipher_length)
465         {
466           /* password message is to long */
467           if (got_public_key_from_server)
468             RSA_free(public_key);
469           DBUG_PRINT("info", ("Password is too long to be encrypted using "
470                               "given public key."));
471           DBUG_RETURN(CR_ERROR);
472         }
473         RSA_public_encrypt(passwd_len, (unsigned char *)passwd_scramble,
474                            encrypted_password, public_key,
475                            RSA_PKCS1_OAEP_PADDING);
476         if (got_public_key_from_server)
477           RSA_free(public_key);
478 
479         if (vio->write_packet(vio, (uchar *)encrypted_password, cipher_length))
480           DBUG_RETURN(CR_ERROR);
481       }
482       else
483       {
484         set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_ERR, unknown_sqlstate,
485                                  ER(CR_AUTH_PLUGIN_ERR),
486                                  "caching_sha2_password",
487                                  "Authentication requires secure connection.");
488         DBUG_RETURN(CR_ERROR);
489       }
490     }
491     else
492     {
493       /* The vio is encrypted already; just send the plain text passwd */
494       if (vio->write_packet(vio, (uchar *)mysql->passwd, passwd_len))
495         DBUG_RETURN(CR_ERROR);
496     }
497   }
498   DBUG_RETURN(CR_OK);
499 }
500 
501 #endif /* HAVE_OPENSSL */
502