diff options
| author | kkadosh | 2018-05-29 19:34:16 +0000 |
|---|---|---|
| committer | jvoisin | 2018-05-29 19:34:16 +0000 |
| commit | 7832438b7abedf567ce6376f99949f419abcdff1 (patch) | |
| tree | 560e43918d1dc36ce4cf760a5b27aed0c563bc1c /src | |
| parent | 9eebe8c67e03e3041d454ea28e93996f7a67740b (diff) | |
Support session encryption
Implement session encryption.
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.m4 | 2 | ||||
| -rw-r--r-- | src/php_snuffleupagus.h | 2 | ||||
| -rw-r--r-- | src/snuffleupagus.c | 6 | ||||
| -rw-r--r-- | src/sp_config.c | 1 | ||||
| -rw-r--r-- | src/sp_config.h | 7 | ||||
| -rw-r--r-- | src/sp_config_keywords.c | 43 | ||||
| -rw-r--r-- | src/sp_config_keywords.h | 1 | ||||
| -rw-r--r-- | src/sp_cookie_encryption.c | 6 | ||||
| -rw-r--r-- | src/sp_crypt.c | 52 | ||||
| -rw-r--r-- | src/sp_crypt.h | 2 | ||||
| -rw-r--r-- | src/sp_session.c | 159 | ||||
| -rw-r--r-- | src/sp_session.h | 11 | ||||
| -rw-r--r-- | src/tests/config/config_crypt_session.ini | 2 | ||||
| -rw-r--r-- | src/tests/config/config_crypt_session_simul.ini | 3 | ||||
| -rw-r--r-- | src/tests/crypt_session_invalid.phpt | 24 | ||||
| -rw-r--r-- | src/tests/crypt_session_invalid_simul.phpt | 27 | ||||
| -rw-r--r-- | src/tests/crypt_session_read_uncrypt.phpt | 33 | ||||
| -rw-r--r-- | src/tests/crypt_session_valid.phpt | 27 | ||||
| -rw-r--r-- | src/tests/crypt_session_valid_simul.phpt | 27 | ||||
| -rw-r--r-- | src/tests/samesite_cookies.phpt | 51 |
20 files changed, 438 insertions, 48 deletions
diff --git a/src/config.m4 b/src/config.m4 index 9909da2..a4fea4d 100644 --- a/src/config.m4 +++ b/src/config.m4 | |||
| @@ -6,7 +6,7 @@ sources="$sources sp_unserialize.c sp_utils.c sp_disable_xxe.c sp_list.c" | |||
| 6 | sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" | 6 | sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" |
| 7 | sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" | 7 | sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" |
| 8 | sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" | 8 | sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" |
| 9 | sources="$sources sp_pcre_compat.c sp_crypt.c" | 9 | sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c" |
| 10 | 10 | ||
| 11 | PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, | 11 | PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, |
| 12 | [ --enable-snuffleupagus Enable snuffleupagus support]) | 12 | [ --enable-snuffleupagus Enable snuffleupagus support]) |
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index c658dac..f80ae66 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "ext/standard/info.h" | 18 | #include "ext/standard/info.h" |
| 19 | #include "ext/standard/php_var.h" | 19 | #include "ext/standard/php_var.h" |
| 20 | #include "ext/pcre/php_pcre.h" | 20 | #include "ext/pcre/php_pcre.h" |
| 21 | #include "ext/session/php_session.h" | ||
| 21 | #include "php.h" | 22 | #include "php.h" |
| 22 | #include "php_ini.h" | 23 | #include "php_ini.h" |
| 23 | #include "zend_hash.h" | 24 | #include "zend_hash.h" |
| @@ -41,6 +42,7 @@ | |||
| 41 | #include "sp_upload_validation.h" | 42 | #include "sp_upload_validation.h" |
| 42 | #include "sp_utils.h" | 43 | #include "sp_utils.h" |
| 43 | #include "sp_crypt.h" | 44 | #include "sp_crypt.h" |
| 45 | #include "sp_session.h" | ||
| 44 | 46 | ||
| 45 | 47 | ||
| 46 | extern zend_module_entry snuffleupagus_module_entry; | 48 | extern zend_module_entry snuffleupagus_module_entry; |
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 3cdcfb9..c3fc686 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c | |||
| @@ -81,6 +81,7 @@ PHP_GINIT_FUNCTION(snuffleupagus) { | |||
| 81 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions); | 81 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions); |
| 82 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions_ret); | 82 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions_ret); |
| 83 | SP_INIT(snuffleupagus_globals->config.config_cookie); | 83 | SP_INIT(snuffleupagus_globals->config.config_cookie); |
| 84 | SP_INIT(snuffleupagus_globals->config.config_session); | ||
| 84 | SP_INIT(snuffleupagus_globals->config.config_disabled_constructs); | 85 | SP_INIT(snuffleupagus_globals->config.config_disabled_constructs); |
| 85 | SP_INIT(snuffleupagus_globals->config.config_eval); | 86 | SP_INIT(snuffleupagus_globals->config.config_eval); |
| 86 | 87 | ||
| @@ -124,6 +125,7 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { | |||
| 124 | pefree(SNUFFLEUPAGUS_G(config.config_snuffleupagus), 1); | 125 | pefree(SNUFFLEUPAGUS_G(config.config_snuffleupagus), 1); |
| 125 | pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1); | 126 | pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1); |
| 126 | pefree(SNUFFLEUPAGUS_G(config.config_upload_validation), 1); | 127 | pefree(SNUFFLEUPAGUS_G(config.config_upload_validation), 1); |
| 128 | pefree(SNUFFLEUPAGUS_G(config.config_session), 1); | ||
| 127 | 129 | ||
| 128 | #define FREE_LST_DISABLE(L) \ | 130 | #define FREE_LST_DISABLE(L) \ |
| 129 | do { \ | 131 | do { \ |
| @@ -229,6 +231,10 @@ static PHP_INI_MH(OnUpdateConfiguration) { | |||
| 229 | } | 231 | } |
| 230 | hook_cookies(); | 232 | hook_cookies(); |
| 231 | 233 | ||
| 234 | if (SNUFFLEUPAGUS_G(config).config_session->encrypt) { | ||
| 235 | hook_session(); | ||
| 236 | } | ||
| 237 | |||
| 232 | if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { | 238 | if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { |
| 233 | if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { | 239 | if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { |
| 234 | zend_extension_entry.startup = NULL; | 240 | zend_extension_entry.startup = NULL; |
diff --git a/src/sp_config.c b/src/sp_config.c index 67140a0..a89174a 100644 --- a/src/sp_config.c +++ b/src/sp_config.c | |||
| @@ -21,6 +21,7 @@ sp_config_tokens const sp_func[] = { | |||
| 21 | {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE}, | 21 | {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE}, |
| 22 | {.func = parse_eval_blacklist, .token = SP_TOKEN_EVAL_BLACKLIST}, | 22 | {.func = parse_eval_blacklist, .token = SP_TOKEN_EVAL_BLACKLIST}, |
| 23 | {.func = parse_eval_whitelist, .token = SP_TOKEN_EVAL_WHITELIST}, | 23 | {.func = parse_eval_whitelist, .token = SP_TOKEN_EVAL_WHITELIST}, |
| 24 | {.func = parse_session, .token = SP_TOKEN_SESSION_ENCRYPTION}, | ||
| 24 | {NULL, NULL}}; | 25 | {NULL, NULL}}; |
| 25 | 26 | ||
| 26 | /* Top level keyword parsing */ | 27 | /* Top level keyword parsing */ |
diff --git a/src/sp_config.h b/src/sp_config.h index e537ec2..b44960f 100644 --- a/src/sp_config.h +++ b/src/sp_config.h | |||
| @@ -66,6 +66,11 @@ typedef struct { | |||
| 66 | } sp_cookie; | 66 | } sp_cookie; |
| 67 | 67 | ||
| 68 | typedef struct { | 68 | typedef struct { |
| 69 | bool encrypt; | ||
| 70 | bool simulation; | ||
| 71 | } sp_config_session; | ||
| 72 | |||
| 73 | typedef struct { | ||
| 69 | bool enable; | 74 | bool enable; |
| 70 | bool simulation; | 75 | bool simulation; |
| 71 | char *dump; | 76 | char *dump; |
| @@ -158,6 +163,7 @@ typedef struct { | |||
| 158 | sp_config_disable_xxe *config_disable_xxe; | 163 | sp_config_disable_xxe *config_disable_xxe; |
| 159 | sp_config_disabled_constructs *config_disabled_constructs; | 164 | sp_config_disabled_constructs *config_disabled_constructs; |
| 160 | sp_config_eval *config_eval; | 165 | sp_config_eval *config_eval; |
| 166 | sp_config_session *config_session; | ||
| 161 | } sp_config; | 167 | } sp_config; |
| 162 | 168 | ||
| 163 | typedef struct { | 169 | typedef struct { |
| @@ -175,6 +181,7 @@ typedef struct { | |||
| 175 | 181 | ||
| 176 | #define SP_TOKEN_AUTO_COOKIE_SECURE ".auto_cookie_secure" | 182 | #define SP_TOKEN_AUTO_COOKIE_SECURE ".auto_cookie_secure" |
| 177 | #define SP_TOKEN_COOKIE_ENCRYPTION ".cookie" | 183 | #define SP_TOKEN_COOKIE_ENCRYPTION ".cookie" |
| 184 | #define SP_TOKEN_SESSION_ENCRYPTION ".session" | ||
| 178 | #define SP_TOKEN_DISABLE_FUNC ".disable_function" | 185 | #define SP_TOKEN_DISABLE_FUNC ".disable_function" |
| 179 | #define SP_TOKEN_GLOBAL ".global" | 186 | #define SP_TOKEN_GLOBAL ".global" |
| 180 | #define SP_TOKEN_GLOBAL_STRICT ".global_strict" | 187 | #define SP_TOKEN_GLOBAL_STRICT ".global_strict" |
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 9faaafb..f702f4d 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c | |||
| @@ -60,6 +60,49 @@ static int parse_enable(char *line, bool *restrict retval, | |||
| 60 | return ret; | 60 | return ret; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | int parse_session(char *line) { | ||
| 64 | sp_config_session *session = | ||
| 65 | pecalloc(sizeof(sp_config_session), 1, 0); | ||
| 66 | |||
| 67 | sp_config_functions sp_config_funcs_session_encryption[] = { | ||
| 68 | {parse_empty, SP_TOKEN_ENCRYPT, &(session->encrypt)}, | ||
| 69 | {parse_empty, SP_TOKEN_SIMULATION, &(session->simulation)}, | ||
| 70 | {0}}; | ||
| 71 | int ret = parse_keywords(sp_config_funcs_session_encryption, line); | ||
| 72 | if (0 != ret) { | ||
| 73 | return ret; | ||
| 74 | } | ||
| 75 | if (session->encrypt) { | ||
| 76 | if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) { | ||
| 77 | sp_log_err( | ||
| 78 | "config", | ||
| 79 | "You're trying to use the session cookie encryption feature" | ||
| 80 | "on line %zu without having set the `.cookie_env_var` option in" | ||
| 81 | "`sp.global`: please set it first.", | ||
| 82 | sp_line_no); | ||
| 83 | pefree(session, 0); | ||
| 84 | return -1; | ||
| 85 | } else if (0 == | ||
| 86 | (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) { | ||
| 87 | sp_log_err( | ||
| 88 | "config", | ||
| 89 | "You're trying to use the session cookie encryption feature" | ||
| 90 | "on line %zu without having set the `.encryption_key` option in" | ||
| 91 | "`sp.global`: please set it first.", | ||
| 92 | sp_line_no); | ||
| 93 | pefree(session, 0); | ||
| 94 | return -1; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | SNUFFLEUPAGUS_G(config).config_session->encrypt = | ||
| 99 | session->encrypt; | ||
| 100 | SNUFFLEUPAGUS_G(config).config_session->simulation = | ||
| 101 | session->simulation; | ||
| 102 | pefree(session, 0); | ||
| 103 | return ret; | ||
| 104 | } | ||
| 105 | |||
| 63 | int parse_random(char *line) { | 106 | int parse_random(char *line) { |
| 64 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable), | 107 | return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable), |
| 65 | NULL); | 108 | NULL); |
diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h index 4205dac..f1f414a 100644 --- a/src/sp_config_keywords.h +++ b/src/sp_config_keywords.h | |||
| @@ -14,5 +14,6 @@ int parse_disabled_functions(char *line); | |||
| 14 | int parse_upload_validation(char *line); | 14 | int parse_upload_validation(char *line); |
| 15 | int parse_eval_blacklist(char *line); | 15 | int parse_eval_blacklist(char *line); |
| 16 | int parse_eval_whitelist(char *line); | 16 | int parse_eval_whitelist(char *line); |
| 17 | int parse_session(char *line); | ||
| 17 | 18 | ||
| 18 | #endif // __SP_CONFIG_KEYWORDS_H | 19 | #endif // __SP_CONFIG_KEYWORDS_H |
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c index 9030112..72223ad 100644 --- a/src/sp_cookie_encryption.c +++ b/src/sp_cookie_encryption.c | |||
| @@ -21,7 +21,6 @@ static inline const sp_cookie *sp_lookup_cookie_config(const char *key) { | |||
| 21 | int decrypt_cookie(zval *pDest, int num_args, va_list args, | 21 | int decrypt_cookie(zval *pDest, int num_args, va_list args, |
| 22 | zend_hash_key *hash_key) { | 22 | zend_hash_key *hash_key) { |
| 23 | const sp_cookie *cookie = sp_lookup_cookie_config(ZSTR_VAL(hash_key->key)); | 23 | const sp_cookie *cookie = sp_lookup_cookie_config(ZSTR_VAL(hash_key->key)); |
| 24 | int ret = 0; | ||
| 25 | 24 | ||
| 26 | /* If the cookie isn't in the conf, it shouldn't be encrypted. */ | 25 | /* If the cookie isn't in the conf, it shouldn't be encrypted. */ |
| 27 | if (!cookie || !cookie->encrypt) { | 26 | if (!cookie || !cookie->encrypt) { |
| @@ -36,11 +35,6 @@ int decrypt_cookie(zval *pDest, int num_args, va_list args, | |||
| 36 | return decrypt_zval(pDest, cookie->simulation, hash_key); | 35 | return decrypt_zval(pDest, cookie->simulation, hash_key); |
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | /* | ||
| 40 | ** This function will return the `data` of length `data_len` encrypted in the | ||
| 41 | ** form `base64(nonce | encrypted_data)` (with `|` being the concatenation | ||
| 42 | ** operation). | ||
| 43 | */ | ||
| 44 | static zend_string *encrypt_data(char *data, unsigned long long data_len) { | 38 | static zend_string *encrypt_data(char *data, unsigned long long data_len) { |
| 45 | zend_string *z = encrypt_zval(data, data_len); | 39 | zend_string *z = encrypt_zval(data, data_len); |
| 46 | sp_log_debug("cookie_encryption", "Cookie value:%s:", z->val); | 40 | sp_log_debug("cookie_encryption", "Cookie value:%s:", z->val); |
diff --git a/src/sp_crypt.c b/src/sp_crypt.c index 0c40f1f..55ae37b 100644 --- a/src/sp_crypt.c +++ b/src/sp_crypt.c | |||
| @@ -4,9 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 5 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 6 | 6 | ||
| 7 | static zend_long nonce_d = 0; | 7 | void generate_key(unsigned char *key) { |
| 8 | |||
| 9 | static void generate_key(unsigned char *key) { | ||
| 10 | PHP_SHA256_CTX ctx; | 8 | PHP_SHA256_CTX ctx; |
| 11 | const char *user_agent = getenv("HTTP_USER_AGENT"); | 9 | const char *user_agent = getenv("HTTP_USER_AGENT"); |
| 12 | const char *env_var = | 10 | const char *env_var = |
| @@ -50,14 +48,13 @@ int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hash_key) { | |||
| 50 | debase64 = php_base64_decode((unsigned char *)(Z_STRVAL_P(pDest)), | 48 | debase64 = php_base64_decode((unsigned char *)(Z_STRVAL_P(pDest)), |
| 51 | Z_STRLEN_P(pDest)); | 49 | Z_STRLEN_P(pDest)); |
| 52 | 50 | ||
| 53 | if (ZSTR_LEN(debase64) < | 51 | if (ZSTR_LEN(debase64) < crypto_secretbox_NONCEBYTES) { |
| 54 | crypto_secretbox_NONCEBYTES + crypto_secretbox_ZEROBYTES) { | ||
| 55 | if (true == simulation) { | 52 | if (true == simulation) { |
| 56 | sp_log_msg( | 53 | sp_log_msg( |
| 57 | "cookie_encryption", SP_LOG_SIMULATION, | 54 | "cookie_encryption", SP_LOG_SIMULATION, |
| 58 | "Buffer underflow tentative detected in cookie encryption handling " | 55 | "Buffer underflow tentative detected in cookie encryption handling " |
| 59 | "for %s. Using the cookie 'as it' instead of decrypting it.", | 56 | "for %s. Using the cookie 'as it' instead of decrypting it.", |
| 60 | ZSTR_VAL(hash_key->key)); | 57 | hash_key ? ZSTR_VAL(hash_key->key) : "the session"); |
| 61 | return ZEND_HASH_APPLY_KEEP; | 58 | return ZEND_HASH_APPLY_KEEP; |
| 62 | } else { | 59 | } else { |
| 63 | sp_log_msg( | 60 | sp_log_msg( |
| @@ -67,9 +64,26 @@ int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hash_key) { | |||
| 67 | } | 64 | } |
| 68 | } | 65 | } |
| 69 | 66 | ||
| 67 | |||
| 68 | if (ZSTR_LEN(debase64) + (size_t)crypto_secretbox_ZEROBYTES < ZSTR_LEN(debase64)) { | ||
| 69 | if (true == simulation) { | ||
| 70 | sp_log_msg( | ||
| 71 | "cookie_encryption", SP_LOG_SIMULATION, | ||
| 72 | "Integer overflow tentative detected in cookie encryption handling " | ||
| 73 | "for %s. Using the cookie 'as it' instead of decrypting it.", | ||
| 74 | hash_key ? ZSTR_VAL(hash_key->key) : "the session"); | ||
| 75 | return ZEND_HASH_APPLY_KEEP; | ||
| 76 | } else { | ||
| 77 | sp_log_msg( | ||
| 78 | "cookie_encryption", SP_LOG_DROP, | ||
| 79 | "Integer overflow tentative detected in cookie encryption handling."); | ||
| 80 | return ZEND_HASH_APPLY_REMOVE; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 70 | generate_key(key); | 84 | generate_key(key); |
| 71 | 85 | ||
| 72 | decrypted = ecalloc(ZSTR_LEN(debase64), 1); | 86 | decrypted = ecalloc(ZSTR_LEN(debase64) + crypto_secretbox_ZEROBYTES, 1); |
| 73 | 87 | ||
| 74 | ret = crypto_secretbox_open( | 88 | ret = crypto_secretbox_open( |
| 75 | decrypted, | 89 | decrypted, |
| @@ -83,12 +97,12 @@ int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hash_key) { | |||
| 83 | "cookie_encryption", SP_LOG_SIMULATION, | 97 | "cookie_encryption", SP_LOG_SIMULATION, |
| 84 | "Something went wrong with the decryption of %s. Using the cookie " | 98 | "Something went wrong with the decryption of %s. Using the cookie " |
| 85 | "'as it' instead of decrypting it", | 99 | "'as it' instead of decrypting it", |
| 86 | ZSTR_VAL(hash_key->key)); | 100 | hash_key ? ZSTR_VAL(hash_key->key) : "the session"); |
| 87 | return ZEND_HASH_APPLY_KEEP; | 101 | return ZEND_HASH_APPLY_KEEP; |
| 88 | } else { | 102 | } else { |
| 89 | sp_log_msg("cookie_encryption", SP_LOG_DROP, | 103 | sp_log_msg("cookie_encryption", SP_LOG_DROP, |
| 90 | "Something went wrong with the decryption of %s.", | 104 | "Something went wrong with the decryption of %s.", |
| 91 | ZSTR_VAL(hash_key->key)); | 105 | hash_key ? ZSTR_VAL(hash_key->key) : "the session"); |
| 92 | return ZEND_HASH_APPLY_REMOVE; | 106 | return ZEND_HASH_APPLY_REMOVE; |
| 93 | } | 107 | } |
| 94 | } | 108 | } |
| @@ -100,8 +114,14 @@ int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hash_key) { | |||
| 100 | return ZEND_HASH_APPLY_KEEP; | 114 | return ZEND_HASH_APPLY_KEEP; |
| 101 | } | 115 | } |
| 102 | 116 | ||
| 117 | /* | ||
| 118 | ** This function will return the `data` of length `data_len` encrypted in the | ||
| 119 | ** form `base64(nonce | encrypted_data)` (with `|` being the concatenation | ||
| 120 | ** operation). | ||
| 121 | */ | ||
| 103 | zend_string *encrypt_zval(char *data, unsigned long long data_len) { | 122 | zend_string *encrypt_zval(char *data, unsigned long long data_len) { |
| 104 | const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1; | 123 | const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1; |
| 124 | // FIXME : We know that this len is too long | ||
| 105 | const size_t emsg_and_nonce_len = | 125 | const size_t emsg_and_nonce_len = |
| 106 | encrypted_msg_len + crypto_secretbox_NONCEBYTES; | 126 | encrypted_msg_len + crypto_secretbox_NONCEBYTES; |
| 107 | 127 | ||
| @@ -112,25 +132,21 @@ zend_string *encrypt_zval(char *data, unsigned long long data_len) { | |||
| 112 | 132 | ||
| 113 | generate_key(key); | 133 | generate_key(key); |
| 114 | 134 | ||
| 135 | // Put random bytes in the nonce | ||
| 136 | php_random_bytes(nonce, sizeof(nonce), 0); | ||
| 137 | |||
| 115 | /* tweetnacl's API requires the message to be padded with | 138 | /* tweetnacl's API requires the message to be padded with |
| 116 | crypto_secretbox_ZEROBYTES zeroes. */ | 139 | crypto_secretbox_ZEROBYTES zeroes. */ |
| 117 | memcpy(data_to_encrypt + crypto_secretbox_ZEROBYTES, data, data_len); | 140 | memcpy(data_to_encrypt + crypto_secretbox_ZEROBYTES, data, data_len); |
| 118 | 141 | ||
| 119 | assert(sizeof(zend_long) <= crypto_secretbox_NONCEBYTES); | 142 | assert(sizeof(zend_long) <= crypto_secretbox_NONCEBYTES); |
| 120 | 143 | ||
| 121 | if (0 == nonce_d) { | ||
| 122 | /* A zend_long should be enough to avoid collisions */ | ||
| 123 | if (php_random_int_throw(0, ZEND_LONG_MAX, &nonce_d) == FAILURE) { | ||
| 124 | return NULL; // LCOV_EXCL_LINE | ||
| 125 | } | ||
| 126 | } | ||
| 127 | nonce_d++; | ||
| 128 | sscanf((char *)nonce, "%ld", &nonce_d); | ||
| 129 | |||
| 130 | memcpy(encrypted_data, nonce, crypto_secretbox_NONCEBYTES); | 144 | memcpy(encrypted_data, nonce, crypto_secretbox_NONCEBYTES); |
| 145 | |||
| 131 | crypto_secretbox(encrypted_data + crypto_secretbox_NONCEBYTES, | 146 | crypto_secretbox(encrypted_data + crypto_secretbox_NONCEBYTES, |
| 132 | data_to_encrypt, encrypted_msg_len, nonce, key); | 147 | data_to_encrypt, encrypted_msg_len, nonce, key); |
| 133 | 148 | ||
| 134 | zend_string *z = php_base64_encode(encrypted_data, emsg_and_nonce_len); | 149 | zend_string *z = php_base64_encode(encrypted_data, emsg_and_nonce_len); |
| 150 | |||
| 135 | return z; | 151 | return z; |
| 136 | } \ No newline at end of file | 152 | } \ No newline at end of file |
diff --git a/src/sp_crypt.h b/src/sp_crypt.h index 1852a0a..3ede104 100644 --- a/src/sp_crypt.h +++ b/src/sp_crypt.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | #include "ext/hash/php_hash_sha.h" | 10 | #include "ext/hash/php_hash_sha.h" |
| 11 | #include "ext/standard/base64.h" | 11 | #include "ext/standard/base64.h" |
| 12 | 12 | ||
| 13 | static void generate_key(unsigned char *key); | 13 | void generate_key(unsigned char *key); |
| 14 | int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hask_key); | 14 | int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hask_key); |
| 15 | zend_string *encrypt_zval(char *data, unsigned long long data_len); | 15 | zend_string *encrypt_zval(char *data, unsigned long long data_len); |
| 16 | 16 | ||
diff --git a/src/sp_session.c b/src/sp_session.c new file mode 100644 index 0000000..4085007 --- /dev/null +++ b/src/sp_session.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | #include "ext/session/php_session.h" | ||
| 3 | |||
| 4 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus); | ||
| 5 | |||
| 6 | #ifdef ZTS | ||
| 7 | static ts_rsrc_id session_globals_id = 0; | ||
| 8 | #define SESSION_G(v) ZEND_TSRMG(session_globals_id, php_ps_globals *, v) | ||
| 9 | #ifdef COMPILE_DL_SESSION | ||
| 10 | ZEND_TSRMLS_CACHE_EXTERN(); | ||
| 11 | #endif | ||
| 12 | #else | ||
| 13 | #define SESSION_G(v) (ps_globals.v) | ||
| 14 | #endif | ||
| 15 | |||
| 16 | static php_ps_globals *session_globals = NULL; | ||
| 17 | static ps_module *s_module; | ||
| 18 | static ps_module *s_original_mod; | ||
| 19 | static int (*old_s_read)(PS_READ_ARGS); | ||
| 20 | static int (*old_s_write)(PS_WRITE_ARGS); | ||
| 21 | static int (*previous_sessionRINIT)(INIT_FUNC_ARGS) = NULL; | ||
| 22 | static ZEND_INI_MH((*old_OnUpdateSaveHandler)) = NULL; | ||
| 23 | |||
| 24 | |||
| 25 | static int sp_hook_s_read(PS_READ_ARGS) { | ||
| 26 | int r = old_s_read(mod_data, key, val, maxlifetime); | ||
| 27 | if (r == SUCCESS && SNUFFLEUPAGUS_G(config).config_session->encrypt && | ||
| 28 | val != NULL && *val != NULL && ZSTR_LEN(*val)) { | ||
| 29 | zend_string *orig_val = *val; | ||
| 30 | zval val_zval; | ||
| 31 | ZVAL_PSTRINGL(&val_zval, ZSTR_VAL(*val), ZSTR_LEN(*val)); | ||
| 32 | |||
| 33 | int ret = decrypt_zval( | ||
| 34 | &val_zval, SNUFFLEUPAGUS_G(config).config_session->simulation, | ||
| 35 | NULL); | ||
| 36 | if (0 != ret) { | ||
| 37 | if (SNUFFLEUPAGUS_G(config).config_session->simulation) { | ||
| 38 | return ret; | ||
| 39 | } else { | ||
| 40 | sp_terminate(); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | *val = zend_string_dup(val_zval.value.str, 0); | ||
| 45 | if (*val == NULL) { | ||
| 46 | *val = ZSTR_EMPTY_ALLOC(); | ||
| 47 | } | ||
| 48 | zend_string_release(orig_val); | ||
| 49 | } | ||
| 50 | |||
| 51 | return r; | ||
| 52 | } | ||
| 53 | |||
| 54 | |||
| 55 | static int sp_hook_s_write(PS_WRITE_ARGS) { | ||
| 56 | if (ZSTR_LEN(val) > 0 && | ||
| 57 | SNUFFLEUPAGUS_G(config).config_session->encrypt) { | ||
| 58 | zend_string *new_val = encrypt_zval(ZSTR_VAL(val), ZSTR_LEN(val)); | ||
| 59 | return old_s_write(mod_data, key, new_val, maxlifetime); | ||
| 60 | } | ||
| 61 | return old_s_write(mod_data, key, val, maxlifetime); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void sp_hook_session_module() { | ||
| 65 | ps_module *old_mod = SESSION_G(mod); | ||
| 66 | ps_module *mod; | ||
| 67 | |||
| 68 | if (old_mod == NULL || s_module == old_mod) { | ||
| 69 | return; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (s_module == NULL) { | ||
| 73 | s_module = mod = malloc(sizeof(ps_module)); | ||
| 74 | if (mod == NULL) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | s_original_mod = old_mod; | ||
| 80 | |||
| 81 | mod = s_module; | ||
| 82 | memcpy(mod, old_mod, sizeof(ps_module)); | ||
| 83 | |||
| 84 | old_s_read = mod->s_read; | ||
| 85 | mod->s_read = sp_hook_s_read; | ||
| 86 | |||
| 87 | old_s_write = mod->s_write; | ||
| 88 | mod->s_write = sp_hook_s_write; | ||
| 89 | |||
| 90 | SESSION_G(mod) = mod; | ||
| 91 | } | ||
| 92 | |||
| 93 | static PHP_INI_MH(sp_OnUpdateSaveHandler) { | ||
| 94 | if (stage == PHP_INI_STAGE_RUNTIME && | ||
| 95 | SESSION_G(session_status) == php_session_none && | ||
| 96 | s_original_mod && | ||
| 97 | zend_string_equals_literal(new_value, "user") == 0 && | ||
| 98 | strcmp(((ps_module *)s_original_mod)->s_name, "user") == | ||
| 99 | 0) { | ||
| 100 | return SUCCESS; | ||
| 101 | } | ||
| 102 | |||
| 103 | SESSION_G(mod) = s_original_mod; | ||
| 104 | |||
| 105 | int r = old_OnUpdateSaveHandler(entry, new_value, mh_arg1, mh_arg2, mh_arg3, | ||
| 106 | stage); | ||
| 107 | |||
| 108 | sp_hook_session_module(); | ||
| 109 | |||
| 110 | return r; | ||
| 111 | } | ||
| 112 | |||
| 113 | static int sp_hook_session_RINIT(INIT_FUNC_ARGS) { | ||
| 114 | if (SESSION_G(mod) == NULL) { | ||
| 115 | zend_ini_entry *ini_entry; | ||
| 116 | if ((ini_entry = zend_hash_str_find_ptr( | ||
| 117 | EG(ini_directives), ZEND_STRL("session.save_handler")))) { | ||
| 118 | if (ini_entry->value) { | ||
| 119 | sp_OnUpdateSaveHandler(NULL, ini_entry->value, NULL, NULL, NULL, 0); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | return previous_sessionRINIT(INIT_FUNC_ARGS_PASSTHRU); | ||
| 124 | } | ||
| 125 | |||
| 126 | void hook_session() { | ||
| 127 | zend_module_entry *module; | ||
| 128 | |||
| 129 | if ((module = zend_hash_str_find_ptr(&module_registry, | ||
| 130 | ZEND_STRL("session"))) == NULL) { | ||
| 131 | return; | ||
| 132 | } | ||
| 133 | |||
| 134 | #ifdef ZTS | ||
| 135 | if (session_globals_id == 0) { | ||
| 136 | session_globals_id = *module->globals_id_ptr; | ||
| 137 | } | ||
| 138 | #else | ||
| 139 | if (session_globals == NULL) { | ||
| 140 | session_globals = module->globals_ptr; | ||
| 141 | } | ||
| 142 | #endif | ||
| 143 | if (old_OnUpdateSaveHandler != NULL) { | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | |||
| 147 | previous_sessionRINIT = module->request_startup_func; | ||
| 148 | module->request_startup_func = sp_hook_session_RINIT; | ||
| 149 | |||
| 150 | zend_ini_entry *ini_entry; | ||
| 151 | if ((ini_entry = zend_hash_str_find_ptr( | ||
| 152 | EG(ini_directives), ZEND_STRL("session.save_handler"))) != NULL) { | ||
| 153 | old_OnUpdateSaveHandler = ini_entry->on_modify; | ||
| 154 | ini_entry->on_modify = sp_OnUpdateSaveHandler; | ||
| 155 | } | ||
| 156 | s_module = NULL; | ||
| 157 | |||
| 158 | sp_hook_session_module(); | ||
| 159 | } \ No newline at end of file | ||
diff --git a/src/sp_session.h b/src/sp_session.h new file mode 100644 index 0000000..c2a0357 --- /dev/null +++ b/src/sp_session.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include "SAPI.h" | ||
| 2 | #include "tweetnacl.h" | ||
| 3 | |||
| 4 | #include "sp_utils.h" | ||
| 5 | |||
| 6 | #include "ext/hash/php_hash.h" | ||
| 7 | #include "ext/hash/php_hash_sha.h" | ||
| 8 | #include "ext/standard/base64.h" | ||
| 9 | |||
| 10 | |||
| 11 | void hook_session(); | ||
diff --git a/src/tests/config/config_crypt_session.ini b/src/tests/config/config_crypt_session.ini new file mode 100644 index 0000000..14b0c2c --- /dev/null +++ b/src/tests/config/config_crypt_session.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); | ||
| 2 | sp.session.encrypt(); \ No newline at end of file | ||
diff --git a/src/tests/config/config_crypt_session_simul.ini b/src/tests/config/config_crypt_session_simul.ini new file mode 100644 index 0000000..fbd43eb --- /dev/null +++ b/src/tests/config/config_crypt_session_simul.ini | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); | ||
| 2 | sp.session.encrypt(); | ||
| 3 | sp.session.simulation(); \ No newline at end of file | ||
diff --git a/src/tests/crypt_session_invalid.phpt b/src/tests/crypt_session_invalid.phpt new file mode 100644 index 0000000..687a407 --- /dev/null +++ b/src/tests/crypt_session_invalid.phpt | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | --TEST-- | ||
| 2 | SESSION crypt and bad decrypt | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_crypt_session.ini | ||
| 7 | --ENV-- | ||
| 8 | return <<<EOF | ||
| 9 | REMOTE_ADDR=127.0.0.1 | ||
| 10 | EOF; | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | // Do it like that to write (encrypt) the session and then to read (decrypt) the session | ||
| 14 | session_start(); // Start new_session , it will read an empty session | ||
| 15 | $_SESSION["toto"] = "tata"; // Encrypt and write the session | ||
| 16 | $id = session_id(); // Get the session_id to use it later | ||
| 17 | session_write_close(); // Close the session | ||
| 18 | putenv("REMOTE_ADDR=127.0.0.2"); | ||
| 19 | session_id($id); // Recover the session with the previous session_id | ||
| 20 | session_start(); // Re start the session, It will read and decrypt the non empty session | ||
| 21 | var_dump($_SESSION); // Dump the session | ||
| 22 | ?> | ||
| 23 | --EXPECTF-- | ||
| 24 | [snuffleupagus][127.0.0.2][cookie_encryption][drop] Something went wrong with the decryption of the session. \ No newline at end of file | ||
diff --git a/src/tests/crypt_session_invalid_simul.phpt b/src/tests/crypt_session_invalid_simul.phpt new file mode 100644 index 0000000..7bfefcb --- /dev/null +++ b/src/tests/crypt_session_invalid_simul.phpt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | --TEST-- | ||
| 2 | SESSION crypt and bad decrypt | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_crypt_session_simul.ini | ||
| 7 | --ENV-- | ||
| 8 | return <<<EOF | ||
| 9 | REMOTE_ADDR=127.0.0.1 | ||
| 10 | EOF; | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | // Do it like that to write (encrypt) the session and then to read (decrypt) the session | ||
| 14 | session_start(); // Start new_session , it will read an empty session | ||
| 15 | $_SESSION["toto"] = "tata"; // Encrypt and write the session | ||
| 16 | $id = session_id(); // Get the session_id to use it later | ||
| 17 | session_write_close(); // Close the session | ||
| 18 | putenv("REMOTE_ADDR=127.0.0.2"); | ||
| 19 | session_id($id); // Recover the session with the previous session_id | ||
| 20 | session_start(); // Re start the session, It will read and decrypt the non empty session | ||
| 21 | var_dump($_SESSION); // Dump the session | ||
| 22 | ?> | ||
| 23 | --EXPECTF-- | ||
| 24 | array(1) { | ||
| 25 | ["toto"]=> | ||
| 26 | string(4) "tata" | ||
| 27 | } | ||
diff --git a/src/tests/crypt_session_read_uncrypt.phpt b/src/tests/crypt_session_read_uncrypt.phpt new file mode 100644 index 0000000..f15d8b6 --- /dev/null +++ b/src/tests/crypt_session_read_uncrypt.phpt | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | --TEST-- | ||
| 2 | SESSION crypt/decrypt valid | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_crypt_session_simul.ini | ||
| 7 | --ENV-- | ||
| 8 | return <<<EOF | ||
| 9 | REMOTE_ADDR=127.0.0.1 | ||
| 10 | EOF; | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | $current_path = dirname(getcwd()) . "/src/tests/" ; | ||
| 14 | ini_set("session.save_path", $current_path); | ||
| 15 | |||
| 16 | session_start(); | ||
| 17 | $id = session_id(); // Get the session_id to use it later | ||
| 18 | $filename_sess = $current_path . "sess_" . $id; | ||
| 19 | file_put_contents($filename_sess, "toto|s:4:\"tata\";"); // Write a unencrypted session | ||
| 20 | session_write_close(); // Close the session | ||
| 21 | |||
| 22 | session_id($id); | ||
| 23 | session_start(); // Try to read the unencrypted session, it will fail to decrypt but it must return the session | ||
| 24 | var_dump($_SESSION); | ||
| 25 | echo "OK"; | ||
| 26 | unlink($filename_sess); | ||
| 27 | ?> | ||
| 28 | --EXPECTF-- | ||
| 29 | array(1) { | ||
| 30 | ["toto"]=> | ||
| 31 | string(4) "tata" | ||
| 32 | } | ||
| 33 | OK | ||
diff --git a/src/tests/crypt_session_valid.phpt b/src/tests/crypt_session_valid.phpt new file mode 100644 index 0000000..bf9fea0 --- /dev/null +++ b/src/tests/crypt_session_valid.phpt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | --TEST-- | ||
| 2 | SESSION crypt/decrypt valid | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_crypt_session.ini | ||
| 7 | --ENV-- | ||
| 8 | return <<<EOF | ||
| 9 | REMOTE_ADDR=127.0.0.1 | ||
| 10 | EOF; | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | // Do it like that to write (encrypt) the session and then to read (decrypt) the session | ||
| 14 | session_start(); // Start new_session , it will read an empty session | ||
| 15 | $_SESSION["toto"] = "tata"; // Encrypt and write the session | ||
| 16 | $id = session_id(); // Get the session_id to use it later | ||
| 17 | |||
| 18 | session_write_close(); // Close the session | ||
| 19 | session_id($id); // Recover the session with the previous session_id | ||
| 20 | session_start(); // Re start the session, It will read and decrypt the non empty session | ||
| 21 | var_dump($_SESSION); // Dump the session | ||
| 22 | ?> | ||
| 23 | --EXPECTF-- | ||
| 24 | array(1) { | ||
| 25 | ["toto"]=> | ||
| 26 | string(4) "tata" | ||
| 27 | } | ||
diff --git a/src/tests/crypt_session_valid_simul.phpt b/src/tests/crypt_session_valid_simul.phpt new file mode 100644 index 0000000..28083cf --- /dev/null +++ b/src/tests/crypt_session_valid_simul.phpt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | --TEST-- | ||
| 2 | SESSION crypt/decrypt valid | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/config_crypt_session_simul.ini | ||
| 7 | --ENV-- | ||
| 8 | return <<<EOF | ||
| 9 | REMOTE_ADDR=127.0.0.1 | ||
| 10 | EOF; | ||
| 11 | --FILE-- | ||
| 12 | <?php | ||
| 13 | // Do it like that to write (encrypt) the session and then to read (decrypt) the session | ||
| 14 | session_start(); // Start new_session , it will read an empty session | ||
| 15 | $_SESSION["toto"] = "tata"; // Encrypt and write the session | ||
| 16 | $id = session_id(); // Get the session_id to use it later | ||
| 17 | session_write_close(); // Close the session | ||
| 18 | |||
| 19 | session_id($id); // Recover the session with the previous session_id | ||
| 20 | session_start(); // Re start the session, It will read and decrypt the non empty session | ||
| 21 | var_dump($_SESSION); // Dump the session | ||
| 22 | ?> | ||
| 23 | --EXPECTF-- | ||
| 24 | array(1) { | ||
| 25 | ["toto"]=> | ||
| 26 | string(4) "tata" | ||
| 27 | } | ||
diff --git a/src/tests/samesite_cookies.phpt b/src/tests/samesite_cookies.phpt index fe74172..d010963 100644 --- a/src/tests/samesite_cookies.phpt +++ b/src/tests/samesite_cookies.phpt | |||
| @@ -27,12 +27,13 @@ if (!setcookie("nice_cookie", "nice_value", 1, "1", "1", true, true)) { | |||
| 27 | echo "setcookie failed.\n"; | 27 | echo "setcookie failed.\n"; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | // If the cookie value start with "!", it means that we don't want the value in the headers, but the encrypted cookie | ||
| 30 | $expected = array( | 31 | $expected = array( |
| 31 | 'Set-Cookie: super_cookie=super_value; path=; samesite=Lax', | 32 | "awful_cookie" => "!awful_value", |
| 32 | 'Set-Cookie: awful_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFyZcYjfEskB0AU0V3%2BvwazcRuU%2Ft6KpcUahvxw%3D; path=; samesite=Strict; HttpOnly', | 33 | "not_encrypted" => "test_value", |
| 33 | 'Set-Cookie: not_encrypted=test_value; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=1; domain=1; HttpOnly', | 34 | "nice_cookie" => "!nice_value", |
| 34 | 'Set-Cookie: nice_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ8ko%2ByA4y%2Bmw5MGBx8fgc3TWOAvhIu%2BfF%2Bx2g%3D%3D; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=1; samesite=Strict; domain=1; secure; HttpOnly', | 35 | "super_cookie" => "super_value", |
| 35 | ); | 36 | ); |
| 36 | 37 | ||
| 37 | $headers = headers_list(); | 38 | $headers = headers_list(); |
| 38 | if (($i = count($expected)) > count($headers)) | 39 | if (($i = count($expected)) > count($headers)) |
| @@ -41,31 +42,37 @@ if (($i = count($expected)) > count($headers)) | |||
| 41 | return; | 42 | return; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | do | 45 | $i = 0; |
| 45 | { | 46 | |
| 47 | do { | ||
| 46 | if (strncmp(current($headers), 'Set-Cookie:', 11) !== 0) | 48 | if (strncmp(current($headers), 'Set-Cookie:', 11) !== 0) |
| 47 | { | 49 | { |
| 48 | continue; | 50 | continue; |
| 49 | } | 51 | } |
| 50 | 52 | foreach ($expected as $key => $value) { | |
| 51 | if (current($headers) === current($expected)) | 53 | if (strpos(current($headers), $key) !== false) { // If the header contains the cookie |
| 52 | { | 54 | if (substr($value, 0, 1) === "!") { // ! is because we don't want to see the cookie value in plaintext, it must be encrypted |
| 53 | $i--; | 55 | if (strpos(current($headers), substr($value,1,-1)) === false) { // If the header doesn't contain de cookie value, it's good |
| 56 | $i++; | ||
| 57 | break; | ||
| 58 | } | ||
| 59 | echo "Received : " . current($headers) . " and the cookie isn't encrypted . \n"; | ||
| 60 | } else { | ||
| 61 | if (strpos(current($headers), $value) !== false) { | ||
| 62 | $i++; | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | echo "Received : " . current($headers) . " and the cookie value of " . $key . " doesn't match it's value. \n"; | ||
| 66 | } | ||
| 67 | break; | ||
| 68 | } | ||
| 54 | } | 69 | } |
| 55 | else | ||
| 56 | { | ||
| 57 | echo "Header mismatch:\n\tExpected: " | ||
| 58 | .current($expected) | ||
| 59 | ."\n\tReceived: ".current($headers)."\n"; | ||
| 60 | } | ||
| 61 | |||
| 62 | next($expected); | ||
| 63 | } | 70 | } |
| 64 | while (next($headers) !== FALSE); | 71 | while (next($headers)); |
| 65 | 72 | ||
| 66 | echo ($i === 0) | 73 | echo ($i === 4) |
| 67 | ? 'OK' | 74 | ? 'OK' |
| 68 | : 'A total of '.$i.' errors found.'; | 75 | : 'A total of '. (count($expected) - $i) .' errors found.'; |
| 69 | ?> | 76 | ?> |
| 70 | --EXPECT-- | 77 | --EXPECT-- |
| 71 | OK | 78 | OK |
