Bug #62743 -ssl-key value is not validated and it allows insecure connections if specified
Submitted: 14 Oct 2011 19:23 Modified: 13 Aug 2012 16:03
Reporter: Chris Calender Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Command-line Clients Severity:S2 (Serious)
Version:5.5.16, 5.5.20, 5.0.95, 5.1.61 OS:Any
Assigned to:
Tags: Contribution, SSL, ssl-key
Triage: Needs Triage: D1 (Critical)

[14 Oct 2011 19:23] Chris Calender
Description:
-ssl-key value is not validated and it allows insecure connections if specified.

For one, the manual says a client should specify the --ssl-ca option to connect for SSL (once it is set up).

However, you can connect by just setting --ssl-key.

Furthermore, you can assign any bogus text to --ssl-key and it is not verified that it exists, *and* more importantly, it allows the client to connect to mysqld.

Also, since I'm passing garbage in as --ssl-key, how is this even creating a valid SSL connection???

How to repeat:
Set up SSL.

Start mysqld with following options:

ssl-ca		= "C:/Program Files/MySQL/mysql-5.5.16/certs/ca-cert.pem"
ssl-cert	= "C:/Program Files/MySQL/mysql-5.5.16/certs/server-cert.pem"
ssl-key		= "C:/Program Files/MySQL/mysql-5.5.16/certs/server-key.pem"

Start up client, and only pass the --ssl-key option (with bogus text):

mysql -ussluser -pssluser -P3430 --ssl-key=buggg

You'll see it connects!

Here is the status output to prove it's using SSL:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-key=buggg
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 5.5.16-log MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.5.16, for Win32 (x86)

Connection id:          11
Current database:
Current user:           ssluser@localhost
SSL:                    Cipher in use is DHE-RSA-AES256-SHA
Using delimiter:        ;
Server version:         5.5.16-log MySQL Community Server (GPL)
Protocol version:       10
Connection:             localhost via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    cp850
Conn.  characterset:    cp850
TCP port:               3430
Uptime:                 35 min 26 sec

Threads: 1  Questions: 24  Slow queries: 0  Opens: 33  Flush tables: 1  Open tables: 0  Queries per second avg: 0.011
--------------

Suggested fix:
For one, validate the value of --ssl-key.

For two, reject connections with incorrect values for --ssl-key.

For three, reject connections with only --ssl-key set, if this is not correct (note this is not correct according to the manual, or update manual if it is allowed).
[14 Oct 2011 20:11] Chris Calender
If you specify *both* --ssl-cert and --ssl-key, then the contents of --ssl-key are verified, and the connection is disallowed if it is not the correct --ssl-key:

Here I tried with bogus text as before, and the connection is refused:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-cert=..\certs\client-cert.pem --ssl-key=bugg
SSL error: Unable to get private key from 'bugg'
ERROR 2026 (HY000): SSL connection error: Unable to get private key

Here I tried with a bogus file, but the file did exist (just with garbage text in it):

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-cert=..\certs\client-cert.pem --ssl-key=..\certs\a.txt
SSL error: Unable to get private key from '..\certs\a.txt'
ERROR 2026 (HY000): SSL connection error: Unable to get private key

And here it shows it works, but only when --ssl-key and --ssl-cert are specified, and correct:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-cert=..\certs\client-cert.pem --ssl-key=..\certs\client-key.pem
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 20
Server version: 5.5.16-log MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

So, it seems the issue is only when *just* --ssl-key is provided.

And in this case, how can one confirm whether SSL is being used or not?
[18 Oct 2011 21:15] Davi Arnaut
Look up the difference between a simple and a authenticated SSL handshake.
[18 Oct 2011 22:12] Chris Calender
Just for clarity, you can see the actual user (and current_user) are both the SSL user:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-key=blah
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.16-log MySQL Community Server (GPL)
...
mysql> status;
--------------
mysql  Ver 14.14 Distrib 5.5.16, for Win32 (x86)

Connection id:          2
Current database:
Current user:           ssluser@localhost
SSL:                    Cipher in use is DHE-RSA-AES256-SHA
Using delimiter:        ;
Server version:         5.5.16-log MySQL Community Server (GPL)
...
--------------

mysql> select user(), current_user();
+-------------------+-------------------+
| user()            | current_user()    |
+-------------------+-------------------+
| ssluser@localhost | ssluser@localhost |
+-------------------+-------------------+
1 row in set (0.00 sec)

mysql> SELECT user,host,ssl_type FROM mysql.user;
+---------+-------------+----------+
| user    | host        | ssl_type |
+---------+-------------+----------+
| root    | localhost   |          |
| root    | 127.0.0.1   |          |
| root    | ::1         |          |
| ssluser | host-laptop | ANY      |
| ssluser | localhost   | ANY      |
+---------+-------------+----------+
5 rows in set (0.00 sec)

Here are the commands I used to create the 2 `ssluser` users, respectively:

GRANT ALL PRIVILEGES ON *.* TO 'ssluser'@'localhost' IDENTIFIED BY 'ssluser' REQUIRE SSL;)
GRANT ALL PRIVILEGES ON *.* TO 'ssluser'@'host-laptop' IDENTIFIED BY 'ssluser' REQUIRE SSL;
[18 Oct 2011 23:48] Davi Arnaut
A documentation request:

"To connect, the client must specify the --ssl-ca option, and may additionally specify the --ssl-key and --ssl-cert options."

could be expanded to:

"To connect, the client must specify the --ssl-ca option in order to authenticate the server certificate, and may additionally specify the --ssl-key and --ssl-cert options. If neither --ssl-ca nor --ssl-capath are specified, the client does not authenticate the server certificate."
[19 Oct 2011 11:12] Davi Arnaut
Some background. In the mysql client, the SSL command option:

o --ssl-ca identifies the Certificate Authority (CA) certificate, which can be used by the client to authenticate the server certificate.
o --ssl-cert identifies the client public key certificate, which can be used by the server to authenticate the server certificate.
o --ssl-key identifies the client private key, which can be used by the client to let the server know that the client owns the certificate.

Much like any browser, the mysql client does not need have any certificate in order to establish a simple SSL connection with a server. Only the server needs a public key certificate. Client-side certificates are only needed if the client wants to authenticate the server certificate, or if the server wants to authenticate a client certificate.
[19 Oct 2011 11:22] Davi Arnaut
Some clarifications on the suggested fix:

> For one, validate the value of --ssl-key.

If a certificate is loaded with --ssl-cert, the consistency of the private key is checked with the corresponding loaded certificate. If no certificate is specified, any given key is simply ignored.

> For two, reject connections with incorrect values for --ssl-key.

Certificate check/verification will fail if the value is incorrect.

> For three, reject connections with only --ssl-key set, if this is not correct (note this
> is not correct according to the manual, or update manual if it is allowed).

It's up to you to configure the server if you want the client to have a certificate.
[19 Oct 2011 13:55] Chris Calender
I love how it seems not a single person has even tested this.  People just want to keep spewing so-called facts about SSL.

Well, if this is all the case, then something needs fixed, and not just the documentation.  Just test it.

You keep saying no one needs to specify any option.  If I do not need to specify any options (according to you), then why must I?

Test it:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430
ERROR 1045 (28000): Access denied for user 'ssluser'@'localhost' (using password: YES)

Now add some bogus crap:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-key=crap
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.16-log MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

How is that not a bug!  Get real.

It's ridiculous people keep wanting to defend something they haven't even tested nor verified.  Why don't you give that a go for once, instead of trying to be a right-fighter, defending your inaccurate point, and fix it instead of trying to side-step the issue?
[19 Oct 2011 15:15] Davi Arnaut
> C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430
> ERROR 1045 (28000): Access denied for user 'ssluser'@'localhost' (using password: YES)

This does not activate SSL on the client, so access is denied.

> C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-key=crap
> Welcome to the MySQL monitor.  Commands end with ; or \g.

Although --ssl-key is ignored, the option implies --ssl as documented. This is equivalent to:

mysql -ussluser -pssluser -P3430 --ssl

> How is that not a bug!  Get real.

It is not a bug because it is possible to establish a SSL connection.

> It's ridiculous people keep wanting to defend something they haven't even tested nor
> verified.

Indeed, I haven't tested nor verified any of this. It's just based on my knowledge of how it works.

> Why don't you give that a go for once, instead of trying to be a right-fighter,
> defending your inaccurate point, and fix it instead of trying to side-step
> the issue?

I don't need to give it a go in order to point ou that the assumptions are wrong.
[19 Oct 2011 15:30] Davi Arnaut
davi@skynet:~/mysql/repo/stage/mysql-5.5$ client/mysql --help
client/mysql  Ver 14.14 Distrib 5.5.17, for Linux (x86_64) using readline 5.1
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

[..]

  --ssl               Enable SSL for connection (automatically enabled with
                      other flags).
  --ssl-ca=name       CA file in PEM format (check OpenSSL docs, implies
                      --ssl).
  --ssl-capath=name   CA directory (check OpenSSL docs, implies --ssl).
  --ssl-cert=name     X509 cert in PEM format (implies --ssl).
  --ssl-cipher=name   SSL cipher to use (implies --ssl).
  --ssl-key=name      X509 key in PEM format (implies --ssl).

If none of the --ssl options are given, SSL is not used. If any of the SSL options are given, SSL is used.
[19 Oct 2011 22:57] Chris Calender
Hi Davi,

I appreciate your comments and insight, and I agree, the manual is very lacking (and incorrect) in the SSL department.  It needs a complete overhaul, imho.

However, I disagree with one of your major points.

You said this (first command was mine):

> > C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-key=crap
> 
> Although --ssl-key is ignored, the option implies --ssl as documented. This is equivalent to:
> 
> mysql -ussluser -pssluser -P3430 --ssl

Well, I thought I'd spend the 3 minutes it took to *test* this out, and it is not the same, because it *does not* work.  See below, where I tried with --ssl, --ssl=1, and then you see it works with --ssl-key=1234:

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl
ERROR 1045 (28000): Access denied for user 'ssluser'@'localhost' (using password: YES)

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl=1
ERROR 1045 (28000): Access denied for user 'ssluser'@'localhost' (using password: YES)

C:\Program Files\MySQL\mysql-5.5.16\bin>mysql -ussluser -pssluser -P3430 --ssl-key=1234
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.5.16-log MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> exit
Bye

Somewhere there is a bug, and not just a documentation bug.
[19 Oct 2011 23:11] Davi Arnaut
> Somewhere there is a bug, and not just a documentation bug.

MySQL client code:

  if (opt_use_ssl)
    mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
                  opt_ssl_capath, opt_ssl_cipher);

MySQL client library code:

#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
  if (mysql->options.ssl_key || mysql->options.ssl_cert ||
      mysql->options.ssl_ca || mysql->options.ssl_capath ||
      mysql->options.ssl_cipher)
    mysql->options.use_ssl= 1;
  if (mysql->options.use_ssl)
    mysql->client_flag|= CLIENT_SSL;
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/

So, in the clients (e.g. mysql, mysqladmin, etc), –ssl only specifies that the SSL options should be set (using mysql_ssl_set). Whether SSL is really used only happens if one of the -ssl-* options is set.

Whatever garbage is fed to –ssl-key makes “use SSL” be activated even though the key is ignored.
[19 Oct 2011 23:15] Chris Calender
Well, the --ssl option says "Enable SSL for connection (automatically enabled with other flags)."

This is not the case, as it does not enable SSL for the connection, as evidenced by the tests.
[19 Oct 2011 23:22] Davi Arnaut
This can be confirmed with something like:

mysql -u user --ssl-cipher=AES128-SHA:foobar

--ssl-key is the only option that in some cases is completely ignored.
[19 Oct 2011 23:23] Davi Arnaut
> Well, the --ssl option says "Enable SSL for connection (automatically enabled with other
> flags)."
> 
> This is not the case, as it does not enable SSL for the connection, as evidenced by the
> tests.

Yeah, agree. That's a bug.
[26 Dec 2011 17:23] Sveta Smirnova
Thank you for the report.

Verified as described.
[2 May 2012 16:32] Pietro Cerutti
I suggest the attached patch.
[2 May 2012 16:33] Pietro Cerutti
Patch usage of ssl parameters

Attachment: client.c.diff (text/x-patch), 761 bytes.

[8 Jul 2012 4:11] Stefan Wrobel
Just stumbled across this bug myself by mistyping the path to my SSL key ... astonished that this hasn't been squashed yet. PLEASE FIX!
[13 Aug 2012 16:03] Paul Dubois
Noted in 5.1.66, 5.5.28, 5.6.7, 5.7.0 changelogs.

The argument to the --ssl-key option was not verified to exist and be
a valid key. The resulting connection used SSL, but the key was not
used.
[15 Aug 2012 15:38] Paul Dubois
By the way, regarding the first sentence in the bug report:

"-ssl-key value is not validated and it allows insecure connections if specified."

It's correct that the --ssl-key value was not validated, thanks for pointing that out. But the connection was secure. You can see that from your examples where the SSL: line of "status" output that showed a cipher was used:

SSL:                    Cipher in use is DHE-RSA-AES256-SHA

This would have said "Not in use" if SSL was not used for the connection.
[16 Aug 2012 16:58] Graham Horner
I can't see that this is a serious bug.  The SSL specification allows encrypted connections without authentication and that's exactly what --ssl-key=blah does.

It's not intuitive: one would have thought --ssl on its own would be the obvious way to set up such a connection but there it is.

It's the documentation that wants a serious sort-out, not so much the code.