From: Tatjana Azundris Nuernberg Date: May 19 2011 9:48am Subject: bzr commit into mysql-5.5 branch (tatjana.nuernberg:3388) Bug#21287 Bug#11745920 List-Archive: http://lists.mysql.com/commits/137681 X-Bug: 21287,11745920 Message-Id: <201105190948.p4J9m9VW013336@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1640485670278754042==" --===============1640485670278754042== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/tnurnberg/forest/11745920/55-11745920/ based on revid:mayank.prasad@stripped 3388 Tatjana Azundris Nuernberg 2011-05-19 Bug#11745920/Bug#21287: "SSL connection error" is not helpful! (ssl-verify-server-cert=true vs localhos) SSL errors on client and now more specific to aid end-user with debugging. Also restructures error handling for compliance with SSL docs. @ include/violite.h new_VioSSLConnectorFd/sslaccept/sslconnect return more elaborate status @ libmysql/errmsg.c SSL errors now extended, more specific @ mysql-test/r/openssl_1.result SSL errors now extended, more specific @ sql-common/client.c Do more detailed error reporting for setup, connect, and server cert verifying phases. @ sql/sql_acl.cc sslaccept() signature has changed @ vio/viossl.c Save the error code and return it to callers of sslaccept and sslconnect. @ vio/viosslfactories.c new_VioSSLConnectorFd(): return error code to caller modified: include/violite.h libmysql/errmsg.c mysql-test/r/openssl_1.result sql-common/client.c sql/sql_acl.cc vio/test-ssl.c vio/test-sslclient.c vio/test-sslserver.c vio/viossl.c vio/viosslfactories.c vio/viotest-ssl.c === modified file 'include/violite.h' --- a/include/violite.h 2011-04-08 10:23:36 +0000 +++ b/include/violite.h 2011-05-19 09:47:43 +0000 @@ -134,13 +134,13 @@ struct st_VioSSLFd SSL_CTX *ssl_context; }; -int sslaccept(struct st_VioSSLFd*, Vio *, long timeout); -int sslconnect(struct st_VioSSLFd*, Vio *, long timeout); +int sslaccept(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr); +int sslconnect(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr); struct st_VioSSLFd *new_VioSSLConnectorFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, - const char *cipher); + const char *cipher, enum enum_ssl_init_error* error); struct st_VioSSLFd *new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, const char *ca_file,const char *ca_path, === modified file 'libmysql/errmsg.c' --- a/libmysql/errmsg.c 2011-03-08 17:39:25 +0000 +++ b/libmysql/errmsg.c 2011-05-19 09:47:43 +0000 @@ -51,7 +51,7 @@ const char *client_errors[]= "Error on SHOW SLAVE HOSTS:", "Error connecting to slave:", "Error connecting to master:", - "SSL connection error", + "SSL connection error: %-.100s", "Malformed packet", "This client library is licensed only for use with MySQL servers having '%s' license", "Invalid use of null pointer", === modified file 'mysql-test/r/openssl_1.result' --- a/mysql-test/r/openssl_1.result 2010-01-29 14:54:27 +0000 +++ b/mysql-test/r/openssl_1.result 2011-05-19 09:47:43 +0000 @@ -44,13 +44,13 @@ ERROR 42000: DELETE command denied to us drop user ssl_user1@localhost, ssl_user2@localhost, ssl_user3@localhost, ssl_user4@localhost, ssl_user5@localhost; drop table t1; -mysqltest: Could not open connection 'default': 2026 SSL connection error -mysqltest: Could not open connection 'default': 2026 SSL connection error -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: ASN: bad other signature confirmation +mysqltest: Could not open connection 'default': 2026 SSL connection error: ASN: bad other signature confirmation +mysqltest: Could not open connection 'default': 2026 SSL connection error: ASN: bad other signature confirmation SSL error: Unable to get private key from '' -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: Unable to get private key SSL error: Unable to get certificate from '' -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: Unable to get certificate SHOW STATUS LIKE 'Ssl_cipher'; Variable_name Value Ssl_cipher DHE-RSA-AES256-SHA @@ -83,7 +83,7 @@ Ssl_cipher AES128-SHA SHOW STATUS LIKE 'Ssl_cipher'; Variable_name Value Ssl_cipher AES128-SHA -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: SSL_CTX_new failed CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); @@ -189,7 +189,7 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; SSL error: Unable to get private key from 'MYSQL_TEST_DIR/std_data/client-cert.pem' -mysqldump: Got error: 2026: SSL connection error when trying to connect +mysqldump: Got error: 2026: SSL connection error: Unable to get private key when trying to connect DROP TABLE t1; Variable_name Value Ssl_cipher DHE-RSA-AES256-SHA === modified file 'sql-common/client.c' --- a/sql-common/client.c 2011-04-28 19:17:29 +0000 +++ b/sql-common/client.c 2011-05-19 09:47:43 +0000 @@ -1840,6 +1840,8 @@ mysql_get_ssl_cipher(MYSQL *mysql __attr ssl_verify_server_cert() vio pointer to a SSL connected vio server_hostname name of the server that we connected to + errptr if we fail, we'll return (a pointer to a string + describing) the reason here RETURN VALUES 0 Success @@ -1849,7 +1851,7 @@ mysql_get_ssl_cipher(MYSQL *mysql __attr #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) -static int ssl_verify_server_cert(Vio *vio, const char* server_hostname) +static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr) { SSL *ssl; X509 *server_cert; @@ -1860,19 +1862,19 @@ static int ssl_verify_server_cert(Vio *v if (!(ssl= (SSL*)vio->ssl_arg)) { - DBUG_PRINT("error", ("No SSL pointer found")); + *errptr= "No SSL pointer found"; DBUG_RETURN(1); } if (!server_hostname) { - DBUG_PRINT("error", ("No server hostname supplied")); + *errptr= "No server hostname supplied"; DBUG_RETURN(1); } if (!(server_cert= SSL_get_peer_certificate(ssl))) { - DBUG_PRINT("error", ("Could not get server certificate")); + *errptr= "Could not get server certificate"; DBUG_RETURN(1); } @@ -1901,7 +1903,7 @@ static int ssl_verify_server_cert(Vio *v DBUG_RETURN(0); } } - DBUG_PRINT("error", ("SSL certificate validation failure")); + *errptr= "SSL certificate validation failure"; DBUG_RETURN(1); } @@ -2507,6 +2509,9 @@ static int send_client_reply_packet(MCPV /* Do the SSL layering. */ struct st_mysql_options *options= &mysql->options; struct st_VioSSLFd *ssl_fd; + enum enum_ssl_init_error ssl_init_error; + const char *cert_error; + unsigned long ssl_error; /* Send mysql->client_flag, max_packet_size - unencrypted otherwise @@ -2526,9 +2531,11 @@ static int send_client_reply_packet(MCPV options->ssl_cert, options->ssl_ca, options->ssl_capath, - options->ssl_cipher))) + options->ssl_cipher, + &ssl_init_error))) { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error)); goto error; } mysql->connector_fd= (unsigned char *) ssl_fd; @@ -2536,18 +2543,24 @@ static int send_client_reply_packet(MCPV /* Connect to the server */ DBUG_PRINT("info", ("IO layer change in progress...")); if (sslconnect(ssl_fd, net->vio, - (long) (mysql->options.connect_timeout))) + (long) (mysql->options.connect_timeout), &ssl_error)) { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + char buf[512]; + ERR_error_string_n(ssl_error, buf, 512); + buf[511]= 0; + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), + buf); goto error; } DBUG_PRINT("info", ("IO layer change done!")); /* Verify server cert */ if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && - ssl_verify_server_cert(net->vio, mysql->host)) + ssl_verify_server_cert(net->vio, mysql->host, &cert_error)) { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), cert_error); goto error; } } === modified file 'sql/sql_acl.cc' --- a/sql/sql_acl.cc 2011-05-16 08:50:42 +0000 +++ b/sql/sql_acl.cc 2011-05-19 09:47:43 +0000 @@ -8528,14 +8528,14 @@ static ulong parse_client_handshake_pack DBUG_PRINT("info", ("client capabilities: %lu", mpvio->client_capabilities)); if (mpvio->client_capabilities & CLIENT_SSL) { - char error_string[1024] __attribute__((unused)); + unsigned long errptr; /* Do the SSL layering. */ if (!ssl_acceptor_fd) return packet_error; DBUG_PRINT("info", ("IO layer change in progress...")); - if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) + if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, &errptr)) { DBUG_PRINT("error", ("Failed to accept new SSL connection")); return packet_error; === modified file 'vio/test-ssl.c' --- a/vio/test-ssl.c 2010-07-15 11:13:30 +0000 +++ b/vio/test-ssl.c 2011-05-19 09:47:43 +0000 @@ -59,6 +59,9 @@ main(int argc, char** argv) struct st_VioSSLFd* ssl_acceptor= 0; struct st_VioSSLFd* ssl_connector= 0; Vio* client_vio=0, *server_vio=0; + enum enum_ssl_init_error ssl_init_error; + unsigned long ssl_error; + MY_INIT(argv[0]); DBUG_PROCESS(argv[0]); DBUG_PUSH(default_dbug_option); @@ -91,16 +94,16 @@ main(int argc, char** argv) ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path, cipher); ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, - ca_path, cipher); + ca_path, cipher, &ssl_init_error); client_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0)); client_vio->sd = sv[0]; client_vio->vioblocking(client_vio, 0, &unused); - sslconnect(ssl_connector,client_vio,60L); + sslconnect(ssl_connector,client_vio,60L,&ssl_error); server_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0)); server_vio->sd = sv[1]; server_vio->vioblocking(client_vio, 0, &unused); - sslaccept(ssl_acceptor,server_vio,60L); + sslaccept(ssl_acceptor,server_vio,60L, &ssl_error); printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd); === modified file 'vio/test-sslclient.c' --- a/vio/test-sslclient.c 2010-07-08 21:20:08 +0000 +++ b/vio/test-sslclient.c 2011-05-19 09:47:43 +0000 @@ -50,6 +50,9 @@ main( int argc __attribute__((unused)), Vio* client_vio=0; int err; char xbuf[100]="Ohohhhhoh1234"; + enum enum_ssl_init_error ssl_init_error; + unsigned long ssl_error; + MY_INIT(argv[0]); DBUG_PROCESS(argv[0]); DBUG_PUSH(default_dbug_option); @@ -60,7 +63,8 @@ main( int argc __attribute__((unused)), if (ca_path!=0) printf("CApath : %s\n", ca_path); - ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path, cipher); + ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path, cipher, + &ssl_init_error); if(!ssl_connector) { fatal_error("client:new_VioSSLConnectorFd failed"); } @@ -81,7 +85,7 @@ main( int argc __attribute__((unused)), /* ----------------------------------------------- */ /* Now we have TCP conncetion. Start SSL negotiation. */ read(client_vio->sd,xbuf, sizeof(xbuf)); - sslconnect(ssl_connector,client_vio,60L); + sslconnect(ssl_connector,client_vio,60L,&ssl_error); err = vio_read(client_vio,xbuf, sizeof(xbuf)); if (err<=0) { my_free(ssl_connector); === modified file 'vio/test-sslserver.c' --- a/vio/test-sslserver.c 2010-07-08 21:20:08 +0000 +++ b/vio/test-sslserver.c 2011-05-19 09:47:43 +0000 @@ -52,6 +52,7 @@ do_ssl_stuff( TH_ARGS* args) const char* s = "Huhuhuhuuu"; Vio* server_vio; int err; + unsigned long ssl_error; DBUG_ENTER("do_ssl_stuff"); server_vio = vio_new(args->sd, VIO_TYPE_TCPIP, TRUE); @@ -60,7 +61,7 @@ do_ssl_stuff( TH_ARGS* args) /* TCP connection is ready. Do server side SSL. */ err = write(server_vio->sd,(uchar*)s, strlen(s)); - sslaccept(args->ssl_acceptor,server_vio,60L); + sslaccept(args->ssl_acceptor,server_vio,60L,&ssl_error); err = server_vio->write(server_vio,(uchar*)s, strlen(s)); DBUG_VOID_RETURN; } === modified file 'vio/viossl.c' --- a/vio/viossl.c 2010-08-16 12:50:27 +0000 +++ b/vio/viossl.c 2011-05-19 09:47:43 +0000 @@ -144,8 +144,9 @@ void vio_ssl_delete(Vio *vio) static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout, - int (*connect_accept_func)(SSL*)) + int (*connect_accept_func)(SSL*), unsigned long *errptr) { + int r; SSL *ssl; my_bool unused; my_bool was_blocking; @@ -160,7 +161,7 @@ static int ssl_do(struct st_VioSSLFd *pt if (!(ssl= SSL_new(ptr->ssl_context))) { DBUG_PRINT("error", ("SSL_new failure")); - report_errors(ssl); + *errptr= ERR_get_error(); vio_blocking(vio, was_blocking, &unused); DBUG_RETURN(1); } @@ -169,10 +170,10 @@ static int ssl_do(struct st_VioSSLFd *pt SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout); SSL_set_fd(ssl, vio->sd); - if (connect_accept_func(ssl) < 1) + if ((r= connect_accept_func(ssl)) < 1) { DBUG_PRINT("error", ("SSL_connect/accept failure")); - report_errors(ssl); + *errptr= SSL_get_error(ssl, r); SSL_free(ssl); vio_blocking(vio, was_blocking, &unused); DBUG_RETURN(1); @@ -220,17 +221,17 @@ static int ssl_do(struct st_VioSSLFd *pt } -int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout) +int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout, unsigned long *errptr) { DBUG_ENTER("sslaccept"); - DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept)); + DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept, errptr)); } -int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout) +int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout, unsigned long *errptr) { DBUG_ENTER("sslconnect"); - DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect)); + DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect, errptr)); } === modified file 'vio/viosslfactories.c' --- a/vio/viosslfactories.c 2010-07-15 11:13:30 +0000 +++ b/vio/viosslfactories.c 2011-05-19 09:47:43 +0000 @@ -165,7 +165,7 @@ static struct st_VioSSLFd * new_VioSSLFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, const char *cipher, SSL_METHOD *method, - enum enum_ssl_init_error* error) + enum enum_ssl_init_error *error) { DH *dh; struct st_VioSSLFd *ssl_fd; @@ -249,11 +249,10 @@ new_VioSSLFd(const char *key_file, const struct st_VioSSLFd * new_VioSSLConnectorFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, - const char *cipher) + const char *cipher, enum enum_ssl_init_error* error) { struct st_VioSSLFd *ssl_fd; int verify= SSL_VERIFY_PEER; - enum enum_ssl_init_error dummy; /* Turn off verification of servers certificate if both @@ -263,7 +262,7 @@ new_VioSSLConnectorFd(const char *key_fi verify= SSL_VERIFY_NONE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_client_method(), &dummy))) + ca_path, cipher, TLSv1_client_method(), error))) { return 0; } === modified file 'vio/viotest-ssl.c' --- a/vio/viotest-ssl.c 2010-07-08 21:20:08 +0000 +++ b/vio/viotest-ssl.c 2011-05-19 09:47:43 +0000 @@ -60,6 +60,9 @@ int main(int argc, char **argv) struct st_VioSSLConnectorFd* ssl_connector=0; Vio* client_vio=0; Vio* server_vio=0; + enum enum_ssl_init_error ssl_init_error; + unsigned long ssl_error; + MY_INIT(argv[0]); DBUG_PROCESS(argv[0]); DBUG_PUSH(default_dbug_option); @@ -92,14 +95,14 @@ int main(int argc, char **argv) ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path); ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, - ca_path); + ca_path, &ssl_init_error); client_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0)); client_vio->sd = sv[0]; - sslconnect(ssl_connector,client_vio); + sslconnect(ssl_connector,client_vio,&ssl_error); server_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0)); server_vio->sd = sv[1]; - sslaccept(ssl_acceptor,server_vio); + sslaccept(ssl_acceptor,server_vio,&ssl_error); printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd); --===============1640485670278754042== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tatjana.nuernberg@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tatjana.nuernberg@stripped\ # hpodt7s4qcfz924l # target_branch: file:///Users/tnurnberg/forest/11745920/55-11745920/ # testament_sha1: 410ebe9eb2f95918d1ca505af237da84540c0eee # timestamp: 2011-05-19 10:48:03 +0100 # base_revision_id: mayank.prasad@stripped\ # 925a2e76elxudi4r # # Begin bundle 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 --===============1640485670278754042==--