From 967c8c90f23c49fcdc69c5318ebafd302aba5192 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Mon, 30 May 2016 16:53:08 -0300 Subject: [PATCH] Fixed minor behavior on the trasnformations and added sha1-mbedtls --- src/Makefile.am | 3 +- .../transformations/html_entity_decode.cc | 169 ++++++- .../transformations/html_entity_decode.h | 21 +- src/actions/transformations/js_decode.cc | 128 ++++- src/actions/transformations/js_decode.h | 1 + src/actions/transformations/sha1.cc | 6 +- src/actions/transformations/transformation.cc | 2 +- src/actions/transformations/url_decode_uni.cc | 151 +++++- src/actions/transformations/url_decode_uni.h | 8 +- src/unique_id.cc | 7 +- src/utils.cc | 392 --------------- src/utils/mbedtls/sha1.c | 448 ++++++++++++++++++ src/utils/mbedtls/sha1.h | 136 ++++++ src/utils/sha1.cc | 264 +---------- src/utils/sha1.h | 48 +- test/test-cases/secrules-language-tests | 2 +- test/unit/unit_test.cc | 66 +-- 17 files changed, 1077 insertions(+), 775 deletions(-) create mode 100644 src/utils/mbedtls/sha1.c create mode 100644 src/utils/mbedtls/sha1.h diff --git a/src/Makefile.am b/src/Makefile.am index 0aa0bcc1..62088939 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,8 @@ libmodsecurity_includesubdir = $(pkgincludedir)/collection/ libmbedtls_la_SOURCES = \ utils/mbedtls/base64.c \ - utils/mbedtls/md5.c + utils/mbedtls/md5.c \ + utils/mbedtls/sha1.c libmbedtls_la_CFLAGS = -D MBEDTLS_CONFIG_FILE=\"mbed-tls-config.h\" -Iutils libmbedtls_la_CPPFLAGS = diff --git a/src/actions/transformations/html_entity_decode.cc b/src/actions/transformations/html_entity_decode.cc index de9d346c..40934eb1 100644 --- a/src/actions/transformations/html_entity_decode.cc +++ b/src/actions/transformations/html_entity_decode.cc @@ -36,26 +36,175 @@ namespace transformations { std::string HtmlEntityDecode::evaluate(std::string value, Transaction *transaction) { + std::string ret; + unsigned char *input = NULL; - if (HtmlEntityDecodeInstantCache::getInstance().count(value) > 0) { - return HtmlEntityDecodeInstantCache::getInstance().at(value); + input = reinterpret_cast + (malloc(sizeof(char) * value.length()+1)); + + if (input == NULL) { + return ""; } - char *tmp = strdup(value.c_str()); + memcpy(input, value.c_str(), value.length()+1); - // FIXME: html_entities_decode_inplace is not working as expected - // temporary disabled to perform the audit_log tests. - // html_entities_decode_inplace((unsigned char *)tmp, value.size()); - std::string ret(""); - ret.assign(tmp); - free(tmp); + size_t i = inplace(input, value.length()); - HtmlEntityDecodeInstantCache::getInstance().cache(value, ret); + ret.assign(reinterpret_cast(input), i); + free(input); return ret; } +int HtmlEntityDecode::inplace(unsigned char *input, u_int64_t input_len) { + unsigned char *d = input; + int i, count; + + if ((input == NULL) || (input_len <= 0)) { + return 0; + } + + i = count = 0; + while ((i < input_len) && (count < input_len)) { + int z, copy = 1; + + /* Require an ampersand and at least one character to + * start looking into the entity. + */ + if ((input[i] == '&') && (i + 1 < input_len)) { + int k, j = i + 1; + + if (input[j] == '#') { + /* Numerical entity. */ + copy++; + + if (!(j + 1 < input_len)) { + goto HTML_ENT_OUT; /* Not enough bytes. */ + } + j++; + + if ((input[j] == 'x') || (input[j] == 'X')) { + /* Hexadecimal entity. */ + copy++; + + if (!(j + 1 < input_len)) { + goto HTML_ENT_OUT; /* Not enough bytes. */ + } + j++; /* j is the position of the first digit now. */ + + k = j; + while ((j < input_len) && (isxdigit(input[j]))) { + j++; + } + if (j > k) { /* Do we have at least one digit? */ + /* Decode the entity. */ + char *x = NULL; + x = reinterpret_cast(malloc(sizeof(char) * + ((j - k) + 1))); + memset(x, '\0', (j - k) + 1); + memcpy(x, (const char *)&input[k], j - k); + *d++ = (unsigned char)strtol(x, NULL, 16); + + count++; + + /* Skip over the semicolon if it's there. */ + if ((j < input_len) && (input[j] == ';')) { + i = j + 1; + } else { + i = j; + } + continue; + } else { + goto HTML_ENT_OUT; + } + } else { + /* Decimal entity. */ + k = j; + while ((j < input_len) && (isdigit(input[j]))) { + j++; + } + if (j > k) { /* Do we have at least one digit? */ + /* Decode the entity. */ + char *x = NULL; + x = reinterpret_cast(malloc(sizeof(char) * + ((j - k) + 1))); + memset(x, '\0', (j - k) + 1); + memcpy(x, (const char *)&input[k], j - k); + *d++ = (unsigned char)strtol(x, NULL, 10); + + count++; + + /* Skip over the semicolon if it's there. */ + if ((j < input_len) && (input[j] == ';')) { + i = j + 1; + } else { + i = j; + } + continue; + } else { + goto HTML_ENT_OUT; + } + } + } else { + /* Text entity. */ + k = j; + while ((j < input_len) && (isalnum(input[j]))) { + j++; + } + if (j > k) { /* Do we have at least one digit? */ + char *x = NULL; + x = reinterpret_cast(malloc(sizeof(char) * + ((j - k) + 1))); + memset(x, '\0', (j - k) + 1); + memcpy(x, (const char *)&input[k], j - k); + + /* Decode the entity. */ + /* ENH What about others? */ + if (strcasecmp(x, "quot") == 0) { + *d++ = '"'; + } else if (strcasecmp(x, "amp") == 0) { + *d++ = '&'; + } else if (strcasecmp(x, "lt") == 0) { + *d++ = '<'; + } else if (strcasecmp(x, "gt") == 0) { + *d++ = '>'; + } else if (strcasecmp(x, "nbsp") == 0) { + *d++ = NBSP; + } else { + /* We do no want to convert this entity, + * copy the raw data over. */ + copy = j - k + 1; + goto HTML_ENT_OUT; + } + + count++; + + /* Skip over the semicolon if it's there. */ + if ((j < input_len) && (input[j] == ';')) { + i = j + 1; + } else { + i = j; + } + + continue; + } + } + } + +HTML_ENT_OUT: + + for (z = 0; ((z < copy) && (count < input_len)); z++) { + *d++ = input[i++]; + count++; + } + } + + *d = '\0'; + + return count; +} + } // namespace transformations } // namespace actions } // namespace modsecurity diff --git a/src/actions/transformations/html_entity_decode.h b/src/actions/transformations/html_entity_decode.h index 69ba776b..d606a296 100644 --- a/src/actions/transformations/html_entity_decode.h +++ b/src/actions/transformations/html_entity_decode.h @@ -30,25 +30,6 @@ namespace actions { namespace transformations { -class HtmlEntityDecodeInstantCache : - public std::unordered_map { - public: - static HtmlEntityDecodeInstantCache& getInstance() { - static HtmlEntityDecodeInstantCache instance; - return instance; - } - - void cache(const std::string& value, const std::string& out) { - emplace(value, out); - if (size() > 100) { - erase(begin()); - } - } - private: - HtmlEntityDecodeInstantCache() {} -}; - - class HtmlEntityDecode : public Transformation { public: explicit HtmlEntityDecode(std::string action) @@ -56,6 +37,8 @@ class HtmlEntityDecode : public Transformation { std::string evaluate(std::string exp, Transaction *transaction) override; + + static int inplace(unsigned char *input, u_int64_t input_len); }; diff --git a/src/actions/transformations/js_decode.cc b/src/actions/transformations/js_decode.cc index 752d88ea..acd48440 100644 --- a/src/actions/transformations/js_decode.cc +++ b/src/actions/transformations/js_decode.cc @@ -36,21 +36,133 @@ namespace transformations { std::string JsDecode::evaluate(std::string value, Transaction *transaction) { + std::string ret; + unsigned char *input = NULL; - char *val = reinterpret_cast( - malloc(sizeof(char) * value.size() + 1)); - memcpy(val, value.c_str(), value.size() + 1); - val[value.size()] = '\0'; + input = reinterpret_cast + (malloc(sizeof(char) * value.length()+1)); - js_decode_nonstrict_inplace((unsigned char *)val, value.size()); - std::string ret(""); - ret.assign(val); - free(val); + if (input == NULL) { + return ""; + } + + memcpy(input, value.c_str(), value.length()+1); + + size_t i = inplace(input, value.length()); + + ret.assign(reinterpret_cast(input), i); + free(input); return ret; } +int JsDecode::inplace(unsigned char *input, u_int64_t input_len) { + unsigned char *d = (unsigned char *)input; + int64_t i, count; + + i = count = 0; + while (i < input_len) { + if (input[i] == '\\') { + /* Character is an escape. */ + + if ((i + 5 < input_len) && (input[i + 1] == 'u') + && (VALID_HEX(input[i + 2])) && (VALID_HEX(input[i + 3])) + && (VALID_HEX(input[i + 4])) && (VALID_HEX(input[i + 5]))) { + /* \uHHHH */ + + /* Use only the lower byte. */ + *d = x2c(&input[i + 4]); + + /* Full width ASCII (ff01 - ff5e) needs 0x20 added */ + if ((*d > 0x00) && (*d < 0x5f) + && ((input[i + 2] == 'f') || (input[i + 2] == 'F')) + && ((input[i + 3] == 'f') || (input[i + 3] == 'F'))) { + (*d) += 0x20; + } + + d++; + count++; + i += 6; + } else if ((i + 3 < input_len) && (input[i + 1] == 'x') + && VALID_HEX(input[i + 2]) && VALID_HEX(input[i + 3])) { + /* \xHH */ + *d++ = x2c(&input[i + 2]); + count++; + i += 4; + } else if ((i + 1 < input_len) && ISODIGIT(input[i + 1])) { + /* \OOO (only one byte, \000 - \377) */ + char buf[4]; + int j = 0; + + while ((i + 1 + j < input_len) && (j < 3)) { + buf[j] = input[i + 1 + j]; + j++; + if (!ISODIGIT(input[i + 1 + j])) break; + } + buf[j] = '\0'; + + if (j > 0) { + /* Do not use 3 characters if we will be > 1 byte */ + if ((j == 3) && (buf[0] > '3')) { + j = 2; + buf[j] = '\0'; + } + *d++ = (unsigned char)strtol(buf, NULL, 8); + i += 1 + j; + count++; + } + } else if (i + 1 < input_len) { + /* \C */ + unsigned char c = input[i + 1]; + switch (input[i + 1]) { + case 'a' : + c = '\a'; + break; + case 'b' : + c = '\b'; + break; + case 'f' : + c = '\f'; + break; + case 'n' : + c = '\n'; + break; + case 'r' : + c = '\r'; + break; + case 't' : + c = '\t'; + break; + case 'v' : + c = '\v'; + break; + /* The remaining (\?,\\,\',\") are just a removal + * of the escape char which is default. + */ + } + + *d++ = c; + i += 2; + count++; + } else { + /* Not enough bytes */ + while (i < input_len) { + *d++ = input[i++]; + count++; + } + } + } else { + *d++ = input[i++]; + count++; + } + } + + *d = '\0'; + + return count; +} + } // namespace transformations } // namespace actions } // namespace modsecurity diff --git a/src/actions/transformations/js_decode.h b/src/actions/transformations/js_decode.h index dc89b50c..df36c6e8 100644 --- a/src/actions/transformations/js_decode.h +++ b/src/actions/transformations/js_decode.h @@ -35,6 +35,7 @@ class JsDecode : public Transformation { std::string evaluate(std::string exp, Transaction *transaction) override; + static int inplace(unsigned char *input, u_int64_t input_len); }; } // namespace transformations diff --git a/src/actions/transformations/sha1.cc b/src/actions/transformations/sha1.cc index 8aec0b7d..ebb71bb9 100644 --- a/src/actions/transformations/sha1.cc +++ b/src/actions/transformations/sha1.cc @@ -40,11 +40,7 @@ Sha1::Sha1(std::string action) std::string Sha1::evaluate(std::string value, Transaction *transaction) { - Utils::SHA1 sha1; - sha1.update(&value); - std::string sha1_bin = sha1.final_bin(); - - return sha1_bin; + return Utils::Sha1::digest(value); } } // namespace transformations diff --git a/src/actions/transformations/transformation.cc b/src/actions/transformations/transformation.cc index cf5c87d1..9abf4434 100644 --- a/src/actions/transformations/transformation.cc +++ b/src/actions/transformations/transformation.cc @@ -110,8 +110,8 @@ Transformation* Transformation::instantiate(std::string a) { IF_MATCH(trimLeft) { return new TrimLeft(a); } IF_MATCH(trimRight) { return new TrimRight(a); } IF_MATCH(trim) { return new Trim(a); } - IF_MATCH(urlDecode) { return new UrlDecode(a); } IF_MATCH(urlDecodeUni) { return new UrlDecodeUni(a); } + IF_MATCH(urlDecode) { return new UrlDecode(a); } IF_MATCH(urlEncode) { return new UrlEncode(a); } IF_MATCH(utf8ToUnicode) { return new Utf8ToUnicode(a); } diff --git a/src/actions/transformations/url_decode_uni.cc b/src/actions/transformations/url_decode_uni.cc index 63a83fbe..97cc7bed 100644 --- a/src/actions/transformations/url_decode_uni.cc +++ b/src/actions/transformations/url_decode_uni.cc @@ -36,18 +36,155 @@ namespace transformations { std::string UrlDecodeUni::evaluate(std::string value, Transaction *transaction) { - int changed = 0; - char *tmp = strdup(value.c_str()); - urldecode_uni_nonstrict_inplace_ex(transaction, (unsigned char *)tmp, - value.size(), &changed); - std::string ret(""); - ret.assign(tmp); - free(tmp); + std::string ret; + unsigned char *input = NULL; + + input = reinterpret_cast + (malloc(sizeof(char) * value.length()+1)); + + if (input == NULL) { + return ""; + } + + memcpy(input, value.c_str(), value.length()+1); + + size_t i = inplace(input, value.length(), transaction); + + ret.assign(reinterpret_cast(input), i); + free(input); return ret; } +/** + * + * IMP1 Assumes NUL-terminated + */ +int UrlDecodeUni::inplace(unsigned char *input, u_int64_t input_len, + Transaction *transaction) { + unsigned char *d = input; + int64_t i, count, fact, j, xv; + int Code, hmap = -1; + + if (input == NULL) return -1; + + i = count = 0; + while (i < input_len) { + if (input[i] == '%') { + if ((i + 1 < input_len) && + ((input[i + 1] == 'u') || (input[i + 1] == 'U'))) { + /* Character is a percent sign. */ + /* IIS-specific %u encoding. */ + if (i + 5 < input_len) { + /* We have at least 4 data bytes. */ + if ((VALID_HEX(input[i + 2])) && + (VALID_HEX(input[i + 3])) && + (VALID_HEX(input[i + 4])) && + (VALID_HEX(input[i + 5]))) { + Code = 0; + fact = 1; + + if (transaction + && transaction->m_rules->unicode_map_table != NULL + && transaction->m_rules->unicode_codepage > 0) { + for (j = 5; j >= 2; j--) { + if (isxdigit((input[i+j]))) { + if (input[i+j] >= 97) { + xv = (input[i+j] - 97) + 10; + } else if (input[i+j] >= 65) { + xv = (input[i+j] - 65) + 10; + } else { + xv = (input[i+j]) - 48; + } + Code += (xv * fact); + fact *= 16; + } + } + + if (Code >= 0 && Code <= 65535) { + Rules *r = transaction->m_rules; + hmap = r->unicode_map_table[Code]; + } + } + + if (hmap != -1) { + *d = hmap; + } else { + /* We first make use of the lower byte here, + * ignoring the higher byte. */ + *d = x2c(&input[i + 4]); + + /* Full width ASCII (ff01 - ff5e) + * needs 0x20 added */ + if ((*d > 0x00) && (*d < 0x5f) + && ((input[i + 2] == 'f') + || (input[i + 2] == 'F')) + && ((input[i + 3] == 'f') + || (input[i + 3] == 'F'))) { + (*d) += 0x20; + } + } + d++; + count++; + i += 6; + } else { + /* Invalid data, skip %u. */ + *d++ = input[i++]; + *d++ = input[i++]; + count += 2; + } + } else { + /* Not enough bytes (4 data bytes), skip %u. */ + *d++ = input[i++]; + *d++ = input[i++]; + count += 2; + } + } else { + /* Standard URL encoding. */ + /* Are there enough bytes available? */ + if (i + 2 < input_len) { + /* Yes. */ + + /* Decode a %xx combo only if it is valid. + */ + char c1 = input[i + 1]; + char c2 = input[i + 2]; + + if (VALID_HEX(c1) && VALID_HEX(c2)) { + *d++ = x2c(&input[i + 1]); + count++; + i += 3; + } else { + /* Not a valid encoding, skip this % */ + *d++ = input[i++]; + count++; + } + } else { + /* Not enough bytes available, skip this % */ + *d++ = input[i++]; + count++; + } + } + } else { + /* Character is not a percent sign. */ + if (input[i] == '+') { + *d++ = ' '; + } else { + *d++ = input[i]; + } + + count++; + i++; + } + } + + *d = '\0'; + + return count; +} + + } // namespace transformations } // namespace actions } // namespace modsecurity diff --git a/src/actions/transformations/url_decode_uni.h b/src/actions/transformations/url_decode_uni.h index b8155d0c..09010d35 100644 --- a/src/actions/transformations/url_decode_uni.h +++ b/src/actions/transformations/url_decode_uni.h @@ -30,11 +30,11 @@ namespace transformations { class UrlDecodeUni : public Transformation { public: - explicit UrlDecodeUni(std::string action) - : Transformation(action) { } + explicit UrlDecodeUni(std::string action) : Transformation(action) { } - std::string evaluate(std::string exp, - Transaction *transaction) override; + std::string evaluate(std::string exp, Transaction *transaction) override; + static int inplace(unsigned char *input, u_int64_t input_len, + Transaction *transaction); }; } // namespace transformations diff --git a/src/unique_id.cc b/src/unique_id.cc index bf80364a..2458e98f 100644 --- a/src/unique_id.cc +++ b/src/unique_id.cc @@ -58,15 +58,14 @@ namespace modsecurity { void UniqueId::fillUniqueId() { std::string macAddress; std::string name; - Utils::SHA1 sha1; + std::string data; macAddress = ethernetMacAddress(); name = machineName(); - sha1.update(&macAddress); - sha1.update(&name); + data = macAddress + name; - this->uniqueId_str = sha1.final(); + this->uniqueId_str = Utils::Sha1::hexdigest(data); } // Based on: diff --git a/src/utils.cc b/src/utils.cc index 6a01f706..78ee8b10 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -254,115 +254,6 @@ double cpu_seconds(void) { } -int js_decode_nonstrict_inplace(unsigned char *input, int64_t input_len) { - unsigned char *d = (unsigned char *)input; - int64_t i, count; - - if (input == NULL) return -1; - - i = count = 0; - while (i < input_len) { - if (input[i] == '\\') { - /* Character is an escape. */ - - if ((i + 5 < input_len) && (input[i + 1] == 'u') - && (VALID_HEX(input[i + 2])) && (VALID_HEX(input[i + 3])) - && (VALID_HEX(input[i + 4])) && (VALID_HEX(input[i + 5]))) { - /* \uHHHH */ - - /* Use only the lower byte. */ - *d = x2c(&input[i + 4]); - - /* Full width ASCII (ff01 - ff5e) needs 0x20 added */ - if ((*d > 0x00) && (*d < 0x5f) - && ((input[i + 2] == 'f') || (input[i + 2] == 'F')) - && ((input[i + 3] == 'f') || (input[i + 3] == 'F'))) { - (*d) += 0x20; - } - - d++; - count++; - i += 6; - } else if ((i + 3 < input_len) && (input[i + 1] == 'x') - && VALID_HEX(input[i + 2]) && VALID_HEX(input[i + 3])) { - /* \xHH */ - *d++ = x2c(&input[i + 2]); - count++; - i += 4; - } else if ((i + 1 < input_len) && ISODIGIT(input[i + 1])) { - /* \OOO (only one byte, \000 - \377) */ - char buf[4]; - int j = 0; - - while ((i + 1 + j < input_len) && (j < 3)) { - buf[j] = input[i + 1 + j]; - j++; - if (!ISODIGIT(input[i + 1 + j])) break; - } - buf[j] = '\0'; - - if (j > 0) { - /* Do not use 3 characters if we will be > 1 byte */ - if ((j == 3) && (buf[0] > '3')) { - j = 2; - buf[j] = '\0'; - } - *d++ = (unsigned char)strtol(buf, NULL, 8); - i += 1 + j; - count++; - } - } else if (i + 1 < input_len) { - /* \C */ - unsigned char c = input[i + 1]; - switch (input[i + 1]) { - case 'a' : - c = '\a'; - break; - case 'b' : - c = '\b'; - break; - case 'f' : - c = '\f'; - break; - case 'n' : - c = '\n'; - break; - case 'r' : - c = '\r'; - break; - case 't' : - c = '\t'; - break; - case 'v' : - c = '\v'; - break; - /* The remaining (\?,\\,\',\") are just a removal - * of the escape char which is default. - */ - } - - *d++ = c; - i += 2; - count++; - } else { - /* Not enough bytes */ - while (i < input_len) { - *d++ = input[i++]; - count++; - } - } - } else { - *d++ = input[i++]; - count++; - } - } - - *d = '\0'; - - return count; -} - - /** * Decode a string that contains CSS-escaped characters. * @@ -503,157 +394,6 @@ int css_decode_inplace(unsigned char *input, int64_t input_len) { } -/** - * - * IMP1 Assumes NUL-terminated - */ -int html_entities_decode_inplace(unsigned char *input, int input_len) { - unsigned char *d = input; - int i, count; - - if ((input == NULL) || (input_len <= 0)) return 0; - - i = count = 0; - while ((i < input_len) && (count < input_len)) { - int z, copy = 1; - - /* Require an ampersand and at least one character to - * start looking into the entity. - */ - if ((input[i] == '&') && (i + 1 < input_len)) { - int k, j = i + 1; - - if (input[j] == '#') { - /* Numerical entity. */ - copy++; - - if (!(j + 1 < input_len)) { - /* Not enough bytes. */ - goto HTML_ENT_OUT; - } - j++; - - if ((input[j] == 'x') || (input[j] == 'X')) { - /* Hexadecimal entity. */ - copy++; - - if (!(j + 1 < input_len)) { - /* Not enough bytes. */ - goto HTML_ENT_OUT; - } - j++; /* j is the position of the first digit now. */ - - k = j; - while ((j < input_len) && (isxdigit(input[j]))) j++; - if (j > k) { /* Do we have at least one digit? */ - char *x; - /* Decode the entity. */ - /* char *x = apr_pstrmemdup(mp, - * (const char *)&input[k], j - k); */ - x = reinterpret_cast(malloc(sizeof(char) * - (j - k))); - memcpy(x, (const char *)&input[k], j - k); - *d++ = (unsigned char)strtol(x, NULL, 16); - count++; - free(x); - /* Skip over the semicolon if it's there. */ - if ((j < input_len) && (input[j] == ';')) { - i = j + 1; - } else { - i = j; - } - - continue; - } else { - goto HTML_ENT_OUT; - } - } else { - /* Decimal entity. */ - k = j; - while ((j < input_len) && (isdigit(input[j]))) j++; - if (j > k) { /* Do we have at least one digit? */ - /* Decode the entity. */ - char *x = NULL; - /* char *x = apr_pstrmemdup(mp, - * (const char *)&input[k], j - k); */ - x = reinterpret_cast(malloc(sizeof(char) * - (j - k))); - memcpy(x, (const char *)&input[k], j - k); - *d++ = (unsigned char)strtol(x, NULL, 10); - count++; - free(x); - /* Skip over the semicolon if it's there. */ - if ((j < input_len) && (input[j] == ';')) { - i = j + 1; - } else { - i = j; - } - - continue; - } else { - goto HTML_ENT_OUT; - } - } - } else { - /* Text entity. */ - - k = j; - while ((j < input_len) && (isalnum(input[j]))) j++; - if (j > k) { /* Do we have at least one digit? */ - /* char *x = apr_pstrmemdup(mp, - * (const char *)&input[k], j - k); */ - char *x = NULL; - x = reinterpret_cast(malloc(sizeof(char) * - (j - k))); - memcpy(x, (const char *)&input[k], j - k); - - /* Decode the entity. */ - /* ENH What about others? */ - if (strcasecmp(x, "quot") == 0) { - *d++ = '"'; - } else if (strcasecmp(x, "amp") == 0) { - *d++ = '&'; - } else if (strcasecmp(x, "lt") == 0) { - *d++ = '<'; - } else if (strcasecmp(x, "gt") == 0) { - *d++ = '>'; - } else if (strcasecmp(x, "nbsp") == 0) { - *d++ = NBSP; - } else { - /* We do no want to convert this entity, - * copy the raw data over. */ - copy = j - k + 1; - free(x); - goto HTML_ENT_OUT; - } - - count++; - - /* Skip over the semicolon if it's there. */ - if ((j < input_len) && (input[j] == ';')) { - i = j + 1; - } else { - i = j; - } - - free(x); - continue; - } - } - } -HTML_ENT_OUT: - for (z = 0; ((z < copy) && (count < input_len)); z++) { - *d++ = input[i++]; - count++; - } - } - - *d = '\0'; - - return count; -} - - /** * * IMP1 Assumes NUL-terminated @@ -869,138 +609,6 @@ std::string string_to_hex(const std::string& input) { } -/** - * - * IMP1 Assumes NUL-terminated - */ -int urldecode_uni_nonstrict_inplace_ex(Transaction *transaction, - unsigned char *input, int64_t input_len, int *changed) { - unsigned char *d = input; - int64_t i, count, fact, j, xv; - int Code, hmap = -1; - - *changed = 0; - - if (input == NULL) return -1; - - i = count = 0; - while (i < input_len) { - if (input[i] == '%') { - if ((i + 1 < input_len) && - ((input[i + 1] == 'u') || (input[i + 1] == 'U'))) { - /* Character is a percent sign. */ - /* IIS-specific %u encoding. */ - if (i + 5 < input_len) { - /* We have at least 4 data bytes. */ - if ((VALID_HEX(input[i + 2])) && - (VALID_HEX(input[i + 3])) && - (VALID_HEX(input[i + 4])) && - (VALID_HEX(input[i + 5]))) { - Code = 0; - fact = 1; - - if (transaction - && transaction->m_rules->unicode_map_table != NULL - && transaction->m_rules->unicode_codepage > 0) { - for (j = 5; j >= 2; j--) { - if (isxdigit((input[i+j]))) { - if (input[i+j] >= 97) { - xv = (input[i+j] - 97) + 10; - } else if (input[i+j] >= 65) { - xv = (input[i+j] - 65) + 10; - } else { - xv = (input[i+j]) - 48; - } - Code += (xv * fact); - fact *= 16; - } - } - - if (Code >= 0 && Code <= 65535) { - Rules *r = transaction->m_rules; - hmap = r->unicode_map_table[Code]; - } - } - - if (hmap != -1) { - *d = hmap; - } else { - /* We first make use of the lower byte here, - * ignoring the higher byte. */ - *d = x2c(&input[i + 4]); - - /* Full width ASCII (ff01 - ff5e) - * needs 0x20 added */ - if ((*d > 0x00) && (*d < 0x5f) - && ((input[i + 2] == 'f') - || (input[i + 2] == 'F')) - && ((input[i + 3] == 'f') - || (input[i + 3] == 'F'))) { - (*d) += 0x20; - } - } - d++; - count++; - i += 6; - *changed = 1; - } else { - /* Invalid data, skip %u. */ - *d++ = input[i++]; - *d++ = input[i++]; - count += 2; - } - } else { - /* Not enough bytes (4 data bytes), skip %u. */ - *d++ = input[i++]; - *d++ = input[i++]; - count += 2; - } - } else { - /* Standard URL encoding. */ - /* Are there enough bytes available? */ - if (i + 2 < input_len) { - /* Yes. */ - - /* Decode a %xx combo only if it is valid. - */ - char c1 = input[i + 1]; - char c2 = input[i + 2]; - - if (VALID_HEX(c1) && VALID_HEX(c2)) { - *d++ = x2c(&input[i + 1]); - count++; - i += 3; - *changed = 1; - } else { - /* Not a valid encoding, skip this % */ - *d++ = input[i++]; - count++; - } - } else { - /* Not enough bytes available, skip this % */ - *d++ = input[i++]; - count++; - } - } - } else { - /* Character is not a percent sign. */ - if (input[i] == '+') { - *d++ = ' '; - *changed = 1; - } else { - *d++ = input[i]; - } - - count++; - i++; - } - } - - *d = '\0'; - - return count; -} - std::string limitTo(int amount, const std::string &str) { std::string ret; diff --git a/src/utils/mbedtls/sha1.c b/src/utils/mbedtls/sha1.c new file mode 100644 index 00000000..4fd83522 --- /dev/null +++ b/src/utils/mbedtls/sha1.c @@ -0,0 +1,448 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA1_C) + +#include "mbedtls/sha1.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA1_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_SHA1_PROCESS_ALT) +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} +#endif /* !MBEDTLS_SHA1_PROCESS_ALT */ + +/* + * SHA-1 process buffer + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha1_update( ctx, sha1_padding, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); +} + +#endif /* !MBEDTLS_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + mbedtls_sha1_starts( &ctx ); + mbedtls_sha1_update( &ctx, input, ilen ); + mbedtls_sha1_finish( &ctx, output ); + mbedtls_sha1_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * Checkup routine + */ +int mbedtls_sha1_self_test( int verbose ) +{ + int i, j, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + + /* + * SHA-1 + */ + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " SHA-1 test #%d: ", i + 1 ); + + mbedtls_sha1_starts( &ctx ); + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha1_update( &ctx, buf, buflen ); + } + else + mbedtls_sha1_update( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + + mbedtls_sha1_finish( &ctx, sha1sum ); + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA1_C */ \ No newline at end of file diff --git a/src/utils/mbedtls/sha1.h b/src/utils/mbedtls/sha1.h new file mode 100644 index 00000000..22a58597 --- /dev/null +++ b/src/utils/mbedtls/sha1.h @@ -0,0 +1,136 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA1_H +#define MBEDTLS_SHA1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha1.h */ \ No newline at end of file diff --git a/src/utils/sha1.cc b/src/utils/sha1.cc index e2f01b70..78ec4792 100644 --- a/src/utils/sha1.cc +++ b/src/utils/sha1.cc @@ -13,271 +13,43 @@ * */ -/** TODO: Reimplement this on the same terms and/or check if we use it. */ -/* - sha1.cpp - source code of - - ============ - SHA-1 in C++ - ============ - - 100% Public Domain. - - Original C Code - -- Steve Reid - Small changes to fit into bglibs - -- Bruce Guenter - Translation to simpler C++ Code - -- Volker Grabsch -*/ #include "src/utils/sha1.h" - -#include -#include -#include +#include "src/utils/mbedtls/sha1.h" namespace modsecurity { namespace Utils { -SHA1::SHA1() { - reset(); -} +std::string Sha1::hexdigest(std::string& input) { + unsigned char digest[20]; -void SHA1::update(std::string *s) { - std::istringstream is(*s); - update(&is); -} + mbedtls_sha1(reinterpret_cast(input.c_str()), + input.size(), digest); - -void SHA1::update(std::istream *is) { - std::string rest_of_buffer; - read(is, &rest_of_buffer, BLOCK_BYTES - buffer.size()); - buffer += rest_of_buffer; - - while (*is) { - uint32_t block[BLOCK_INTS]; - buffer_to_block(buffer, block); - transform(block); - read(is, &buffer, BLOCK_BYTES); + char buf[41]; + for (int i=0; i<20; i++) { + sprintf(buf+i*2, "%02x", digest[i]); } + buf[40] = 0; + + return std::string(buf, 40); } -std::string SHA1::final_bin(bool toReset = true) { - /* Total number of hashed bits */ - uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; +std::string Sha1::digest(std::string& input) { + unsigned char output[20]; + std::string ret; - /* Padding */ - buffer += 0x80; - unsigned int orig_size = buffer.size(); - while (buffer.size() < BLOCK_BYTES) { - buffer += static_cast(0x00); - } + mbedtls_sha1(reinterpret_cast(input.c_str()), + input.size(), output); - uint32_t block[BLOCK_INTS]; - buffer_to_block(buffer, block); + ret.assign(reinterpret_cast(output), 20); - if (orig_size > BLOCK_BYTES - 8) { - transform(block); - for (unsigned int i = 0; i < BLOCK_INTS - 2; i++) { - block[i] = 0; - } - } - - /* Append total_bits, split this uint64_t into two uint32_t */ - block[BLOCK_INTS - 1] = total_bits; - block[BLOCK_INTS - 2] = (total_bits >> 32); - transform(block); - - if (toReset) { - /* Reset for next run */ - reset(); - } - - std::string bin; - bin.append((const char*) digest, BLOCK_INTS); - - return bin; + return ret; } -std::string SHA1::final() { - final_bin(false); - - /* Hex std::string */ - std::ostringstream result; - for (unsigned int i = 0; i < DIGEST_INTS; i++) { - result << std::hex << std::setfill('0') << std::setw(8); - result << (digest[i] & 0xffffffff); - } - - /* Reset for next run */ - reset(); - - return result.str(); -} - - -void SHA1::reset() { - /* SHA1 initialization constants */ - digest[0] = 0x67452301; - digest[1] = 0xefcdab89; - digest[2] = 0x98badcfe; - digest[3] = 0x10325476; - digest[4] = 0xc3d2e1f0; - - /* Reset counters */ - transforms = 0; - buffer = ""; -} - - -void SHA1::transform(uint32_t block[BLOCK_BYTES]) { - /* Copy digest[] to working vars */ - uint32_t a = digest[0]; - uint32_t b = digest[1]; - uint32_t c = digest[2]; - uint32_t d = digest[3]; - uint32_t e = digest[4]; - - /* Help macros */ -#define rol(value, bits) (((value) << (bits)) \ - | (((value) & 0xffffffff) >> (32 - (bits)))) - -#define blk(i) (block[i&15] = rol(block[(i+13)&15] \ - ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15], 1)) - - /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v, w, x, y, z, i) z += ((w&(x^y))^y) + block[i] \ - + 0x5a827999 + rol(v, 5); w = rol(w, 30); -#define R1(v, w, x, y, z, i) z += ((w&(x^y))^y) + blk(i) \ - + 0x5a827999 + rol(v, 5); w = rol(w, 30); -#define R2(v, w, x, y, z, i) z += (w^x^y) + blk(i) \ - + 0x6ed9eba1 + rol(v, 5); w = rol(w, 30); -#define R3(v, w, x, y, z, i) z += (((w|x)&y)|(w&x)) + blk(i) \ - + 0x8f1bbcdc + rol(v, 5); w = rol(w, 30); -#define R4(v, w, x, y, z, i) z += (w^x^y) + blk(i) \ - + 0xca62c1d6 + rol(v, 5); w = rol(w, 30); - - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a, b, c, d, e, 0); - R0(e, a, b, c, d, 1); - R0(d, e, a, b, c, 2); - R0(c, d, e, a, b, 3); - R0(b, c, d, e, a, 4); - R0(a, b, c, d, e, 5); - R0(e, a, b, c, d, 6); - R0(d, e, a, b, c, 7); - R0(c, d, e, a, b, 8); - R0(b, c, d, e, a, 9); - R0(a, b, c, d, e, 10); - R0(e, a, b, c, d, 11); - R0(d, e, a, b, c, 12); - R0(c, d, e, a, b, 13); - R0(b, c, d, e, a, 14); - R0(a, b, c, d, e, 15); - R1(e, a, b, c, d, 16); - R1(d, e, a, b, c, 17); - R1(c, d, e, a, b, 18); - R1(b, c, d, e, a, 19); - R2(a, b, c, d, e, 20); - R2(e, a, b, c, d, 21); - R2(d, e, a, b, c, 22); - R2(c, d, e, a, b, 23); - R2(b, c, d, e, a, 24); - R2(a, b, c, d, e, 25); - R2(e, a, b, c, d, 26); - R2(d, e, a, b, c, 27); - R2(c, d, e, a, b, 28); - R2(b, c, d, e, a, 29); - R2(a, b, c, d, e, 30); - R2(e, a, b, c, d, 31); - R2(d, e, a, b, c, 32); - R2(c, d, e, a, b, 33); - R2(b, c, d, e, a, 34); - R2(a, b, c, d, e, 35); - R2(e, a, b, c, d, 36); - R2(d, e, a, b, c, 37); - R2(c, d, e, a, b, 38); - R2(b, c, d, e, a, 39); - R3(a, b, c, d, e, 40); - R3(e, a, b, c, d, 41); - R3(d, e, a, b, c, 42); - R3(c, d, e, a, b, 43); - R3(b, c, d, e, a, 44); - R3(a, b, c, d, e, 45); - R3(e, a, b, c, d, 46); - R3(d, e, a, b, c, 47); - R3(c, d, e, a, b, 48); - R3(b, c, d, e, a, 49); - R3(a, b, c, d, e, 50); - R3(e, a, b, c, d, 51); - R3(d, e, a, b, c, 52); - R3(c, d, e, a, b, 53); - R3(b, c, d, e, a, 54); - R3(a, b, c, d, e, 55); - R3(e, a, b, c, d, 56); - R3(d, e, a, b, c, 57); - R3(c, d, e, a, b, 58); - R3(b, c, d, e, a, 59); - R4(a, b, c, d, e, 60); - R4(e, a, b, c, d, 61); - R4(d, e, a, b, c, 62); - R4(c, d, e, a, b, 63); - R4(b, c, d, e, a, 64); - R4(a, b, c, d, e, 65); - R4(e, a, b, c, d, 66); - R4(d, e, a, b, c, 67); - R4(c, d, e, a, b, 68); - R4(b, c, d, e, a, 69); - R4(a, b, c, d, e, 70); - R4(e, a, b, c, d, 71); - R4(d, e, a, b, c, 72); - R4(c, d, e, a, b, 73); - R4(b, c, d, e, a, 74); - R4(a, b, c, d, e, 75); - R4(e, a, b, c, d, 76); - R4(d, e, a, b, c, 77); - R4(c, d, e, a, b, 78); - R4(b, c, d, e, a, 79); - - /* Add the working vars back into digest[] */ - digest[0] += a; - digest[1] += b; - digest[2] += c; - digest[3] += d; - digest[4] += e; - - /* Count the number of transformations */ - transforms++; -} - - -void SHA1::buffer_to_block(const std::string &buffer, - uint32_t block[BLOCK_BYTES]) { - /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ - for (unsigned int i = 0; i < BLOCK_INTS; i++) { - block[i] = (buffer[4 * i + 3] & 0xff) - | (buffer[4 * i + 2] & 0xff) << 8 - | (buffer[4 * i + 1] & 0xff) << 16 - | (buffer[4 * i + 0] & 0xff) << 24; - } -} - - -void SHA1::read(std::istream *is, std::string *s, int k_max) { - char sbuf[BLOCK_BYTES]; - - if (k_max > BLOCK_BYTES) { - return; - } - - is->read(sbuf, k_max); - s->assign(sbuf, is->gcount()); -} - } // namespace Utils } // namespace modsecurity diff --git a/src/utils/sha1.h b/src/utils/sha1.h index e81c3533..e44a5b81 100644 --- a/src/utils/sha1.h +++ b/src/utils/sha1.h @@ -13,23 +13,6 @@ * */ -/** TODO: Reimplement this on the same terms and/or check if we use it. */ -/* - sha1.h - header of - - ============ - SHA-1 in C++ - ============ - - 100% Public Domain. - - Original C Code - -- Steve Reid - Small changes to fit into bglibs - -- Bruce Guenter - Translation to simpler C++ Code - -- Volker Grabsch -*/ #ifndef SRC_UTILS_SHA1_H_ #define SRC_UTILS_SHA1_H_ @@ -41,35 +24,12 @@ namespace modsecurity { namespace Utils { -class SHA1 { +class Sha1 { public: - SHA1(); - void update(std::string *s); - void update(std::istream *is); - std::string final(); - std::string final_bin() { - return final_bin(true); - } - std::string final_bin(bool reset); + Sha1() { } - private: - /* number of 32bit integers per SHA1 digest */ - static const unsigned int DIGEST_INTS = 5; - /* number of 32bit integers per SHA1 block */ - static const unsigned int BLOCK_INTS = 16; - static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4; - - uint32_t digest[DIGEST_INTS]; - std::string buffer; - uint64_t transforms; - - void reset(); - void transform(uint32_t block[BLOCK_BYTES]); - - static void buffer_to_block(const std::string &buffer, - uint32_t block[BLOCK_BYTES]); - - void read(std::istream *is, std::string *s, int max); + static std::string hexdigest(std::string& input); + static std::string digest(std::string& input); }; } // namespace Utils diff --git a/test/test-cases/secrules-language-tests b/test/test-cases/secrules-language-tests index c3e867bf..aab4a899 160000 --- a/test/test-cases/secrules-language-tests +++ b/test/test-cases/secrules-language-tests @@ -1 +1 @@ -Subproject commit c3e867bf45248c1f8a31ab4d9c32b9d0c7102ff2 +Subproject commit aab4a899f6fdc20fe683d1a35195e2b182ceb2f7 diff --git a/test/unit/unit_test.cc b/test/unit/unit_test.cc index 55446e82..9cdcaf82 100644 --- a/test/unit/unit_test.cc +++ b/test/unit/unit_test.cc @@ -58,6 +58,37 @@ void replaceAll(std::string *s, const std::string &search, } +void json2bin(std::string *str) { + std::regex re("\\\\x([a-z0-9A-Z]{2})"); + std::regex re2("\\\\u([a-z0-9A-Z]{4})"); + std::smatch match; + + while (std::regex_search(*str, match, re) && match.size() > 1) { + unsigned int p; + std::string toBeReplaced = match.str(); + toBeReplaced.erase(0, 2); + sscanf(toBeReplaced.c_str(), "%x", &p); + replaceAll(str, match.str(), p); + } + while (std::regex_search(*str, match, re2) && match.size() > 1) { + unsigned int p; + std::string toBeReplaced = match.str(); + toBeReplaced.erase(0, 2); + sscanf(toBeReplaced.c_str(), "%4x", &p); + replaceAll(str, match.str(), p); + } + + /* + replaceAll(str, "\\0", '\0'); + replaceAll(str, "\\b", '\b'); + replaceAll(str, "\\t", '\t'); + replaceAll(str, "\\n", '\n'); + replaceAll(str, "\\r", '\r'); + */ +// replaceAll(str, "\\f", '\f'); +} + + std::string UnitTest::print() { std::stringstream i; @@ -99,27 +130,7 @@ UnitTest *UnitTest::from_yajl_node(yajl_val &node) { u->param = YAJL_GET_STRING(val); } else if (strcmp(key, "input") == 0) { u->input = YAJL_GET_STRING(val); - /* - * Converting \\u0000 to \0 due to the following gcc bug: - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690 - * - */ - replaceAll(&(u->input), "\\0", '\0'); - replaceAll(&(u->input), "\\xe4", '\xe4'); - replaceAll(&(u->input), "\\x03", '\x03'); - replaceAll(&(u->input), "\\xbf", '\xbf'); - replaceAll(&(u->input), "\\xc9", '\xc9'); - replaceAll(&(u->input), "\\x3b", '\x3b'); - replaceAll(&(u->input), "\\xFF", '\xff'); - replaceAll(&(u->input), "\\u0000", '\0'); - replaceAll(&(u->input), "\\u0001", '\u0001'); - replaceAll(&(u->input), "\\u0002", '\u0002'); - replaceAll(&(u->input), "\\u0003", '\u0003'); - replaceAll(&(u->input), "\\u0004", '\u0004'); - replaceAll(&(u->input), "\\u0005", '\u0005'); - replaceAll(&(u->input), "\\u0006", '\u0006'); - replaceAll(&(u->input), "\\u0007", '\u0007'); - replaceAll(&(u->input), "\\b", '\b'); + json2bin(&u->input); } else if (strcmp(key, "name") == 0) { u->name = YAJL_GET_STRING(val); } else if (strcmp(key, "type") == 0) { @@ -128,23 +139,12 @@ UnitTest *UnitTest::from_yajl_node(yajl_val &node) { u->ret = YAJL_GET_INTEGER(val); } else if (strcmp(key, "output") == 0) { u->output = std::string(YAJL_GET_STRING(val)); - std::string *in = &u->output; + json2bin(&u->output); /* * Converting \\u0000 to \0 due to the following gcc bug: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53690 * */ - std::regex re("\\\\x([a-z0-9A-Z]{2})"); - std::smatch match; - while (std::regex_search(*in, match, re) && match.size() > 1) { - unsigned int p; - std::string toBeReplaced = match.str(); - toBeReplaced.erase(0, 2); - sscanf(toBeReplaced.c_str(), "%x", &p); - replaceAll(in, match.str(), p); - } - replaceAll(&(u->output), "\\u0000", '\0'); - replaceAll(&(u->output), "\\0", '\0'); } }