~ubuntu-branches/ubuntu/vivid/tomcat6/vivid-proposed

« back to all changes in this revision

Viewing changes to debian/patches/cve-2012-3439.patch

  • Committer: Package Import Robot
  • Author(s): tony mancill
  • Date: 2013-08-03 21:50:20 UTC
  • mfrom: (1.2.9)
  • Revision ID: package-import@ubuntu.com-20130803215020-glb1brkoau0zxr5x
Tags: 6.0.37-1
* New upstream release.
  - Drop patches for CVE-2012-4534, CVE-2012-4431, CVE-2012-3546,
    CVE-2012-2733, CVE-2012-3439
  - Drop 0011-CVE-02012-0022-regression-fix.patch
  - Drop 0017-eclipse-compiler-update.patch
* Freshened remaining patches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
--- trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java       2012/09/04 19:47:42     1380828
2
 
+++ trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java       2012/09/04 19:48:27     1380829
3
 
@@ -27,9 +27,9 @@
4
 
 import java.util.Map;
5
 
 import java.util.StringTokenizer;
6
 
 
7
 
+import javax.servlet.http.HttpServletRequest;
8
 
 import javax.servlet.http.HttpServletResponse;
9
 
 
10
 
-
11
 
 import org.apache.catalina.LifecycleException;
12
 
 import org.apache.catalina.Realm;
13
 
 import org.apache.catalina.connector.Request;
14
 
@@ -80,6 +80,7 @@
15
 
 
16
 
     public DigestAuthenticator() {
17
 
         super();
18
 
+        setCache(false);
19
 
         try {
20
 
             if (md5Helper == null)
21
 
                 md5Helper = MessageDigest.getInstance("MD5");
22
 
@@ -100,16 +101,16 @@
23
 
 
24
 
 
25
 
     /**
26
 
-     * List of client nonce values currently being tracked
27
 
+     * List of server nonce values currently being tracked
28
 
      */
29
 
-    protected Map<String,NonceInfo> cnonces;
30
 
+    protected Map<String,NonceInfo> nonces;
31
 
 
32
 
 
33
 
     /**
34
 
-     * Maximum number of client nonces to keep in the cache. If not specified,
35
 
+     * Maximum number of server nonces to keep in the cache. If not specified,
36
 
      * the default value of 1000 is used.
37
 
      */
38
 
-    protected int cnonceCacheSize = 1000;
39
 
+    protected int nonceCacheSize = 1000;
40
 
 
41
 
 
42
 
     /**
43
 
@@ -150,13 +151,13 @@
44
 
     }
45
 
 
46
 
 
47
 
-    public int getCnonceCacheSize() {
48
 
-        return cnonceCacheSize;
49
 
+    public int getNonceCacheSize() {
50
 
+        return nonceCacheSize;
51
 
     }
52
 
 
53
 
 
54
 
-    public void setCnonceCacheSize(int cnonceCacheSize) {
55
 
-        this.cnonceCacheSize = cnonceCacheSize;
56
 
+    public void setNonceCacheSize(int nonceCacheSize) {
57
 
+        this.nonceCacheSize = nonceCacheSize;
58
 
     }
59
 
 
60
 
 
61
 
@@ -263,18 +264,19 @@
62
 
         // Validate any credentials already included with this request
63
 
         String authorization = request.getHeader("authorization");
64
 
         DigestInfo digestInfo = new DigestInfo(getOpaque(), getNonceValidity(),
65
 
-                getKey(), cnonces, isValidateUri());
66
 
+                getKey(), nonces, isValidateUri());
67
 
         if (authorization != null) {
68
 
-            if (digestInfo.validate(request, authorization, config)) {
69
 
-                principal = digestInfo.authenticate(context.getRealm());
70
 
-            }
71
 
+            if (digestInfo.parse(request, authorization)) {
72
 
+                if (digestInfo.validate(request, config)) {
73
 
+                    principal = digestInfo.authenticate(context.getRealm());
74
 
+                }
75
 
             
76
 
-            if (principal != null) {
77
 
-                String username = parseUsername(authorization);
78
 
-                register(request, response, principal,
79
 
-                         Constants.DIGEST_METHOD,
80
 
-                         username, null);
81
 
-                return (true);
82
 
+                if (principal != null && !digestInfo.isNonceStale()) {
83
 
+                    register(request, response, principal,
84
 
+                            HttpServletRequest.DIGEST_AUTH,
85
 
+                            digestInfo.getUsername(), null);
86
 
+                    return true;
87
 
+                }
88
 
             }
89
 
         }
90
 
 
91
 
@@ -285,10 +287,9 @@
92
 
         String nonce = generateNonce(request);
93
 
 
94
 
         setAuthenticateHeader(request, response, config, nonce,
95
 
-                digestInfo.isNonceStale());
96
 
+                principal != null && digestInfo.isNonceStale());
97
 
         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
98
 
-        //      hres.flushBuffer();
99
 
-        return (false);
100
 
+        return false;
101
 
 
102
 
     }
103
 
 
104
 
@@ -301,7 +302,10 @@
105
 
      * can be identified, return <code>null</code>
106
 
      *
107
 
      * @param authorization Authorization string to be parsed
108
 
+     *
109
 
+     * @deprecated  Unused. Will be removed in Tomcat 8.0.x
110
 
      */
111
 
+    @Deprecated
112
 
     protected String parseUsername(String authorization) {
113
 
 
114
 
         // Validate the authorization credentials format
115
 
@@ -345,7 +349,7 @@
116
 
         } else if (quotedString.length() > 2) {
117
 
             return quotedString.substring(1, quotedString.length() - 1);
118
 
         } else {
119
 
-            return new String();
120
 
+            return "";
121
 
         }
122
 
     }
123
 
 
124
 
@@ -376,7 +380,14 @@
125
 
             buffer = md5Helper.digest(ipTimeKey.getBytes());
126
 
         }
127
 
 
128
 
-        return currentTime + ":" + md5Encoder.encode(buffer);
129
 
+        String nonce = currentTime + ":" + md5Encoder.encode(buffer);
130
 
+
131
 
+        NonceInfo info = new NonceInfo(currentTime, 100);
132
 
+        synchronized (nonces) {
133
 
+            nonces.put(nonce, info);
134
 
+        }
135
 
+
136
 
+        return nonce;
137
 
     }
138
 
 
139
 
 
140
 
@@ -450,7 +461,7 @@
141
 
             setOpaque(generateSessionId());
142
 
         }
143
 
         
144
 
-        cnonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
145
 
+        nonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
146
 
 
147
 
             private static final long serialVersionUID = 1L;
148
 
             private static final long LOG_SUPPRESS_TIME = 5 * 60 * 1000;
149
 
@@ -462,7 +473,7 @@
150
 
                     Map.Entry<String,NonceInfo> eldest) {
151
 
                 // This is called from a sync so keep it simple
152
 
                 long currentTime = System.currentTimeMillis();
153
 
-                if (size() > getCnonceCacheSize()) {
154
 
+                if (size() > getNonceCacheSize()) {
155
 
                     if (lastLog < currentTime &&
156
 
                             currentTime - eldest.getValue().getTimestamp() <
157
 
                             getNonceValidity()) {
158
 
@@ -480,10 +491,10 @@
159
 
  
160
 
     private static class DigestInfo {
161
 
 
162
 
-        private String opaque;
163
 
-        private long nonceValidity;
164
 
-        private String key;
165
 
-        private Map<String,NonceInfo> cnonces;
166
 
+        private final String opaque;
167
 
+        private final long nonceValidity;
168
 
+        private final String key;
169
 
+        private final Map<String,NonceInfo> nonces;
170
 
         private boolean validateUri = true;
171
 
 
172
 
         private String userName = null;
173
 
@@ -495,21 +506,27 @@
174
 
         private String cnonce = null;
175
 
         private String realmName = null;
176
 
         private String qop = null;
177
 
+        private String opaqueReceived = null;
178
 
 
179
 
         private boolean nonceStale = false;
180
 
 
181
 
 
182
 
         public DigestInfo(String opaque, long nonceValidity, String key,
183
 
-                Map<String,NonceInfo> cnonces, boolean validateUri) {
184
 
+                Map<String,NonceInfo> nonces, boolean validateUri) {
185
 
             this.opaque = opaque;
186
 
             this.nonceValidity = nonceValidity;
187
 
             this.key = key;
188
 
-            this.cnonces = cnonces;
189
 
+            this.nonces = nonces;
190
 
             this.validateUri = validateUri;
191
 
         }
192
 
 
193
 
-        public boolean validate(Request request, String authorization,
194
 
-                LoginConfig config) {
195
 
+
196
 
+        public String getUsername() {
197
 
+            return userName;
198
 
+        }
199
 
+
200
 
+
201
 
+        public boolean parse(Request request, String authorization) {
202
 
             // Validate the authorization credentials format
203
 
             if (authorization == null) {
204
 
                 return false;
205
 
@@ -523,7 +540,6 @@
206
 
             String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
207
 
 
208
 
             method = request.getMethod();
209
 
-            String opaque = null;
210
 
 
211
 
             for (int i = 0; i < tokens.length; i++) {
212
 
                 String currentToken = tokens[i];
213
 
@@ -555,9 +571,13 @@
214
 
                 if ("response".equals(currentTokenName))
215
 
                     response = removeQuotes(currentTokenValue);
216
 
                 if ("opaque".equals(currentTokenName))
217
 
-                    opaque = removeQuotes(currentTokenValue);
218
 
+                    opaqueReceived = removeQuotes(currentTokenValue);
219
 
             }
220
 
 
221
 
+            return true;
222
 
+        }
223
 
+
224
 
+        public boolean validate(Request request, LoginConfig config) {
225
 
             if ( (userName == null) || (realmName == null) || (nonce == null)
226
 
                  || (uri == null) || (response == null) ) {
227
 
                 return false;
228
 
@@ -573,7 +593,23 @@
229
 
                     uriQuery = request.getRequestURI() + "?" + query;
230
 
                 }
231
 
                 if (!uri.equals(uriQuery)) {
232
 
-                    return false;
233
 
+                    // Some clients (older Android) use an absolute URI for
234
 
+                    // DIGEST but a relative URI in the request line.
235
 
+                    // request. 2.3.5 < fixed Android version <= 4.0.3
236
 
+                    String host = request.getHeader("host");
237
 
+                    String scheme = request.getScheme();
238
 
+                    if (host != null && !uriQuery.startsWith(scheme)) {
239
 
+                        StringBuilder absolute = new StringBuilder();
240
 
+                        absolute.append(scheme);
241
 
+                        absolute.append("://");
242
 
+                        absolute.append(host);
243
 
+                        absolute.append(uriQuery);
244
 
+                        if (!uri.equals(absolute.toString())) {
245
 
+                            return false;
246
 
+                        }
247
 
+                    } else {
248
 
+                        return false;
249
 
+                    }
250
 
                 }
251
 
             }
252
 
 
253
 
@@ -587,7 +623,7 @@
254
 
             }
255
 
             
256
 
             // Validate the opaque string
257
 
-            if (!this.opaque.equals(opaque)) {
258
 
+            if (!opaque.equals(opaqueReceived)) {
259
 
                 return false;
260
 
             }
261
 
 
262
 
@@ -606,7 +642,9 @@
263
 
             long currentTime = System.currentTimeMillis();
264
 
             if ((currentTime - nonceTime) > nonceValidity) {
265
 
                 nonceStale = true;
266
 
-                return false;
267
 
+                synchronized (nonces) {
268
 
+                    nonces.remove(nonce);
269
 
+                }
270
 
             }
271
 
             String serverIpTimeKey =
272
 
                 request.getRemoteAddr() + ":" + nonceTime + ":" + key;
273
 
@@ -625,7 +663,7 @@
274
 
             }
275
 
 
276
 
             // Validate cnonce and nc
277
 
-            // Check if presence of nc and nonce is consistent with presence of qop
278
 
+            // Check if presence of nc and Cnonce is consistent with presence of qop
279
 
             if (qop == null) {
280
 
                 if (cnonce != null || nc != null) {
281
 
                     return false;
282
 
@@ -634,7 +672,9 @@
283
 
                 if (cnonce == null || nc == null) {
284
 
                     return false;
285
 
                 }
286
 
-                if (nc.length() != 8) {
287
 
+                // RFC 2617 says nc must be 8 digits long. Older Android clients
288
 
+                // use 6. 2.3.5 < fixed Android version <= 4.0.3
289
 
+                if (nc.length() < 6 || nc.length() > 8) {
290
 
                     return false;
291
 
                 }
292
 
                 long count;
293
 
@@ -644,21 +684,18 @@
294
 
                     return false;
295
 
                 }
296
 
                 NonceInfo info;
297
 
-                synchronized (cnonces) {
298
 
-                    info = cnonces.get(cnonce);
299
 
+                synchronized (nonces) {
300
 
+                    info = nonces.get(nonce);
301
 
                 }
302
 
                 if (info == null) {
303
 
-                    info = new NonceInfo();
304
 
+                    // Nonce is valid but not in cache. It must have dropped out
305
 
+                    // of the cache - force a re-authentication
306
 
+                    nonceStale = true;
307
 
                 } else {
308
 
-                    if (count <= info.getCount()) {
309
 
+                    if (!info.nonceCountValid(count)) {
310
 
                         return false;
311
 
                     }
312
 
                 }
313
 
-                info.setCount(count);
314
 
-                info.setTimestamp(currentTime);
315
 
-                synchronized (cnonces) {
316
 
-                    cnonces.put(cnonce, info);
317
 
-                }
318
 
             }
319
 
             return true;
320
 
         }
321
 
@@ -685,19 +722,31 @@
322
 
     }
323
 
 
324
 
     private static class NonceInfo {
325
 
-        private volatile long count;
326
 
         private volatile long timestamp;
327
 
-        
328
 
-        public void setCount(long l) {
329
 
-            count = l;
330
 
+        private volatile boolean seen[];
331
 
+        private volatile int offset;
332
 
+        private volatile int count = 0;
333
 
+
334
 
+        public NonceInfo(long currentTime, int seenWindowSize) {
335
 
+            this.timestamp = currentTime;
336
 
+            seen = new boolean[seenWindowSize];
337
 
+            offset = seenWindowSize / 2;
338
 
         }
339
 
         
340
 
-        public long getCount() {
341
 
-            return count;
342
 
-        }
343
 
-        
344
 
-        public void setTimestamp(long l) {
345
 
-            timestamp = l;
346
 
+        public synchronized boolean nonceCountValid(long nonceCount) {
347
 
+            if ((count - offset) >= nonceCount ||
348
 
+                    (nonceCount > count - offset + seen.length)) {
349
 
+                return false;
350
 
+            }
351
 
+            int checkIndex = (int) ((nonceCount + offset) % seen.length);
352
 
+            if (seen[checkIndex]) {
353
 
+                return false;
354
 
+            } else {
355
 
+                seen[checkIndex] = true;
356
 
+                seen[count % seen.length] = false;
357
 
+                count++;
358
 
+                return true;
359
 
+            }
360
 
         }
361
 
         
362
 
         public long getTimestamp() {