Skip to content

Commit b481c0a

Browse files
committed
CONC-724: Added TLS verification callback support
For testing purposes (the python3 dummy server can't handle further communication after TLS handshake succeeded) support for verification callback was added. my_bool callback(MYSQL *mysql, unsigned int *flags, my_bool verified) Parameter: - mysql connection handle for current connection - flags verification flags - verified true if callback was called after verification, otherwise false Return value: - False (0) to continue - True (1) to abort tls connection The callback function can be registered via mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, callback);
1 parent 375720d commit b481c0a

File tree

6 files changed

+82
-6
lines changed

6 files changed

+82
-6
lines changed

include/ma_common.h

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct st_mysql_options_extension {
8888
void (*status_callback)(void *ptr, enum enum_mariadb_status_info type, ...);
8989
void *status_data;
9090
my_bool tls_allow_invalid_server_cert;
91+
my_bool (*tls_verification_callback)(MYSQL *mysql, unsigned int *verification_flags, my_bool verified);
9192
};
9293

9394
typedef struct st_connection_handler

include/mariadb_com.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ typedef struct st_net {
297297
unsigned char reading_or_writing;
298298
char save_char;
299299
char unused_1;
300-
my_bool tls_verify_status;
300+
unsigned char tls_verify_status;
301301
my_bool compress;
302302
my_bool unused_2;
303303
char *unused_3;

include/mysql.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ extern const char *SQLSTATE_UNKNOWN;
259259
MARIADB_OPT_RPL_REGISTER_REPLICA,
260260
MARIADB_OPT_STATUS_CALLBACK,
261261
MARIADB_OPT_SERVER_PLUGINS,
262-
MARIADB_OPT_BULK_UNIT_RESULTS
262+
MARIADB_OPT_BULK_UNIT_RESULTS,
263+
MARIADB_OPT_TLS_VERIFICATION_CALLBACK
263264
};
264265

265266
enum mariadb_value {

libmariadb/ma_tls.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,17 @@ int ma_pvio_tls_verify_server_cert(MARIADB_TLS *ctls, unsigned int flags)
119119
return 0;
120120
}
121121

122-
rc= ma_tls_verify_server_cert(ctls, flags);
122+
if (mysql->options.extension->tls_verification_callback &&
123+
mysql->options.extension->tls_verification_callback(mysql, &flags, 0))
124+
rc= 1;
125+
else {
126+
rc= ma_tls_verify_server_cert(ctls, flags);
127+
if (mysql->options.extension->tls_verification_callback &&
128+
mysql->options.extension->tls_verification_callback(mysql, &flags, 1))
129+
{
130+
rc= 1;
131+
}
132+
}
123133

124134
/* Set error messages */
125135
if (!mysql->net.last_errno)

libmariadb/mariadb_lib.c

+3
Original file line numberDiff line numberDiff line change
@@ -3853,6 +3853,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
38533853
case MARIADB_OPT_BULK_UNIT_RESULTS:
38543854
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, bulk_unit_results, *(my_bool *)arg1);
38553855
break;
3856+
case MARIADB_OPT_TLS_VERIFICATION_CALLBACK:
3857+
OPT_SET_EXTENDED_VALUE(&mysql->options, tls_verification_callback, arg1);
3858+
break;
38563859
default:
38573860
va_end(ap);
38583861
SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);

unittest/libmariadb/tls.c.in

+64-3
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
4242
FAIL_IF(!(status & (flag)), (text));\
4343
}
4444

45-
#define CHECK_NO_TLS_FLAGS(m)\
45+
#define CHECK_NO_TLS_FLAG(m, flag, text)\
4646
{\
4747
unsigned int status;\
4848
mariadb_get_infov(mysql, MARIADB_TLS_VERIFY_STATUS, &status);\
49-
FAIL_IF(status), "Expected MARIADB_TLS_VERIFY_OK");\
49+
FAIL_IF((status & (flag)), (text));\
5050
}
5151

5252
my_bool auto_generated_cert= 0;
@@ -141,7 +141,7 @@ static int test_start_tls_server(MYSQL *my __attribute__((unused)))
141141

142142
snprintf(hostname, sizeof(hostname), "--host=%s", tls_dummy_host);
143143
snprintf(port, sizeof(port), "--port=%d", tls_dummy_port);
144-
execlp("@Python3_EXECUTABLE@", "@Python3_EXECUTABLE@", "tls_server.py", hostname, port, NULL);
144+
execlp("@Python3_EXECUTABLE@", "@Python3_EXECUTABLE@", "@CC_SOURCE_DIR@/unittest/libmariadb/tls_server.py", hostname, port, NULL);
145145
}
146146

147147
#endif
@@ -658,11 +658,72 @@ static int stop_tls_server(MYSQL *my __attribute__((unused)))
658658
return OK;
659659
}
660660

661+
my_bool tls_wildcard_callback(MYSQL *mysql, unsigned int *flags, my_bool verified)
662+
{
663+
if (!verified)
664+
{
665+
free(mysql->host);
666+
mysql->host= strdup("test.example.com");
667+
*flags= MARIADB_TLS_VERIFY_HOST;
668+
return 0;
669+
}
670+
/* Indicate error, since the dummy server can't handle further client server
671+
communication after TLS handshake */
672+
mysql->net.tls_verify_status|= MARIADB_TLS_VERIFY_ERROR;
673+
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
674+
ER(CR_SSL_CONNECTION_ERROR),
675+
"Certificate verification aborted by callback");
676+
return 1;
677+
}
678+
679+
static int test_cert_wildcard(MYSQL *my __attribute((unused)))
680+
{
681+
MYSQL *mysql= mysql_init(NULL);
682+
if (set_tls_dummy_options("CMD:create_new=True commonName='*.example.com'"))
683+
{
684+
diag("Error when setting TLS options");
685+
return FAIL;
686+
}
687+
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
688+
mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, tls_wildcard_callback);
689+
690+
if (!my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
691+
{
692+
CHECK_NO_TLS_FLAG(mysql, MARIADB_TLS_VERIFY_HOST, "Hostname verification didn't pass");
693+
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_TRUST, "Self signed certificate expected");
694+
mysql_close(mysql);
695+
} else {
696+
mysql_close(mysql);
697+
return FAIL;
698+
}
699+
700+
mysql= mysql_init(NULL);
701+
if (set_tls_dummy_options("CMD:create_new=True commonName='*.noexample.com'"))
702+
{
703+
diag("Error when setting TLS options");
704+
return FAIL;
705+
}
706+
mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL);
707+
mysql_optionsv(mysql, MARIADB_OPT_TLS_VERIFICATION_CALLBACK, tls_wildcard_callback);
708+
709+
if (!my_test_connect(mysql, tls_dummy_host, "tlsuser", "foo", NULL, tls_dummy_port, NULL, 0, 0))
710+
{
711+
CHECK_TLS_FLAGS(mysql, MARIADB_TLS_VERIFY_HOST, "Hostname verification passed with wrong wildcard");
712+
mysql_close(mysql);
713+
} else {
714+
mysql_close(mysql);
715+
return FAIL;
716+
}
717+
return OK;
718+
}
719+
720+
661721
struct my_tests_st my_tests[] = {
662722
/* Don't add test above, test_init needs to be run first */
663723
{"test_start_tls_server", test_start_tls_server, TEST_CONNECTION_NONE, 0, NULL, NULL},
664724
{"test_init", test_init, TEST_CONNECTION_NONE, 0, NULL, NULL},
665725
/* Here you can add more tests */
726+
{"test_cert_wildcard", test_cert_wildcard, TEST_CONNECTION_NEW, 0, NULL, NULL},
666727
{"test_cert_expired", test_cert_expired, TEST_CONNECTION_NEW, 0, NULL, NULL},
667728
{"test_pw_check", test_pw_check, TEST_CONNECTION_NEW, 0, NULL, NULL},
668729
{"test_ca_cert_check", test_ca_cert_check, TEST_CONNECTION_NONE, 0, NULL, NULL},

0 commit comments

Comments
 (0)