59
59
60
60
#ifdef HAVE_FTP_SSL
61
61
#include <openssl/ssl.h>
62
+ #include <openssl/err.h>
62
63
#endif
63
64
64
65
#include "ftp.h"
@@ -100,6 +101,11 @@ static databuf_t* data_close(ftpbuf_t *ftp, databuf_t *data);
100
101
/* generic file lister */
101
102
static char * * ftp_genlist (ftpbuf_t * ftp , const char * cmd , const size_t cmd_len , const char * path , const size_t path_len );
102
103
104
+ #ifdef HAVE_FTP_SSL
105
+ /* shuts down a TLS/SSL connection */
106
+ static void ftp_ssl_shutdown (ftpbuf_t * ftp , php_socket_t fd , SSL * ssl_handle );
107
+ #endif
108
+
103
109
/* IP and port conversion box */
104
110
union ipbox {
105
111
struct in_addr ia [2 ];
@@ -173,8 +179,7 @@ ftp_close(ftpbuf_t *ftp)
173
179
if (ftp -> fd != -1 ) {
174
180
#ifdef HAVE_FTP_SSL
175
181
if (ftp -> ssl_active ) {
176
- SSL_shutdown (ftp -> ssl_handle );
177
- SSL_free (ftp -> ssl_handle );
182
+ ftp_ssl_shutdown (ftp , ftp -> fd , ftp -> ssl_handle );
178
183
}
179
184
#endif
180
185
closesocket (ftp -> fd );
@@ -1881,6 +1886,62 @@ data_accept(databuf_t *data, ftpbuf_t *ftp)
1881
1886
}
1882
1887
/* }}} */
1883
1888
1889
+ /* {{{ ftp_ssl_shutdown
1890
+ */
1891
+ #ifdef HAVE_FTP_SSL
1892
+ static void ftp_ssl_shutdown (ftpbuf_t * ftp , php_socket_t fd , SSL * ssl_handle ) {
1893
+ /* In TLS 1.3 it's common to receive session tickets after the handshake has completed. We need to train
1894
+ the socket (read the tickets until EOF/close_notify alert) before closing the socket. Otherwise the
1895
+ server might get an ECONNRESET which might lead to data truncation on server side.
1896
+ */
1897
+ char buf [256 ]; /* We will use this for the OpenSSL error buffer, so it has
1898
+ to be at least 256 bytes long.*/
1899
+ int done = 1 , err , nread ;
1900
+ unsigned long sslerror ;
1901
+
1902
+ err = SSL_shutdown (ssl_handle );
1903
+ if (err < 0 ) {
1904
+ php_error_docref (NULL , E_WARNING , "SSL_shutdown failed" );
1905
+ }
1906
+ else if (err == 0 ) {
1907
+ /* The shutdown is not yet finished. Call SSL_read() to do a bidirectional shutdown. */
1908
+ done = 0 ;
1909
+ }
1910
+
1911
+ while (!done ) {
1912
+ if (data_available (ftp , fd )) {
1913
+ ERR_clear_error ();
1914
+ nread = SSL_read (ssl_handle , buf , sizeof (buf ));
1915
+ err = SSL_get_error (ssl_handle , nread );
1916
+ switch (err ) {
1917
+ case SSL_ERROR_NONE : /* this is not an error */
1918
+ case SSL_ERROR_ZERO_RETURN : /* no more data */
1919
+ /* This is the expected response. There was no data but only
1920
+ the close notify alert */
1921
+ done = 1 ;
1922
+ break ;
1923
+ case SSL_ERROR_WANT_READ :
1924
+ /* there's data pending, re-invoke SSL_read() */
1925
+ break ;
1926
+ case SSL_ERROR_WANT_WRITE :
1927
+ /* SSL wants a write. Really odd. Let's bail out. */
1928
+ done = 1 ;
1929
+ break ;
1930
+ default :
1931
+ if ((sslerror = ERR_get_error ())) {
1932
+ ERR_error_string_n (sslerror , buf , sizeof (buf ));
1933
+ }
1934
+ php_error_docref (NULL , E_WARNING , "SSL_read on shutdown: %s (%d)" , (sslerror ? buf : strerror (errno )), errno );
1935
+ done = 1 ;
1936
+ break ;
1937
+ }
1938
+ }
1939
+ }
1940
+ (void )SSL_free (ssl_handle );
1941
+ }
1942
+ #endif
1943
+ /* }}} */
1944
+
1884
1945
/* {{{ data_close
1885
1946
*/
1886
1947
databuf_t *
@@ -1893,8 +1954,7 @@ data_close(ftpbuf_t *ftp, databuf_t *data)
1893
1954
#ifdef HAVE_FTP_SSL
1894
1955
if (data -> ssl_active ) {
1895
1956
/* don't free the data context, it's the same as the control */
1896
- SSL_shutdown (data -> ssl_handle );
1897
- SSL_free (data -> ssl_handle );
1957
+ ftp_ssl_shutdown (ftp , data -> listener , data -> ssl_handle );
1898
1958
data -> ssl_active = 0 ;
1899
1959
}
1900
1960
#endif
@@ -1904,8 +1964,7 @@ data_close(ftpbuf_t *ftp, databuf_t *data)
1904
1964
#ifdef HAVE_FTP_SSL
1905
1965
if (data -> ssl_active ) {
1906
1966
/* don't free the data context, it's the same as the control */
1907
- SSL_shutdown (data -> ssl_handle );
1908
- SSL_free (data -> ssl_handle );
1967
+ ftp_ssl_shutdown (ftp , data -> fd , data -> ssl_handle );
1909
1968
data -> ssl_active = 0 ;
1910
1969
}
1911
1970
#endif
0 commit comments