@@ -219,6 +219,149 @@ void php_openssl_add_crypto_cipher(zval *crypto, SSL *ssl)
219219 }
220220}
221221
222+ int php_openssl_get_ctx_session_callbacks_index (void )
223+ {
224+ static int index = -1 ;
225+ if (index < 0 ) {
226+ index = SSL_CTX_get_ex_new_index (0 , "PHP openssl session callbacks index" , NULL , NULL , NULL );
227+ }
228+ return index ;
229+ }
230+
231+ int php_openssl_get_ctx_stream_index (void )
232+ {
233+ static int index = -1 ;
234+ if (index < 0 ) {
235+ index = SSL_CTX_get_ex_new_index (0 , "PHP openssl ctx stream index" , NULL , NULL , NULL );
236+ }
237+ return index ;
238+ }
239+
240+ static php_openssl_session_callbacks_t * php_openssl_ctx_session_callbacks (SSL_CTX * ctx )
241+ {
242+ return (php_openssl_session_callbacks_t * )SSL_CTX_get_ex_data (ctx ,
243+ php_openssl_get_ctx_session_callbacks_index ());
244+ }
245+
246+ int php_openssl_session_new_cb (SSL * ssl , SSL_SESSION * session )
247+ {
248+ php_stream * stream = (php_stream * )SSL_get_ex_data (ssl , php_openssl_get_ssl_stream_data_index ());
249+ php_openssl_session_callbacks_t * cbs = php_openssl_ctx_session_callbacks (SSL_get_SSL_CTX (ssl ));
250+ if (!stream || !cbs ) {
251+ return 0 ;
252+ }
253+
254+ /* Increment reference - we're giving ownership to the PHP object */
255+ SSL_SESSION_up_ref (session );
256+
257+ zval args [2 ];
258+ ZVAL_RES (& args [0 ], stream -> res );
259+ php_openssl_session_object_init (& args [1 ], session );
260+
261+ zend_call_known_fcc (& cbs -> new_cb , NULL , 2 , args , NULL );
262+
263+ zval_ptr_dtor (& args [1 ]);
264+ return 0 ;
265+ }
266+
267+ SSL_SESSION * php_openssl_session_get_cb (SSL * ssl , const unsigned char * session_id , int session_id_len , int * copy )
268+ {
269+ php_stream * stream = (php_stream * )SSL_get_ex_data (ssl , php_openssl_get_ssl_stream_data_index ());
270+ php_openssl_session_callbacks_t * cbs = php_openssl_ctx_session_callbacks (SSL_get_SSL_CTX (ssl ));
271+ if (!stream || !cbs ) {
272+ * copy = 0 ;
273+ return NULL ;
274+ }
275+
276+ zval args [2 ], retval ;
277+ ZVAL_RES (& args [0 ], stream -> res );
278+ ZVAL_STRINGL (& args [1 ], (char * )session_id , session_id_len );
279+
280+ SSL_SESSION * session = NULL ;
281+ zend_call_known_fcc (& cbs -> get_cb , & retval , 2 , args , NULL );
282+ zval_ptr_dtor (& args [1 ]);
283+
284+ if (php_openssl_is_session_ce (& retval )) {
285+ SSL_SESSION * found = php_openssl_session_from_zval (& retval );
286+ if (found != NULL ) {
287+ /* OpenSSL takes ownership of the returned session. */
288+ SSL_SESSION_up_ref (found );
289+ session = found ;
290+ }
291+ } else if (Z_TYPE (retval ) != IS_NULL ) {
292+ zend_type_error ("session_get_cb return type must be null or Openssl\\Session" );
293+ }
294+
295+ zval_ptr_dtor (& retval );
296+ * copy = 0 ;
297+ return session ;
298+ }
299+
300+ void php_openssl_session_remove_cb (SSL_CTX * ctx , SSL_SESSION * session )
301+ {
302+ php_stream * stream = (php_stream * )SSL_CTX_get_ex_data (ctx , php_openssl_get_ctx_stream_index ());
303+ php_openssl_session_callbacks_t * cbs = php_openssl_ctx_session_callbacks (ctx );
304+ if (!stream || !cbs ) {
305+ return ;
306+ }
307+
308+ unsigned int session_id_len = 0 ;
309+ const unsigned char * session_id = SSL_SESSION_get_id (session , & session_id_len );
310+
311+ zval args [2 ];
312+ ZVAL_RES (& args [0 ], stream -> res );
313+ ZVAL_STRINGL (& args [1 ], (char * )session_id , session_id_len );
314+
315+ zend_call_known_fcc (& cbs -> remove_cb , NULL , 2 , args , NULL );
316+ zval_ptr_dtor (& args [1 ]);
317+ }
318+
319+ zend_result php_openssl_validate_and_allocate_session_callback (php_stream * stream ,
320+ php_openssl_session_callbacks_t * * callbacks , const zval * callable ,
321+ enum php_openssl_session_callback_type cb_type , bool is_persistent )
322+ {
323+ const char * callback_name ;
324+ switch (cb_type ) {
325+ case PHP_OPENSSL_NEW_CB : callback_name = "session_new_cb" ; break ;
326+ case PHP_OPENSSL_GET_CB : callback_name = "session_get_cb" ; break ;
327+ case PHP_OPENSSL_REMOVE_CB : callback_name = "session_remove_cb" ; break ;
328+ }
329+
330+ /* Callbacks not supported for persistent streams */
331+ if (is_persistent ) {
332+ php_stream_warn (stream , PersistentNotSupported ,
333+ "%s is not supported for persistent streams" , callback_name );
334+ return FAILURE ;
335+ }
336+
337+ char * is_callable_error = NULL ;
338+ zend_fcall_info_cache fcc ;
339+ if (!zend_is_callable_ex (callable , NULL , 0 , NULL , & fcc , & is_callable_error )) {
340+ if (is_callable_error ) {
341+ zend_type_error ("%s must be a valid callback, %s" , callback_name , is_callable_error );
342+ efree (is_callable_error );
343+ } else {
344+ zend_type_error ("%s must be a valid callback" , callback_name );
345+ }
346+ return FAILURE ;
347+ }
348+
349+ if (!* callbacks ) {
350+ * callbacks = (php_openssl_session_callbacks_t * )pecalloc (
351+ 1 , sizeof (php_openssl_session_callbacks_t ), is_persistent );
352+ (* callbacks )-> refcount = 1 ;
353+ }
354+
355+ zend_fcc_addref (& fcc );
356+ switch (cb_type ) {
357+ case PHP_OPENSSL_NEW_CB : (* callbacks )-> new_cb = fcc ; break ;
358+ case PHP_OPENSSL_GET_CB : (* callbacks )-> get_cb = fcc ; break ;
359+ case PHP_OPENSSL_REMOVE_CB : (* callbacks )-> remove_cb = fcc ; break ;
360+ }
361+
362+ return SUCCESS ;
363+ }
364+
222365zend_result php_openssl_set_local_cert (SSL_CTX * ctx , php_stream * stream )
223366{
224367 zval * val ;
0 commit comments