@@ -694,6 +694,7 @@ mysqlnd_xor_string(char * dst, const size_t dst_len, const char * xor_str, const
694
694
}
695
695
}
696
696
697
+ #ifndef PHP_WIN32
697
698
698
699
#include <openssl/rsa.h>
699
700
#include <openssl/pem.h>
@@ -740,6 +741,91 @@ mysqlnd_sha256_public_encrypt(MYSQLND_CONN_DATA * conn, mysqlnd_rsa_t server_pub
740
741
}
741
742
/* }}} */
742
743
744
+ #else
745
+
746
+ #include <wincrypt.h>
747
+ #include <bcrypt.h>
748
+
749
+ typedef HANDLE mysqlnd_rsa_t ;
750
+
751
+ /* {{{ mysqlnd_sha256_get_rsa_from_pem */
752
+ static mysqlnd_rsa_t
753
+ mysqlnd_sha256_get_rsa_from_pem (const char * buf , size_t len )
754
+ {
755
+ BCRYPT_KEY_HANDLE ret = 0 ;
756
+ LPCSTR der_buf = NULL ;
757
+ DWORD der_len ;
758
+ CERT_PUBLIC_KEY_INFO * key_info = NULL ;
759
+ DWORD key_info_len ;
760
+ ALLOCA_FLAG (use_heap );
761
+
762
+ if (!CryptStringToBinaryA (buf , len , CRYPT_STRING_BASE64HEADER , NULL , & der_len , NULL , NULL )) {
763
+ goto finish ;
764
+ }
765
+ der_buf = do_alloca (der_len , use_heap );
766
+ if (!CryptStringToBinaryA (buf , len , CRYPT_STRING_BASE64HEADER , der_buf , & der_len , NULL , NULL )) {
767
+ goto finish ;
768
+ }
769
+ if (!CryptDecodeObjectEx (X509_ASN_ENCODING , X509_PUBLIC_KEY_INFO , der_buf , der_len , CRYPT_ENCODE_ALLOC_FLAG , NULL , & key_info , & key_info_len )) {
770
+ goto finish ;
771
+ }
772
+ if (!CryptImportPublicKeyInfoEx2 (X509_ASN_ENCODING , key_info , CRYPT_OID_INFO_PUBKEY_ENCRYPT_KEY_FLAG , NULL , & ret )) {
773
+ goto finish ;
774
+ }
775
+
776
+ finish :
777
+ if (key_info ) {
778
+ LocalFree (key_info );
779
+ }
780
+ if (der_buf ) {
781
+ free_alloca (der_buf , use_heap );
782
+ }
783
+ return (mysqlnd_rsa_t ) ret ;
784
+ }
785
+ /* }}} */
786
+
787
+ /* {{{ mysqlnd_sha256_public_encrypt */
788
+ static zend_uchar *
789
+ 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 )
790
+ {
791
+ zend_uchar * ret = NULL ;
792
+ DWORD server_public_key_len = passwd_len ;
793
+ BCRYPT_OAEP_PADDING_INFO padding_info ;
794
+
795
+ DBG_ENTER ("mysqlnd_sha256_public_encrypt" );
796
+
797
+ ZeroMemory (& padding_info , sizeof padding_info );
798
+ padding_info .pszAlgId = BCRYPT_SHA1_ALGORITHM ;
799
+ if (BCryptEncrypt ((BCRYPT_KEY_HANDLE ) server_public_key , xor_str , passwd_len + 1 , & padding_info ,
800
+ NULL , 0 , NULL , 0 , & server_public_key_len , BCRYPT_PAD_OAEP )) {
801
+ DBG_RETURN (0 );
802
+ }
803
+
804
+ /*
805
+ Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
806
+ RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
807
+ http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
808
+ */
809
+ if ((size_t ) server_public_key_len <= passwd_len + 41 ) {
810
+ /* password message is to long */
811
+ SET_CLIENT_ERROR (conn -> error_info , CR_UNKNOWN_ERROR , UNKNOWN_SQLSTATE , "password is too long" );
812
+ DBG_ERR ("password is too long" );
813
+ DBG_RETURN (0 );
814
+ }
815
+
816
+ * auth_data_len = server_public_key_len ;
817
+ ret = malloc (* auth_data_len );
818
+ if (BCryptEncrypt ((BCRYPT_KEY_HANDLE ) server_public_key , xor_str , passwd_len + 1 , & padding_info ,
819
+ NULL , 0 , ret , server_public_key_len , & server_public_key_len , BCRYPT_PAD_OAEP )) {
820
+ DBG_RETURN (0 );
821
+ }
822
+ BCryptDestroyKey ((BCRYPT_KEY_HANDLE ) server_public_key );
823
+ DBG_RETURN (ret );
824
+ }
825
+ /* }}} */
826
+
827
+ #endif
828
+
743
829
/* {{{ mysqlnd_sha256_get_rsa_key */
744
830
static mysqlnd_rsa_t
745
831
mysqlnd_sha256_get_rsa_key (MYSQLND_CONN_DATA * conn ,
@@ -916,6 +1002,8 @@ void php_mysqlnd_scramble_sha2(zend_uchar * const buffer, const zend_uchar * con
916
1002
}
917
1003
/* }}} */
918
1004
1005
+ #ifndef PHP_WIN32
1006
+
919
1007
/* {{{ mysqlnd_caching_sha2_public_encrypt */
920
1008
static size_t
921
1009
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 )
@@ -941,6 +1029,47 @@ mysqlnd_caching_sha2_public_encrypt(MYSQLND_CONN_DATA * conn, mysqlnd_rsa_t serv
941
1029
}
942
1030
/* }}} */
943
1031
1032
+ #else
1033
+
1034
+ /* {{{ mysqlnd_caching_sha2_public_encrypt */
1035
+ static size_t
1036
+ 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 )
1037
+ {
1038
+ DWORD server_public_key_len = passwd_len ;
1039
+ BCRYPT_OAEP_PADDING_INFO padding_info ;
1040
+
1041
+ DBG_ENTER ("mysqlnd_caching_sha2_public_encrypt" );
1042
+
1043
+ ZeroMemory (& padding_info , sizeof padding_info );
1044
+ padding_info .pszAlgId = BCRYPT_SHA1_ALGORITHM ;
1045
+ if (BCryptEncrypt ((BCRYPT_KEY_HANDLE ) server_public_key , xor_str , passwd_len + 1 , & padding_info ,
1046
+ NULL , 0 , NULL , 0 , & server_public_key_len , BCRYPT_PAD_OAEP )) {
1047
+ DBG_RETURN (0 );
1048
+ }
1049
+
1050
+ /*
1051
+ Because RSA_PKCS1_OAEP_PADDING is used there is a restriction on the passwd_len.
1052
+ RSA_PKCS1_OAEP_PADDING is recommended for new applications. See more here:
1053
+ http://www.openssl.org/docs/crypto/RSA_public_encrypt.html
1054
+ */
1055
+ if ((size_t ) server_public_key_len <= passwd_len + 41 ) {
1056
+ /* password message is to long */
1057
+ SET_CLIENT_ERROR (conn -> error_info , CR_UNKNOWN_ERROR , UNKNOWN_SQLSTATE , "password is too long" );
1058
+ DBG_ERR ("password is too long" );
1059
+ DBG_RETURN (0 );
1060
+ }
1061
+
1062
+ * crypted = emalloc (server_public_key_len );
1063
+ if (BCryptEncrypt ((BCRYPT_KEY_HANDLE ) server_public_key , xor_str , passwd_len + 1 , & padding_info ,
1064
+ NULL , 0 , * crypted , server_public_key_len , & server_public_key_len , BCRYPT_PAD_OAEP )) {
1065
+ DBG_RETURN (0 );
1066
+ }
1067
+ DBG_RETURN (server_public_key_len );
1068
+ }
1069
+ /* }}} */
1070
+
1071
+ #endif
1072
+
944
1073
/* {{{ mysqlnd_native_auth_get_auth_data */
945
1074
static zend_uchar *
946
1075
mysqlnd_caching_sha2_get_auth_data (struct st_mysqlnd_authentication_plugin * self ,
0 commit comments