summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/subversion/subversion-1.8.9
diff options
context:
space:
mode:
authorYue Tao <Yue.Tao@windriver.com>2014-10-22 03:37:28 -0400
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-11-21 16:49:37 +0000
commit09430c66b3757fb9fd7e9fd2ebd5a87bafb983c2 (patch)
tree22c7ba9eea05e3c97916f386d37eef496daadca3 /meta/recipes-devtools/subversion/subversion-1.8.9
parent929d04b40416d1695c5df0f55c1d6000e24bb245 (diff)
downloadpoky-09430c66b3757fb9fd7e9fd2ebd5a87bafb983c2.tar.gz
subversion: Security Advisory - subversion - CVE-2014-3522
The Serf RA layer in Apache Subversion 1.4.0 through 1.7.x before 1.7.18 and 1.8.x before 1.8.10 does not properly handle wildcards in the Common Name (CN) or subjectAltName field of the X.509 certificate, which allows man-in-the-middle attackers to spoof servers via a crafted certificate.<a href=http://cwe.mitre.org/data/definitions/297.html target=_blank>CWE-297: Improper Validation of Certificate with Host Mismatch</a> http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3522 (From OE-Core rev: 06a33cd00ea11abec1ebe9d5883e44778075ccc6) (From OE-Core rev: 529ce75be949944a6e54151cd4233703e40c6351) Signed-off-by: Yue Tao <Yue.Tao@windriver.com> Signed-off-by: Jackie Huang <jackie.huang@windriver.com> Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> Signed-off-by: Armin Kuster <akuster808@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-devtools/subversion/subversion-1.8.9')
-rw-r--r--meta/recipes-devtools/subversion/subversion-1.8.9/subversion-CVE-2014-3522.patch444
1 files changed, 444 insertions, 0 deletions
diff --git a/meta/recipes-devtools/subversion/subversion-1.8.9/subversion-CVE-2014-3522.patch b/meta/recipes-devtools/subversion/subversion-1.8.9/subversion-CVE-2014-3522.patch
new file mode 100644
index 0000000000..f259e5490a
--- /dev/null
+++ b/meta/recipes-devtools/subversion/subversion-1.8.9/subversion-CVE-2014-3522.patch
@@ -0,0 +1,444 @@
1Upstream-Status: Backport
2
3Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
4
5Index: subversion/include/private/svn_cert.h
6===================================================================
7--- subversion/include/private/svn_cert.h (nonexistent)
8+++ subversion/include/private/svn_cert.h (working copy)
9@@ -0,0 +1,68 @@
10+/**
11+ * @copyright
12+ * ====================================================================
13+ * Licensed to the Apache Software Foundation (ASF) under one
14+ * or more contributor license agreements. See the NOTICE file
15+ * distributed with this work for additional information
16+ * regarding copyright ownership. The ASF licenses this file
17+ * to you under the Apache License, Version 2.0 (the
18+ * "License"); you may not use this file except in compliance
19+ * with the License. You may obtain a copy of the License at
20+ *
21+ * http://www.apache.org/licenses/LICENSE-2.0
22+ *
23+ * Unless required by applicable law or agreed to in writing,
24+ * software distributed under the License is distributed on an
25+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
26+ * KIND, either express or implied. See the License for the
27+ * specific language governing permissions and limitations
28+ * under the License.
29+ * ====================================================================
30+ * @endcopyright
31+ *
32+ * @file svn_cert.h
33+ * @brief Implementation of certificate validation functions
34+ */
35+
36+#ifndef SVN_CERT_H
37+#define SVN_CERT_H
38+
39+#include <apr.h>
40+
41+#include "svn_types.h"
42+#include "svn_string.h"
43+
44+#ifdef __cplusplus
45+extern "C" {
46+#endif /* __cplusplus */
47+
48+
49+/* Return TRUE iff @a pattern matches @a hostname as defined
50+ * by the matching rules of RFC 6125. In the context of RFC
51+ * 6125 the pattern is the domain name portion of the presented
52+ * identifier (which comes from the Common Name or a DNSName
53+ * portion of the subjectAltName of an X.509 certificate) and
54+ * the hostname is the source domain (i.e. the host portion
55+ * of the URI the user entered).
56+ *
57+ * @note With respect to wildcards we only support matching
58+ * wildcards in the left-most label and as the only character
59+ * in the left-most label (i.e. we support RFC 6125 s. 6.4.3
60+ * Rule 1 and 2 but not the optional Rule 3). This may change
61+ * in the future.
62+ *
63+ * @note Subversion does not at current support internationalized
64+ * domain names. Both values are presumed to be in NR-LDH label
65+ * or A-label form (see RFC 5890 for the definition).
66+ *
67+ * @since New in 1.9.
68+ */
69+svn_boolean_t
70+svn_cert__match_dns_identity(svn_string_t *pattern, svn_string_t *hostname);
71+
72+
73+#ifdef __cplusplus
74+}
75+#endif /* __cplusplus */
76+
77+#endif /* SVN_CERT_H */
78Index: subversion/libsvn_ra_serf/util.c
79===================================================================
80--- subversion/libsvn_ra_serf/util.c (revision 1615128)
81+++ subversion/libsvn_ra_serf/util.c (working copy)
82@@ -28,7 +28,6 @@
83 #define APR_WANT_STRFUNC
84 #include <apr.h>
85 #include <apr_want.h>
86-#include <apr_fnmatch.h>
87
88 #include <serf.h>
89 #include <serf_bucket_types.h>
90@@ -49,6 +48,7 @@
91 #include "private/svn_fspath.h"
92 #include "private/svn_subr_private.h"
93 #include "private/svn_auth_private.h"
94+#include "private/svn_cert.h"
95
96 #include "ra_serf.h"
97
98@@ -274,7 +274,6 @@ ssl_server_cert(void *baton, int failures,
99 apr_hash_t *subject = NULL;
100 apr_hash_t *serf_cert = NULL;
101 void *creds;
102- int found_matching_hostname = 0;
103
104 svn_failures = (ssl_convert_serf_failures(failures)
105 | conn->server_cert_failures);
106@@ -286,26 +285,37 @@ ssl_server_cert(void *baton, int failures,
107 ### This should really be handled by serf, which should pass an error
108 for this case, but that has backwards compatibility issues. */
109 apr_array_header_t *san;
110+ svn_boolean_t found_san_entry = FALSE;
111+ svn_boolean_t found_matching_hostname = FALSE;
112+ svn_string_t *actual_hostname =
113+ svn_string_create(conn->session->session_url.hostname, scratch_pool);
114
115 serf_cert = serf_ssl_cert_certificate(cert, scratch_pool);
116
117 san = svn_hash_gets(serf_cert, "subjectAltName");
118 /* Try to find matching server name via subjectAltName first... */
119- if (san) {
120+ if (san)
121+ {
122 int i;
123- for (i = 0; i < san->nelts; i++) {
124+ found_san_entry = san->nelts > 0;
125+ for (i = 0; i < san->nelts; i++)
126+ {
127 const char *s = APR_ARRAY_IDX(san, i, const char*);
128- if (apr_fnmatch(s, conn->session->session_url.hostname,
129- APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
130- {
131- found_matching_hostname = 1;
132+ svn_string_t *cert_hostname = svn_string_create(s, scratch_pool);
133+
134+ if (svn_cert__match_dns_identity(cert_hostname, actual_hostname))
135+ {
136+ found_matching_hostname = TRUE;
137 break;
138- }
139- }
140- }
141+ }
142+ }
143+ }
144
145- /* Match server certificate CN with the hostname of the server */
146- if (!found_matching_hostname)
147+ /* Match server certificate CN with the hostname of the server iff
148+ * we didn't find any subjectAltName fields and try to match them.
149+ * Per RFC 2818 they are authoritative if present and CommonName
150+ * should be ignored. */
151+ if (!found_matching_hostname && !found_san_entry)
152 {
153 const char *hostname = NULL;
154
155@@ -314,13 +324,20 @@ ssl_server_cert(void *baton, int failures,
156 if (subject)
157 hostname = svn_hash_gets(subject, "CN");
158
159- if (!hostname
160- || apr_fnmatch(hostname, conn->session->session_url.hostname,
161- APR_FNM_PERIOD | APR_FNM_CASE_BLIND) != APR_SUCCESS)
162- {
163- svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
164- }
165- }
166+ if (hostname)
167+ {
168+ svn_string_t *cert_hostname = svn_string_create(hostname,
169+ scratch_pool);
170+
171+ if (svn_cert__match_dns_identity(cert_hostname, actual_hostname))
172+ {
173+ found_matching_hostname = TRUE;
174+ }
175+ }
176+ }
177+
178+ if (!found_matching_hostname)
179+ svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
180 }
181
182 if (!svn_failures)
183Index: subversion/libsvn_subr/dirent_uri.c
184===================================================================
185--- subversion/libsvn_subr/dirent_uri.c (revision 1615128)
186+++ subversion/libsvn_subr/dirent_uri.c (working copy)
187@@ -38,6 +38,7 @@
188
189 #include "dirent_uri.h"
190 #include "private/svn_fspath.h"
191+#include "private/svn_cert.h"
192
193 /* The canonical empty path. Can this be changed? Well, change the empty
194 test below and the path library will work, not so sure about the fs/wc
195@@ -2597,3 +2598,81 @@ svn_urlpath__canonicalize(const char *uri,
196 }
197 return uri;
198 }
199+
200+
201+/* -------------- The cert API (see private/svn_cert.h) ------------- */
202+
203+svn_boolean_t
204+svn_cert__match_dns_identity(svn_string_t *pattern, svn_string_t *hostname)
205+{
206+ apr_size_t pattern_pos = 0, hostname_pos = 0;
207+
208+ /* support leading wildcards that composed of the only character in the
209+ * left-most label. */
210+ if (pattern->len >= 2 &&
211+ pattern->data[pattern_pos] == '*' &&
212+ pattern->data[pattern_pos + 1] == '.')
213+ {
214+ while (hostname_pos < hostname->len &&
215+ hostname->data[hostname_pos] != '.')
216+ {
217+ hostname_pos++;
218+ }
219+ /* Assume that the wildcard must match something. Rule 2 says
220+ * that *.example.com should not match example.com. If the wildcard
221+ * ends up not matching anything then it matches .example.com which
222+ * seems to be essentially the same as just example.com */
223+ if (hostname_pos == 0)
224+ return FALSE;
225+
226+ pattern_pos++;
227+ }
228+
229+ while (pattern_pos < pattern->len && hostname_pos < hostname->len)
230+ {
231+ char pattern_c = pattern->data[pattern_pos];
232+ char hostname_c = hostname->data[hostname_pos];
233+
234+ /* fold case as described in RFC 4343.
235+ * Note: We actually convert to lowercase, since our URI
236+ * canonicalization code converts to lowercase and generally
237+ * most certs are issued with lowercase DNS names, meaning
238+ * this avoids the fold operation in most cases. The RFC
239+ * suggests the opposite transformation, but doesn't require
240+ * any specific implementation in any case. It is critical
241+ * that this folding be locale independent so you can't use
242+ * tolower(). */
243+ pattern_c = canonicalize_to_lower(pattern_c);
244+ hostname_c = canonicalize_to_lower(hostname_c);
245+
246+ if (pattern_c != hostname_c)
247+ {
248+ /* doesn't match */
249+ return FALSE;
250+ }
251+ else
252+ {
253+ /* characters match so skip both */
254+ pattern_pos++;
255+ hostname_pos++;
256+ }
257+ }
258+
259+ /* ignore a trailing period on the hostname since this has no effect on the
260+ * security of the matching. See the following for the long explanation as
261+ * to why:
262+ * https://bugzilla.mozilla.org/show_bug.cgi?id=134402#c28
263+ */
264+ if (pattern_pos == pattern->len &&
265+ hostname_pos == hostname->len - 1 &&
266+ hostname->data[hostname_pos] == '.')
267+ hostname_pos++;
268+
269+ if (pattern_pos != pattern->len || hostname_pos != hostname->len)
270+ {
271+ /* end didn't match */
272+ return FALSE;
273+ }
274+
275+ return TRUE;
276+}
277Index: subversion/tests/libsvn_subr/dirent_uri-test.c
278===================================================================
279--- subversion/tests/libsvn_subr/dirent_uri-test.c (revision 1615128)
280+++ subversion/tests/libsvn_subr/dirent_uri-test.c (working copy)
281@@ -37,6 +37,7 @@
282 #include "svn_pools.h"
283 #include "svn_dirent_uri.h"
284 #include "private/svn_fspath.h"
285+#include "private/svn_cert.h"
286
287 #include "../svn_test.h"
288
289@@ -2714,6 +2715,145 @@ test_fspath_get_longest_ancestor(apr_pool_t *pool)
290 return SVN_NO_ERROR;
291 }
292
293+struct cert_match_dns_test {
294+ const char *pattern;
295+ const char *hostname;
296+ svn_boolean_t expected;
297+};
298+
299+static svn_error_t *
300+run_cert_match_dns_tests(struct cert_match_dns_test *tests, apr_pool_t *pool)
301+{
302+ struct cert_match_dns_test *ct;
303+ apr_pool_t *iterpool = svn_pool_create(pool);
304+
305+ for (ct = tests; ct->pattern; ct++)
306+ {
307+ svn_boolean_t result;
308+ svn_string_t *pattern, *hostname;
309+
310+ svn_pool_clear(iterpool);
311+
312+ pattern = svn_string_create(ct->pattern, iterpool);
313+ hostname = svn_string_create(ct->hostname, iterpool);
314+
315+ result = svn_cert__match_dns_identity(pattern, hostname);
316+ if (result != ct->expected)
317+ return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
318+ "Expected %s but got %s for pattern '%s' on "
319+ "hostname '%s'",
320+ ct->expected ? "match" : "no match",
321+ result ? "match" : "no match",
322+ pattern->data, hostname->data);
323+
324+ }
325+
326+ svn_pool_destroy(iterpool);
327+
328+ return SVN_NO_ERROR;
329+}
330+
331+static struct cert_match_dns_test cert_match_dns_tests[] = {
332+ { "foo.example.com", "foo.example.com", TRUE }, /* exact match */
333+ { "foo.example.com", "FOO.EXAMPLE.COM", TRUE }, /* case differences */
334+ { "FOO.EXAMPLE.COM", "foo.example.com", TRUE },
335+ { "*.example.com", "FoO.ExAmPlE.CoM", TRUE },
336+ { "*.ExAmPlE.CoM", "foo.example.com", TRUE },
337+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", TRUE },
338+ { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", TRUE },
339+ { "foo.example.com", "bar.example.com", FALSE }, /* difference at start */
340+ { "foo.example.com", "foo.example.net", FALSE }, /* difference at end */
341+ { "foo.example.com", "foo.example.commercial", FALSE }, /* hostname longer */
342+ { "foo.example.commercial", "foo.example.com", FALSE }, /* pattern longer */
343+ { "foo.example.comcom", "foo.example.com", FALSE }, /* repeated suffix */
344+ { "foo.example.com", "foo.example.comcom", FALSE },
345+ { "foo.example.com.com", "foo.example.com", FALSE },
346+ { "foo.example.com", "foo.example.com.com", FALSE },
347+ { "foofoo.example.com", "foo.example.com", FALSE }, /* repeated prefix */
348+ { "foo.example.com", "foofoo.example.com", FALSE },
349+ { "foo.foo.example.com", "foo.example.com", FALSE },
350+ { "foo.example.com", "foo.foo.example.com", FALSE },
351+ { "foo.*.example.com", "foo.bar.example.com", FALSE }, /* RFC 6125 s. 6.4.3
352+ Rule 1 */
353+ { "*.example.com", "foo.example.com", TRUE }, /* RFC 6125 s. 6.4.3 Rule 2 */
354+ { "*.example.com", "bar.foo.example.com", FALSE }, /* Rule 2 */
355+ { "*.example.com", "example.com", FALSE }, /* Rule 2 */
356+ { "*.example.com", ".example.com", FALSE }, /* RFC doesn't say what to do
357+ here and a leading period on
358+ a hostname doesn't make sense
359+ so we'll just reject this. */
360+ { "*", "foo.example.com", FALSE }, /* wildcard must be left-most label,
361+ implies that there must be more than
362+ one label. */
363+ { "*", "example.com", FALSE },
364+ { "*", "com", FALSE },
365+ { "*.example.com", "foo.example.net", FALSE }, /* difference in literal text
366+ with a wildcard. */
367+ { "*.com", "example.com", TRUE }, /* See Errata ID 3090 for RFC 6125,
368+ probably shouldn't allow this but
369+ we do for now. */
370+ { "*.", "example.com", FALSE }, /* test some dubious 2 character wildcard
371+ patterns */
372+ { "*.", "example.", TRUE }, /* This one feels questionable */
373+ { "*.", "example", FALSE },
374+ { "*.", ".", FALSE },
375+ { "a", "a", TRUE }, /* check that single letter exact matches work */
376+ { "a", "b", FALSE }, /* and single letter not matches shouldn't */
377+ { "*.*.com", "foo.example.com", FALSE }, /* unsupported wildcards */
378+ { "*.*.com", "example.com", FALSE },
379+ { "**.example.com", "foo.example.com", FALSE },
380+ { "**.example.com", "example.com", FALSE },
381+ { "f*.example.com", "foo.example.com", FALSE },
382+ { "f*.example.com", "bar.example.com", FALSE },
383+ { "*o.example.com", "foo.example.com", FALSE },
384+ { "*o.example.com", "bar.example.com", FALSE },
385+ { "f*o.example.com", "foo.example.com", FALSE },
386+ { "f*o.example.com", "bar.example.com", FALSE },
387+ { "foo.e*.com", "foo.example.com", FALSE },
388+ { "foo.*e.com", "foo.example.com", FALSE },
389+ { "foo.e*e.com", "foo.example.com", FALSE },
390+ { "foo.example.com", "foo.example.com.", TRUE }, /* trailing dot */
391+ { "*.example.com", "foo.example.com.", TRUE },
392+ { "foo", "foo.", TRUE },
393+ { "foo.example.com.", "foo.example.com", FALSE },
394+ { "*.example.com.", "foo.example.com", FALSE },
395+ { "foo.", "foo", FALSE },
396+ { "foo.example.com", "foo.example.com..", FALSE },
397+ { "*.example.com", "foo.example.com..", FALSE },
398+ { "foo", "foo..", FALSE },
399+ { "foo.example.com..", "foo.example.com", FALSE },
400+ { "*.example.com..", "foo.example.com", FALSE },
401+ { "foo..", "foo", FALSE },
402+ { NULL }
403+};
404+
405+static svn_error_t *
406+test_cert_match_dns_identity(apr_pool_t *pool)
407+{
408+ return run_cert_match_dns_tests(cert_match_dns_tests, pool);
409+}
410+
411+/* This test table implements results that should happen if we supported
412+ * RFC 6125 s. 6.4.3 Rule 3. We don't so it's expected to fail for now. */
413+static struct cert_match_dns_test rule3_tests[] = {
414+ { "baz*.example.net", "baz1.example.net", TRUE },
415+ { "*baz.example.net", "foobaz.example.net", TRUE },
416+ { "b*z.example.net", "buuz.example.net", TRUE },
417+ { "b*z.example.net", "bz.example.net", FALSE }, /* presume wildcard can't
418+ match nothing */
419+ { "baz*.example.net", "baz.example.net", FALSE },
420+ { "*baz.example.net", "baz.example.net", FALSE },
421+ { "b*z.example.net", "buuzuuz.example.net", TRUE }, /* presume wildcard
422+ should be greedy */
423+ { NULL }
424+};
425+
426+static svn_error_t *
427+test_rule3(apr_pool_t *pool)
428+{
429+ return run_cert_match_dns_tests(rule3_tests, pool);
430+}
431+
432
433 /* The test table. */
434
435@@ -2812,5 +2952,9 @@ struct svn_test_descriptor_t test_funcs[] =
436 "test svn_fspath__dirname/basename/split"),
437 SVN_TEST_PASS2(test_fspath_get_longest_ancestor,
438 "test svn_fspath__get_longest_ancestor"),
439+ SVN_TEST_PASS2(test_cert_match_dns_identity,
440+ "test svn_cert__match_dns_identity"),
441+ SVN_TEST_XFAIL2(test_rule3,
442+ "test match with RFC 6125 s. 6.4.3 Rule 3"),
443 SVN_TEST_NULL
444 };