Permalink
Browse files

Bug#17208 SSL: client does not verify server certificate

 - Add new function 'ssl_verify_server_cert' which is used if we are 
   connecting to the server with SSL. It will compare the hostname in 
   the server's cert against the hostname that we used when connecting 
   to the server. Will reject the connection if hostname does not match.
 - Add new option "OPT_SSL_VERIFY_SERVER_CERT" to be passed to mysql_options
   which will turn on checking of servers cert.
 - Add new argument "ssl-verify-server-cert" to all mysql* clients which 
   will activate the above option.
 - Generate a new server cert with 1024 bits that has "localhost" as the server name.
  • Loading branch information...
msvensson@neptunus.(none)
msvensson@neptunus.(none) committed Apr 18, 2006
1 parent d66ac94 commit a51668c74c498e3e5702342fe5ced68afbee0756
@@ -1,13 +1,14 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Serial Number:
e9:07:d1:01:94:ee:66:ca
Signature Algorithm: md5WithRSAEncryption
Issuer: C=SE, L=Uppsala, O=MySQL AB, CN=Abstract MySQL Developer/Email=abstract.mysql.developer@mysql.com
Issuer: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB, CN=localhost/emailAddress=abstract.mysql.developer@mysql.com
Validity
Not Before: Sep 12 16:22:06 2003 GMT
Not After : Sep 9 16:22:06 2013 GMT
Subject: C=SE, L=Uppsala, O=MySQL AB, CN=MySQL Server/Email=abstract.mysql.developer@mysql.com
Not Before: Apr 18 15:35:37 2006 GMT
Not After : Jan 12 15:35:37 2009 GMT
Subject: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB, CN=localhost/emailAddress=abstract.mysql.developer@mysql.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
@@ -23,45 +24,42 @@ Certificate:
3d:0e:4d:2a:a8:b8:ca:99:8d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
6E:E4:9B:6A:C5:EA:E4:E6:C7:EF:D7:1E:C8:63:45:60:2B:1B:D4:D4
X509v3 Authority Key Identifier:
keyid:88:98:65:D9:F3:F2:8B:03:1D:66:60:61:23:FA:AD:73:6D:D3:68:92
DirName:/C=SE/L=Uppsala/O=MySQL AB/CN=Abstract MySQL Developer/Email=abstract.mysql.developer@mysql.com
serial:00
keyid:6E:E4:9B:6A:C5:EA:E4:E6:C7:EF:D7:1E:C8:63:45:60:2B:1B:D4:D4
DirName:/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB/CN=localhost/emailAddress=abstract.mysql.developer@mysql.com
serial:E9:07:D1:01:94:EE:66:CA

X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: md5WithRSAEncryption
31:77:69:b9:bd:ab:29:f3:fc:5a:09:16:6f:5d:42:ea:ba:01:
55:69:e3:75:cf:b8:d1:b7:b9:bf:da:63:85:8c:48:92:06:60:
76:97:e0:00:78:4b:ad:da:ab:6a:90:6d:8b:03:a8:b1:e9:09:
78:e1:29:98:56:12:60:6b:42:fe:e8:a7:c4:f8:d6:15:07:e8:
2b:c2:d8:8a:e5:1b:2e:51:08:9b:56:e3:b3:7a:4c:3e:e5:be:
4a:4d:f8:65:7b:a8:21:e0:ca:fe:8b:ab:d7:ec:f2:2d:f7:d0:
bf:d7:c5:23:1c:08:d8:aa:57:c7:f3:5f:ba:33:3f:78:d1:f4:
8e:5e
1f:03:59:6e:ff:1f:9d:c7:19:9e:8e:b2:1a:c0:0b:9e:ee:94:
35:77:2a:93:04:ea:d5:a8:fc:36:5a:5b:e3:1c:02:b8:cf:04:
6e:21:b0:27:f6:96:6e:d6:8f:cd:02:cf:23:f3:e7:ff:6a:ee:
a9:09:c5:c9:07:81:b6:d2:bc:bd:13:47:0d:7b:76:f6:8a:c4:
76:24:f8:4c:4e:26:fc:d8:c0:1f:3d:40:19:43:8e:41:ab:99:
3a:99:9b:24:7c:ae:78:f3:df:2f:a2:ed:8f:27:0a:0a:0b:04:
bf:25:74:88:87:96:c8:68:d5:bc:5b:a0:ef:14:aa:53:6e:c4:
a3:e3
-----BEGIN CERTIFICATE-----
MIIDkTCCAvqgAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBiDELMAkGA1UEBhMCU0Ux
EDAOBgNVBAcTB1VwcHNhbGExETAPBgNVBAoTCE15U1FMIEFCMSEwHwYDVQQDExhB
YnN0cmFjdCBNeVNRTCBEZXZlbG9wZXIxMTAvBgkqhkiG9w0BCQEWImFic3RyYWN0
Lm15c3FsLmRldmVsb3BlckBteXNxbC5jb20wHhcNMDMwOTEyMTYyMjA2WhcNMTMw
OTA5MTYyMjA2WjB8MQswCQYDVQQGEwJTRTEQMA4GA1UEBxMHVXBwc2FsYTERMA8G
A1UEChMITXlTUUwgQUIxFTATBgNVBAMTDE15U1FMIFNlcnZlcjExMC8GCSqGSIb3
DQEJARYiYWJzdHJhY3QubXlzcWwuZGV2ZWxvcGVyQG15c3FsLmNvbTCBnzANBgkq
hkiG9w0BAQEFAAOBjQAwgYkCgYEA6YZ6VYSITL6k+JJzMBJJC3qFhzk0OQ19C40Y
wheVE1LSP1UQV8g/WvWy+ovQZ0nMqoL8n84AtHPzNtI608KwDhTD1LIhdKHwMYFg
h5hzXBDBsRpN8fOwmD/w15ebK/3VIXmyL+tkFcmbnfyeLdT4BFvqqXVLQsM9Dk0q
qLjKmY0CAwEAAaOCARQwggEQMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9w
ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRu5Jtqxerk5sfv
1x7IY0VgKxvU1DCBtQYDVR0jBIGtMIGqgBSImGXZ8/KLAx1mYGEj+q1zbdNokqGB
jqSBizCBiDELMAkGA1UEBhMCU0UxEDAOBgNVBAcTB1VwcHNhbGExETAPBgNVBAoT
CE15U1FMIEFCMSEwHwYDVQQDExhBYnN0cmFjdCBNeVNRTCBEZXZlbG9wZXIxMTAv
BgkqhkiG9w0BCQEWImFic3RyYWN0Lm15c3FsLmRldmVsb3BlckBteXNxbC5jb22C
AQAwDQYJKoZIhvcNAQEEBQADgYEAMXdpub2rKfP8WgkWb11C6roBVWnjdc+40be5
v9pjhYxIkgZgdpfgAHhLrdqrapBtiwOosekJeOEpmFYSYGtC/uinxPjWFQfoK8LY
iuUbLlEIm1bjs3pMPuW+Sk34ZXuoIeDK/our1+zyLffQv9fFIxwI2KpXx/NfujM/
eNH0jl4=
MIIDijCCAvOgAwIBAgIJAOkH0QGU7mbKMA0GCSqGSIb3DQEBBAUAMIGLMQswCQYD
VQQGEwJTRTEQMA4GA1UECBMHVXBwc2FsYTEQMA4GA1UEBxMHVXBwc2FsYTERMA8G
A1UEChMITXlTUUwgQUIxEjAQBgNVBAMTCWxvY2FsaG9zdDExMC8GCSqGSIb3DQEJ
ARYiYWJzdHJhY3QubXlzcWwuZGV2ZWxvcGVyQG15c3FsLmNvbTAeFw0wNjA0MTgx
NTM1MzdaFw0wOTAxMTIxNTM1MzdaMIGLMQswCQYDVQQGEwJTRTEQMA4GA1UECBMH
VXBwc2FsYTEQMA4GA1UEBxMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwgQUIxEjAQ
BgNVBAMTCWxvY2FsaG9zdDExMC8GCSqGSIb3DQEJARYiYWJzdHJhY3QubXlzcWwu
ZGV2ZWxvcGVyQG15c3FsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6YZ6VYSITL6k+JJzMBJJC3qFhzk0OQ19C40YwheVE1LSP1UQV8g/WvWy+ovQZ0nM
qoL8n84AtHPzNtI608KwDhTD1LIhdKHwMYFgh5hzXBDBsRpN8fOwmD/w15ebK/3V
IXmyL+tkFcmbnfyeLdT4BFvqqXVLQsM9Dk0qqLjKmY0CAwEAAaOB8zCB8DAdBgNV
HQ4EFgQUbuSbasXq5ObH79ceyGNFYCsb1NQwgcAGA1UdIwSBuDCBtYAUbuSbasXq
5ObH79ceyGNFYCsb1NShgZGkgY4wgYsxCzAJBgNVBAYTAlNFMRAwDgYDVQQIEwdV
cHBzYWxhMRAwDgYDVQQHEwdVcHBzYWxhMREwDwYDVQQKEwhNeVNRTCBBQjESMBAG
A1UEAxMJbG9jYWxob3N0MTEwLwYJKoZIhvcNAQkBFiJhYnN0cmFjdC5teXNxbC5k
ZXZlbG9wZXJAbXlzcWwuY29tggkA6QfRAZTuZsowDAYDVR0TBAUwAwEB/zANBgkq
hkiG9w0BAQQFAAOBgQAfA1lu/x+dxxmejrIawAue7pQ1dyqTBOrVqPw2WlvjHAK4
zwRuIbAn9pZu1o/NAs8j8+f/au6pCcXJB4G20ry9E0cNe3b2isR2JPhMTib82MAf
PUAZQ45Bq5k6mZskfK54898vou2PJwoKCwS/JXSIh5bIaNW8W6DvFKpTbsSj4w==
-----END CERTIFICATE-----
@@ -51,5 +51,5 @@ enum options_client
#endif
OPT_TRIGGERS,
OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE,
OPT_TZ_UTC, OPT_AUTO_CLOSE
OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_SSL_VERIFY_SERVER_CERT
};
@@ -3123,6 +3123,8 @@ sql_real_connect(char *host,char *database,char *user,char *password,
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -340,6 +340,8 @@ int main(int argc,char *argv[])
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -905,6 +905,8 @@ static int dbConnect(char *host, char *user,char *passwd)
if (opt_use_ssl)
mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -384,6 +384,8 @@ static MYSQL *db_connect(char *host, char *database, char *user, char *passwd)
if (opt_use_ssl)
mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -109,6 +109,8 @@ int main(int argc, char **argv)
if (opt_use_ssl)
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(char*)&opt_ssl_verify_server_cert);
#endif
if (opt_protocol)
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
@@ -108,7 +108,7 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC,
OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH,
OPT_SSL_CIPHER,OPT_PS_PROTOCOL,OPT_SP_PROTOCOL,OPT_CURSOR_PROTOCOL,
OPT_VIEW_PROTOCOL};
OPT_VIEW_PROTOCOL, OPT_SSL_VERIFY_SERVER_CERT};

/* ************************************************************************ */
/*
@@ -2378,8 +2378,12 @@ int do_connect(struct st_query *q)

#ifdef HAVE_OPENSSL
if (opt_use_ssl || con_ssl)
{
mysql_ssl_set(&next_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
&opt_ssl_verify_server_cert);
}
#endif
if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR)
con_sock=fn_format(buff, con_sock, TMPDIR, "",0);
@@ -4604,9 +4608,14 @@ int main(int argc, char **argv)
mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name);

#ifdef HAVE_OPENSSL
opt_ssl_verify_server_cert= TRUE; /* Always on in mysqltest */
if (opt_use_ssl)
{
mysql_ssl_set(&cur_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
mysql_options(&cur_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
&opt_ssl_verify_server_cert);
}
#endif

if (!(cur_con->name = my_strdup("default", MYF(MY_WME))))
@@ -149,7 +149,8 @@ enum mysql_option
MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT
};

struct st_mysql_options {
@@ -164,6 +165,7 @@ struct st_mysql_options {
char *ssl_ca; /* PEM CA file */
char *ssl_capath; /* PEM directory of CA-s? */
char *ssl_cipher; /* cipher to use */
my_bool ssl_verify_server_cert; /* if to verify server cert */
char *shared_memory_base_name;
unsigned long max_allowed_packet;
my_bool use_ssl; /* if to use SSL or not */
@@ -37,5 +37,10 @@
{"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).",
(gptr*) &opt_ssl_cipher, (gptr*) &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},

#ifdef MYSQL_CLIENT
{"ssl-verify-server-cert", OPT_SSL_VERIFY_SERVER_CERT,
"Verify servers \"Common Name\" in it's cert against hostname used when connecting. This option is disabled by default.",
(gptr*) &opt_ssl_verify_server_cert, (gptr*) &opt_ssl_verify_server_cert,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
#endif /* HAVE_OPENSSL */
@@ -21,4 +21,7 @@ static char *opt_ssl_cert = 0;
static char *opt_ssl_ca = 0;
static char *opt_ssl_capath = 0;
static char *opt_ssl_cipher = 0;
#ifdef MYSQL_CLIENT
static my_bool opt_ssl_verify_server_cert= 0;
#endif
#endif
@@ -1500,6 +1500,7 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
mysql->options.ssl_ca= strdup_if_not_null(ca);
mysql->options.ssl_capath= strdup_if_not_null(capath);
mysql->options.ssl_cipher= strdup_if_not_null(cipher);
mysql->options.ssl_verify_server_cert= FALSE; /* Off by default */
#endif /* HAVE_OPENSSL */
DBUG_RETURN(0);
}
@@ -1521,7 +1522,7 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
if (ssl_fd)
SSL_CTX_free(ssl_fd->ssl_context);
my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR));
@@ -1534,6 +1535,77 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
mysql->connector_fd = 0;
DBUG_VOID_RETURN;
}

/*
Check the server's (subject) Common Name against the
hostname we connected to
SYNOPSIS
ssl_verify_server_cert()
vio pointer to a SSL connected vio
server_hostname name of the server that we connected to
RETURN VALUES
0 Success
1 Failed to validate server
*/
static int ssl_verify_server_cert(Vio *vio, const char* server_hostname)
{
SSL *ssl;
X509 *server_cert;
char *cp1, *cp2;
char buf[256];
DBUG_ENTER("ssl_verify_server_cert");
DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));

if (!(ssl= (SSL*)vio->ssl_arg))
{
DBUG_PRINT("error", ("No SSL pointer found"));
DBUG_RETURN(1);
}

if (!server_hostname)
{
DBUG_PRINT("error", ("No server hostname supplied"));
DBUG_RETURN(1);
}

if (!(server_cert= SSL_get_peer_certificate(ssl)))
{
DBUG_PRINT("error", ("Could not get server certificate"));
DBUG_RETURN(1);
}

/*
We already know that the certificate exchanged was valid; the SSL library
handled that. Now we need to verify that the contents of the certificate
are what we expect.
*/

X509_NAME_oneline(X509_get_subject_name(server_cert), buf, sizeof(buf));
X509_free (server_cert);

DBUG_PRINT("info", ("hostname in cert: %s", buf));
cp1 = strstr(buf, "/CN=");
if (cp1)
{
cp1 += 4; // Skip the "/CN=" that we found
// Search for next / which might be the delimiter for email
cp2 = strchr(cp1, '/');
if (cp2)
*cp2 = '\0';
DBUG_PRINT("info", ("Server hostname in cert: %s", cp1));
if (!strcmp(cp1, server_hostname))
{
/* Success */
DBUG_RETURN(0);
}
}
DBUG_PRINT("error", ("SSL certificate validation failure"));
DBUG_RETURN(1);
}

#endif /* HAVE_OPENSSL */


@@ -2049,7 +2121,14 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
}
DBUG_PRINT("info", ("IO layer change done!"));

/* TODO Verify server cert */
/* Verify server cert */
if (mysql->options.ssl_verify_server_cert &&
ssl_verify_server_cert(mysql->net.vio, mysql->host))
{
set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate);
goto error;
}

}
#endif /* HAVE_OPENSSL */

@@ -2789,6 +2868,9 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
case MYSQL_OPT_RECONNECT:
mysql->reconnect= *(my_bool *) arg;
break;
case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
mysql->options.ssl_verify_server_cert= *(my_bool *) arg;
break;
default:
DBUG_RETURN(1);
}
@@ -290,20 +290,20 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file,
const char *cipher)
{
struct st_VioSSLFd *ssl_fd;
int verify= SSL_VERIFY_NONE;
int verify= SSL_VERIFY_PEER;
if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file,
ca_path, cipher, TLSv1_client_method())))
{
return 0;
}

/* Init the the VioSSLFd as a "connector" ie. the client side */

/*
The verify_callback function is used to control the behaviour
when the SSL_VERIFY_PEER flag is set. Here it is SSL_VERIFY_NONE
and thus callback is set to NULL
when the SSL_VERIFY_PEER flag is set.
*/
SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL);
SSL_CTX_set_verify(ssl_fd->ssl_context, verify, vio_verify_callback);

return ssl_fd;
}

0 comments on commit a51668c

Please sign in to comment.