1/************************************************************************************
2 Copyright (C) 2012 Monty Program AB
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not see <http://www.gnu.org/licenses>
16 or write to the Free Software Foundation, Inc.,
17 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18
19 *************************************************************************************/
20#include <ma_global.h>
21#include <ma_sys.h>
22#include <ma_common.h>
23#include <ma_pvio.h>
24#include <errmsg.h>
25#include <string.h>
26#include <mysql/client_plugin.h>
27#include <string.h>
28#include <openssl/ssl.h> /* SSL and SSL_CTX */
29#include <openssl/err.h> /* error reporting */
30#include <openssl/conf.h>
31#include <openssl/md4.h>
32
33#if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C)
34#include <openssl/applink.c>
35#endif
36
37#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
38#include <openssl/x509v3.h>
39#define HAVE_OPENSSL_CHECK_HOST 1
40#endif
41
42#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
43#define HAVE_OPENSSL_1_1_API
44#endif
45
46#if OPENSSL_VERSION_NUMBER < 0x10000000L
47#define SSL_OP_NO_TLSv1_1 0L
48#define SSL_OP_NO_TLSv1_2 0L
49#define CRYPTO_THREADID_set_callback CRYPTO_set_id_callback
50#define CRYPTO_THREADID_get_callback CRYPTO_get_id_callback
51#endif
52
53#ifdef HAVE_TLS_SESSION_CACHE
54#undef HAVE_TLS_SESSION_CACHE
55#endif
56#if defined(OPENSSL_USE_BIOMETHOD)
57#undef OPENSSL_USE_BIOMETHOD
58#endif
59#ifndef HAVE_OPENSSL_DEFAULT
60#include <memory.h>
61#define ma_malloc(A,B) malloc((A))
62#undef ma_free
63#define ma_free(A) free((A))
64#define ma_snprintf snprintf
65#define ma_vsnprintf vsnprintf
66#undef SAFE_MUTEX
67#endif
68#include <ma_pthread.h>
69
70#include <mariadb_async.h>
71#include <ma_context.h>
72
73extern my_bool ma_tls_initialized;
74extern unsigned int mariadb_deinitialize_ssl;
75
76#define MAX_SSL_ERR_LEN 100
77char tls_library_version[TLS_VERSION_LENGTH];
78
79static pthread_mutex_t LOCK_openssl_config;
80#ifndef HAVE_OPENSSL_1_1_API
81static pthread_mutex_t *LOCK_crypto= NULL;
82#endif
83#if defined(OPENSSL_USE_BIOMETHOD)
84static int ma_bio_read(BIO *h, char *buf, int size);
85static int ma_bio_write(BIO *h, const char *buf, int size);
86static BIO_METHOD ma_BIO_method;
87#endif
88
89
90static long ma_tls_version_options(const char *version)
91{
92 long protocol_options,
93 disable_all_protocols;
94
95 protocol_options= disable_all_protocols=
96 SSL_OP_NO_SSLv2 |
97 SSL_OP_NO_SSLv3 |
98 SSL_OP_NO_TLSv1 |
99 SSL_OP_NO_TLSv1_1 |
100 SSL_OP_NO_TLSv1_2
101#ifdef TLS1_3_VERSION
102 | SSL_OP_NO_TLSv1_3
103#endif
104 ;
105
106 if (!version)
107 return 0;
108
109 if (strstr(version, "TLSv1.0"))
110 protocol_options&= ~SSL_OP_NO_TLSv1;
111 if (strstr(version, "TLSv1.1"))
112 protocol_options&= ~SSL_OP_NO_TLSv1_1;
113 if (strstr(version, "TLSv1.2"))
114 protocol_options&= ~SSL_OP_NO_TLSv1_2;
115#ifdef TLS1_3_VERSION
116 if (strstr(version, "TLSv1.3"))
117 protocol_options&= ~SSL_OP_NO_TLSv1_3;
118#endif
119
120 if (protocol_options != disable_all_protocols)
121 return protocol_options;
122 return 0;
123}
124
125static void ma_tls_set_error(MYSQL *mysql)
126{
127 ulong ssl_errno= ERR_get_error();
128 char ssl_error[MAX_SSL_ERR_LEN];
129 const char *ssl_error_reason;
130 MARIADB_PVIO *pvio= mysql->net.pvio;
131
132 if (!ssl_errno)
133 {
134 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
135 return;
136 }
137 if ((ssl_error_reason= ERR_reason_error_string(ssl_errno)))
138 {
139 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
140 0, ssl_error_reason);
141 return;
142 }
143 snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%lu", ssl_errno);
144 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0, ssl_error);
145 return;
146}
147
148#ifndef HAVE_OPENSSL_1_1_API
149/*
150 thread safe callbacks for OpenSSL
151 Crypto call back functions will be
152 set during ssl_initialization
153 */
154#if OPENSSL_VERSION_NUMBER < 0x10000000L
155static unsigned long my_cb_threadid(void)
156{
157 /* cast pthread_t to unsigned long */
158 return (unsigned long) pthread_self();
159}
160#else
161static void my_cb_threadid(CRYPTO_THREADID *id)
162{
163 CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
164}
165#endif
166#endif
167
168#ifdef HAVE_TLS_SESSION_CACHE
169typedef struct st_ma_tls_session {
170 char md4_hash[17];
171 SSL_SESSION *session;
172} MA_SSL_SESSION;
173
174MA_SSL_SESSION *ma_tls_sessions= NULL;
175int ma_tls_session_cache_size= 128;
176
177static char *ma_md4_hash(const char *host, const char *user, unsigned int port, char *md4)
178{
179 char buffer[195]; /* MAX_USERNAME_LEN + MAX_HOST_NAME_LEN + 2 + 5 */
180 snprintf(buffer, 194, "%s@%s:%d", user ? user : "", host, port);
181 buffer[194]= 0;
182 MD4((unsigned char *)buffer, strlen(buffer), (unsigned char *)md4);
183 return md4;
184}
185
186MA_SSL_SESSION *ma_tls_get_session(MYSQL *mysql)
187{
188 char md4[17];
189 int i;
190
191 if (!ma_tls_sessions)
192 return NULL;
193
194 memset(md4, 0, 16);
195 ma_md4_hash(mysql->host, mysql->user, mysql->port, md4);
196 for (i=0; i < ma_tls_session_cache_size; i++)
197 {
198 if (ma_tls_sessions[i].session &&
199 !strncmp(ma_tls_sessions[i].md4_hash, md4, 16))
200 {
201 return &ma_tls_sessions[i];
202 }
203 }
204 return NULL;
205}
206
207
208#if OPENSSL_USE_BIOMETHOD
209static int ma_bio_read(BIO *bio, char *buf, int size)
210{
211 MARIADB_PVIO *pvio= (MARIADB_PVIO *)bio->ptr;
212 size_t rc;
213
214 rc= pvio->methods->read(pvio, buf, (size_t)size);
215 BIO_clear_retry_flags(bio);
216 return (int)rc;
217}
218static int ma_bio_write(BIO *bio, const char *buf, int size)
219{
220 MARIADB_PVIO *pvio= (MARIADB_PVIO *)bio->ptr;
221 size_t rc;
222
223 rc= pvio->methods->write(pvio, buf, (size_t)size);
224 BIO_clear_retry_flags(bio);
225 return (int)rc;
226}
227#endif
228
229static int ma_tls_session_cb(SSL *ssl, SSL_SESSION *session)
230{
231 MYSQL *mysql;
232 MA_SSL_SESSION *stored_session;
233 int i;
234
235 mysql= (MYSQL *)SSL_get_app_data(ssl);
236
237 /* check if we already stored session key */
238 if ((stored_session= ma_tls_get_session(mysql)))
239 {
240 SSL_SESSION_free(stored_session->session);
241 stored_session->session= session;
242 return 1;
243 }
244
245 for (i=0; i < ma_tls_session_cache_size; i++)
246 {
247 if (!ma_tls_sessions[i].session)
248 {
249 ma_md4_hash(mysql->host, mysql->user, mysql->port, ma_tls_sessions[i].md4_hash);
250 ma_tls_sessions[i].session= session;
251 }
252 return 1;
253 }
254 return 0;
255}
256
257static void ma_tls_remove_session_cb(SSL_CTX* ctx __attribute__((unused)),
258 SSL_SESSION* session)
259{
260 int i;
261 for (i=0; i < ma_tls_session_cache_size; i++)
262 if (session == ma_tls_sessions[i].session)
263 {
264 ma_tls_sessions[i].md4_hash[0]= 0;
265 SSL_SESSION_free(ma_tls_sessions[i].session);
266 ma_tls_sessions[i].session= NULL;
267 }
268}
269#endif
270
271#ifndef HAVE_OPENSSL_1_1_API
272static void my_cb_locking(int mode, int n,
273 const char *file __attribute__((unused)),
274 int line __attribute__((unused)))
275{
276 if (mode & CRYPTO_LOCK)
277 pthread_mutex_lock(&LOCK_crypto[n]);
278 else
279 pthread_mutex_unlock(&LOCK_crypto[n]);
280}
281
282static int ssl_thread_init()
283{
284 if (!CRYPTO_THREADID_get_callback()
285#ifndef OPENSSL_NO_DEPRECATED
286 && !CRYPTO_get_id_callback()
287#endif
288 )
289 {
290 int i, max= CRYPTO_num_locks();
291
292 if (LOCK_crypto == NULL)
293 {
294 if (!(LOCK_crypto=
295 (pthread_mutex_t *)ma_malloc(sizeof(pthread_mutex_t) * max, MYF(0))))
296 return 1;
297
298 for (i=0; i < max; i++)
299 pthread_mutex_init(&LOCK_crypto[i], NULL);
300 }
301 CRYPTO_set_locking_callback(my_cb_locking);
302 CRYPTO_THREADID_set_callback(my_cb_threadid);
303 }
304 return 0;
305}
306#endif
307
308#if defined(_WIN32) || !defined(DISABLE_SIGPIPE)
309#define disable_sigpipe()
310#else
311#include <signal.h>
312static void ma_sigpipe_handler()
313{
314}
315
316static void disable_sigpipe()
317{
318 struct sigaction old_handler, new_handler={NULL};
319 if (!sigaction (SIGPIPE, NULL, &old_handler) &&
320 !old_handler.sa_handler)
321 {
322 new_handler.sa_handler= ma_sigpipe_handler;
323 new_handler.sa_flags= 0;
324 if (!sigemptyset(&new_handler.sa_mask))
325 sigaction(SIGPIPE, &new_handler, NULL);
326 }
327}
328#endif
329
330/*
331 Initializes SSL
332
333 SYNOPSIS
334 my_ssl_start
335 mysql connection handle
336
337 RETURN VALUES
338 0 success
339 1 error
340*/
341int ma_tls_start(char *errmsg __attribute__((unused)), size_t errmsg_len __attribute__((unused)))
342{
343 int rc= 1;
344 char *p;
345 if (ma_tls_initialized)
346 return 0;
347
348 /* lock mutex to prevent multiple initialization */
349 pthread_mutex_init(&LOCK_openssl_config, NULL);
350 pthread_mutex_lock(&LOCK_openssl_config);
351#ifdef HAVE_OPENSSL_1_1_API
352 if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL))
353 goto end;
354#else
355 if (ssl_thread_init())
356 {
357 strncpy(errmsg, "Not enough memory", errmsg_len);
358 goto end;
359 }
360 SSL_library_init();
361#if SSLEAY_VERSION_NUMBER >= 0x00907000L
362 OPENSSL_config(NULL);
363#endif
364#endif
365#ifndef HAVE_OPENSSL_1_1_API
366 /* load errors */
367 SSL_load_error_strings();
368 /* digests and ciphers */
369 OpenSSL_add_all_algorithms();
370#endif
371 disable_sigpipe();
372#ifdef OPENSSL_USE_BIOMETHOD
373 memcpy(&ma_BIO_method, BIO_s_socket(), sizeof(BIO_METHOD));
374 ma_BIO_method.bread= ma_bio_read;
375 ma_BIO_method.bwrite= ma_bio_write;
376#endif
377 snprintf(tls_library_version, TLS_VERSION_LENGTH - 1, "%s",
378#if defined(LIBRESSL_VERSION_NUMBER) || !defined(HAVE_OPENSSL_1_1_API)
379 SSLeay_version(SSLEAY_VERSION));
380#else
381 OpenSSL_version(OPENSSL_VERSION));
382#endif
383 /* remove date from version */
384 if ((p= strstr(tls_library_version, " ")))
385 *p= 0;
386 rc= 0;
387 ma_tls_initialized= TRUE;
388end:
389 pthread_mutex_unlock(&LOCK_openssl_config);
390 return rc;
391}
392
393/*
394 Release SSL and free resources
395 Will be automatically executed by
396 mysql_server_end() function
397
398 SYNOPSIS
399 my_ssl_end()
400 void
401
402 RETURN VALUES
403 void
404*/
405void ma_tls_end()
406{
407 if (ma_tls_initialized)
408 {
409 pthread_mutex_lock(&LOCK_openssl_config);
410#ifndef HAVE_OPENSSL_1_1_API
411 if (LOCK_crypto)
412 {
413 int i;
414 CRYPTO_set_locking_callback(NULL);
415 CRYPTO_THREADID_set_callback(NULL);
416
417 for (i=0; i < CRYPTO_num_locks(); i++)
418 pthread_mutex_destroy(&LOCK_crypto[i]);
419 ma_free((gptr)LOCK_crypto);
420 LOCK_crypto= NULL;
421 }
422#endif
423 if (mariadb_deinitialize_ssl)
424 {
425#ifndef HAVE_OPENSSL_1_1_API
426 ERR_remove_thread_state(NULL);
427 EVP_cleanup();
428 CRYPTO_cleanup_all_ex_data();
429 ERR_free_strings();
430 CONF_modules_free();
431 CONF_modules_unload(1);
432#endif
433 }
434 ma_tls_initialized= FALSE;
435 pthread_mutex_unlock(&LOCK_openssl_config);
436 pthread_mutex_destroy(&LOCK_openssl_config);
437 }
438 return;
439}
440
441int ma_tls_get_password(char *buf, int size,
442 int rwflag __attribute__((unused)),
443 void *userdata)
444{
445 memset(buf, 0, size);
446 if (userdata)
447 strncpy(buf, (char *)userdata, size);
448 return (int)strlen(buf);
449}
450
451
452static int ma_tls_set_certs(MYSQL *mysql, SSL *ssl)
453{
454 char *certfile= mysql->options.ssl_cert,
455 *keyfile= mysql->options.ssl_key;
456 char *pw= (mysql->options.extension) ?
457 mysql->options.extension->tls_pw : NULL;
458 SSL_CTX *ctx= SSL_get_SSL_CTX(ssl);
459
460
461 /* add cipher */
462 if ((mysql->options.ssl_cipher &&
463 mysql->options.ssl_cipher[0] != 0))
464 {
465 if(SSL_set_cipher_list(ssl, mysql->options.ssl_cipher) == 0)
466 goto error;
467 }
468
469 /* ca_file and ca_path */
470 if (!SSL_CTX_load_verify_locations(ctx,
471 mysql->options.ssl_ca,
472 mysql->options.ssl_capath))
473 {
474 if (mysql->options.ssl_ca || mysql->options.ssl_capath)
475 goto error;
476 if (SSL_CTX_set_default_verify_paths(ctx) == 0)
477 goto error;
478 }
479
480 if (keyfile && !certfile)
481 certfile= keyfile;
482 if (certfile && !keyfile)
483 keyfile= certfile;
484
485 /* set cert */
486 if (certfile && certfile[0] != 0)
487 {
488 if (SSL_CTX_use_certificate_chain_file(ctx, certfile) != 1 ||
489 SSL_use_certificate_file(ssl, certfile, SSL_FILETYPE_PEM) != 1)
490 goto error;
491 }
492 if (keyfile && keyfile[0])
493 {
494 FILE *fp;
495 if ((fp= fopen(keyfile, "rb")))
496 {
497 EVP_PKEY *key= EVP_PKEY_new();
498 PEM_read_PrivateKey(fp, &key, NULL, pw);
499 fclose(fp);
500 if (SSL_use_PrivateKey(ssl, key) != 1)
501 {
502 unsigned long err= ERR_peek_error();
503 EVP_PKEY_free(key);
504 if (!(ERR_GET_LIB(err) == ERR_LIB_X509 &&
505 ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE))
506 goto error;
507 }
508 EVP_PKEY_free(key);
509 } else {
510 my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
511 CER(CR_FILE_NOT_FOUND), keyfile);
512 return 1;
513 }
514 }
515 /* verify key */
516 if (certfile && !SSL_check_private_key(ssl))
517 goto error;
518
519 if (mysql->options.extension &&
520 (mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath))
521 {
522 X509_STORE *certstore;
523
524 if ((certstore= SSL_CTX_get_cert_store(ctx)))
525 {
526 if (X509_STORE_load_locations(certstore, mysql->options.extension->ssl_crl,
527 mysql->options.extension->ssl_crlpath) == 0)
528 goto error;
529
530 X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
531 }
532 }
533 SSL_CTX_set_verify(ctx, (mysql->options.ssl_ca || mysql->options.ssl_capath)?
534 SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
535 return 0;
536
537error:
538 ma_tls_set_error(mysql);
539 return 1;
540}
541
542void *ma_tls_init(MYSQL *mysql)
543{
544 SSL *ssl= NULL;
545 SSL_CTX *ctx= NULL;
546 long options= SSL_OP_ALL |
547 SSL_OP_NO_SSLv2 |
548 SSL_OP_NO_SSLv3;
549#ifdef HAVE_TLS_SESSION_CACHE
550 MA_SSL_SESSION *session= ma_tls_get_session(mysql);
551#endif
552 pthread_mutex_lock(&LOCK_openssl_config);
553
554 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
555 if (!(ctx= SSL_CTX_new(TLS_client_method())))
556#else
557 if (!(ctx= SSL_CTX_new(SSLv23_client_method())))
558#endif
559 goto error;
560 if (mysql->options.extension)
561 options|= ma_tls_version_options(mysql->options.extension->tls_version);
562 SSL_CTX_set_options(ctx, options);
563#ifdef HAVE_TLS_SESSION_CACHE
564 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT);
565 ma_tls_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_tls_session) * ma_tls_session_cache_size);
566 SSL_CTX_sess_set_new_cb(ctx, ma_tls_session_cb);
567 SSL_CTX_sess_set_remove_cb(ctx, ma_tls_remove_session_cb);
568#endif
569
570 if (!(ssl= SSL_new(ctx)))
571 goto error;
572
573 if (ma_tls_set_certs(mysql, ssl))
574 {
575 goto error;
576 }
577
578 if (!SSL_set_app_data(ssl, mysql))
579 goto error;
580
581#ifdef HAVE_TLS_SESSION_CACHE
582 if (session)
583 SSL_set_session(ssl, session->session);
584#endif
585
586 pthread_mutex_unlock(&LOCK_openssl_config);
587 return (void *)ssl;
588error:
589 pthread_mutex_unlock(&LOCK_openssl_config);
590 if (ctx)
591 SSL_CTX_free(ctx);
592 if (ssl)
593 SSL_free(ssl);
594 return NULL;
595}
596
597my_bool ma_tls_connect(MARIADB_TLS *ctls)
598{
599 SSL *ssl = (SSL *)ctls->ssl;
600 my_bool blocking, try_connect= 1;
601 MYSQL *mysql;
602 MARIADB_PVIO *pvio;
603 int rc;
604#ifdef OPENSSL_USE_BIOMETHOD
605 BIO_METHOD *bio_method= NULL;
606 BIO *bio;
607#endif
608
609 mysql= (MYSQL *)SSL_get_app_data(ssl);
610 pvio= mysql->net.pvio;
611
612 /* Set socket to non blocking if not already set */
613 if (!(blocking= pvio->methods->is_blocking(pvio)))
614 pvio->methods->blocking(pvio, FALSE, 0);
615
616 SSL_clear(ssl);
617
618#ifdef OPENSSL_USE_BIOMETHOD
619 bio= BIO_new(&ma_BIO_method);
620 bio->ptr= pvio;
621 SSL_set_bio(ssl, bio, bio);
622 BIO_set_fd(bio, mysql_get_socket(mysql), BIO_NOCLOSE);
623#else
624 SSL_set_fd(ssl, (int)mysql_get_socket(mysql));
625#endif
626
627 while (try_connect && (rc= SSL_connect(ssl)) == -1)
628 {
629 switch(SSL_get_error(ssl, rc)) {
630 case SSL_ERROR_WANT_READ:
631 if (pvio->methods->wait_io_or_timeout(pvio, TRUE, mysql->options.connect_timeout) < 1)
632 try_connect= 0;
633 break;
634 case SSL_ERROR_WANT_WRITE:
635 if (pvio->methods->wait_io_or_timeout(pvio, TRUE, mysql->options.connect_timeout) < 1)
636 try_connect= 0;
637 break;
638 default:
639 try_connect= 0;
640 }
641 }
642 if (rc != 1)
643 {
644 ma_tls_set_error(mysql);
645 /* restore blocking mode */
646 if (!blocking)
647 pvio->methods->blocking(pvio, FALSE, 0);
648 return 1;
649 }
650 if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
651 {
652 rc= SSL_get_verify_result(ssl);
653 if (rc != X509_V_OK)
654 {
655 my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
656 ER(CR_SSL_CONNECTION_ERROR), X509_verify_cert_error_string(rc));
657 /* restore blocking mode */
658 if (!blocking)
659 pvio->methods->blocking(pvio, FALSE, 0);
660
661 return 1;
662 }
663 }
664 pvio->ctls->ssl= ctls->ssl= (void *)ssl;
665
666 return 0;
667}
668
669static my_bool
670ma_tls_async_check_result(int res, struct mysql_async_context *b, SSL *ssl)
671{
672 int ssl_err;
673 b->events_to_wait_for= 0;
674 if (res >= 0)
675 return 1;
676 ssl_err= SSL_get_error(ssl, res);
677 if (ssl_err == SSL_ERROR_WANT_READ)
678 b->events_to_wait_for|= MYSQL_WAIT_READ;
679 else if (ssl_err == SSL_ERROR_WANT_WRITE)
680 b->events_to_wait_for|= MYSQL_WAIT_WRITE;
681 else
682 return 1;
683 if (b->suspend_resume_hook)
684 (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
685 my_context_yield(&b->async_context);
686 if (b->suspend_resume_hook)
687 (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
688 return 0;
689}
690
691ssize_t ma_tls_read_async(MARIADB_PVIO *pvio,
692 const unsigned char *buffer,
693 size_t length)
694{
695 int res;
696 struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
697 MARIADB_TLS *ctls= pvio->ctls;
698
699 for (;;)
700 {
701 res= SSL_read((SSL *)ctls->ssl, (void *)buffer, (int)length);
702 if (ma_tls_async_check_result(res, b, (SSL *)ctls->ssl))
703 return res;
704 }
705}
706
707ssize_t ma_tls_write_async(MARIADB_PVIO *pvio,
708 const unsigned char *buffer,
709 size_t length)
710{
711 int res;
712 struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
713 MARIADB_TLS *ctls= pvio->ctls;
714
715 for (;;)
716 {
717 res= SSL_write((SSL *)ctls->ssl, (void *)buffer, (int)length);
718 if (ma_tls_async_check_result(res, b, (SSL *)ctls->ssl))
719 return res;
720 }
721}
722
723
724ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
725{
726 int rc;
727 MARIADB_PVIO *pvio= ctls->pvio;
728
729 while ((rc= SSL_read((SSL *)ctls->ssl, (void *)buffer, (int)length)) < 0)
730 {
731 int error= SSL_get_error((SSL *)ctls->ssl, rc);
732 if (error != SSL_ERROR_WANT_READ)
733 return rc;
734 if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.read_timeout) < 1)
735 return rc;
736 }
737 return rc;
738}
739
740ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
741{
742 int rc;
743 MARIADB_PVIO *pvio= ctls->pvio;
744
745 while ((rc= SSL_write((SSL *)ctls->ssl, (void *)buffer, (int)length)) <= 0)
746 {
747 int error= SSL_get_error((SSL *)ctls->ssl, rc);
748 if (error != SSL_ERROR_WANT_WRITE)
749 return rc;
750 if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.write_timeout) < 1)
751 return rc;
752 }
753 return rc;
754}
755
756my_bool ma_tls_close(MARIADB_TLS *ctls)
757{
758 int i, rc;
759 SSL *ssl;
760 SSL_CTX *ctx= NULL;
761
762 if (!ctls || !ctls->ssl)
763 return 1;
764 ssl= (SSL *)ctls->ssl;
765 ctx= SSL_get_SSL_CTX(ssl);
766 if (ctx)
767 SSL_CTX_free(ctx);
768
769 SSL_set_quiet_shutdown(ssl, 1);
770 /* 2 x pending + 2 * data = 4 */
771 for (i=0; i < 4; i++)
772 if ((rc= SSL_shutdown(ssl)))
773 break;
774
775 /* Since we transferred ownership of BIO to ssl, BIO will
776 automatically freed - no need for an explicit BIO_free_all */
777
778 SSL_free(ssl);
779 ctls->ssl= NULL;
780
781 return rc;
782}
783
784int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
785{
786 X509 *cert;
787 MYSQL *mysql;
788 SSL *ssl;
789 MARIADB_PVIO *pvio;
790#if !defined(HAVE_OPENSSL_CHECK_HOST)
791 X509_NAME *x509sn;
792 int cn_pos;
793 X509_NAME_ENTRY *cn_entry;
794 ASN1_STRING *cn_asn1;
795 const char *cn_str;
796#endif
797
798 if (!ctls || !ctls->ssl)
799 return 1;
800 ssl= (SSL *)ctls->ssl;
801
802 mysql= (MYSQL *)SSL_get_app_data(ssl);
803 pvio= mysql->net.pvio;
804
805 if (!mysql->host)
806 {
807 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
808 ER(CR_SSL_CONNECTION_ERROR), "Invalid (empty) hostname");
809 return 1;
810 }
811
812 if (!(cert= SSL_get_peer_certificate(ssl)))
813 {
814 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
815 ER(CR_SSL_CONNECTION_ERROR), "Unable to get server certificate");
816 return 1;
817 }
818#ifdef HAVE_OPENSSL_CHECK_HOST
819 if (X509_check_host(cert, mysql->host, 0, 0, 0) != 1
820 && X509_check_ip_asc(cert, mysql->host, 0) != 1)
821 goto error;
822#else
823 x509sn= X509_get_subject_name(cert);
824
825 if ((cn_pos= X509_NAME_get_index_by_NID(x509sn, NID_commonName, -1)) < 0)
826 goto error;
827
828 if (!(cn_entry= X509_NAME_get_entry(x509sn, cn_pos)))
829 goto error;
830
831 if (!(cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry)))
832 goto error;
833
834 cn_str = (char *)ASN1_STRING_data(cn_asn1);
835
836 /* Make sure there is no embedded \0 in the CN */
837 if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn_str))
838 goto error;
839
840 if (strcmp(cn_str, mysql->host))
841 goto error;
842#endif
843 X509_free(cert);
844
845 return 0;
846error:
847 X509_free(cert);
848
849 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
850 ER(CR_SSL_CONNECTION_ERROR), "Validation of SSL server certificate failed");
851 return 1;
852}
853
854const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
855{
856 if (!ctls || !ctls->ssl)
857 return NULL;
858 return SSL_get_cipher_name(ctls->ssl);
859}
860
861unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
862{
863 X509 *cert= NULL;
864 MYSQL *mysql;
865 unsigned int fp_len;
866
867 if (!ctls || !ctls->ssl)
868 return 0;
869
870 mysql= SSL_get_app_data(ctls->ssl);
871
872 if (!(cert= SSL_get_peer_certificate(ctls->ssl)))
873 {
874 my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
875 ER(CR_SSL_CONNECTION_ERROR),
876 "Unable to get server certificate");
877 goto end;
878 }
879
880 if (len < EVP_MAX_MD_SIZE)
881 {
882 my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
883 ER(CR_SSL_CONNECTION_ERROR),
884 "Finger print buffer too small");
885 goto end;
886 }
887 if (!X509_digest(cert, EVP_sha1(), (unsigned char *)fp, &fp_len))
888 {
889 my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
890 ER(CR_SSL_CONNECTION_ERROR),
891 "invalid finger print of server certificate");
892 goto end;
893 }
894
895 X509_free(cert);
896 return (fp_len);
897end:
898 X509_free(cert);
899 return 0;
900}
901
902
903int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
904{
905 if (!ctls || !ctls->ssl)
906 return -1;
907
908 return SSL_version(ctls->ssl) & 0xFF;
909}
910
911