static uint32_t search_for_pres_ctx( MmsTracker& mms, const uint8_t* data, unsigned len, uint32_t idx )
{
- // define some constants for search windows
- constexpr uint32_t fully_encoded_data_window = 3;
- constexpr uint32_t pres_ctx_window = 3;
- constexpr uint32_t max_depth_idx = fully_encoded_data_window + pres_ctx_window;
-
- // try to determine if the ACSE layer exists
- // len reduction is to allow space for the forward looking checks
- bool ctx_likely = false;
- for ( uint32_t init_byte = idx; ( init_byte < len - max_depth_idx ) && !ctx_likely; init_byte++)
+ assert( data );
+
+ // Maximum length bytes to skip before resetting pattern search
+ constexpr uint32_t MAX_SKIP_BYTES = 2;
+
+ enum
{
- // require the user-data fully encoded data tag ( | 61 | )
- if ( data[init_byte] != 0x61 )
- {
- continue;
- }
+ USER_DATA_TAG = 0x61,
+ ENCODED_DATA_TAG = 0x30,
+ PRES_CTX_TAG = 0x02,
+ PRES_CTX_LEN = 0x01,
+ };
- // make sure there is still enough space left in the buffer for the forward search
- // allow up to two bytes for the fully encoded data field
- if ( !verify_search_depth_idx( len, init_byte, max_depth_idx ) )
+ while ( idx < len )
+ {
+ switch ( mms.state )
{
- // not enough data to process
- assert( !ctx_likely );
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG:
+ if ( data[idx] == USER_DATA_TAG )
+ {
+ mms.state = MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN;
+ mms.state_remain = 0;
+ }
break;
- }
- for ( uint32_t encode_tag_shift = 1; ( encode_tag_shift < fully_encoded_data_window ) && !ctx_likely; encode_tag_shift++ )
- {
- uint32_t encode_tag_byte = init_byte + encode_tag_shift;
- // look for the ' fully encoded data ' user data tag ( | 30 | );
- if ( data[encode_tag_byte] != 0x30 )
+ case MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN:
+ if ( data[idx] == ENCODED_DATA_TAG )
+ {
+ mms.state = MMS_STATE__OSI_PRES_CTX_SKIP_ENCODED_DATA_LEN;
+ mms.state_remain = 0;
+ }
+ else if ( data[idx] == USER_DATA_TAG )
{
- continue;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN;
+ mms.state_remain = 0;
}
+ else if ( ++mms.state_remain > MAX_SKIP_BYTES )
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ break;
- for ( uint32_t pres_ctx_shift = 1; ( pres_ctx_shift < + pres_ctx_window ) && !ctx_likely; pres_ctx_shift++ )
+ case MMS_STATE__OSI_PRES_CTX_SKIP_ENCODED_DATA_LEN:
+ if ( data[idx] == PRES_CTX_TAG )
{
- // look for the presentation context tag and length ( | 02 01 | )
- bool ctx_b1 = data[encode_tag_byte + pres_ctx_shift] == 0x02;
- bool ctx_b2 = data[encode_tag_byte + pres_ctx_shift + 1] == 0x01;
- if ( ctx_b1 && ctx_b2 )
- {
- switch ( data[encode_tag_byte + pres_ctx_shift + 2] )
- {
- // set the state accordingly when the OSI ACSE presentation context ( | 01 | ) has been found
- case PresCtx::PRES_CTX_ACSE:
- {
- // place the index at the last byte of the presentation context
- idx = init_byte + encode_tag_shift + pres_ctx_shift + 2;
- mms.state = MMS_STATE__OSI_ACSE;
- ctx_likely = true;
- break;
- }
- // set the state accordingly when the MMS presentation context ( | 03 | ) has been found
- case PresCtx::PRES_CTX_MMS:
- {
- // place the index at the last byte of the presentation context
- idx = init_byte + encode_tag_shift + pres_ctx_shift + 2;
- mms.state = MMS_STATE__MMS;
- ctx_likely = true;
- break;
- }
- // no default as we want to keep looking if an acceptable context is not found
- }
- }
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_LEN;
+ mms.state_remain = 0;
+ }
+ else if ( data[idx] == USER_DATA_TAG )
+ {
+ mms.state = MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN;
+ mms.state_remain = 0;
}
+ else if ( ++mms.state_remain > MAX_SKIP_BYTES )
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ break;
+
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_TAG:
+ if ( data[idx] == PRES_CTX_TAG )
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_LEN;
+ else
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ break;
+
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_LEN:
+ if ( data[idx] == PRES_CTX_LEN )
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_CONTEXT;
+ else
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ break;
+
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_CONTEXT:
+ switch ( data[idx] )
+ {
+ case PresCtx::PRES_CTX_ACSE:
+ mms.state = MMS_STATE__OSI_ACSE;
+ return idx;
+
+ case PresCtx::PRES_CTX_MMS:
+ mms.state = MMS_STATE__MMS;
+ return idx;
+
+ default:
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ break;
+ }
+ break;
+
+ default:
+ assert( false );
+ break;
}
+
+ idx++;
}
+
return idx;
}
// process the User Data Presentation type
case MMS_STATE__OSI_PRES_USER_DATA:
{
- idx = search_for_pres_ctx(mms, data, len, idx);
- break;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ // Avoid processing current byte twice
+ continue;
}
break;
}
- //
+ // Initialize presentation context search
case MMS_STATE__OSI_PRES_CP_CPA_USER_DATA_ACSE_LOCATE:
+ {
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ continue;
+ }
+
+ // Presentation context search states
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG: // fallthrough intentional
+ case MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN: // fallthrough intentional
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_ENCODED_DATA_TAG: // fallthrough intentional
+ case MMS_STATE__OSI_PRES_CTX_SKIP_ENCODED_DATA_LEN: // fallthrough intentional
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_TAG: // fallthrough intentional
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_LEN: // fallthrough intentional
+ case MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_CONTEXT:
{
idx = search_for_pres_ctx(mms, data, len, idx);
break;
CHECK(result3 == 1);
}
+TEST_CASE("search_for_pres_ctx: complete pattern found", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 4);
+}
+
+TEST_CASE("search_for_pres_ctx: ACSE context found", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02, 0x01, 0x01 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_ACSE));
+ CHECK(result == 4);
+}
+
+TEST_CASE("search_for_pres_ctx: small payload no pattern", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0xFF };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: small payload partial match", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: buffer without 0x61 byte", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: buffer boundary protection", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_LEN));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: pattern with offset", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0xFF, 0xAA, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 6);
+}
+
+TEST_CASE("search_for_pres_ctx: wrong encoded data tag resets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0xFF, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 6);
+}
+
+TEST_CASE("search_for_pres_ctx: wrong pres_ctx tag resets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0xFF, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 7);
+}
+
+TEST_CASE("search_for_pres_ctx: wrong length resets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02, 0xFF, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 8);
+}
+
+TEST_CASE("search_for_pres_ctx: unknown context value resets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02, 0x01, 0xFF, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 9);
+}
+
+TEST_CASE("search_for_pres_ctx: single byte at buffer end", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0xFF, 0xAA, 0x61 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: empty buffer", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[1] = { };
+ unsigned len = 0;
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == 0);
+}
+
+TEST_CASE("search_for_pres_ctx: resume from skip_user_data_len state", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 3);
+}
+
+TEST_CASE("search_for_pres_ctx: resume with wrong byte resets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0xFF, 0xFF, 0xFF, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 7);
+}
+
+TEST_CASE("search_for_pres_ctx: pattern at exact buffer end", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 4);
+}
+
+TEST_CASE("search_for_pres_ctx: multiple false starts", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0xFF, 0x61, 0x30, 0xFF, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 9);
+}
+
+TEST_CASE("search_for_pres_ctx: fragmented across packets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data1[] = { 0x61, 0x30 };
+ uint32_t result1 = search_for_pres_ctx(mms, data1, sizeof(data1), 0);
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SKIP_ENCODED_DATA_LEN));
+ CHECK(result1 == sizeof(data1));
+
+ uint8_t data2[] = { 0x02, 0x01 };
+ uint32_t result2 = search_for_pres_ctx(mms, data2, sizeof(data2), 0);
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_CONTEXT));
+ CHECK(result2 == sizeof(data2));
+
+ uint8_t data3[] = { 0x03 };
+ uint32_t result3 = search_for_pres_ctx(mms, data3, sizeof(data3), 0);
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result3 == 0);
+}
+
+TEST_CASE("search_for_pres_ctx: OOB protection with partial match", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0x02, 0x01 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_CONTEXT));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: ASN.1 with length bytes", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x14, 0x30, 0x12, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 6);
+}
+
+TEST_CASE("search_for_pres_ctx: max skip bytes boundary exactly 2 bytes", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0xFF, 0xAA, 0xBB, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: skip encoded data len exceeds max skip bytes", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x30, 0xFF, 0xAA, 0xBB, 0x61, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 9);
+}
+
+TEST_CASE("search_for_pres_ctx: fragmented in length field", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data1[] = { 0x61, 0x14 };
+ uint32_t result1 = search_for_pres_ctx(mms, data1, sizeof(data1), 0);
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SKIP_USER_DATA_LEN));
+ CHECK(result1 == sizeof(data1));
+
+ uint8_t data2[] = { 0x30, 0x12, 0x02, 0x01 };
+ uint32_t result2 = search_for_pres_ctx(mms, data2, sizeof(data2), 0);
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_CONTEXT));
+ CHECK(result2 == sizeof(data2));
+
+ uint8_t data3[] = { 0x03 };
+ uint32_t result3 = search_for_pres_ctx(mms, data3, sizeof(data3), 0);
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result3 == 0);
+}
+
+TEST_CASE("search_for_pres_ctx: 2-byte ASN.1 length encoding", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x82, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 5);
+}
+
+TEST_CASE("search_for_pres_ctx: state_remain resets correctly", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0x14, 0x30, 0x12, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__MMS));
+ CHECK(result == 6);
+}
+
+TEST_CASE("search_for_pres_ctx: exactly at max skip bytes then tag found", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x61, 0xFF, 0xAA, 0xBB, 0x30, 0x02, 0x01, 0x03 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: OOB read protection small payload", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x62, 0x63 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: resume from pres_ctx state", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0x02 };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_LEN));
+ CHECK(result == len);
+}
+
+TEST_CASE("search_for_pres_ctx: resume from pres_ctx wrong tag resets", "[mms][pres_ctx]")
+{
+ MmsTracker mms;
+ mms.state = MMS_STATE__OSI_PRES_CTX_SEARCH_PRES_CTX_TAG;
+ mms.state_remain = 0;
+
+ uint8_t data[] = { 0xFF };
+ unsigned len = sizeof(data);
+ uint32_t idx = 0;
+
+ uint32_t result = search_for_pres_ctx(mms, data, len, idx);
+
+ CHECK((mms.state == MMS_STATE__OSI_PRES_CTX_SEARCH_USER_DATA_TAG));
+ CHECK(result == len);
+}
+
#endif