]>
Commit | Line | Data |
---|---|---|
0545caaa | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 The Squid Software Foundation and contributors |
0545caaa AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
f7f3304a | 9 | #include "squid.h" |
22aa015b | 10 | #include "testRFC1738.h" |
7f861c77 | 11 | #include "unitTestMain.h" |
1fa9b1a7 | 12 | |
074d6a40 | 13 | #include <cassert> |
1fa9b1a7 | 14 | |
1fa9b1a7 AJ |
15 | /* Being a C library code it is best bodily included and tested with C++ type-safe techniques. */ |
16 | #include "lib/rfc1738.c" | |
17 | ||
18 | CPPUNIT_TEST_SUITE_REGISTRATION( testRFC1738 ); | |
19 | ||
20 | /* Regular Format de-coding tests */ | |
21 | void testRFC1738::testUrlDecode() | |
22 | { | |
23 | char *unescaped_str; | |
24 | ||
25 | /* regular URL-path */ | |
26 | unescaped_str = xstrdup("%2Fdata%2Fsource%2Fpath"); | |
27 | rfc1738_unescape(unescaped_str); | |
28 | CPPUNIT_ASSERT(memcmp(unescaped_str, "/data/source/path",18)==0); | |
29 | xfree(unescaped_str); | |
30 | ||
31 | /* path in full URL */ | |
32 | unescaped_str = xstrdup("http://foo.invalid%2Fdata%2Fsource%2Fpath"); | |
33 | rfc1738_unescape(unescaped_str); | |
34 | CPPUNIT_ASSERT(memcmp(unescaped_str, "http://foo.invalid/data/source/path",36)==0); | |
35 | xfree(unescaped_str); | |
36 | ||
37 | // TODO query string... | |
38 | ||
39 | /* Newline %0A encoded */ | |
40 | unescaped_str = xstrdup("w%0Ard"); | |
41 | rfc1738_unescape(unescaped_str); | |
42 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w\nrd",5)==0); | |
43 | xfree(unescaped_str); | |
44 | ||
45 | /* Handle Un-encoded % */ | |
46 | unescaped_str = xstrdup("w%rd"); | |
47 | rfc1738_unescape(unescaped_str); | |
48 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%rd",5)==0); | |
49 | xfree(unescaped_str); | |
50 | ||
51 | /* Handle encoded % */ | |
52 | unescaped_str = xstrdup("w%%rd"); | |
53 | rfc1738_unescape(unescaped_str); | |
b40aeba5 | 54 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%rd",5)==0); |
1fa9b1a7 AJ |
55 | xfree(unescaped_str); |
56 | ||
57 | /* Handle mixed-encoded % */ | |
58 | unescaped_str = xstrdup("w%%%rd"); | |
59 | rfc1738_unescape(unescaped_str); | |
60 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%%rd",6)==0); | |
61 | xfree(unescaped_str); | |
62 | ||
63 | /* A corrupt string */ | |
64 | unescaped_str = xstrdup("Bad String %1"); | |
65 | rfc1738_unescape(unescaped_str); | |
66 | CPPUNIT_ASSERT(memcmp(unescaped_str, "Bad String %1",14)==0); | |
67 | xfree(unescaped_str); | |
68 | ||
1fa9b1a7 AJ |
69 | /* A partly corrupt string */ |
70 | unescaped_str = xstrdup("Bad String %1A%3"); | |
71 | rfc1738_unescape(unescaped_str); | |
72 | CPPUNIT_ASSERT(memcmp(unescaped_str, "Bad String \032%3",15)==0); | |
73 | xfree(unescaped_str); | |
74 | ||
75 | /* A non corrupt string */ | |
76 | unescaped_str = xstrdup("Good String %1A"); | |
77 | rfc1738_unescape(unescaped_str); | |
78 | CPPUNIT_ASSERT(memcmp(unescaped_str, "Good String \032",14)==0); | |
79 | xfree(unescaped_str); | |
80 | } | |
81 | ||
82 | /** | |
83 | * Public API is formed of a triplet of encode functions mapping to the rfc1738_do_encode() engine. | |
84 | * | |
85 | * Flags: | |
86 | * rfc1738_escape == 0 | |
87 | * rfc1738_escape_unescaped == -1 | |
88 | * rfc1738_escape_part == 1 | |
89 | */ | |
90 | void testRFC1738::testUrlEncode() | |
91 | { | |
92 | char *result; | |
93 | ||
1fa9b1a7 AJ |
94 | /* TEST: Escaping only unsafe characters */ |
95 | ||
96 | /* regular URL (no encoding needed) */ | |
97 | result = rfc1738_do_escape("http://foo.invalid/data/source/path", RFC1738_ESCAPE_UNSAFE); | |
98 | CPPUNIT_ASSERT(memcmp(result, "http://foo.invalid/data/source/path",36)==0); | |
99 | ||
100 | /* long string of unsafe # characters */ | |
101 | result = rfc1738_do_escape("################ ################ ################ ################ ################ ################ ################ ################", RFC1738_ESCAPE_UNSAFE); | |
102 | CPPUNIT_ASSERT(memcmp(result, "%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23",406)==0); | |
103 | ||
1fa9b1a7 AJ |
104 | /* TEST: escaping only reserved characters */ |
105 | ||
106 | /* regular URL (full encoding requested) */ | |
107 | result = rfc1738_do_escape("http://foo.invalid/data/source/path", RFC1738_ESCAPE_RESERVED); | |
108 | CPPUNIT_ASSERT(memcmp(result, "http%3A%2F%2Ffoo.invalid%2Fdata%2Fsource%2Fpath",48)==0); | |
109 | ||
110 | /* regular path (encoding wanted for ALL special chars) */ | |
111 | result = rfc1738_do_escape("/data/source/path", RFC1738_ESCAPE_RESERVED); | |
112 | CPPUNIT_ASSERT(memcmp(result, "%2Fdata%2Fsource%2Fpath",24)==0); | |
113 | ||
1fa9b1a7 AJ |
114 | /* TEST: safety-escaping a string already partially escaped */ |
115 | ||
116 | /* escaping of dangerous characters in a partially escaped string */ | |
117 | result = rfc1738_do_escape("http://foo.invalid/data%2Fsource[]", RFC1738_ESCAPE_UNESCAPED); | |
118 | CPPUNIT_ASSERT(memcmp(result, "http://foo.invalid/data%2Fsource%5B%5D",39)==0); | |
119 | ||
120 | /* escaping of hexadecimal 0xFF characters in a partially escaped string */ | |
121 | result = rfc1738_do_escape("http://foo.invalid/data%2Fsource\xFF\xFF", RFC1738_ESCAPE_UNESCAPED); | |
122 | CPPUNIT_ASSERT(memcmp(result, "http://foo.invalid/data%2Fsource%FF%FF",39)==0); | |
123 | ||
124 | } | |
125 | ||
126 | /** SECURITY BUG TESTS: avoid null truncation attacks by skipping %00 bytes */ | |
127 | void testRFC1738::PercentZeroNullDecoding() | |
128 | { | |
129 | char *unescaped_str; | |
130 | ||
131 | /* Attack with %00 encoded NULL */ | |
132 | unescaped_str = xstrdup("w%00rd"); | |
133 | rfc1738_unescape(unescaped_str); | |
134 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%00rd",7)==0); | |
135 | xfree(unescaped_str); | |
136 | ||
137 | /* Attack with %0 encoded NULL */ | |
138 | unescaped_str = xstrdup("w%0rd"); | |
139 | rfc1738_unescape(unescaped_str); | |
140 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%0rd",6)==0); | |
141 | xfree(unescaped_str); | |
142 | ||
143 | /* Handle '0' bytes embeded in encoded % */ | |
144 | unescaped_str = xstrdup("w%%00%rd"); | |
145 | rfc1738_unescape(unescaped_str); | |
146 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%00%rd",8)==0); | |
147 | xfree(unescaped_str); | |
148 | ||
149 | /* Handle NULL bytes with encoded % */ | |
150 | unescaped_str = xstrdup("w%%%00%rd"); | |
151 | rfc1738_unescape(unescaped_str); | |
152 | CPPUNIT_ASSERT(memcmp(unescaped_str, "w%%00%rd",9)==0); | |
153 | xfree(unescaped_str); | |
154 | } | |
f53969cc | 155 |