]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1667 in SNORT/snort3 from ~MDAGON/snort3:hpack_string to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 12 Jul 2019 17:14:05 +0000 (13:14 -0400)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 12 Jul 2019 17:14:05 +0000 (13:14 -0400)
Squashed commit of the following:

commit 74d40186fe6b3dd1207eb70e621e966de29051df
Author: mdagon <mdagon@cisco.com>
Date:   Wed Jul 3 12:04:12 2019 -0400

    http2: hpack string decode

src/service_inspectors/http2_inspect/CMakeLists.txt
src/service_inspectors/http2_inspect/http2_enum.h
src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc [moved from src/service_inspectors/http2_inspect/http2_hpack_decode.cc with 86% similarity]
src/service_inspectors/http2_inspect/http2_hpack_int_decode.h [moved from src/service_inspectors/http2_inspect/http2_hpack_decode.h with 86% similarity]
src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_hpack_string_decode.h [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_tables.cc
src/service_inspectors/http2_inspect/test/CMakeLists.txt
src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc [moved from src/service_inspectors/http2_inspect/test/http2_hpack_decode_test.cc with 62% similarity]
src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc [new file with mode: 0644]

index 90b40758f8ff053c2605e14dee78f48f462972b5..b9406e6342bb1f7e4b9100a1e7edce6f1b6f4c47 100644 (file)
@@ -5,8 +5,10 @@ set (FILE_LIST
     http2_enum.h
     http2_flow_data.cc
     http2_flow_data.h
-    http2_hpack_decode.cc
-    http2_hpack_decode.h
+    http2_hpack_int_decode.cc
+    http2_hpack_int_decode.h
+    http2_hpack_string_decode.cc
+    http2_hpack_string_decode.h    
     http2_inspect.cc
     http2_inspect_impl.cc
     http2_inspect.h
index a1fc4ca1de25650fb1c77567d97a39a7620c9910..63a2557325a9b7ab5cf58efff2982bd3fbee03f0 100644 (file)
@@ -51,6 +51,7 @@ enum EventSid
     EVENT__NONE = -1,
     EVENT_INT_DECODE_FAILURE = 1,
     EVENT_INT_LEADING_ZEROS = 2,
+    EVENT_STRING_DECODE_FAILURE = 3,
     EVENT__MAX_VALUE
 };
 
@@ -62,6 +63,9 @@ enum Infraction
     INF_INT_MISSING_BYTES = 1,
     INF_INT_OVERFLOW = 2,
     INF_INT_LEADING_ZEROS = 3,
+    INF_STRING_EMPTY_BUFF = 4,
+    INF_STRING_MISSING_BYTES = 5,
+    INF_OUT_BUFF_OUT_OF_SPACE = 6,
     INF__MAX_VALUE
 };    
  
similarity index 86%
rename from src/service_inspectors/http2_inspect/http2_hpack_decode.cc
rename to src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc
index e723012bd313d7861bf182fa1b7b916d0d3eb886..e2ab8c434e78fb5d3c8543d459717ecb9aec8ee0 100644 (file)
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
-// http2_hpack_decode.cc author Maya Dagon <mdagon@cisco.com>
+// http2_hpack_int_decode.cc author Maya Dagon <mdagon@cisco.com>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "http2_hpack_decode.h"
+#include "http2_hpack_int_decode.h"
 
 #include "http2_enum.h"
 
@@ -37,20 +37,20 @@ Http2HpackIntDecode::Http2HpackIntDecode(uint8_t prefix, Http2EventGen* events,
     assert ((0 < prefix) && (prefix < 9));
 }
 
-bool Http2HpackIntDecode::translate(const Field& msg, int32_t& bytes_consumed, uint64_t& result)
+bool Http2HpackIntDecode::translate(const uint8_t* in_buff, const uint32_t in_len,
+    uint32_t& bytes_consumed, uint64_t& result)
 {
     bytes_consumed = 0;
     result = 0;
 
-    if (bytes_consumed >= msg.length())
+    if (in_len == 0)
     {
         *infractions += INF_INT_EMPTY_BUFF;
         events->create_event(EVENT_INT_DECODE_FAILURE);
         return false;
     }
 
-    const uint8_t* buff = msg.start();
-    const uint8_t prefix_val = buff[bytes_consumed++] & prefix_mask;
+    const uint8_t prefix_val = in_buff[bytes_consumed++] & prefix_mask;
 
     if (prefix_val < prefix_mask)
     {
@@ -61,13 +61,13 @@ bool Http2HpackIntDecode::translate(const Field& msg, int32_t& bytes_consumed, u
     uint8_t byte = 0;
     for (uint8_t multiplier = 0; multiplier < 64; multiplier += 7)
     {
-        if (bytes_consumed >= msg.length())
+        if (bytes_consumed >= in_len)
         {
             *infractions += INF_INT_MISSING_BYTES;
             events->create_event(EVENT_INT_DECODE_FAILURE);
             return false;
         }
-        byte = buff[bytes_consumed++];
+        byte = in_buff[bytes_consumed++];
 
         // For multiplier == 63, do overflow checks
         if (multiplier == 63)
similarity index 86%
rename from src/service_inspectors/http2_inspect/http2_hpack_decode.h
rename to src/service_inspectors/http2_inspect/http2_hpack_int_decode.h
index bc22111117153ff46ead43de0626372b2fed4a2a..48ef44557b61a87b9097f9415095ae00c2e0ced2 100644 (file)
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
-// http2_hpack_decode.h author Maya Dagon <mdagon@cisco.com>
+// http2_hpack_int_decode.h author Maya Dagon <mdagon@cisco.com>
 
-#ifndef HTTP2_HPACK_DECODE_H
-#define HTTP2_HPACK_DECODE_H
+#ifndef HTTP2_HPACK_INT_DECODE_H
+#define HTTP2_HPACK_INT_DECODE_H
 
 #include "http2_enum.h"
 #include "main/snort_types.h"
-#include "service_inspectors/http_inspect/http_field.h"
 #include "utils/event_gen.h"
 #include "utils/infractions.h"
 
@@ -35,7 +34,8 @@ class Http2HpackIntDecode
 {
 public:
     Http2HpackIntDecode(uint8_t prefix, Http2EventGen* events, Http2Infractions* infractions);
-    bool translate(const Field& msg, int32_t& bytes_consumed, uint64_t& result);
+    bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed,
+        uint64_t& result);
 
 private:
     const uint8_t prefix_mask;
diff --git a/src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc b/src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc
new file mode 100644 (file)
index 0000000..2c24afc
--- /dev/null
@@ -0,0 +1,98 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_hpack_string_decode.cc author Maya Dagon <mdagon@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "http2_hpack_string_decode.h"
+
+#include "http2_enum.h"
+
+using namespace Http2Enums;
+
+static const uint8_t HUFFMAN_FLAG = 0x80;
+
+Http2HpackStringDecode::Http2HpackStringDecode(Http2EventGen* events,
+    Http2Infractions* infractions) : decode7(new Http2HpackIntDecode(7, events, infractions)),
+    events(events), infractions(infractions)
+{ }
+
+bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in_len,
+    uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written)
+{
+    bytes_consumed = 0;
+    bytes_written = 0;
+
+    if (in_len == 0)
+    {
+        *infractions += INF_STRING_EMPTY_BUFF;
+        events->create_event(EVENT_STRING_DECODE_FAILURE);
+        return false;
+    }
+
+    const bool isHuffman = (in_buff[0] & HUFFMAN_FLAG) != 0;
+
+    // Get length
+    uint64_t encoded_len;
+    if (!decode7->translate(in_buff, in_len, bytes_consumed, encoded_len))
+        return false;
+
+    if (encoded_len > (uint64_t)(in_len - bytes_consumed))
+    {
+        *infractions += INF_STRING_MISSING_BYTES;
+        events->create_event(EVENT_STRING_DECODE_FAILURE);
+        return false;
+    }
+
+    if (encoded_len == 0)
+        return true;
+
+    if (!isHuffman)
+        return get_string(in_buff, encoded_len, bytes_consumed, out_buff, out_len, bytes_written);
+
+    return get_huffman_string(in_buff, encoded_len, bytes_consumed, out_buff, out_len,
+        bytes_written);
+}
+
+Http2HpackStringDecode::~Http2HpackStringDecode()
+{
+    assert(decode7 != nullptr);
+    delete decode7;
+}
+
+bool Http2HpackStringDecode::get_string(const uint8_t* in_buff, const uint32_t encoded_len,
+    uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written)
+{
+    if (encoded_len > out_len)
+    {
+        *infractions += INF_OUT_BUFF_OUT_OF_SPACE;
+        events->create_event(EVENT_STRING_DECODE_FAILURE);
+        return false;
+    }
+
+    while (bytes_written < encoded_len)
+        out_buff[bytes_written++] = in_buff[bytes_consumed++];
+
+    return true;
+}
+
+bool Http2HpackStringDecode::get_huffman_string(const uint8_t*, const uint32_t, uint32_t&,
+    uint8_t*, const uint32_t, uint32_t&) { return false; }
+
diff --git a/src/service_inspectors/http2_inspect/http2_hpack_string_decode.h b/src/service_inspectors/http2_inspect/http2_hpack_string_decode.h
new file mode 100644 (file)
index 0000000..172d768
--- /dev/null
@@ -0,0 +1,50 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_hpack_string_decode.h author Maya Dagon <mdagon@cisco.com>
+
+#ifndef HTTP2_HPACK_STRING_DECODE_H
+#define HTTP2_HPACK_STRING_DECODE_H
+
+#include "http2_enum.h"
+#include "http2_hpack_int_decode.h"
+
+#include "main/snort_types.h"
+#include "utils/event_gen.h"
+#include "utils/infractions.h"
+
+class Http2HpackStringDecode
+{
+public:
+    Http2HpackStringDecode(Http2EventGen* events, Http2Infractions* infractions);
+    bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed,
+        uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written);
+    ~Http2HpackStringDecode();
+
+private:
+    bool get_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed,
+        uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written);
+    bool get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len,
+        uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written);
+
+    Http2HpackIntDecode* const decode7;
+    Http2EventGen* const events;
+    Http2Infractions* const infractions;
+};
+
+#endif
+
index cb52a679552fea95f2eed07c61cbc5c0373e229d..b50303848132ed79a1a5562f3d234a307aff094a 100644 (file)
@@ -30,8 +30,9 @@ using namespace Http2Enums;
 
 const snort::RuleMap Http2Module::http2_events[] =
 {
-    { EVENT_INT_DECODE_FAILURE, "Failed to decode integer value" },
+    { EVENT_INT_DECODE_FAILURE, "Error in HPACK integer value" },
     { EVENT_INT_LEADING_ZEROS, "Integer value has leading zeros" },
+    { EVENT_STRING_DECODE_FAILURE, "Error in HPACK string value" },
     { 0, nullptr }
 };
 
index 6402e3e660adfffb915db005199841852c68ec45..37e0ed03861a8adfb759807b2f95dbebf73ae0aa 100644 (file)
@@ -14,7 +14,12 @@ add_cpputest( http2_stream_splitter_impl_test
         ../http2_tables.cc
         ../../../framework/module.cc
 )
-add_cpputest( http2_hpack_decode_test
+add_cpputest( http2_hpack_int_decode_test
     SOURCES
-        ../http2_hpack_decode.cc
+        ../http2_hpack_int_decode.cc
+)
+add_cpputest( http2_hpack_string_decode_test
+    SOURCES
+        ../http2_hpack_int_decode.cc
+        ../http2_hpack_string_decode.cc
 )
similarity index 62%
rename from src/service_inspectors/http2_inspect/test/http2_hpack_decode_test.cc
rename to src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc
index facce5ec3bb0799737ae5c6eb322216562b04729..706f1f8b23f8b61379473d2902b827b8e90df1e7 100644 (file)
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 
-// http2_hpack_decode_test.cc author Maya Dagon <mdagon@cisco.com>
+// http2_hpack_int_decode_test.cc author Maya Dagon <mdagon@cisco.com>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "../http2_enum.h"
-#include "../http2_hpack_decode.h"
+#include "../http2_hpack_int_decode.h"
 
 #include <CppUTest/CommandLineTestRunner.h>
 #include <CppUTest/TestHarness.h>
@@ -37,11 +37,10 @@ int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { re
 
 using namespace Http2Enums;
 
-
 //
 // The following tests should result in a successful decode, no infractions/events
 //
-TEST_GROUP(http2_hpack_decode_success)
+TEST_GROUP(http2_hpack_int_decode_success)
 {
     Http2EventGen events;
     Http2Infractions inf;
@@ -55,134 +54,125 @@ TEST_GROUP(http2_hpack_decode_success)
     }
 };
 
-TEST(http2_hpack_decode_success, 10_using_5_bits)
+TEST(http2_hpack_int_decode_success, 10_using_5_bits)
 {
-    // prepare field to decode - example from RFC 7541 c.1.1
+    // prepare buf to decode - example from RFC 7541 c.1.1
     uint8_t buf = 10;
-    Field f(1, &buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode->translate(f, bytes_processed, res);
+    bool success = decode->translate(&buf, 1, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 10);
     CHECK(bytes_processed == 1);
 }
 
-TEST(http2_hpack_decode_success, 10_using_5_bits_wtail)
+TEST(http2_hpack_int_decode_success, 10_using_5_bits_wtail)
 {
-    // prepare field to decode - same as above with an extra byte as leftover
+    // prepare buf to decode - same as above with an extra byte as leftover
     uint8_t buf[2] = { 10, 0xff };
-    Field f(2, buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode->translate(f, bytes_processed, res);
+    bool success = decode->translate(buf, 2, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 10);
     CHECK(bytes_processed == 1);
 }
 
-TEST(http2_hpack_decode_success, 1337_using_5_bits)
+TEST(http2_hpack_int_decode_success, 1337_using_5_bits)
 {
-    // prepare field to decode - example from RFC 7541 c.1.2
+    // prepare buf to decode - example from RFC 7541 c.1.2
     uint8_t buf[3] = { 31, 0x9a, 10 };
-    Field f(3, buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode->translate(f, bytes_processed, res);
+    bool success = decode->translate(buf, 3, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 1337);
     CHECK(bytes_processed == 3);
 }
 
-TEST(http2_hpack_decode_success, 42_using_8_bits)
+TEST(http2_hpack_int_decode_success, 42_using_8_bits)
 {
-    // prepare decode object  
+    // prepare decode object
     Http2HpackIntDecode decode_8(8, &events, &inf);
-    // prepare field to decode - example from RFC 7541 c.1.3
+    // prepare buf to decode - example from RFC 7541 c.1.3
     uint8_t buf = 42;
-    Field f(1, &buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode_8.translate(f, bytes_processed, res);
+    bool success = decode_8.translate(&buf, 1, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 42);
     CHECK(bytes_processed == 1);
 }
 
-TEST(http2_hpack_decode_success, max_val_using_5_bit)
+TEST(http2_hpack_int_decode_success, max_val_using_5_bit)
 {
-    // prepare field to decode - 2^64-1
-    uint8_t buf[11] = { 31, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1};
-    Field f(11, buf, false);
+    // prepare buf to decode - 2^64-1
+    uint8_t buf[11] = { 31, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1 };
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode->translate(f, bytes_processed, res);
+    bool success = decode->translate(buf, 11, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 0xFFFFFFFFFFFFFFFF);
     CHECK(bytes_processed == 11);
 }
 
-TEST(http2_hpack_decode_success, 31_using_5_bits)
-{ 
-    // prepare field to decode - 2^N -1
-    uint8_t buf[2] = {31, 0};
-    Field f(2, buf, false);
+TEST(http2_hpack_int_decode_success, 31_using_5_bits)
+{
+    // prepare buf to decode - 2^N -1
+    uint8_t buf[2] = { 31, 0 };
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode->translate(f, bytes_processed, res);
+    bool success = decode->translate(buf, 2, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 31);
     CHECK(bytes_processed == 2);
 }
 
-TEST(http2_hpack_decode_success, 0_using_5_bits)
-{ 
-    // prepare field to decode - 0 using 5 bits
+TEST(http2_hpack_int_decode_success, 0_using_5_bits)
+{
+    // prepare buf to decode - 0 using 5 bits
     uint8_t buf = 0;
-    Field f(1, &buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode->translate(f, bytes_processed, res);
+    bool success = decode->translate(&buf, 1, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 0);
     CHECK(bytes_processed == 1);
 }
 
-
 //
 // The following tests should result in a failure and set infractions/events
 //
-TEST_GROUP(http2_hpack_decode_failure)
+TEST_GROUP(http2_hpack_int_decode_failure)
 {
 };
 
-TEST(http2_hpack_decode_failure, 0_len_field)
+TEST(http2_hpack_int_decode_failure, 0_len_field)
 {
-    // prepare decode object  
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode decode_8(8, &local_events, &local_inf);
-    // prepare field to decode - use field length 0
+    // prepare buf to decode - use buf length 0
     uint8_t buf = 42;
-    Field f(0, &buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = decode_8.translate(f, bytes_processed, res);
+    bool success = decode_8.translate(&buf, 0, bytes_processed, res);
     // check results
     CHECK(success == false);
     CHECK(bytes_processed == 0);
@@ -190,19 +180,18 @@ TEST(http2_hpack_decode_failure, 0_len_field)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
 }
 
-TEST(http2_hpack_decode_failure, too_short)
+TEST(http2_hpack_int_decode_failure, too_short)
 {
-    // prepare decode object  
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - buffer ends before decode finished
+    // prepare buf to decode - buffer ends before decode finished
     uint8_t buf[3] = { 31, 0x9a, 10 };
-    Field f(2, buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 2, bytes_processed, res);
     // check results
     CHECK(success == false);
     CHECK(bytes_processed == 2);
@@ -210,19 +199,18 @@ TEST(http2_hpack_decode_failure, too_short)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
 }
 
-TEST(http2_hpack_decode_failure, multiplier_bigger_than_63)
+TEST(http2_hpack_int_decode_failure, multiplier_bigger_than_63)
 {
     // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - multiplier > 63
+    // prepare buf to decode - multiplier > 63
     uint8_t buf[13] = { 31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 1 };
-    Field f(13, buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 13, bytes_processed, res);
     // check results
     CHECK(success == false);
     CHECK(bytes_processed == 11);
@@ -230,19 +218,18 @@ TEST(http2_hpack_decode_failure, multiplier_bigger_than_63)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
 }
 
-TEST(http2_hpack_decode_failure, add_val_overflow)
+TEST(http2_hpack_int_decode_failure, add_val_overflow)
 {
-    // prepare decode object    
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - value to add itself is already creating overflow
+    // prepare buf to decode - value to add itself is already creating overflow
     uint8_t buf[12] = { 31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 1 };
-    Field f(12, buf, false);
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 12, bytes_processed, res);
     // check results
     CHECK(success == false);
     CHECK(bytes_processed == 11);
@@ -250,19 +237,18 @@ TEST(http2_hpack_decode_failure, add_val_overflow)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
 }
 
-TEST(http2_hpack_decode_failure, add_val_overflow2)
+TEST(http2_hpack_int_decode_failure, add_val_overflow2)
 {
-    // prepare decode object    
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - adding value to result kept so far creates overflow
-    uint8_t buf[11] = { 31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1};
-    Field f(11, buf, false);
+    // prepare buf to decode - adding value to result kept so far creates overflow
+    uint8_t buf[11] = { 31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1 };
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 11, bytes_processed, res);
     // check results
     CHECK(success == false);
     CHECK(bytes_processed == 11);
@@ -270,19 +256,18 @@ TEST(http2_hpack_decode_failure, add_val_overflow2)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
 }
 
-TEST(http2_hpack_decode_failure, 2_64_using_5_bit)
+TEST(http2_hpack_int_decode_failure, 2_64_using_5_bit)
 {
-    // prepare decode object    
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - 2^64
-    uint8_t buf[11] = { 31, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1};
-    Field f(11, buf, false);
+    // prepare buf to decode - 2^64
+    uint8_t buf[11] = { 31, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1 };
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 11, bytes_processed, res);
     // check results
     CHECK(success == false);
     CHECK(bytes_processed == 11);
@@ -290,28 +275,26 @@ TEST(http2_hpack_decode_failure, 2_64_using_5_bit)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
 }
 
-
 //
 // The following tests should result in a successful decode and set
 // leading zeros infraction and event
 //
-TEST_GROUP(http2_hpack_decode_leading_zeros)
+TEST_GROUP(http2_hpack_int_decode_leading_zeros)
 {
 };
 
-TEST(http2_hpack_decode_leading_zeros, leading_zeros)
+TEST(http2_hpack_int_decode_leading_zeros, leading_zeros)
 {
-    // prepare decode object    
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - MSB is zero
-    uint8_t buf[3] = { 31, 0x80, 0};
-    Field f(3, buf, false);
+    // prepare buf to decode - MSB is zero
+    uint8_t buf[3] = { 31, 0x80, 0 };
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 3, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 31);
@@ -320,20 +303,19 @@ TEST(http2_hpack_decode_leading_zeros, leading_zeros)
     CHECK(local_events.get_raw() == (1<<(EVENT_INT_LEADING_ZEROS-1)));
 }
 
-TEST(http2_hpack_decode_leading_zeros, leading_0_byte_11)
+TEST(http2_hpack_int_decode_leading_zeros, leading_0_byte_11)
 {
-    // prepare decode object    
+    // prepare decode object
     Http2EventGen local_events;
     Http2Infractions local_inf;
     Http2HpackIntDecode local_decode(5, &local_events, &local_inf);
-    // prepare field to decode - multiplier 63 doesn't create overflow, should alert on
+    // prepare buf to decode - multiplier 63 doesn't create overflow, should alert on
     // leading 0
-    uint8_t buf[11] = { 31, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0};
-    Field f(11, buf, false);
+    uint8_t buf[11] = { 31, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 };
     // decode
-    int32_t bytes_processed = 0;
+    uint32_t bytes_processed = 0;
     uint64_t res = 0;
-    bool success = local_decode.translate(f, bytes_processed, res);
+    bool success = local_decode.translate(buf, 11, bytes_processed, res);
     // check results
     CHECK(success == true);
     CHECK(res == 0x7FFFFFFFFFFFFFFF);
@@ -346,3 +328,4 @@ int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
 }
+
diff --git a/src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc b/src/service_inspectors/http2_inspect/test/http2_hpack_string_decode_test.cc
new file mode 100644 (file)
index 0000000..478fef0
--- /dev/null
@@ -0,0 +1,280 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// http2_hpack_string_decode_test.cc author Maya Dagon <mdagon@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../http2_enum.h"
+#include "../http2_hpack_string_decode.h"
+#include "../../http_inspect/http_enum.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+namespace snort
+{
+// Stubs whose sole purpose is to make the test code link
+int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
+}
+
+using namespace Http2Enums;
+
+//
+// The following tests should result in a successful decode, no infractions/events
+//
+TEST_GROUP(http2_hpack_string_decode_success)
+{
+    Http2EventGen events;
+    Http2Infractions inf;
+    Http2HpackStringDecode* const decode = new Http2HpackStringDecode(&events, &inf);
+
+    void teardown() override
+    {
+        CHECK(inf.none_found() == true);
+        CHECK(events.none_found() == true);
+        delete decode;
+    }
+};
+
+TEST(http2_hpack_string_decode_success, custom_key_len_10)
+{
+    // prepare buf to decode - example from RFC 7541 c.3.3
+    uint8_t buf[11] = { 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79 };
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[10];
+    bool success = decode->translate(buf, 11, bytes_processed, res, 10, bytes_written);
+    // check results
+    CHECK(success == true);
+    CHECK(memcmp(res, "custom-key", 10) == 0);
+    CHECK(bytes_processed == 11);
+    CHECK(bytes_written == 10);
+}
+
+TEST(http2_hpack_string_decode_success, custom_key_len_10_wtail)
+{
+    // prepare buf to decode - same as above with an extra byte as leftover
+    uint8_t buf[12] = { 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x79 };
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[12];
+    bool success = decode->translate(buf, 12, bytes_processed, res, 12, bytes_written);
+    // check results
+    CHECK(success == true);
+    CHECK(memcmp(res, "custom-key", 10) == 0);
+    CHECK(bytes_processed == 11);
+    CHECK(bytes_written == 10);
+}
+
+TEST(http2_hpack_string_decode_success, int_is_more_than_1_byte)
+{
+    // prepare buf to decode - length is 2^7
+    uint8_t buf[130];
+    buf[0] = 0x7f;
+    buf[1] = 1;
+    memset(&buf[2], 'A', 128);
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[130];
+    bool success = decode->translate(buf, 130, bytes_processed, res, 130, bytes_written);
+    // check results
+    CHECK(success == true);
+    CHECK(bytes_processed == 130);
+    CHECK(bytes_written == 128);
+    CHECK(memcmp(res, &buf[2], 128) == 0);
+}
+
+TEST(http2_hpack_string_decode_success, empty_string)
+{
+    // prepare buf to decode - length is 0 (empty string)
+    uint8_t buf = 0;
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res = 10; // random value, just to check it wasn't overwritten
+    bool success = decode->translate(&buf, 1, bytes_processed, &res, 1, bytes_written);
+    // check results
+    CHECK(success == true);
+    CHECK(bytes_processed == 1);
+    CHECK(bytes_written == 0);
+    CHECK(res == 10);
+}
+
+TEST(http2_hpack_string_decode_success, string_len_1)
+{
+    // prepare buf to decode - length is 1
+    uint8_t buf[2] = { 1, 'A' };
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res = 0;
+    bool success = decode->translate(buf, 2, bytes_processed, &res, 1, bytes_written);
+    // check results
+    CHECK(success == true);
+    CHECK(bytes_processed == 2);
+    CHECK(bytes_written == 1);
+    CHECK(res == 'A');
+}
+
+TEST(http2_hpack_string_decode_success, max_field_length)
+{
+    // prepare buf to decode - int + string == MAX_OCTETS (Field limitation)
+    uint8_t buf[HttpEnums::MAX_OCTETS];
+    buf[0] = 0x7F;
+    buf[1] = 0xA1;
+    buf[2] = 0xF1;
+    buf[3]= 0x3;
+    memset(&buf[4], 'A', HttpEnums::MAX_OCTETS-4);
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[HttpEnums::MAX_OCTETS];
+    bool success = decode->translate(buf, HttpEnums::MAX_OCTETS, bytes_processed, res,
+        HttpEnums::MAX_OCTETS, bytes_written);
+    // check results
+    CHECK(success == true);
+    CHECK(bytes_processed == HttpEnums::MAX_OCTETS);
+    CHECK(bytes_written == (HttpEnums::MAX_OCTETS-4));
+    CHECK(memcmp(res, &buf[4], bytes_written) == 0);
+}
+
+//
+// The following tests should trigger infractions/events
+//
+TEST_GROUP(http2_hpack_string_decode_infractions)
+{
+};
+
+TEST(http2_hpack_string_decode_infractions, 0_len_field)
+{
+    // prepare decode object
+    Http2EventGen local_events;
+    Http2Infractions local_inf;
+    Http2HpackStringDecode local_decode(&local_events, &local_inf);
+    // prepare buf to decode - use field length 0
+    uint8_t buf = 0;
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res;
+    bool success = local_decode.translate(&buf, 0, bytes_processed, &res, 1, bytes_written);
+    // check results
+    CHECK(success == false);
+    CHECK(bytes_processed == 0);
+    CHECK(bytes_written == 0);
+    CHECK(local_inf.get_raw() == (1<<INF_STRING_EMPTY_BUFF));
+    CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
+}
+
+TEST(http2_hpack_string_decode_infractions, missing_bytes)
+{
+    // prepare decode object
+    Http2EventGen local_events;
+    Http2Infractions local_inf;
+    Http2HpackStringDecode local_decode(&local_events, &local_inf);
+    // prepare buf to decode - length is 1, no string
+    uint8_t buf = 1;
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[2];
+    bool success = local_decode.translate(&buf, 1, bytes_processed, res, 2, bytes_written);
+    // check results
+    CHECK(success == false);
+    CHECK(bytes_written == 0);
+    CHECK(bytes_processed == 1);
+    CHECK(local_inf.get_raw() == (1<<INF_STRING_MISSING_BYTES));
+    CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
+}
+
+TEST(http2_hpack_string_decode_infractions, bad_int)
+{
+    // prepare decode object
+    Http2EventGen local_events;
+    Http2Infractions local_inf;
+    Http2HpackStringDecode local_decode(&local_events, &local_inf);
+    // prepare buf to decode - bad int
+    uint8_t buf[2] = { 0x7f, 0x80 };
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[2];
+    bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written);
+    // check results
+    CHECK(success == false);
+    CHECK(bytes_processed == 2);
+    CHECK(bytes_written == 0);
+    CHECK(local_inf.get_raw() == (1<<INF_INT_MISSING_BYTES));
+    CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
+}
+
+TEST(http2_hpack_string_decode_infractions, max_field_length_plus_1)
+{
+    // prepare decode object
+    Http2EventGen local_events;
+    Http2Infractions local_inf;
+    Http2HpackStringDecode local_decode(&local_events, &local_inf);
+    // prepare buf to decode -  int + string == MAX_OCTETS+1 (Field limitation + 1)
+    uint8_t buf[HttpEnums::MAX_OCTETS];
+    buf[0] = 0x7F;
+    buf[1] = 0xA2;
+    buf[2] = 0xF1;
+    buf[3]= 0x3;
+    memset(&buf[4], 'A', HttpEnums::MAX_OCTETS-4);
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[HttpEnums::MAX_OCTETS];
+    bool success = local_decode.translate(buf, HttpEnums::MAX_OCTETS, bytes_processed, res,
+        HttpEnums::MAX_OCTETS, bytes_written);
+    // check results
+    CHECK(success == false);
+    CHECK(bytes_processed == 4);
+    CHECK(bytes_written == 0);
+    CHECK(local_inf.get_raw() == (1<<INF_STRING_MISSING_BYTES));
+    CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
+}
+
+TEST(http2_hpack_string_decode_infractions, out_buf_out_of_space)
+{
+    // prepare decode object
+    Http2EventGen local_events;
+    Http2Infractions local_inf;
+    Http2HpackStringDecode local_decode(&local_events, &local_inf);
+    // prepare buf to decode 
+    uint8_t buf[HttpEnums::MAX_OCTETS];
+    buf[0] = 0x7F;
+    buf[1] = 0xA1;
+    buf[2] = 0xF1;
+    buf[3]= 0x3;
+    memset(&buf[4], 'A', HttpEnums::MAX_OCTETS-4);
+    // decode
+    uint32_t bytes_processed = 0, bytes_written = 0;
+    uint8_t res[HttpEnums::MAX_OCTETS-5];
+    bool success = local_decode.translate(buf, HttpEnums::MAX_OCTETS, bytes_processed, res,
+        HttpEnums::MAX_OCTETS-5, bytes_written);
+    // check results
+    CHECK(success == false);
+    CHECK(bytes_processed == 4);
+    CHECK(bytes_written == 0);
+    CHECK(local_inf.get_raw() == (1<<INF_OUT_BUFF_OUT_OF_SPACE));
+    CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
+