From 3a2b966711dbe6fa937c485d7ad56916219badb2 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Thu, 17 Sep 2015 10:14:57 +0200 Subject: Add UTF-8 validation function and validate input to libIDN functions This is required to protect against the CVE-2015-2059 vulnerability in libIDN. Test-Information: Added unit tests for UTF-8 validation and tested that existing unit tests still pass. Change-Id: I0a94136894c6e0004081456c59155a78a3dabf5f diff --git a/Swiften/IDN/LibIDNConverter.cpp b/Swiften/IDN/LibIDNConverter.cpp index f36929a..78303b1 100644 --- a/Swiften/IDN/LibIDNConverter.cpp +++ b/Swiften/IDN/LibIDNConverter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Isode Limited. + * Copyright (c) 2012-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,12 +11,15 @@ extern "C" { #include } -#include #include #include +#include + +#include + #include #include -#include +#include using namespace Swift; @@ -37,6 +40,10 @@ namespace { template ContainerType getStringPreparedInternal(const StringType& s, IDNConverter::StringPrepProfile profile) { ContainerType input(s.begin(), s.end()); + if (!UTF8IsValid(s.data(), s.size())) { + return ContainerType(); + } + input.resize(MAX_STRINGPREP_SIZE); if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast(0), getLibIDNProfile(profile)) == 0) { return input; diff --git a/Swiften/IDN/SConscript b/Swiften/IDN/SConscript index 4c1a71d..7a3c061 100644 --- a/Swiften/IDN/SConscript +++ b/Swiften/IDN/SConscript @@ -14,7 +14,9 @@ if myenv.get("HAVE_LIBIDN") : myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) myenv.Append(CPPDEFINES = ["HAVE_LIBIDN"]) objects += myenv.SwiftenObject(["LibIDNConverter.cpp"]) -objects += myenv.SwiftenObject(["PlatformIDNConverter.cpp"]) +objects += myenv.SwiftenObject([ + "PlatformIDNConverter.cpp" + ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) @@ -23,6 +25,7 @@ if env["TEST"] : test_env.UseFlags(swiften_env["CPPUNIT_FLAGS"]) env.Append(UNITTEST_OBJECTS = test_env.SwiftenObject([ File("UnitTest/IDNConverterTest.cpp"), + File("UnitTest/UTF8ValidatorTest.cpp") ])) diff --git a/Swiften/IDN/UTF8Validator.h b/Swiften/IDN/UTF8Validator.h new file mode 100644 index 0000000..5df8769 --- /dev/null +++ b/Swiften/IDN/UTF8Validator.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include + +namespace Swift { + +// UTF-8 validation based on the description in https://tools.ietf.org/html/rfc3629#section-3 . +template +bool UTF8IsValid(const CharType* data, size_t length) { + bool isValid = true; + const CharType* current = data; + const CharType* end = data + length; + while (isValid && (current < end)) { + // one byte sequences + if ((*current & 0x80) == 0x0) { + current++; + continue; + } + // longer byte sequences + else { + // two byte sequences + if ((*current & 0xE0) == 0xC0) { + current++; + if ( (current < end) && ((*current & 0xC0) == 0x80) ) { + current++; + continue; + } + } + // three byte sequences + else if ((*current & 0xF0) == 0xE0) { + current++; + if ( ((current + 1) < end) && ((*current & 0xC0) == 0x80) ) { + current++; + if ((*current & 0xC0) == 0x80) { + current++; + continue; + } + } + } + // four byte sequences + else if ((*current & 0xF8) == 0xF0) { + current++; + if ( ((current + 2) < end) && ((*current & 0xC0) == 0x80) ) { + current++; + if ((*current & 0xC0) == 0x80) { + current++; + if ((*current & 0xC0) == 0x80) { + current++; + continue; + } + } + } + } + // invalid sequences + isValid = false; + } + } + return isValid; +} + +} diff --git a/Swiften/IDN/UnitTest/UTF8ValidatorTest.cpp b/Swiften/IDN/UnitTest/UTF8ValidatorTest.cpp new file mode 100644 index 0000000..0295757 --- /dev/null +++ b/Swiften/IDN/UnitTest/UTF8ValidatorTest.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include +#include + +#include + +using namespace Swift; + +class UTF8ValidatorTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(UTF8ValidatorTest); + + CPPUNIT_TEST(testValidUTF8Sequences); + CPPUNIT_TEST(testInvalidUTF8Sequences); + + CPPUNIT_TEST_SUITE_END(); + +public: + void testValidUTF8Sequences() { + { + unsigned char test[] = {0x74, 0x65, 0x73, 0x74}; + CPPUNIT_ASSERT(UTF8IsValid(test, sizeof(test))); + } + + { + unsigned char test[] = {0xf4, 0x8f, 0x80, 0xbf}; + CPPUNIT_ASSERT(UTF8IsValid(test, sizeof(test))); + } + } + + void testInvalidUTF8Sequences() { + { + unsigned char test[] = {0x41, 0xC2, 0x3E, 0x42}; + CPPUNIT_ASSERT(!UTF8IsValid(test, sizeof(test))); + } + + { + unsigned char test[] = {0xf4}; + CPPUNIT_ASSERT(!UTF8IsValid(test, sizeof(test))); + } + + { + unsigned char test[] = {0xf4, 0x8f, 0x65, 0x73, 0x80, 0xbf}; + CPPUNIT_ASSERT(!UTF8IsValid(test, sizeof(test))); + } + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(UTF8ValidatorTest); -- cgit v0.10.2-6-g49f6