summaryrefslogtreecommitdiff
path: root/src/sp_unserialize.c
diff options
context:
space:
mode:
authorjvoisin2022-03-20 18:20:45 +0100
committerjvoisin2022-03-20 18:20:45 +0100
commit81dd7f2ef07af306fe83d7755cbac4529aa9fc8d (patch)
tree32cc44c6231b30db5ac7b15699297863460784aa /src/sp_unserialize.c
parent83b01942dfc80474cc05e09aeef4b44307a7120b (diff)
parentc38df1077a6c1dfbca1baca049214d053e2e7684 (diff)
Merge remote-tracking branch 'sektioneins/master'
Diffstat (limited to 'src/sp_unserialize.c')
-rw-r--r--src/sp_unserialize.c117
1 files changed, 70 insertions, 47 deletions
diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c
index 8977dd9..c2173d3 100644
--- a/src/sp_unserialize.c
+++ b/src/sp_unserialize.c
@@ -1,28 +1,70 @@
1#include "php_snuffleupagus.h" 1#include "php_snuffleupagus.h"
2 2
3// condensed version of PHP's php_hash_do_hash_hmac() in ext/hash/hash.c
4#if PHP_VERSION_ID < 80000
5static inline void *php_hash_alloc_context(const php_hash_ops *ops) {
6 /* Zero out context memory so serialization doesn't expose internals */
7 return ecalloc(1, ops->context_size);
8}
9#endif
10
11static zend_string *sp_do_hash_hmac_sha256(char *data, size_t data_len, char *key, size_t key_len)
12{
13#if PHP_VERSION_ID < 80000
14 const php_hash_ops *ops = php_hash_fetch_ops(ZEND_STRL("sha256"));
15#else
16 zend_string *algo = zend_string_init(ZEND_STRL("sha256"), 0);
17 const php_hash_ops *ops = php_hash_fetch_ops(algo);
18 zend_string_release_ex(algo, 0);
19#endif
20
21 if (!ops || !ops->is_crypto) {
22 sp_log_err("hmac", "unsupported hash algorithm: sha256");
23 return NULL;
24 }
25
26 void *context = php_hash_alloc_context(ops);
27
28 unsigned char *K = emalloc(ops->block_size);
29 zend_string *digest = zend_string_alloc(ops->digest_size, 0);
30
31 php_hash_hmac_prep_key(K, ops, context, (unsigned char *) key, key_len);
32 php_hash_hmac_round((unsigned char *) ZSTR_VAL(digest), ops, context, K, (unsigned char *) data, data_len);
33 php_hash_string_xor_char(K, K, 0x6A, ops->block_size);
34 php_hash_hmac_round((unsigned char *) ZSTR_VAL(digest), ops, context, K, (unsigned char *) ZSTR_VAL(digest), ops->digest_size);
35
36 /* Zero the key */
37 ZEND_SECURE_ZERO(K, ops->block_size);
38 efree(K);
39 efree(context);
40
41 zend_string *hex_digest = zend_string_safe_alloc(ops->digest_size, 2, 0, 0);
42
43 php_hash_bin2hex(ZSTR_VAL(hex_digest), (unsigned char *) ZSTR_VAL(digest), ops->digest_size);
44 ZSTR_VAL(hex_digest)[2 * ops->digest_size] = 0;
45 zend_string_release_ex(digest, 0);
46 return hex_digest;
47}
48
49// ------------------
50
3PHP_FUNCTION(sp_serialize) { 51PHP_FUNCTION(sp_serialize) {
4 zif_handler orig_handler; 52 zif_handler orig_handler;
5 53
6 /* Call the original `serialize` function. */ 54 /* Call the original `serialize` function. */
7 orig_handler = 55 orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("serialize"));
8 zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), 56 if (orig_handler) {
9 "serialize", sizeof("serialize") - 1); 57 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
10 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 58 }
11 59
12 /* Compute the HMAC of the textual representation of the serialized data*/ 60 /* Compute the HMAC of the textual representation of the serialized data*/
13 zval func_name; 61 zend_string *hmac = sp_do_hash_hmac_sha256(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), ZSTR_VAL(SPCFG(encryption_key)), ZSTR_LEN(SPCFG(encryption_key)));
14 zval hmac;
15 zval params[3];
16 62
17 ZVAL_STRING(&func_name, "hash_hmac"); 63 if (!hmac) {
18 ZVAL_STRING(&params[0], "sha256"); 64 zend_bailout();
19 params[1] = *return_value; 65 }
20 ZVAL_STRING(
21 &params[2],
22 ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key));
23 call_user_function(CG(function_table), NULL, &func_name, &hmac, 3, params);
24 66
25 size_t len = Z_STRLEN_P(return_value) + Z_STRLEN(hmac); 67 size_t len = Z_STRLEN_P(return_value) + ZSTR_LEN(hmac);
26 if (len < Z_STRLEN_P(return_value)) { 68 if (len < Z_STRLEN_P(return_value)) {
27 // LCOV_EXCL_START 69 // LCOV_EXCL_START
28 sp_log_err("overflow_error", 70 sp_log_err("overflow_error",
@@ -30,15 +72,11 @@ PHP_FUNCTION(sp_serialize) {
30 zend_bailout(); 72 zend_bailout();
31 // LCOV_EXCL_STOP 73 // LCOV_EXCL_STOP
32 } 74 }
33 zend_string *res = zend_string_alloc(len, 0);
34
35 memcpy(ZSTR_VAL(res), Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
36 memcpy(ZSTR_VAL(res) + Z_STRLEN_P(return_value), Z_STRVAL(hmac),
37 Z_STRLEN(hmac));
38 75
39 /* Append the computed HMAC to the serialized data. */ 76 /* Append the computed HMAC to the serialized data. */
40 return_value->value.str = res; 77 zend_string *orig_ret_str = return_value->value.str;
41 return; 78 RETVAL_NEW_STR(zend_string_concat2(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), ZSTR_VAL(hmac), ZSTR_LEN(hmac)));
79 zend_string_free(orig_ret_str);
42} 80}
43 81
44PHP_FUNCTION(sp_unserialize) { 82PHP_FUNCTION(sp_unserialize) {
@@ -47,12 +85,10 @@ PHP_FUNCTION(sp_unserialize) {
47 char *buf = NULL; 85 char *buf = NULL;
48 char *serialized_str = NULL; 86 char *serialized_str = NULL;
49 char *hmac = NULL; 87 char *hmac = NULL;
50 zval expected_hmac;
51 size_t buf_len = 0; 88 size_t buf_len = 0;
52 zval *opts = NULL; 89 zval *opts = NULL;
53 90
54 const sp_config_unserialize *config_unserialize = 91 const sp_config_unserialize *config_unserialize = &(SPCFG(unserialize));
55 SNUFFLEUPAGUS_G(config).config_unserialize;
56 92
57 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &opts) == 93 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &opts) ==
58 FAILURE) { 94 FAILURE) {
@@ -68,40 +104,27 @@ PHP_FUNCTION(sp_unserialize) {
68 serialized_str = ecalloc(buf_len - 64 + 1, 1); 104 serialized_str = ecalloc(buf_len - 64 + 1, 1);
69 memcpy(serialized_str, buf, buf_len - 64); 105 memcpy(serialized_str, buf, buf_len - 64);
70 106
71 zval func_name; 107 zend_string *expected_hmac = sp_do_hash_hmac_sha256(serialized_str, strlen(serialized_str), ZSTR_VAL(SPCFG(encryption_key)), ZSTR_LEN(SPCFG(encryption_key)));
72 ZVAL_STRING(&func_name, "hash_hmac");
73
74 zval params[3];
75 ZVAL_STRING(&params[0], "sha256");
76 ZVAL_STRING(&params[1], serialized_str);
77 ZVAL_STRING(
78 &params[2],
79 ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key));
80 call_user_function(CG(function_table), NULL, &func_name, &expected_hmac, 3,
81 params);
82 108
83 unsigned int status = 0; 109 unsigned int status = 0;
84 for (uint8_t i = 0; i < 64; i++) { 110 if (expected_hmac) {
85 status |= (hmac[i] ^ (Z_STRVAL(expected_hmac))[i]); 111 for (uint8_t i = 0; i < 64; i++) {
86 } 112 status |= (hmac[i] ^ (ZSTR_VAL(expected_hmac))[i]);
113 }
114 } else { status = 1; }
87 115
88 if (0 == status) { 116 if (0 == status) {
89 if ((orig_handler = zend_hash_str_find_ptr( 117 if ((orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("unserialize")))) {
90 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize",
91 sizeof("unserialize") - 1))) {
92 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 118 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
93 } 119 }
94 } else { 120 } else {
95 if (config_unserialize->dump) { 121 if (config_unserialize->dump) {
96 sp_log_request(config_unserialize->dump, 122 sp_log_request(config_unserialize->dump,
97 config_unserialize->textual_representation, 123 config_unserialize->textual_representation);
98 SP_TOKEN_UNSERIALIZE_HMAC);
99 } 124 }
100 if (true == config_unserialize->simulation) { 125 if (true == config_unserialize->simulation) {
101 sp_log_simulation("unserialize", "Invalid HMAC for %s", serialized_str); 126 sp_log_simulation("unserialize", "Invalid HMAC for %s", serialized_str);
102 if ((orig_handler = zend_hash_str_find_ptr( 127 if ((orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("unserialize")))) {
103 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize",
104 sizeof("unserialize") - 1))) {
105 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 128 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
106 } 129 }
107 } else { 130 } else {