summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-09-17 08:14:57 (GMT)
committerSwift Review <review@swift.im>2015-10-16 10:38:19 (GMT)
commit3a2b966711dbe6fa937c485d7ad56916219badb2 (patch)
tree30e9f30bc3f2a3ca6b4ed0c5c11f4ae0703485d0
parent582ca915b5b82ada46d1183a7b882455ee01b7b1 (diff)
downloadswift-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.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,7 +1,7 @@
1/* 1/*
2 * Copyright (c) 2012-2013 Isode Limited. 2 * Copyright (c) 2012-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include <Swiften/IDN/LibIDNConverter.h> 7#include <Swiften/IDN/LibIDNConverter.h>
@@ -9,16 +9,19 @@
9extern "C" { 9extern "C" {
10 #include <stringprep.h> 10 #include <stringprep.h>
11 #include <idna.h> 11 #include <idna.h>
12} 12}
13 13
14#include <vector>
15#include <cassert> 14#include <cassert>
16#include <cstdlib> 15#include <cstdlib>
16#include <vector>
17
18#include <boost/shared_ptr.hpp>
19
17#include <Swiften/Base/ByteArray.h> 20#include <Swiften/Base/ByteArray.h>
18#include <Swiften/Base/SafeAllocator.h> 21#include <Swiften/Base/SafeAllocator.h>
19#include <boost/shared_ptr.hpp> 22#include <Swiften/IDN/UTF8Validator.h>
20 23
21using namespace Swift; 24using namespace Swift;
22 25
23namespace { 26namespace {
24 static const int MAX_STRINGPREP_SIZE = 1024; 27 static const int MAX_STRINGPREP_SIZE = 1024;
@@ -35,10 +38,14 @@ namespace {
35 } 38 }
36 39
37 template<typename StringType, typename ContainerType> 40 template<typename StringType, typename ContainerType>
38 ContainerType getStringPreparedInternal(const StringType& s, IDNConverter::StringPrepProfile profile) { 41 ContainerType getStringPreparedInternal(const StringType& s, IDNConverter::StringPrepProfile profile) {
39 ContainerType input(s.begin(), s.end()); 42 ContainerType input(s.begin(), s.end());
43 if (!UTF8IsValid(s.data(), s.size())) {
44 return ContainerType();
45 }
46
40 input.resize(MAX_STRINGPREP_SIZE); 47 input.resize(MAX_STRINGPREP_SIZE);
41 if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) { 48 if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) {
42 return input; 49 return input;
43 } 50 }
44 else { 51 else {
diff --git a/Swiften/IDN/SConscript b/Swiften/IDN/SConscript
index 4c1a71d..7a3c061 100644
--- a/Swiften/IDN/SConscript
+++ b/Swiften/IDN/SConscript
@@ -12,17 +12,20 @@ if myenv.get("HAVE_ICU") :
12 objects += myenv.SwiftenObject(["ICUConverter.cpp"]) 12 objects += myenv.SwiftenObject(["ICUConverter.cpp"])
13if myenv.get("HAVE_LIBIDN") : 13if myenv.get("HAVE_LIBIDN") :
14 myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) 14 myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"])
15 myenv.Append(CPPDEFINES = ["HAVE_LIBIDN"]) 15 myenv.Append(CPPDEFINES = ["HAVE_LIBIDN"])
16 objects += myenv.SwiftenObject(["LibIDNConverter.cpp"]) 16 objects += myenv.SwiftenObject(["LibIDNConverter.cpp"])
17objects += myenv.SwiftenObject(["PlatformIDNConverter.cpp"]) 17objects += myenv.SwiftenObject([
18 "PlatformIDNConverter.cpp"
19 ])
18 20
19swiften_env.Append(SWIFTEN_OBJECTS = [objects]) 21swiften_env.Append(SWIFTEN_OBJECTS = [objects])
20 22
21if env["TEST"] : 23if env["TEST"] :
22 test_env = myenv.Clone() 24 test_env = myenv.Clone()
23 test_env.UseFlags(swiften_env["CPPUNIT_FLAGS"]) 25 test_env.UseFlags(swiften_env["CPPUNIT_FLAGS"])
24 env.Append(UNITTEST_OBJECTS = test_env.SwiftenObject([ 26 env.Append(UNITTEST_OBJECTS = test_env.SwiftenObject([
25 File("UnitTest/IDNConverterTest.cpp"), 27 File("UnitTest/IDNConverterTest.cpp"),
28 File("UnitTest/UTF8ValidatorTest.cpp")
26 ])) 29 ]))
27 30
28 31
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 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#pragma once
8
9#include <cstddef>
10
11namespace Swift {
12
13// UTF-8 validation based on the description in https://tools.ietf.org/html/rfc3629#section-3 .
14template <typename CharType>
15bool UTF8IsValid(const CharType* data, size_t length) {
16 bool isValid = true;
17 const CharType* current = data;
18 const CharType* end = data + length;
19 while (isValid && (current < end)) {
20 // one byte sequences
21 if ((*current & 0x80) == 0x0) {
22 current++;
23 continue;
24 }
25 // longer byte sequences
26 else {
27 // two byte sequences
28 if ((*current & 0xE0) == 0xC0) {
29 current++;
30 if ( (current < end) && ((*current & 0xC0) == 0x80) ) {
31 current++;
32 continue;
33 }
34 }
35 // three byte sequences
36 else if ((*current & 0xF0) == 0xE0) {
37 current++;
38 if ( ((current + 1) < end) && ((*current & 0xC0) == 0x80) ) {
39 current++;
40 if ((*current & 0xC0) == 0x80) {
41 current++;
42 continue;
43 }
44 }
45 }
46 // four byte sequences
47 else if ((*current & 0xF8) == 0xF0) {
48 current++;
49 if ( ((current + 2) < end) && ((*current & 0xC0) == 0x80) ) {
50 current++;
51 if ((*current & 0xC0) == 0x80) {
52 current++;
53 if ((*current & 0xC0) == 0x80) {
54 current++;
55 continue;
56 }
57 }
58 }
59 }
60 // invalid sequences
61 isValid = false;
62 }
63 }
64 return isValid;
65}
66
67}
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 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#include <cppunit/extensions/HelperMacros.h>
8#include <cppunit/extensions/TestFactoryRegistry.h>
9
10#include <Swiften/IDN/UTF8Validator.h>
11
12using namespace Swift;
13
14class UTF8ValidatorTest : public CppUnit::TestFixture {
15 CPPUNIT_TEST_SUITE(UTF8ValidatorTest);
16
17 CPPUNIT_TEST(testValidUTF8Sequences);
18 CPPUNIT_TEST(testInvalidUTF8Sequences);
19
20 CPPUNIT_TEST_SUITE_END();
21
22public:
23 void testValidUTF8Sequences() {
24 {
25 unsigned char test[] = {0x74, 0x65, 0x73, 0x74};
26 CPPUNIT_ASSERT(UTF8IsValid(test, sizeof(test)));
27 }
28
29 {
30 unsigned char test[] = {0xf4, 0x8f, 0x80, 0xbf};
31 CPPUNIT_ASSERT(UTF8IsValid(test, sizeof(test)));
32 }
33 }
34
35 void testInvalidUTF8Sequences() {
36 {
37 unsigned char test[] = {0x41, 0xC2, 0x3E, 0x42};
38 CPPUNIT_ASSERT(!UTF8IsValid(test, sizeof(test)));
39 }
40
41 {
42 unsigned char test[] = {0xf4};
43 CPPUNIT_ASSERT(!UTF8IsValid(test, sizeof(test)));
44 }
45
46 {
47 unsigned char test[] = {0xf4, 0x8f, 0x65, 0x73, 0x80, 0xbf};
48 CPPUNIT_ASSERT(!UTF8IsValid(test, sizeof(test)));
49 }
50 }
51
52};
53
54CPPUNIT_TEST_SUITE_REGISTRATION(UTF8ValidatorTest);