Skip to content

Commit 612e3ba

Browse files
committed
Session supports optional OpenSSL encryption.
1 parent 14319c2 commit 612e3ba

File tree

2 files changed

+166
-4
lines changed

2 files changed

+166
-4
lines changed

ext/session/php_session.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#include "ext/standard/php_var.h"
2121
#include "ext/hash/php_hash.h"
2222

23+
#if defined(HAVE_OPENSSL_EXT)
24+
# include "ext/openssl/php_openssl.h"
25+
#endif
26+
2327
#define PHP_SESSION_API 20161017
2428

2529
#include "php_version.h"
@@ -201,6 +205,15 @@ typedef struct _php_ps_globals {
201205
bool lazy_write; /* omit session write when it is possible */
202206
bool in_save_handler; /* state if session is in save handler or not */
203207
bool set_handler; /* state if session module i setting handler or not */
208+
#if defined(HAVE_OPENSSL_EXT)
209+
bool ssl_encrypt; /* encrypt the session data */
210+
zend_string *ssl_iv;
211+
char *ssl_tag;
212+
char *ssl_method;
213+
zend_long ssl_method_len;
214+
zend_long ssl_iv_len;
215+
zend_long ssl_tag_len;
216+
#endif
204217
zend_string *session_vars; /* serialized original session data */
205218
} php_ps_globals;
206219

ext/session/session.c

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ static inline void php_rinit_session_globals(void) /* {{{ */
116116
PS(define_sid) = 1;
117117
PS(session_vars) = NULL;
118118
PS(module_number) = my_module_number;
119+
#if defined(HAVE_OPENSSL_EXT)
120+
PS(ssl_iv) = NULL;
121+
#endif
119122
ZVAL_UNDEF(&PS(http_session_vars));
120123
}
121124
/* }}} */
@@ -143,6 +146,13 @@ static inline void php_rshutdown_session_globals(void) /* {{{ */
143146
PS(session_vars) = NULL;
144147
}
145148

149+
#if defined(HAVE_OPENSSL_EXT)
150+
if (PS(ssl_iv)) {
151+
zend_string_release_ex(PS(ssl_iv), 0);
152+
PS(ssl_iv) = NULL;
153+
}
154+
#endif
155+
146156
/* User save handlers may end up directly here by misuse, bugs in user script, etc. */
147157
/* Set session status to prevent error while restoring save handler INI value. */
148158
PS(session_status) = php_session_none;
@@ -462,6 +472,41 @@ static int php_session_initialize(void) /* {{{ */
462472
php_session_decode(val);
463473
zend_string_release_ex(val, 0);
464474
}
475+
#if defined(HAVE_OPENSSL_EXT)
476+
if (PS(ssl_encrypt)) {
477+
zend_long ssl_method_len = strlen(PS(ssl_method));
478+
if (!ssl_method_len) {
479+
php_error_docref(NULL, E_WARNING, "A cipher method is needed to encrypt the session");
480+
PS(ssl_encrypt) = 0;
481+
} else {
482+
zend_string *iv;
483+
zend_long iv_len;
484+
zend_long ssl_tag_len = strlen(PS(ssl_tag));
485+
486+
if (PS(ssl_iv))
487+
zend_string_release_ex(PS(ssl_iv), 0);
488+
489+
if ((iv_len = php_openssl_cipher_iv_length(PS(ssl_method))) == -1 || iv_len == 0) {
490+
php_error_docref(NULL, E_ERROR, "session.ssl_method `%s` is invalid", PS(ssl_method));
491+
return FAILURE;
492+
}
493+
494+
if ((iv = php_openssl_random_pseudo_bytes(iv_len)) == NULL) {
495+
php_error_docref(NULL, E_ERROR, "session iv data failure");
496+
return FAILURE;
497+
}
498+
499+
if (!ssl_tag_len)
500+
PS(ssl_tag) = NULL;
501+
PS(ssl_tag_len) = ssl_tag_len;
502+
503+
ZSTR_VAL(iv)[iv_len] = 0;
504+
PS(ssl_method_len) = ssl_method_len;
505+
PS(ssl_iv) = iv;
506+
PS(ssl_iv_len) = iv_len;
507+
}
508+
}
509+
#endif
465510
return SUCCESS;
466511
}
467512
/* }}} */
@@ -823,6 +868,13 @@ PHP_INI_BEGIN()
823868
PHP_INI_ENTRY("session.sid_length", "32", PHP_INI_ALL, OnUpdateSidLength)
824869
PHP_INI_ENTRY("session.sid_bits_per_character", "4", PHP_INI_ALL, OnUpdateSidBits)
825870
STD_PHP_INI_BOOLEAN("session.lazy_write", "1", PHP_INI_ALL, OnUpdateLazyWrite, lazy_write, php_ps_globals, ps_globals)
871+
#if defined(HAVE_OPENSSL_EXT)
872+
STD_PHP_INI_BOOLEAN("session.ssl_encrypt", "0", PHP_INI_ALL, OnUpdateBool, ssl_encrypt, php_ps_globals, ps_globals)
873+
STD_PHP_INI_ENTRY("session.ssl_method", "", PHP_INI_ALL, OnUpdateSessionString, ssl_method, php_ps_globals, ps_globals)
874+
STD_PHP_INI_ENTRY("session.ssl_tag", "", PHP_INI_ALL, OnUpdateSessionString, ssl_tag, php_ps_globals, ps_globals)
875+
#endif
876+
877+
/* Commented out until future discussion */
826878

827879
/* Upload progress */
828880
STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",
@@ -836,15 +888,69 @@ PHP_INI_BEGIN()
836888
STD_PHP_INI_ENTRY("session.upload_progress.freq", "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq, php_ps_globals, ps_globals)
837889
STD_PHP_INI_ENTRY("session.upload_progress.min_freq",
838890
"1", ZEND_INI_PERDIR, OnUpdateReal, rfc1867_min_freq,php_ps_globals, ps_globals)
839-
840-
/* Commented out until future discussion */
841891
/* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
842892
PHP_INI_END()
843-
/* }}} */
893+
/* }}} */
844894

845895
/* ***************
846896
* Serializers *
847897
*************** */
898+
899+
#if defined(HAVE_OPENSSL_EXT)
900+
static int php_session_encrypt(smart_str *buf) /* {{{ */
901+
{
902+
zend_string* buffer;
903+
smart_str res = {0};
904+
905+
if (!PS(ssl_encrypt) || !PS(id) || !buf->a)
906+
return SUCCESS;
907+
908+
zval *ztag = NULL;
909+
910+
if (PS(ssl_tag_len) > 0) {
911+
ztag = emalloc(sizeof(*ztag));
912+
ZVAL_STRINGL(ztag, PS(ssl_tag), PS(ssl_tag_len));
913+
}
914+
915+
if ((buffer = php_openssl_encrypt(ZSTR_VAL(buf->s), buf->a, PS(ssl_method), PS(ssl_method_len),
916+
ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 0, ZSTR_VAL(PS(ssl_iv)), PS(ssl_iv_len),
917+
ztag, PS(ssl_tag_len), NULL, 0)) == NULL) {
918+
php_error_docref(NULL, E_WARNING, "Cannot encrypt the session data with method '%s', tag '%s'",
919+
PS(ssl_method), PS(ssl_tag));
920+
efree(ztag);
921+
return FAILURE;
922+
}
923+
924+
smart_str_free(buf);
925+
res.s = zend_string_dup(buffer, 0);
926+
res.a = ZSTR_LEN(buffer);
927+
*buf = res;
928+
zend_string_release_ex(buffer, 0);
929+
efree(ztag);
930+
return SUCCESS;
931+
}
932+
/* }}} */
933+
934+
static zend_string *php_session_decrypt(PS_SERIALIZER_DECODE_ARGS) /* {{{ */
935+
{
936+
zend_string* buffer;
937+
938+
if (!PS(ssl_encrypt) || !PS(id) || !vallen)
939+
return NULL;
940+
941+
if ((buffer = php_openssl_decrypt((char *)val, vallen, PS(ssl_method), PS(ssl_method_len),
942+
ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 0, ZSTR_VAL(PS(ssl_iv)), PS(ssl_iv_len),
943+
PS(ssl_tag), PS(ssl_tag_len), NULL, 0)) == NULL) {
944+
php_error_docref(NULL, E_WARNING, "Cannot decrypt the session data with method '%s'",
945+
PS(ssl_method));
946+
return NULL;
947+
}
948+
949+
return buffer;
950+
}
951+
/* }}} */
952+
#endif
953+
848954
PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */
849955
{
850956
smart_str buf = {0};
@@ -853,6 +959,9 @@ PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */
853959
IF_SESSION_VARS() {
854960
PHP_VAR_SERIALIZE_INIT(var_hash);
855961
php_var_serialize(&buf, Z_REFVAL(PS(http_session_vars)), &var_hash);
962+
#if defined(HAVE_OPENSSL_EXT)
963+
php_session_encrypt(&buf);
964+
#endif
856965
PHP_VAR_SERIALIZE_DESTROY(var_hash);
857966
}
858967
return buf.s;
@@ -867,6 +976,13 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */
867976
int result;
868977
zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
869978

979+
#if defined(HAVE_OPENSSL_EXT)
980+
zend_string* buffer = php_session_decrypt(val, vallen);
981+
if (buffer) {
982+
val = ZSTR_VAL(buffer);
983+
endptr = val + ZSTR_LEN(buffer);
984+
}
985+
#endif
870986
ZVAL_NULL(&session_vars);
871987
PHP_VAR_UNSERIALIZE_INIT(var_hash);
872988
result = php_var_unserialize(
@@ -887,9 +1003,14 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */
8871003
Z_ADDREF_P(&PS(http_session_vars));
8881004
zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars));
8891005
zend_string_release_ex(var_name, 0);
1006+
#if defined(HAVE_OPENSSL_EXT)
1007+
if (buffer)
1008+
zend_string_release_ex(buffer, 0);
1009+
#endif
1010+
8901011
return result || !vallen ? SUCCESS : FAILURE;
8911012
}
892-
/* }}} */
1013+
/* }}} */
8931014

8941015
#define PS_BIN_NR_OF_BITS 8
8951016
#define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
@@ -911,6 +1032,9 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */
9111032
);
9121033

9131034
smart_str_0(&buf);
1035+
#if defined(HAVE_OPENSSL_EXT)
1036+
php_session_encrypt(&buf);
1037+
#endif
9141038
PHP_VAR_SERIALIZE_DESTROY(var_hash);
9151039

9161040
return buf.s;
@@ -925,6 +1049,13 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
9251049
zend_string *name;
9261050
php_unserialize_data_t var_hash;
9271051
zval *current, rv;
1052+
#if defined(HAVE_OPENSSL_EXT)
1053+
zend_string* buffer = php_session_decrypt(val, vallen);
1054+
if (buffer) {
1055+
val = ZSTR_VAL(buffer);
1056+
endptr = val + ZSTR_LEN(buffer);
1057+
}
1058+
#endif
9281059

9291060
PHP_VAR_UNSERIALIZE_INIT(var_hash);
9301061

@@ -954,6 +1085,10 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
9541085

9551086
php_session_normalize_vars();
9561087
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1088+
#if defined(HAVE_OPENSSL_EXT)
1089+
if (buffer)
1090+
zend_string_release_ex(buffer, 0);
1091+
#endif
9571092

9581093
return SUCCESS;
9591094
}
@@ -981,6 +1116,9 @@ PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */
9811116
);
9821117

9831118
smart_str_0(&buf);
1119+
#if defined(HAVE_OPENSSL_EXT)
1120+
php_session_encrypt(&buf);
1121+
#endif
9841122

9851123
PHP_VAR_SERIALIZE_DESTROY(var_hash);
9861124
return buf.s;
@@ -997,6 +1135,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
9971135
php_unserialize_data_t var_hash;
9981136
zval *current, rv;
9991137

1138+
#if defined(HAVE_OPENSSL_EXT)
1139+
zend_string* buffer = php_session_decrypt(val, vallen);
1140+
if (buffer) {
1141+
val = ZSTR_VAL(buffer);
1142+
endptr = val + ZSTR_LEN(buffer);
1143+
}
1144+
#endif
10001145
PHP_VAR_UNSERIALIZE_INIT(var_hash);
10011146

10021147
p = val;
@@ -1031,6 +1176,10 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
10311176
php_session_normalize_vars();
10321177

10331178
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1179+
#if defined(HAVE_OPENSSL_EXT)
1180+
if (buffer)
1181+
zend_string_release_ex(buffer, 0);
1182+
#endif
10341183

10351184
return retval;
10361185
}

0 commit comments

Comments
 (0)