]> granicus.if.org Git - php/commitdiff
Add SHA256 authentication support - password hashing to mysqlnd
authorandrey <andrey@php.net>
Tue, 25 Sep 2012 12:04:36 +0000 (14:04 +0200)
committerandrey <andrey@php.net>
Tue, 25 Sep 2012 12:04:36 +0000 (14:04 +0200)
Automatic switchover to SSL with plain-text password is not part of this

ext/mysqli/mysqli_nonapi.c
ext/mysqlnd/config9.m4
ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd.h
ext/mysqlnd/mysqlnd_auth.c
ext/mysqlnd/mysqlnd_enum_n_def.h
ext/mysqlnd/mysqlnd_structs.h
ext/mysqlnd/mysqlnd_wireprotocol.c
ext/mysqlnd/mysqlnd_wireprotocol.h
ext/mysqlnd/php_mysqlnd.c

index 5e9c01378a2a18c5e7707af30bdd0f79d9a43be2..2b6a1af0edfd0184d207cfccb46770779206741a 100644 (file)
@@ -728,7 +728,7 @@ static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, z
        int ret = 0;
 
        ALLOC_HASHTABLE(new_hash);
-       zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(in_zval_array)), NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_init(new_hash, in_zval_array? zend_hash_num_elements(Z_ARRVAL_P(in_zval_array)):0, NULL, ZVAL_PTR_DTOR, 0);
        if (in_array) {
                for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(in_zval_array));
                         zend_hash_get_current_data(Z_ARRVAL_P(in_zval_array), (void **) &elem) == SUCCESS;
index 2c15c34e8d39c44242f04dd696b011f445ed2853..3fc767b231d68da7edf78f3e2adbd6357d6271ff 100644 (file)
@@ -28,7 +28,17 @@ if test "$PHP_MYSQLND" != "no" || test "$PHP_MYSQLND_ENABLED" = "yes"; then
   if test "$PHP_MYSQLND_COMPRESSION_SUPPORT" != "no"; then
     AC_DEFINE([MYSQLND_COMPRESSION_WANTED], 1, [Enable compressed protocol support])
   fi
-  AC_DEFINE([MYSQLND_SSL_SUPPORTED], 1, [Enable SSL support])
+
+  AC_DEFINE([MYSQLND_SSL_SUPPORTED], 1, [Enable core mysqlnd SSL code])
+
+  test -z "$PHP_OPENSSL" && PHP_OPENSSL=no
+
+  if test "$PHP_OPENSSL" != "no" || test "$PHP_OPENSSL_DIR" != "no"; then
+    AC_CHECK_LIB(ssl, DSA_get_default_method, AC_DEFINE(HAVE_DSA_DEFAULT_METHOD, 1, [OpenSSL 0.9.7 or later]))
+    AC_CHECK_LIB(crypto, X509_free, AC_DEFINE(HAVE_DSA_DEFAULT_METHOD, 1, [OpenSSL 0.9.7 or later]))
+
+    PHP_SETUP_OPENSSL(MYSQLND_SHARED_LIBADD, [AC_DEFINE(MYSQLND_HAVE_SSL,1,[Enable mysqlnd code that uses OpenSSL directly])])
+  fi
 
   mysqlnd_sources="$mysqlnd_base_sources $mysqlnd_ps_sources"
   PHP_NEW_EXTENSION(mysqlnd, $mysqlnd_sources, $ext_shared)
index d7462f77a54b6d4a3ce114c07e60cf4d3c3537c7..f7f3245a2c42d54d1c6a08fc61d707bcd9ee922e 100644 (file)
@@ -581,12 +581,14 @@ mysqlnd_run_authentication(
                        }
                        memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
 
-                       DBG_INF_FMT("salt=[%*.s]", plugin_data_len - 1, plugin_data);
+                       DBG_INF_FMT("salt(%d)=[%.*s]", plugin_data_len, plugin_data_len, plugin_data);
                        /* The data should be allocated with malloc() */
                        scrambled_data =
                                auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
-                                                                                                  plugin_data, plugin_data_len, options, mysql_flags TSRMLS_CC);
-
+                                                                                                  plugin_data, plugin_data_len, options, &conn->net->data->options, mysql_flags TSRMLS_CC);
+                       if (!scrambled_data || conn->error_info->error_no) {
+                               goto end;                       
+                       }
                        if (FALSE == is_change_user) {
                                ret = mysqlnd_auth_handshake(conn, user, passwd, passwd_len, db, db_len, options, mysql_flags,
                                                                                        charset_no,
@@ -1334,13 +1336,12 @@ _mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long s
                DBG_RETURN(FAIL);
        }
 
-       *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array TSRMLS_CC);
-
        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
        FD_ZERO(&efds);
 
        if (r_array != NULL) {
+               *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array TSRMLS_CC);
                set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
                if (set_count > max_set_count) {
                        max_set_count = set_count;
index 30d425780236e07d9152da5ce61d702b7002e918..b0db48f5f71b45623b2b6aed210dd5b2464d06c4 100644 (file)
@@ -277,6 +277,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqlnd)
        long                    debug_malloc_fail_threshold;
        long                    debug_calloc_fail_threshold;
        long                    debug_realloc_fail_threshold;
+       char *                  sha256_server_public_key;
 ZEND_END_MODULE_GLOBALS(mysqlnd)
 
 PHPAPI ZEND_EXTERN_MODULE_GLOBALS(mysqlnd)
index 10c932a9683c38cc1b18625bc55919a9763c7c42..295b6a338bb28ff055252394e22f1fefd07f1312 100644 (file)
@@ -360,7 +360,9 @@ mysqlnd_native_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self
                                                                  size_t * auth_data_len,
                                                                  MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd,
                                                                  const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
-                                                                 const MYSQLND_OPTIONS * const options, unsigned long mysql_flags
+                                                                 const MYSQLND_OPTIONS * const options,
+                                                                 const MYSQLND_NET_OPTIONS * const net_options,
+                                                                 unsigned long mysql_flags
                                                                  TSRMLS_DC)
 {
        zend_uchar * ret = NULL;
@@ -418,7 +420,9 @@ mysqlnd_pam_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
                                                           size_t * auth_data_len,
                                                           MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd,
                                                           const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
-                                                          const MYSQLND_OPTIONS * const options, unsigned long mysql_flags
+                                                          const MYSQLND_OPTIONS * const options,
+                                                          const MYSQLND_NET_OPTIONS * const net_options,
+                                                          unsigned long mysql_flags
                                                           TSRMLS_DC)
 {
        zend_uchar * ret = NULL;
@@ -442,7 +446,7 @@ static struct st_mysqlnd_authentication_plugin mysqlnd_pam_authentication_plugin
                MYSQLND_VERSION_ID,
                MYSQLND_VERSION,
                "PHP License 3.01",
-               "Andrey Hristov <andrey@mysql.com>,  Ulf Wendel <uwendel@mysql.com>, Georg Richter <georg@mysql.com>",
+               "Andrey Hristov <andrey@php.net>,  Ulf Wendel <uw@php.net>, Georg Richter <georg@php.net>",
                {
                        NULL, /* no statistics , will be filled later if there are some */
                        NULL, /* no statistics */
@@ -457,12 +461,190 @@ static struct st_mysqlnd_authentication_plugin mysqlnd_pam_authentication_plugin
 };
 
 
+/******************************************* SHA256 Password ***********************************/
+#ifdef MYSQLND_HAVE_SSL
+static void
+mysqlnd_xor_string(char * dst, const size_t dst_len, const char * xor_str, const size_t xor_str_len)
+{
+       unsigned int i;
+       for (i = 0; i <= dst_len; ++i) {
+               dst[i] ^= xor_str[i % xor_str_len];
+       }
+}
+
+
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+
+/* {{{ mysqlnd_sha256_get_rsa_key */
+static RSA *
+mysqlnd_sha256_get_rsa_key(MYSQLND_CONN_DATA * conn,
+                                                  const MYSQLND_OPTIONS * const options,
+                                                  const MYSQLND_NET_OPTIONS * const net_options
+                                                  TSRMLS_DC)
+{
+       RSA * ret = NULL;
+       int len;
+       const char * fname = (net_options->sha256_server_public_key && net_options->sha256_server_public_key[0] != '\0')? 
+                                                               net_options->sha256_server_public_key:
+                                                               MYSQLND_G(sha256_server_public_key);
+       php_stream * stream;
+       DBG_ENTER("mysqlnd_sha256_get_rsa_key");
+
+       if (!fname || fname[0] == '\0') {
+               MYSQLND_PACKET_SHA256_PK_REQUEST * pk_req_packet = NULL;
+               MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * pk_resp_packet = NULL;
+
+               do {
+                       DBG_INF("requesting the public key from the server");
+                       pk_req_packet = conn->protocol->m.get_sha256_pk_request_packet(conn->protocol, FALSE TSRMLS_CC);
+                       if (!pk_req_packet) {
+                               SET_OOM_ERROR(*conn->error_info);
+                               break;
+                       }
+                       pk_resp_packet = conn->protocol->m.get_sha256_pk_request_response_packet(conn->protocol, FALSE TSRMLS_CC);
+                       if (!pk_resp_packet) {
+                               SET_OOM_ERROR(*conn->error_info);
+                               PACKET_FREE(pk_req_packet);
+                               break;
+                       }
+
+                       if (! PACKET_WRITE(pk_req_packet, conn)) {
+                               DBG_ERR_FMT("Error while sending public key request packet");
+                               php_error(E_WARNING, "Error while sending public key request packet. PID=%d", getpid());
+                               CONN_SET_STATE(conn, CONN_QUIT_SENT);
+                               break;
+                       }
+                       if (FAIL == PACKET_READ(pk_resp_packet, conn) || NULL == pk_resp_packet->public_key) {
+                               DBG_ERR_FMT("Error while receiving public key");
+                               php_error(E_WARNING, "Error while receiving public key. PID=%d", getpid());
+                               CONN_SET_STATE(conn, CONN_QUIT_SENT);
+                               break;
+                       }
+                       DBG_INF_FMT("Public key(%d):\n%s", pk_resp_packet->public_key_len, pk_resp_packet->public_key);
+                       /* now extract the public key */
+                       {
+                               BIO * bio = BIO_new_mem_buf(pk_resp_packet->public_key, pk_resp_packet->public_key_len);
+                               ret = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
+                               BIO_free(bio);
+                       }
+               } while (0);
+               PACKET_FREE(pk_req_packet);
+               PACKET_FREE(pk_resp_packet);
+
+               DBG_INF_FMT("ret=%p", ret);
+               DBG_RETURN(ret);
+       
+               SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE,
+                       "sha256_server_public_key is not set for the connection or as mysqlnd.sha256_server_public_key");
+               DBG_ERR("server_public_key is not set");
+               DBG_RETURN(NULL);
+       } else {
+               char * key_str = NULL;
+               stream = php_stream_open_wrapper((char *) fname, "rb", REPORT_ERRORS, NULL);
+
+               if (stream) {
+                       if ((len = php_stream_copy_to_mem(stream, &key_str, PHP_STREAM_COPY_ALL, 0)) >= 0 ) {
+                               BIO * bio = BIO_new_mem_buf(key_str, len);
+                               ret = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
+                               BIO_free(bio);
+                       }
+                       if (key_str) {
+                               DBG_INF_FMT("Public key:%*.s", len, key_str);
+                               efree(key_str);
+                       }
+               }
+               php_stream_free(stream, PHP_STREAM_FREE_CLOSE);
+       }
+       DBG_RETURN(ret)
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_sha256_auth_get_auth_data */
+static zend_uchar *
+mysqlnd_sha256_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
+                                                                 size_t * auth_data_len,
+                                                                 MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd,
+                                                                 const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
+                                                                 const MYSQLND_OPTIONS * const options,
+                                                                 const MYSQLND_NET_OPTIONS * const net_options,
+                                                                 unsigned long mysql_flags
+                                                                 TSRMLS_DC)
+{
+       RSA * server_public_key;
+       zend_uchar * ret = NULL;
+       DBG_ENTER("mysqlnd_sha256_auth_get_auth_data");
+       DBG_INF_FMT("salt(%d)=[%.*s]", auth_plugin_data_len, auth_plugin_data_len, auth_plugin_data);
+
+       *auth_data_len = 0;
+
+       server_public_key = mysqlnd_sha256_get_rsa_key(conn, options, net_options TSRMLS_CC);
+
+       if (server_public_key) {
+               int server_public_key_len;
+               char xor_str[passwd_len + 1];
+               memcpy(xor_str, passwd, passwd_len);
+               xor_str[passwd_len] = '\0';
+               mysqlnd_xor_string(xor_str, passwd_len, (char *) auth_plugin_data, auth_plugin_data_len);
+
+               server_public_key_len = RSA_size(server_public_key);
+               /*
+                 Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
+                 RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
+                 http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
+               */
+               if ((size_t) server_public_key_len - 41 <= passwd_len) {
+                       /* password message is to long */
+                       SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "password is too long");
+                       DBG_ERR("password is too long");
+                       DBG_RETURN(NULL);
+               }
+
+               *auth_data_len = server_public_key_len;
+               ret = malloc(*auth_data_len);
+               RSA_public_encrypt(passwd_len + 1, (zend_uchar *) xor_str, ret, server_public_key, RSA_PKCS1_OAEP_PADDING);
+       }
+
+       DBG_RETURN(ret);
+}
+/* }}} */
+
+
+static struct st_mysqlnd_authentication_plugin mysqlnd_sha256_authentication_plugin =
+{
+       {
+               MYSQLND_PLUGIN_API_VERSION,
+               "auth_plugin_sha256_password",
+               MYSQLND_VERSION_ID,
+               MYSQLND_VERSION,
+               "PHP License 3.01",
+               "Andrey Hristov <andrey@mysql.com>,  Ulf Wendel <uwendel@mysql.com>",
+               {
+                       NULL, /* no statistics , will be filled later if there are some */
+                       NULL, /* no statistics */
+               },
+               {
+                       NULL /* plugin shutdown */
+               }
+       },
+       {/* methods */
+               mysqlnd_sha256_auth_get_auth_data
+       }
+};
+#endif
+
 /* {{{ mysqlnd_register_builtin_authentication_plugins */
 void
 mysqlnd_register_builtin_authentication_plugins(TSRMLS_D)
 {
        mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_native_auth_plugin TSRMLS_CC);
        mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_pam_authentication_plugin TSRMLS_CC);
+#ifdef MYSQLND_HAVE_SSL
+       mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_sha256_authentication_plugin TSRMLS_CC);
+#endif
 }
 /* }}} */
 
index c8daa0c79bf58cc38a1c0da831affe52295e12e5..60e53b3c60b4dbf6034d6a7e91eb677514b1db0b 100644 (file)
@@ -166,6 +166,7 @@ typedef enum mysqlnd_option
        MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
        MYSQL_PLUGIN_DIR,
        MYSQL_DEFAULT_AUTH,
+       MYSQL_SERVER_PUBLIC_KEY,
 #if MYSQLND_UNICODE
        MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE = 200,
 #endif
@@ -537,6 +538,8 @@ enum mysqlnd_packet_type
        PROT_STATS_PACKET,
        PROT_PREPARE_RESP_PACKET,
        PROT_CHG_USER_RESP_PACKET,
+       PROT_SHA256_PK_REQUEST_PACKET,
+       PROT_SHA256_PK_REQUEST_RESPONSE_PACKET,
        PROT_LAST /* should always be last */
 };
 
index 856ebd2ead9aab8e60e5863ed5637c77df41e553..511a168b564976c8c24577807d853a0898513ef4 100644 (file)
@@ -207,6 +207,13 @@ typedef struct st_mysqlnd_net_options
        char            *ssl_passphrase;
        zend_bool       ssl_verify_peer;
        uint64_t        flags;
+
+       char *          sha256_server_public_key;
+
+       char *          unused1;
+       char *          unused2;
+       char *          unused3;
+       char *          unused4;
 } MYSQLND_NET_OPTIONS;
 
 
@@ -341,6 +348,8 @@ struct st_mysqlnd_packet_stats;
 struct st_mysqlnd_packet_prepare_response;
 struct st_mysqlnd_packet_chg_user_resp;
 struct st_mysqlnd_packet_auth_pam;
+struct st_mysqlnd_packet_sha256_pk_request;
+struct st_mysqlnd_packet_sha256_pk_request_response;
 
 typedef struct st_mysqlnd_packet_greet *               (*func_mysqlnd_protocol__get_greet_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_auth *                        (*func_mysqlnd_protocol__get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
@@ -355,6 +364,8 @@ typedef struct st_mysqlnd_packet_row *                      (*func_mysqlnd_protocol__get_row_packet
 typedef struct st_mysqlnd_packet_stats *               (*func_mysqlnd_protocol__get_stats_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_prepare_response *(*func_mysqlnd_protocol__get_prepare_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_chg_user_resp*(*func_mysqlnd_protocol__get_change_user_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
+typedef struct st_mysqlnd_packet_sha256_pk_request *(*func_mysqlnd_protocol__get_sha256_pk_request_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
+typedef struct st_mysqlnd_packet_sha256_pk_request_response *(*func_mysqlnd_protocol__get_sha256_pk_request_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 
 struct st_mysqlnd_protocol_methods
 {
@@ -371,12 +382,12 @@ struct st_mysqlnd_protocol_methods
        func_mysqlnd_protocol__get_stats_packet get_stats_packet;
        func_mysqlnd_protocol__get_prepare_response_packet get_prepare_response_packet;
        func_mysqlnd_protocol__get_change_user_response_packet get_change_user_response_packet;
+       func_mysqlnd_protocol__get_sha256_pk_request_packet get_sha256_pk_request_packet;
+       func_mysqlnd_protocol__get_sha256_pk_request_response_packet get_sha256_pk_request_response_packet;
 
        void * unused1;
        void * unused2;
        void * unused3;
-       void * unused4;
-       void * unused5;
 };
 
 
@@ -1098,7 +1109,8 @@ typedef zend_uchar * (*func_auth_plugin__get_auth_data)(struct st_mysqlnd_authen
                                                                                                                size_t * auth_data_len,
                                                                                                                MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd,
                                                                                                                const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
-                                                                                                               const MYSQLND_OPTIONS * const options, unsigned long mysql_flags
+                                                                                                               const MYSQLND_OPTIONS * const options, 
+                                                                                                               const MYSQLND_NET_OPTIONS * const net_options, unsigned long mysql_flags
                                                                                                                TSRMLS_DC);
 
 struct st_mysqlnd_authentication_plugin
index 3551c027cdf9ea6859ed953a390d69cf02f26e71..e41c771a8a0898f917754602e07ab4754fcf65a1 100644 (file)
@@ -623,7 +623,7 @@ php_mysqlnd_auth_response_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_D
                                memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
                        }
                        DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
-                       DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
+                       DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
                }
        } else {
                /* Everything was fine! */
@@ -2078,6 +2078,89 @@ php_mysqlnd_chg_user_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_
 /* }}} */
 
 
+/* {{{ php_mysqlnd_sha256_pk_request_write */
+static
+size_t php_mysqlnd_sha256_pk_request_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
+{
+       zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
+       size_t sent;
+
+       DBG_ENTER("php_mysqlnd_sha256_pk_request_write");
+
+       int1store(buffer + MYSQLND_HEADER_SIZE, '\1');
+       sent = conn->net->data->m.send_ex(conn->net, buffer, 1, conn->stats, conn->error_info TSRMLS_CC);
+
+       DBG_RETURN(sent);
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_sha256_pk_request_free_mem */
+static
+void php_mysqlnd_sha256_pk_request_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
+{
+       if (!stack_allocation) {
+               MYSQLND_PACKET_SHA256_PK_REQUEST * p = (MYSQLND_PACKET_SHA256_PK_REQUEST *) _packet;
+               mnd_pefree(p, p->header.persistent);
+       }
+}
+/* }}} */
+
+
+#define SHA256_PK_REQUEST_RESP_BUFFER_SIZE 2048
+
+/* {{{ php_mysqlnd_sha256_pk_request_response_read */
+static enum_func_status
+php_mysqlnd_sha256_pk_request_response_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
+{
+       zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
+       zend_uchar *p = buf;
+       zend_uchar *begin = buf;
+       MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * packet= (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
+
+       DBG_ENTER("php_mysqlnd_sha256_pk_request_response_read");
+
+       /* leave space for terminating safety \0 */
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET);
+       BAIL_IF_NO_MORE_DATA;
+
+       p++;
+       BAIL_IF_NO_MORE_DATA;
+
+       packet->public_key_len = packet->header.size - (p - buf);
+       packet->public_key = mnd_emalloc(packet->public_key_len + 1);
+       memcpy(packet->public_key, p, packet->public_key_len);
+       packet->public_key[packet->public_key_len] = '\0';
+
+       DBG_RETURN(PASS);
+
+premature_end:
+       DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
+       php_error_docref(NULL TSRMLS_CC, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
+                                        p - begin - packet->header.size);
+       DBG_RETURN(FAIL);
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_sha256_pk_request_response_free_mem */
+static void
+php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
+{
+       MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * p = (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
+       if (p->public_key) {
+               mnd_efree(p->public_key);
+               p->public_key = NULL;
+       }
+       p->public_key_len = 0;
+
+       if (!stack_allocation) {
+               mnd_pefree(p, p->header.persistent);
+       }
+}
+/* }}} */
+
+
 /* {{{ packet_methods */
 static
 mysqlnd_packet_methods packet_methods[PROT_LAST] =
@@ -2159,7 +2242,19 @@ mysqlnd_packet_methods packet_methods[PROT_LAST] =
                php_mysqlnd_chg_user_read, /* read */
                NULL, /* write */
                php_mysqlnd_chg_user_free_mem,
-       } /* PROT_CHG_USER_RESP_PACKET */
+       }, /* PROT_CHG_USER_RESP_PACKET */
+       {
+               sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST),
+               NULL, /* read */
+               php_mysqlnd_sha256_pk_request_write,
+               php_mysqlnd_sha256_pk_request_free_mem,
+       }, /* PROT_SHA256_PK_REQUEST_PACKET */
+       {
+               sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE),
+               php_mysqlnd_sha256_pk_request_response_read,
+               NULL, /* write */
+               php_mysqlnd_sha256_pk_request_response_free_mem,
+       } /* PROT_SHA256_PK_REQUEST_RESPONSE_PACKET */
 };
 /* }}} */
 
@@ -2359,6 +2454,37 @@ MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)(MYSQLND_PROTOC
 /* }}} */
 
 
+/* {{{ mysqlnd_protocol::get_sha256_pk_request_packet */
+static struct st_mysqlnd_packet_sha256_pk_request *
+MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
+{
+       struct st_mysqlnd_packet_sha256_pk_request * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_PACKET].struct_size, persistent);
+       DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_packet");
+       if (packet) {
+               packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_PACKET];
+               packet->header.persistent = persistent;
+       }
+       DBG_RETURN(packet);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_protocol::get_sha256_pk_request_response_packet */
+static struct st_mysqlnd_packet_sha256_pk_request_response *
+MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
+{
+       struct st_mysqlnd_packet_sha256_pk_request_response * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET].struct_size, persistent);
+       DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_response_packet");
+       if (packet) {
+               packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET];
+               packet->header.persistent = persistent;
+       }
+       DBG_RETURN(packet);
+}
+/* }}} */
+
+
+
 MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
        MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
@@ -2372,7 +2498,9 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
        MYSQLND_METHOD(mysqlnd_protocol, get_row_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet),
-       MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)
+       MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet),
+       MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet),
+       MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)
 MYSQLND_CLASS_METHODS_END;
 
 
index 96322d706026adfa6078ed4c756738cbee2f5028..e5008e6db559ce9d5954b10435a1363bea29e2b8 100644 (file)
@@ -286,6 +286,18 @@ typedef struct st_mysqlnd_packet_chg_user_resp {
 } MYSQLND_PACKET_CHG_USER_RESPONSE;
 
 
+/* Command packet */
+typedef struct st_mysqlnd_packet_sha256_pk_request {
+       MYSQLND_PACKET_HEADER                   header;
+} MYSQLND_PACKET_SHA256_PK_REQUEST;
+
+typedef struct  st_mysqlnd_packet_sha256_pk_request_response {
+       MYSQLND_PACKET_HEADER   header;
+       zend_uchar                              *public_key;
+       size_t                                  public_key_len;
+} MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE;
+
+
 PHPAPI void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const pass, size_t pass_len);
 
 unsigned long  php_mysqlnd_net_field_length(zend_uchar **packet);
index 0a8fd609086c2bf8acda91e1cc6d004b4d1ff5e7..8dccf37c4b3cd7e503995c7afa1a21d39057a870 100644 (file)
@@ -170,11 +170,17 @@ PHP_MINFO_FUNCTION(mysqlnd)
 #else
                                                                "not supported");
 #endif
-       php_info_print_table_row(2, "SSL",
+       php_info_print_table_row(2, "core SSL",
 #ifdef MYSQLND_SSL_SUPPORTED
                                                                "supported");
 #else
                                                                "not supported");
+#endif
+       php_info_print_table_row(2, "extended SSL",
+#ifdef MYSQLND_HAVE_SSL
+                                                               "supported");
+#else
+                                                               "not supported");
 #endif
        snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_cmd_buffer_size));
        php_info_print_table_row(2, "Command buffer size", buf);
@@ -234,6 +240,7 @@ static PHP_GINIT_FUNCTION(mysqlnd)
        mysqlnd_globals->debug_malloc_fail_threshold = -1;
        mysqlnd_globals->debug_calloc_fail_threshold = -1;
        mysqlnd_globals->debug_realloc_fail_threshold = -1;
+       mysqlnd_globals->sha256_server_public_key = NULL;
 }
 /* }}} */
 
@@ -261,6 +268,7 @@ PHP_INI_BEGIN()
        STD_PHP_INI_ENTRY("mysqlnd.net_read_timeout",   "31536000",     PHP_INI_SYSTEM, OnUpdateLong,   net_read_timeout, zend_mysqlnd_globals, mysqlnd_globals)
        STD_PHP_INI_ENTRY("mysqlnd.log_mask",                           "0",    PHP_INI_ALL,    OnUpdateLong,   log_mask, zend_mysqlnd_globals, mysqlnd_globals)
        STD_PHP_INI_ENTRY("mysqlnd.mempool_default_size","16000",   PHP_INI_ALL,        OnUpdateLong,   mempool_default_size,   zend_mysqlnd_globals,           mysqlnd_globals)
+       STD_PHP_INI_ENTRY("mysqlnd.sha256_server_public_key",NULL,      PHP_INI_SYSTEM, OnUpdateString, sha256_server_public_key, zend_mysqlnd_globals, mysqlnd_globals)
 
 #if PHP_DEBUG
        STD_PHP_INI_ENTRY("mysqlnd.debug_emalloc_fail_threshold","-1",   PHP_INI_SYSTEM,        OnUpdateLong,   debug_emalloc_fail_threshold,   zend_mysqlnd_globals,           mysqlnd_globals)