diff options
| author | Tobias Markmann <tm@ayena.de> | 2015-09-17 08:14:57 (GMT) | 
|---|---|---|
| committer | Swift Review <review@swift.im> | 2015-10-16 10:38:19 (GMT) | 
| commit | 3a2b966711dbe6fa937c485d7ad56916219badb2 (patch) | |
| tree | 30e9f30bc3f2a3ca6b4ed0c5c11f4ae0703485d0 | |
| parent | 582ca915b5b82ada46d1183a7b882455ee01b7b1 (diff) | |
| download | swift-3a2b966711dbe6fa937c485d7ad56916219badb2.zip swift-3a2b966711dbe6fa937c485d7ad56916219badb2.tar.bz2  | |
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
| -rw-r--r-- | Swiften/IDN/LibIDNConverter.cpp | 13 | ||||
| -rw-r--r-- | Swiften/IDN/SConscript | 5 | ||||
| -rw-r--r-- | Swiften/IDN/UTF8Validator.h | 67 | ||||
| -rw-r--r-- | Swiften/IDN/UnitTest/UTF8ValidatorTest.cpp | 54 | 
4 files changed, 135 insertions, 4 deletions
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 <idna.h>  } -#include <vector>  #include <cassert>  #include <cstdlib> +#include <vector> + +#include <boost/shared_ptr.hpp> +  #include <Swiften/Base/ByteArray.h>  #include <Swiften/Base/SafeAllocator.h> -#include <boost/shared_ptr.hpp> +#include <Swiften/IDN/UTF8Validator.h>  using namespace Swift; @@ -37,6 +40,10 @@ namespace {  	template<typename StringType, typename ContainerType>  	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<Stringprep_profile_flags>(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 <cstddef> + +namespace Swift { + +// UTF-8 validation based on the description in https://tools.ietf.org/html/rfc3629#section-3 . +template <typename CharType> +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 <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/IDN/UTF8Validator.h> + +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);  | 
 Swift