diff options
author | andrey <andrey@php.net> | 2012-09-25 14:04:36 +0200 |
---|---|---|
committer | andrey <andrey@php.net> | 2012-09-25 14:04:36 +0200 |
commit | 571b46bff68925f15f578147278b43c6f88083f0 (patch) | |
tree | 101cf8e3f35f89acb3290e07ca5712b93a8aae09 /ext | |
parent | 8a930c93dd673b9f13350590a7b6e3a1a5ce4431 (diff) | |
download | php-git-571b46bff68925f15f578147278b43c6f88083f0.tar.gz |
Add SHA256 authentication support - password hashing to mysqlnd
Automatic switchover to SSL with plain-text password is not part of this
Diffstat (limited to 'ext')
-rw-r--r-- | ext/mysqli/mysqli_nonapi.c | 2 | ||||
-rw-r--r-- | ext/mysqlnd/config9.m4 | 12 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd.c | 11 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd.h | 1 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_auth.c | 188 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_enum_n_def.h | 3 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_structs.h | 18 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 134 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.h | 12 | ||||
-rw-r--r-- | ext/mysqlnd/php_mysqlnd.c | 10 |
10 files changed, 374 insertions, 17 deletions
diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index 5e9c01378a..2b6a1af0ed 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -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; diff --git a/ext/mysqlnd/config9.m4 b/ext/mysqlnd/config9.m4 index 2c15c34e8d..3fc767b231 100644 --- a/ext/mysqlnd/config9.m4 +++ b/ext/mysqlnd/config9.m4 @@ -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) diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index d7462f77a5..f7f3245a2c 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -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; diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index 30d4257802..b0db48f5f7 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -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) diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c index 10c932a968..295b6a338b 100644 --- a/ext/mysqlnd/mysqlnd_auth.c +++ b/ext/mysqlnd/mysqlnd_auth.c @@ -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 } /* }}} */ diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index c8daa0c79b..60e53b3c60 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -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 */ }; diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 856ebd2ead..511a168b56 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -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 diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 3551c027cd..e41c771a8a 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -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; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index 96322d7060..e5008e6db5 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -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); diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c index 0a8fd60908..8dccf37c4b 100644 --- a/ext/mysqlnd/php_mysqlnd.c +++ b/ext/mysqlnd/php_mysqlnd.c @@ -170,12 +170,18 @@ 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); snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_read_buffer_size)); @@ -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) |