summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/IDN/LibIDNConverter.cpp13
-rw-r--r--Swiften/IDN/SConscript5
-rw-r--r--Swiften/IDN/UTF8Validator.h67
-rw-r--r--Swiften/IDN/UnitTest/UTF8ValidatorTest.cpp54
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);