Skip to content

Commit addb6e4

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix GH-9348: FTP & SSL session reuse
2 parents f61f8d4 + ac8a58f commit addb6e4

File tree

3 files changed

+28
-3
lines changed

3 files changed

+28
-3
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ PHP NEWS
1414
. Fixed bug GH-12705 (Segmentation fault in fpm_status_export_to_zval).
1515
(Patrick Prasse)
1616

17+
- FTP:
18+
. Fixed bug GH-9348 (FTP & SSL session reuse). (nielsdos)
19+
1720
- LibXML:
1821
. Fixed test failures for libxml2 2.12.0. (nielsdos)
1922

ext/ftp/ftp.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ ftp_close(ftpbuf_t *ftp)
167167
if (ftp == NULL) {
168168
return NULL;
169169
}
170+
if (ftp->last_ssl_session) {
171+
SSL_SESSION_free(ftp->last_ssl_session);
172+
}
170173
if (ftp->data) {
171174
data_close(ftp, ftp->data);
172175
}
@@ -229,6 +232,20 @@ ftp_quit(ftpbuf_t *ftp)
229232
}
230233
/* }}} */
231234

235+
static int ftp_ssl_new_session_cb(SSL *ssl, SSL_SESSION *sess)
236+
{
237+
ftpbuf_t *ftp = SSL_get_app_data(ssl);
238+
239+
/* Technically there can be multiple sessions per connection, but we only care about the most recent one. */
240+
if (ftp->last_ssl_session) {
241+
SSL_SESSION_free(ftp->last_ssl_session);
242+
}
243+
ftp->last_ssl_session = SSL_get1_session(ssl);
244+
245+
/* Return 0 as we are not using OpenSSL's session cache. */
246+
return 0;
247+
}
248+
232249
/* {{{ ftp_login */
233250
int
234251
ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pass, const size_t pass_len)
@@ -279,10 +296,13 @@ ftp_login(ftpbuf_t *ftp, const char *user, const size_t user_len, const char *pa
279296
#endif
280297
SSL_CTX_set_options(ctx, ssl_ctx_options);
281298

282-
/* allow SSL to re-use sessions */
283-
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
299+
/* Allow SSL to re-use sessions.
300+
* We're relying on our own session storage as only at most one session will ever be active per FTP connection. */
301+
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH | SSL_SESS_CACHE_NO_INTERNAL);
302+
SSL_CTX_sess_set_new_cb(ctx, ftp_ssl_new_session_cb);
284303

285304
ftp->ssl_handle = SSL_new(ctx);
305+
SSL_set_app_data(ftp->ssl_handle, ftp); /* Needed for ftp_ssl_new_session_cb */
286306
SSL_CTX_free(ctx);
287307

288308
if (ftp->ssl_handle == NULL) {
@@ -1789,14 +1809,15 @@ data_accept(databuf_t *data, ftpbuf_t *ftp)
17891809
}
17901810

17911811
/* get the session from the control connection so we can re-use it */
1792-
session = SSL_get_session(ftp->ssl_handle);
1812+
session = ftp->last_ssl_session;
17931813
if (session == NULL) {
17941814
php_error_docref(NULL, E_WARNING, "data_accept: failed to retrieve the existing SSL session");
17951815
SSL_free(data->ssl_handle);
17961816
return 0;
17971817
}
17981818

17991819
/* and set it on the data connection */
1820+
SSL_set_app_data(data->ssl_handle, ftp); /* Needed for ftp_ssl_new_session_cb */
18001821
res = SSL_set_session(data->ssl_handle, session);
18011822
if (res == 0) {
18021823
php_error_docref(NULL, E_WARNING, "data_accept: failed to set the existing SSL session");

ext/ftp/ftp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ typedef struct ftpbuf
8282
int old_ssl; /* old mode = forced data encryption */
8383
SSL *ssl_handle; /* handle for control connection */
8484
int ssl_active; /* ssl active on control conn */
85+
SSL_SESSION *last_ssl_session; /* last negotiated session */
8586
#endif
8687

8788
} ftpbuf_t;

0 commit comments

Comments
 (0)