@@ -699,15 +699,55 @@ mysqlnd_xor_string(char * dst, const size_t dst_len, const char * xor_str, const
699699#include <openssl/pem.h>
700700#include <openssl/err.h>
701701
702+ typedef RSA * mysqlnd_rsa_t ;
703+
704+ /* {{{ mysqlnd_sha256_get_rsa_from_pem */
705+ static mysqlnd_rsa_t
706+ mysqlnd_sha256_get_rsa_from_pem (const char * buf , size_t len )
707+ {
708+ BIO * bio = BIO_new_mem_buf (buf , len );
709+ RSA * ret = PEM_read_bio_RSA_PUBKEY (bio , NULL , NULL , NULL );
710+ BIO_free (bio );
711+ return ret ;
712+ }
713+ /* }}} */
714+
715+ /* {{{ mysqlnd_sha256_public_encrypt */
716+ static zend_uchar *
717+ mysqlnd_sha256_public_encrypt (MYSQLND_CONN_DATA * conn , mysqlnd_rsa_t server_public_key , size_t passwd_len , size_t * auth_data_len , char * xor_str )
718+ {
719+ zend_uchar * ret = NULL ;
720+ size_t server_public_key_len = (size_t ) RSA_size (server_public_key );
721+
722+ DBG_ENTER ("mysqlnd_sha256_public_encrypt" );
723+ /*
724+ Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
725+ RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
726+ http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
727+ */
728+ if (server_public_key_len <= passwd_len + 41 ) {
729+ /* password message is to long */
730+ SET_CLIENT_ERROR (conn -> error_info , CR_UNKNOWN_ERROR , UNKNOWN_SQLSTATE , "password is too long" );
731+ DBG_ERR ("password is too long" );
732+ DBG_RETURN (NULL );
733+ }
734+
735+ * auth_data_len = server_public_key_len ;
736+ ret = malloc (* auth_data_len );
737+ RSA_public_encrypt (passwd_len + 1 , (zend_uchar * ) xor_str , ret , server_public_key , RSA_PKCS1_OAEP_PADDING );
738+ RSA_free (server_public_key );
739+ DBG_RETURN (ret );
740+ }
741+ /* }}} */
702742
703743/* {{{ mysqlnd_sha256_get_rsa_key */
704- static RSA *
744+ static mysqlnd_rsa_t
705745mysqlnd_sha256_get_rsa_key (MYSQLND_CONN_DATA * conn ,
706746 const MYSQLND_SESSION_OPTIONS * const session_options ,
707747 const MYSQLND_PFC_DATA * const pfc_data
708748 )
709749{
710- RSA * ret = NULL ;
750+ mysqlnd_rsa_t ret = NULL ;
711751 const char * fname = (pfc_data -> sha256_server_public_key && pfc_data -> sha256_server_public_key [0 ] != '\0' )?
712752 pfc_data -> sha256_server_public_key :
713753 MYSQLND_G (sha256_server_public_key );
@@ -739,11 +779,7 @@ mysqlnd_sha256_get_rsa_key(MYSQLND_CONN_DATA * conn,
739779 }
740780 DBG_INF_FMT ("Public key(%d):\n%s" , pk_resp_packet .public_key_len , pk_resp_packet .public_key );
741781 /* now extract the public key */
742- {
743- BIO * bio = BIO_new_mem_buf (pk_resp_packet .public_key , pk_resp_packet .public_key_len );
744- ret = PEM_read_bio_RSA_PUBKEY (bio , NULL , NULL , NULL );
745- BIO_free (bio );
746- }
782+ ret = mysqlnd_sha256_get_rsa_from_pem ((const char * ) pk_resp_packet .public_key , pk_resp_packet .public_key_len );
747783 } while (0 );
748784 PACKET_FREE (& pk_req_packet );
749785 PACKET_FREE (& pk_resp_packet );
@@ -762,9 +798,7 @@ mysqlnd_sha256_get_rsa_key(MYSQLND_CONN_DATA * conn,
762798
763799 if (stream ) {
764800 if ((key_str = php_stream_copy_to_mem (stream , PHP_STREAM_COPY_ALL , 0 )) != NULL ) {
765- BIO * bio = BIO_new_mem_buf (ZSTR_VAL (key_str ), ZSTR_LEN (key_str ));
766- ret = PEM_read_bio_RSA_PUBKEY (bio , NULL , NULL , NULL );
767- BIO_free (bio );
801+ ret = mysqlnd_sha256_get_rsa_from_pem (ZSTR_VAL (key_str ), ZSTR_LEN (key_str ));
768802 DBG_INF ("Successfully loaded" );
769803 DBG_INF_FMT ("Public key:%*.s" , ZSTR_LEN (key_str ), ZSTR_VAL (key_str ));
770804 zend_string_release_ex (key_str , 0 );
@@ -788,7 +822,7 @@ mysqlnd_sha256_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self
788822 const zend_ulong mysql_flags
789823 )
790824{
791- RSA * server_public_key ;
825+ mysqlnd_rsa_t server_public_key ;
792826 zend_uchar * ret = NULL ;
793827 DBG_ENTER ("mysqlnd_sha256_auth_get_auth_data" );
794828 DBG_INF_FMT ("salt(%d)=[%.*s]" , auth_plugin_data_len , auth_plugin_data_len , auth_plugin_data );
@@ -805,31 +839,12 @@ mysqlnd_sha256_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self
805839 server_public_key = mysqlnd_sha256_get_rsa_key (conn , session_options , pfc_data );
806840
807841 if (server_public_key ) {
808- int server_public_key_len ;
809842 ALLOCA_FLAG (use_heap );
810843 char * xor_str = do_alloca (passwd_len + 1 , use_heap );
811844 memcpy (xor_str , passwd , passwd_len );
812845 xor_str [passwd_len ] = '\0' ;
813846 mysqlnd_xor_string (xor_str , passwd_len , (char * ) auth_plugin_data , auth_plugin_data_len );
814-
815- server_public_key_len = RSA_size (server_public_key );
816- /*
817- Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
818- RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
819- http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
820- */
821- if ((size_t ) server_public_key_len - 41 <= passwd_len ) {
822- /* password message is to long */
823- free_alloca (xor_str , use_heap );
824- SET_CLIENT_ERROR (conn -> error_info , CR_UNKNOWN_ERROR , UNKNOWN_SQLSTATE , "password is too long" );
825- DBG_ERR ("password is too long" );
826- DBG_RETURN (NULL );
827- }
828-
829- * auth_data_len = server_public_key_len ;
830- ret = malloc (* auth_data_len );
831- RSA_public_encrypt (passwd_len + 1 , (zend_uchar * ) xor_str , ret , server_public_key , RSA_PKCS1_OAEP_PADDING );
832- RSA_free (server_public_key );
847+ ret = mysqlnd_sha256_public_encrypt (conn , server_public_key , passwd_len , auth_data_len , xor_str );
833848 free_alloca (xor_str , use_heap );
834849 }
835850 }
@@ -901,6 +916,30 @@ void php_mysqlnd_scramble_sha2(zend_uchar * const buffer, const zend_uchar * con
901916}
902917/* }}} */
903918
919+ /* {{{ mysqlnd_caching_sha2_public_encrypt */
920+ static size_t
921+ mysqlnd_caching_sha2_public_encrypt (MYSQLND_CONN_DATA * conn , mysqlnd_rsa_t server_public_key , size_t passwd_len , unsigned char * * crypted , char * xor_str )
922+ {
923+ size_t server_public_key_len = (size_t ) RSA_size (server_public_key );
924+
925+ DBG_ENTER ("mysqlnd_caching_sha2_public_encrypt" );
926+ /*
927+ Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
928+ RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
929+ http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
930+ */
931+ if (server_public_key_len <= passwd_len + 41 ) {
932+ /* password message is to long */
933+ SET_CLIENT_ERROR (conn -> error_info , CR_UNKNOWN_ERROR , UNKNOWN_SQLSTATE , "password is too long" );
934+ DBG_ERR ("password is too long" );
935+ DBG_RETURN (0 );
936+ }
937+
938+ * crypted = emalloc (server_public_key_len );
939+ RSA_public_encrypt (passwd_len + 1 , (zend_uchar * ) xor_str , * crypted , server_public_key , RSA_PKCS1_OAEP_PADDING );
940+ DBG_RETURN (server_public_key_len );
941+ }
942+ /* }}} */
904943
905944/* {{{ mysqlnd_native_auth_get_auth_data */
906945static zend_uchar *
@@ -938,10 +977,10 @@ mysqlnd_caching_sha2_get_auth_data(struct st_mysqlnd_authentication_plugin * sel
938977}
939978/* }}} */
940979
941- static RSA *
980+ static mysqlnd_rsa_t
942981mysqlnd_caching_sha2_get_key (MYSQLND_CONN_DATA * conn )
943982{
944- RSA * ret = NULL ;
983+ mysqlnd_rsa_t ret = NULL ;
945984 const MYSQLND_PFC_DATA * const pfc_data = conn -> protocol_frame_codec -> data ;
946985 const char * fname = (pfc_data -> sha256_server_public_key && pfc_data -> sha256_server_public_key [0 ] != '\0' )?
947986 pfc_data -> sha256_server_public_key :
@@ -975,11 +1014,7 @@ mysqlnd_caching_sha2_get_key(MYSQLND_CONN_DATA *conn)
9751014 }
9761015 DBG_INF_FMT ("Public key(%d):\n%s" , pk_resp_packet .public_key_len , pk_resp_packet .public_key );
9771016 /* now extract the public key */
978- {
979- BIO * bio = BIO_new_mem_buf (pk_resp_packet .public_key , pk_resp_packet .public_key_len );
980- ret = PEM_read_bio_RSA_PUBKEY (bio , NULL , NULL , NULL );
981- BIO_free (bio );
982- }
1017+ ret = mysqlnd_sha256_get_rsa_from_pem ((const char * ) pk_resp_packet .public_key , pk_resp_packet .public_key_len );
9831018 } while (0 );
9841019 PACKET_FREE (& req_packet );
9851020 PACKET_FREE (& pk_resp_packet );
@@ -998,9 +1033,7 @@ mysqlnd_caching_sha2_get_key(MYSQLND_CONN_DATA *conn)
9981033
9991034 if (stream ) {
10001035 if ((key_str = php_stream_copy_to_mem (stream , PHP_STREAM_COPY_ALL , 0 )) != NULL ) {
1001- BIO * bio = BIO_new_mem_buf (ZSTR_VAL (key_str ), ZSTR_LEN (key_str ));
1002- ret = PEM_read_bio_RSA_PUBKEY (bio , NULL , NULL , NULL );
1003- BIO_free (bio );
1036+ ret = mysqlnd_sha256_get_rsa_from_pem (ZSTR_VAL (key_str ), ZSTR_LEN (key_str ));
10041037 DBG_INF ("Successfully loaded" );
10051038 DBG_INF_FMT ("Public key:%*.s" , ZSTR_LEN (key_str ), ZSTR_VAL (key_str ));
10061039 zend_string_release (key_str );
@@ -1013,16 +1046,15 @@ mysqlnd_caching_sha2_get_key(MYSQLND_CONN_DATA *conn)
10131046}
10141047
10151048
1016- /* {{{ mysqlnd_caching_sha2_get_key */
1049+ /* {{{ mysqlnd_caching_sha2_get_and_use_key */
10171050static size_t
10181051mysqlnd_caching_sha2_get_and_use_key (MYSQLND_CONN_DATA * conn ,
10191052 const zend_uchar * auth_plugin_data , const size_t auth_plugin_data_len ,
10201053 unsigned char * * crypted ,
10211054 const char * const passwd ,
10221055 const size_t passwd_len )
10231056{
1024- static RSA * server_public_key ;
1025- server_public_key = mysqlnd_caching_sha2_get_key (conn );
1057+ mysqlnd_rsa_t server_public_key = mysqlnd_caching_sha2_get_key (conn );
10261058
10271059 DBG_ENTER ("mysqlnd_caching_sha2_get_and_use_key(" );
10281060
@@ -1033,23 +1065,7 @@ mysqlnd_caching_sha2_get_and_use_key(MYSQLND_CONN_DATA *conn,
10331065 memcpy (xor_str , passwd , passwd_len );
10341066 xor_str [passwd_len ] = '\0' ;
10351067 mysqlnd_xor_string (xor_str , passwd_len , (char * ) auth_plugin_data , SCRAMBLE_LENGTH );
1036-
1037- server_public_key_len = RSA_size (server_public_key );
1038- /*
1039- Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
1040- RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
1041- http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
1042- */
1043- if ((size_t ) server_public_key_len - 41 <= passwd_len ) {
1044- /* password message is to long */
1045- free_alloca (xor_str , use_heap );
1046- SET_CLIENT_ERROR (conn -> error_info , CR_UNKNOWN_ERROR , UNKNOWN_SQLSTATE , "password is too long" );
1047- DBG_ERR ("password is too long" );
1048- DBG_RETURN (0 );
1049- }
1050-
1051- * crypted = emalloc (server_public_key_len );
1052- RSA_public_encrypt (passwd_len + 1 , (zend_uchar * ) xor_str , * crypted , server_public_key , RSA_PKCS1_OAEP_PADDING );
1068+ server_public_key_len = mysqlnd_caching_sha2_public_encrypt (conn , server_public_key , passwd_len , crypted , xor_str );
10531069 free_alloca (xor_str , use_heap );
10541070 DBG_RETURN (server_public_key_len );
10551071 }
0 commit comments