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
EVENT__NONE = -1,
EVENT_INT_DECODE_FAILURE = 1,
EVENT_INT_LEADING_ZEROS = 2,
+ EVENT_STRING_DECODE_FAILURE = 3,
EVENT__MAX_VALUE
};
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
};
// 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"
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)
{
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)
// 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"
{
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;
--- /dev/null
+//--------------------------------------------------------------------------
+// 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; }
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
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 }
};
../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
)
// 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>
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;
}
};
-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);
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);
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);
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);
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);
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);
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);
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);
{
return CommandLineTestRunner::RunAllTests(argc, argv);
}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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);
+}
+