Skip to content

Commit af00aa2

Browse files
committed
Session supports optional OpenSSL encryption.
1 parent 467d8b3 commit af00aa2

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
@@ -25,6 +25,10 @@
2525
# include "ext/hash/php_hash.h"
2626
#endif
2727

28+
#if defined(HAVE_OPENSSL_EXT)
29+
# include "ext/openssl/php_openssl.h"
30+
#endif
31+
2832
#define PHP_SESSION_API 20161017
2933

3034
#include "php_version.h"
@@ -205,6 +209,15 @@ typedef struct _php_ps_globals {
205209
zend_bool lazy_write; /* omit session write when it is possible */
206210
zend_bool in_save_handler; /* state if session is in save handler or not */
207211
zend_bool set_handler; /* state if session module i setting handler or not */
212+
#if defined(HAVE_OPENSSL_EXT)
213+
zend_bool ssl_encrypt; /* encrypt the session data */
214+
zend_string *ssl_iv;
215+
char *ssl_tag;
216+
char *ssl_method;
217+
zend_long ssl_method_len;
218+
zend_long ssl_iv_len;
219+
zend_long ssl_tag_len;
220+
#endif
208221
zend_string *session_vars; /* serialized original session data */
209222
} php_ps_globals;
210223

ext/session/session.c

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ static inline void php_rinit_session_globals(void) /* {{{ */
120120
PS(define_sid) = 1;
121121
PS(session_vars) = NULL;
122122
PS(module_number) = my_module_number;
123+
#if defined(HAVE_OPENSSL_EXT)
124+
PS(ssl_iv) = NULL;
125+
#endif
123126
ZVAL_UNDEF(&PS(http_session_vars));
124127
}
125128
/* }}} */
@@ -147,6 +150,13 @@ static inline void php_rshutdown_session_globals(void) /* {{{ */
147150
PS(session_vars) = NULL;
148151
}
149152

153+
#if defined(HAVE_OPENSSL_EXT)
154+
if (PS(ssl_iv)) {
155+
zend_string_release_ex(PS(ssl_iv), 0);
156+
PS(ssl_iv) = NULL;
157+
}
158+
#endif
159+
150160
/* User save handlers may end up directly here by misuse, bugs in user script, etc. */
151161
/* Set session status to prevent error while restoring save handler INI value. */
152162
PS(session_status) = php_session_none;
@@ -457,6 +467,41 @@ static int php_session_initialize(void) /* {{{ */
457467
php_session_decode(val);
458468
zend_string_release_ex(val, 0);
459469
}
470+
#if defined(HAVE_OPENSSL_EXT)
471+
if (PS(ssl_encrypt)) {
472+
zend_long ssl_method_len = strlen(PS(ssl_method));
473+
if (!ssl_method_len) {
474+
php_error_docref(NULL, E_WARNING, "A cipher method is needed to encrypt the session");
475+
PS(ssl_encrypt) = 0;
476+
} else {
477+
zend_string *iv;
478+
zend_long iv_len;
479+
zend_long ssl_tag_len = strlen(PS(ssl_tag));
480+
481+
if (PS(ssl_iv))
482+
zend_string_release_ex(PS(ssl_iv), 0);
483+
484+
if ((iv_len = php_openssl_cipher_iv_length(PS(ssl_method))) == -1 || iv_len == 0) {
485+
php_error_docref(NULL, E_ERROR, "session.ssl_method `%s` is invalid", PS(ssl_method));
486+
return FAILURE;
487+
}
488+
489+
if ((iv = php_openssl_random_pseudo_bytes(iv_len)) == NULL) {
490+
php_error_docref(NULL, E_ERROR, "session iv data failure");
491+
return FAILURE;
492+
}
493+
494+
if (!ssl_tag_len)
495+
PS(ssl_tag) = NULL;
496+
PS(ssl_tag_len) = ssl_tag_len;
497+
498+
ZSTR_VAL(iv)[iv_len] = 0;
499+
PS(ssl_method_len) = ssl_method_len;
500+
PS(ssl_iv) = iv;
501+
PS(ssl_iv_len) = iv_len;
502+
}
503+
}
504+
#endif
460505
return SUCCESS;
461506
}
462507
/* }}} */
@@ -813,6 +858,13 @@ PHP_INI_BEGIN()
813858
PHP_INI_ENTRY("session.sid_length", "32", PHP_INI_ALL, OnUpdateSidLength)
814859
PHP_INI_ENTRY("session.sid_bits_per_character", "4", PHP_INI_ALL, OnUpdateSidBits)
815860
STD_PHP_INI_BOOLEAN("session.lazy_write", "1", PHP_INI_ALL, OnUpdateLazyWrite, lazy_write, php_ps_globals, ps_globals)
861+
#if defined(HAVE_OPENSSL_EXT)
862+
STD_PHP_INI_BOOLEAN("session.ssl_encrypt", "0", PHP_INI_ALL, OnUpdateBool, ssl_encrypt, php_ps_globals, ps_globals)
863+
STD_PHP_INI_ENTRY("session.ssl_method", "", PHP_INI_ALL, OnUpdateSessionString, ssl_method, php_ps_globals, ps_globals)
864+
STD_PHP_INI_ENTRY("session.ssl_tag", "", PHP_INI_ALL, OnUpdateSessionString, ssl_tag, php_ps_globals, ps_globals)
865+
#endif
866+
867+
/* Commented out until future discussion */
816868

817869
/* Upload progress */
818870
STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",
@@ -826,15 +878,69 @@ PHP_INI_BEGIN()
826878
STD_PHP_INI_ENTRY("session.upload_progress.freq", "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq, php_ps_globals, ps_globals)
827879
STD_PHP_INI_ENTRY("session.upload_progress.min_freq",
828880
"1", ZEND_INI_PERDIR, OnUpdateReal, rfc1867_min_freq,php_ps_globals, ps_globals)
829-
830-
/* Commented out until future discussion */
831881
/* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
832882
PHP_INI_END()
833-
/* }}} */
883+
/* }}} */
834884

835885
/* ***************
836886
* Serializers *
837887
*************** */
888+
889+
#if defined(HAVE_OPENSSL_EXT)
890+
static int php_session_encrypt(smart_str *buf) /* {{{ */
891+
{
892+
zend_string* buffer;
893+
smart_str res = {0};
894+
895+
if (!PS(ssl_encrypt) || !PS(id) || !buf->a)
896+
return SUCCESS;
897+
898+
zval *ztag = NULL;
899+
900+
if (PS(ssl_tag_len) > 0) {
901+
ztag = emalloc(sizeof(*ztag));
902+
ZVAL_STRINGL(ztag, PS(ssl_tag), PS(ssl_tag_len));
903+
}
904+
905+
if ((buffer = php_openssl_encrypt(ZSTR_VAL(buf->s), buf->a, PS(ssl_method), PS(ssl_method_len),
906+
ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 0, ZSTR_VAL(PS(ssl_iv)), PS(ssl_iv_len),
907+
ztag, PS(ssl_tag_len), NULL, 0)) == NULL) {
908+
php_error_docref(NULL, E_WARNING, "Cannot encrypt the session data with method '%s', tag '%s'",
909+
PS(ssl_method), PS(ssl_tag));
910+
efree(ztag);
911+
return FAILURE;
912+
}
913+
914+
smart_str_free(buf);
915+
res.s = zend_string_dup(buffer, 0);
916+
res.a = ZSTR_LEN(buffer);
917+
*buf = res;
918+
zend_string_release_ex(buffer, 0);
919+
efree(ztag);
920+
return SUCCESS;
921+
}
922+
/* }}} */
923+
924+
static zend_string *php_session_decrypt(PS_SERIALIZER_DECODE_ARGS) /* {{{ */
925+
{
926+
zend_string* buffer;
927+
928+
if (!PS(ssl_encrypt) || !PS(id) || !vallen)
929+
return NULL;
930+
931+
if ((buffer = php_openssl_decrypt((char *)val, vallen, PS(ssl_method), PS(ssl_method_len),
932+
ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 0, ZSTR_VAL(PS(ssl_iv)), PS(ssl_iv_len),
933+
PS(ssl_tag), PS(ssl_tag_len), NULL, 0)) == NULL) {
934+
php_error_docref(NULL, E_WARNING, "Cannot decrypt the session data with method '%s'",
935+
PS(ssl_method));
936+
return NULL;
937+
}
938+
939+
return buffer;
940+
}
941+
/* }}} */
942+
#endif
943+
838944
PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */
839945
{
840946
smart_str buf = {0};
@@ -843,6 +949,9 @@ PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */
843949
IF_SESSION_VARS() {
844950
PHP_VAR_SERIALIZE_INIT(var_hash);
845951
php_var_serialize(&buf, Z_REFVAL(PS(http_session_vars)), &var_hash);
952+
#if defined(HAVE_OPENSSL_EXT)
953+
php_session_encrypt(&buf);
954+
#endif
846955
PHP_VAR_SERIALIZE_DESTROY(var_hash);
847956
}
848957
return buf.s;
@@ -857,6 +966,13 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */
857966
int result;
858967
zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
859968

969+
#if defined(HAVE_OPENSSL_EXT)
970+
zend_string* buffer = php_session_decrypt(val, vallen);
971+
if (buffer) {
972+
val = ZSTR_VAL(buffer);
973+
endptr = val + ZSTR_LEN(buffer);
974+
}
975+
#endif
860976
ZVAL_NULL(&session_vars);
861977
PHP_VAR_UNSERIALIZE_INIT(var_hash);
862978
result = php_var_unserialize(
@@ -877,9 +993,14 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */
877993
Z_ADDREF_P(&PS(http_session_vars));
878994
zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars));
879995
zend_string_release_ex(var_name, 0);
996+
#if defined(HAVE_OPENSSL_EXT)
997+
if (buffer)
998+
zend_string_release_ex(buffer, 0);
999+
#endif
1000+
8801001
return SUCCESS;
8811002
}
882-
/* }}} */
1003+
/* }}} */
8831004

8841005
#define PS_BIN_NR_OF_BITS 8
8851006
#define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
@@ -901,6 +1022,9 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */
9011022
);
9021023

9031024
smart_str_0(&buf);
1025+
#if defined(HAVE_OPENSSL_EXT)
1026+
php_session_encrypt(&buf);
1027+
#endif
9041028
PHP_VAR_SERIALIZE_DESTROY(var_hash);
9051029

9061030
return buf.s;
@@ -915,6 +1039,13 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
9151039
zend_string *name;
9161040
php_unserialize_data_t var_hash;
9171041
zval *current, rv;
1042+
#if defined(HAVE_OPENSSL_EXT)
1043+
zend_string* buffer = php_session_decrypt(val, vallen);
1044+
if (buffer) {
1045+
val = ZSTR_VAL(buffer);
1046+
endptr = val + ZSTR_LEN(buffer);
1047+
}
1048+
#endif
9181049

9191050
PHP_VAR_UNSERIALIZE_INIT(var_hash);
9201051

@@ -944,6 +1075,10 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
9441075

9451076
php_session_normalize_vars();
9461077
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1078+
#if defined(HAVE_OPENSSL_EXT)
1079+
if (buffer)
1080+
zend_string_release_ex(buffer, 0);
1081+
#endif
9471082

9481083
return SUCCESS;
9491084
}
@@ -971,6 +1106,9 @@ PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */
9711106
);
9721107

9731108
smart_str_0(&buf);
1109+
#if defined(HAVE_OPENSSL_EXT)
1110+
php_session_encrypt(&buf);
1111+
#endif
9741112

9751113
PHP_VAR_SERIALIZE_DESTROY(var_hash);
9761114
return buf.s;
@@ -987,6 +1125,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
9871125
php_unserialize_data_t var_hash;
9881126
zval *current, rv;
9891127

1128+
#if defined(HAVE_OPENSSL_EXT)
1129+
zend_string* buffer = php_session_decrypt(val, vallen);
1130+
if (buffer) {
1131+
val = ZSTR_VAL(buffer);
1132+
endptr = val + ZSTR_LEN(buffer);
1133+
}
1134+
#endif
9901135
PHP_VAR_UNSERIALIZE_INIT(var_hash);
9911136

9921137
p = val;
@@ -1018,6 +1163,10 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
10181163
php_session_normalize_vars();
10191164

10201165
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1166+
#if defined(HAVE_OPENSSL_EXT)
1167+
if (buffer)
1168+
zend_string_release_ex(buffer, 0);
1169+
#endif
10211170

10221171
return retval;
10231172
}

0 commit comments

Comments
 (0)