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