[SCM] tomcat6 packaging branch, master, updated. debian/6.0.35-5-1-gd118a22

tony mancill tmancill at debian.org
Mon Nov 26 01:49:11 UTC 2012


The following commit has been merged in the master branch:
commit d118a22ff304bcb8d80e9ec0658c86bb3905fd89
Author: Michael Gilbert <mgilbert at debian.org>
Date:   Sat Nov 17 23:15:03 2012 +0000

    Imported Debian patch 6.0.35-5+nmu1

diff --git a/debian/changelog b/debian/changelog
index 9a42388..7510660 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+tomcat6 (6.0.35-5+nmu1) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * Fix multiple security issues (closes: #692440)
+    - cve-2012-2733: denial-of-service by triggering out of memory error.
+    - cve-2012-3439: multiple replay attack issues in digest authentication. 
+
+ -- Michael Gilbert <mgilbert at debian.org>  Sat, 17 Nov 2012 23:15:03 +0000
+
 tomcat6 (6.0.35-5) unstable; urgency=low
 
   * Apply patch to README.Debian to explain setting the HTTPOnly flag
diff --git a/debian/patches/cve-2012-2733.patch b/debian/patches/cve-2012-2733.patch
new file mode 100644
index 0000000..8172ccb
--- /dev/null
+++ b/debian/patches/cve-2012-2733.patch
@@ -0,0 +1,31 @@
+--- trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java	2012/07/02 12:47:54	1356207
++++ trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java	2012/07/02 13:01:28	1356208
+@@ -673,10 +673,6 @@
+         
+         do {
+             status = parseHeader();
+-        } while ( status == HeaderParseStatus.HAVE_MORE_HEADERS );
+-        if (status == HeaderParseStatus.DONE) {
+-            parsingHeader = false;
+-            end = pos;
+             // Checking that
+             // (1) Headers plus request line size does not exceed its limit
+             // (2) There are enough bytes to avoid expanding the buffer when
+@@ -685,11 +681,15 @@
+             // limitation to enforce the meaning of headerBufferSize
+             // From the way how buf is allocated and how blank lines are being
+             // read, it should be enough to check (1) only.
+-            if (end - skipBlankLinesBytes > headerBufferSize
+-                    || buf.length - end < socketReadBufferSize) {
++            if (pos - skipBlankLinesBytes > headerBufferSize
++                    || buf.length - pos < socketReadBufferSize) {
+                 throw new IllegalArgumentException(
+                         sm.getString("iib.requestheadertoolarge.error"));
+             }
++        } while ( status == HeaderParseStatus.HAVE_MORE_HEADERS );
++        if (status == HeaderParseStatus.DONE) {
++            parsingHeader = false;
++            end = pos;
+             return true;
+         } else {
+             return false;
diff --git a/debian/patches/cve-2012-3439.patch b/debian/patches/cve-2012-3439.patch
new file mode 100644
index 0000000..630ecee
--- /dev/null
+++ b/debian/patches/cve-2012-3439.patch
@@ -0,0 +1,362 @@
+--- trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java	2012/09/04 19:47:42	1380828
++++ trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java	2012/09/04 19:48:27	1380829
+@@ -27,9 +27,9 @@
+ import java.util.Map;
+ import java.util.StringTokenizer;
+ 
++import javax.servlet.http.HttpServletRequest;
+ import javax.servlet.http.HttpServletResponse;
+ 
+-
+ import org.apache.catalina.LifecycleException;
+ import org.apache.catalina.Realm;
+ import org.apache.catalina.connector.Request;
+@@ -80,6 +80,7 @@
+ 
+     public DigestAuthenticator() {
+         super();
++        setCache(false);
+         try {
+             if (md5Helper == null)
+                 md5Helper = MessageDigest.getInstance("MD5");
+@@ -100,16 +101,16 @@
+ 
+ 
+     /**
+-     * List of client nonce values currently being tracked
++     * List of server nonce values currently being tracked
+      */
+-    protected Map<String,NonceInfo> cnonces;
++    protected Map<String,NonceInfo> nonces;
+ 
+ 
+     /**
+-     * Maximum number of client nonces to keep in the cache. If not specified,
++     * Maximum number of server nonces to keep in the cache. If not specified,
+      * the default value of 1000 is used.
+      */
+-    protected int cnonceCacheSize = 1000;
++    protected int nonceCacheSize = 1000;
+ 
+ 
+     /**
+@@ -150,13 +151,13 @@
+     }
+ 
+ 
+-    public int getCnonceCacheSize() {
+-        return cnonceCacheSize;
++    public int getNonceCacheSize() {
++        return nonceCacheSize;
+     }
+ 
+ 
+-    public void setCnonceCacheSize(int cnonceCacheSize) {
+-        this.cnonceCacheSize = cnonceCacheSize;
++    public void setNonceCacheSize(int nonceCacheSize) {
++        this.nonceCacheSize = nonceCacheSize;
+     }
+ 
+ 
+@@ -263,18 +264,19 @@
+         // Validate any credentials already included with this request
+         String authorization = request.getHeader("authorization");
+         DigestInfo digestInfo = new DigestInfo(getOpaque(), getNonceValidity(),
+-                getKey(), cnonces, isValidateUri());
++                getKey(), nonces, isValidateUri());
+         if (authorization != null) {
+-            if (digestInfo.validate(request, authorization, config)) {
+-                principal = digestInfo.authenticate(context.getRealm());
+-            }
++            if (digestInfo.parse(request, authorization)) {
++                if (digestInfo.validate(request, config)) {
++                    principal = digestInfo.authenticate(context.getRealm());
++                }
+             
+-            if (principal != null) {
+-                String username = parseUsername(authorization);
+-                register(request, response, principal,
+-                         Constants.DIGEST_METHOD,
+-                         username, null);
+-                return (true);
++                if (principal != null && !digestInfo.isNonceStale()) {
++                    register(request, response, principal,
++                            HttpServletRequest.DIGEST_AUTH,
++                            digestInfo.getUsername(), null);
++                    return true;
++                }
+             }
+         }
+ 
+@@ -285,10 +287,9 @@
+         String nonce = generateNonce(request);
+ 
+         setAuthenticateHeader(request, response, config, nonce,
+-                digestInfo.isNonceStale());
++                principal != null && digestInfo.isNonceStale());
+         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+-        //      hres.flushBuffer();
+-        return (false);
++        return false;
+ 
+     }
+ 
+@@ -301,7 +302,10 @@
+      * can be identified, return <code>null</code>
+      *
+      * @param authorization Authorization string to be parsed
++     *
++     * @deprecated  Unused. Will be removed in Tomcat 8.0.x
+      */
++    @Deprecated
+     protected String parseUsername(String authorization) {
+ 
+         // Validate the authorization credentials format
+@@ -345,7 +349,7 @@
+         } else if (quotedString.length() > 2) {
+             return quotedString.substring(1, quotedString.length() - 1);
+         } else {
+-            return new String();
++            return "";
+         }
+     }
+ 
+@@ -376,7 +380,14 @@
+             buffer = md5Helper.digest(ipTimeKey.getBytes());
+         }
+ 
+-        return currentTime + ":" + md5Encoder.encode(buffer);
++        String nonce = currentTime + ":" + md5Encoder.encode(buffer);
++
++        NonceInfo info = new NonceInfo(currentTime, 100);
++        synchronized (nonces) {
++            nonces.put(nonce, info);
++        }
++
++        return nonce;
+     }
+ 
+ 
+@@ -450,7 +461,7 @@
+             setOpaque(generateSessionId());
+         }
+         
+-        cnonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
++        nonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
+ 
+             private static final long serialVersionUID = 1L;
+             private static final long LOG_SUPPRESS_TIME = 5 * 60 * 1000;
+@@ -462,7 +473,7 @@
+                     Map.Entry<String,NonceInfo> eldest) {
+                 // This is called from a sync so keep it simple
+                 long currentTime = System.currentTimeMillis();
+-                if (size() > getCnonceCacheSize()) {
++                if (size() > getNonceCacheSize()) {
+                     if (lastLog < currentTime &&
+                             currentTime - eldest.getValue().getTimestamp() <
+                             getNonceValidity()) {
+@@ -480,10 +491,10 @@
+  
+     private static class DigestInfo {
+ 
+-        private String opaque;
+-        private long nonceValidity;
+-        private String key;
+-        private Map<String,NonceInfo> cnonces;
++        private final String opaque;
++        private final long nonceValidity;
++        private final String key;
++        private final Map<String,NonceInfo> nonces;
+         private boolean validateUri = true;
+ 
+         private String userName = null;
+@@ -495,21 +506,27 @@
+         private String cnonce = null;
+         private String realmName = null;
+         private String qop = null;
++        private String opaqueReceived = null;
+ 
+         private boolean nonceStale = false;
+ 
+ 
+         public DigestInfo(String opaque, long nonceValidity, String key,
+-                Map<String,NonceInfo> cnonces, boolean validateUri) {
++                Map<String,NonceInfo> nonces, boolean validateUri) {
+             this.opaque = opaque;
+             this.nonceValidity = nonceValidity;
+             this.key = key;
+-            this.cnonces = cnonces;
++            this.nonces = nonces;
+             this.validateUri = validateUri;
+         }
+ 
+-        public boolean validate(Request request, String authorization,
+-                LoginConfig config) {
++
++        public String getUsername() {
++            return userName;
++        }
++
++
++        public boolean parse(Request request, String authorization) {
+             // Validate the authorization credentials format
+             if (authorization == null) {
+                 return false;
+@@ -523,7 +540,6 @@
+             String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
+ 
+             method = request.getMethod();
+-            String opaque = null;
+ 
+             for (int i = 0; i < tokens.length; i++) {
+                 String currentToken = tokens[i];
+@@ -555,9 +571,13 @@
+                 if ("response".equals(currentTokenName))
+                     response = removeQuotes(currentTokenValue);
+                 if ("opaque".equals(currentTokenName))
+-                    opaque = removeQuotes(currentTokenValue);
++                    opaqueReceived = removeQuotes(currentTokenValue);
+             }
+ 
++            return true;
++        }
++
++        public boolean validate(Request request, LoginConfig config) {
+             if ( (userName == null) || (realmName == null) || (nonce == null)
+                  || (uri == null) || (response == null) ) {
+                 return false;
+@@ -573,7 +593,23 @@
+                     uriQuery = request.getRequestURI() + "?" + query;
+                 }
+                 if (!uri.equals(uriQuery)) {
+-                    return false;
++                    // Some clients (older Android) use an absolute URI for
++                    // DIGEST but a relative URI in the request line.
++                    // request. 2.3.5 < fixed Android version <= 4.0.3
++                    String host = request.getHeader("host");
++                    String scheme = request.getScheme();
++                    if (host != null && !uriQuery.startsWith(scheme)) {
++                        StringBuilder absolute = new StringBuilder();
++                        absolute.append(scheme);
++                        absolute.append("://");
++                        absolute.append(host);
++                        absolute.append(uriQuery);
++                        if (!uri.equals(absolute.toString())) {
++                            return false;
++                        }
++                    } else {
++                        return false;
++                    }
+                 }
+             }
+ 
+@@ -587,7 +623,7 @@
+             }
+             
+             // Validate the opaque string
+-            if (!this.opaque.equals(opaque)) {
++            if (!opaque.equals(opaqueReceived)) {
+                 return false;
+             }
+ 
+@@ -606,7 +642,9 @@
+             long currentTime = System.currentTimeMillis();
+             if ((currentTime - nonceTime) > nonceValidity) {
+                 nonceStale = true;
+-                return false;
++                synchronized (nonces) {
++                    nonces.remove(nonce);
++                }
+             }
+             String serverIpTimeKey =
+                 request.getRemoteAddr() + ":" + nonceTime + ":" + key;
+@@ -625,7 +663,7 @@
+             }
+ 
+             // Validate cnonce and nc
+-            // Check if presence of nc and nonce is consistent with presence of qop
++            // Check if presence of nc and Cnonce is consistent with presence of qop
+             if (qop == null) {
+                 if (cnonce != null || nc != null) {
+                     return false;
+@@ -634,7 +672,9 @@
+                 if (cnonce == null || nc == null) {
+                     return false;
+                 }
+-                if (nc.length() != 8) {
++                // RFC 2617 says nc must be 8 digits long. Older Android clients
++                // use 6. 2.3.5 < fixed Android version <= 4.0.3
++                if (nc.length() < 6 || nc.length() > 8) {
+                     return false;
+                 }
+                 long count;
+@@ -644,21 +684,18 @@
+                     return false;
+                 }
+                 NonceInfo info;
+-                synchronized (cnonces) {
+-                    info = cnonces.get(cnonce);
++                synchronized (nonces) {
++                    info = nonces.get(nonce);
+                 }
+                 if (info == null) {
+-                    info = new NonceInfo();
++                    // Nonce is valid but not in cache. It must have dropped out
++                    // of the cache - force a re-authentication
++                    nonceStale = true;
+                 } else {
+-                    if (count <= info.getCount()) {
++                    if (!info.nonceCountValid(count)) {
+                         return false;
+                     }
+                 }
+-                info.setCount(count);
+-                info.setTimestamp(currentTime);
+-                synchronized (cnonces) {
+-                    cnonces.put(cnonce, info);
+-                }
+             }
+             return true;
+         }
+@@ -685,19 +722,31 @@
+     }
+ 
+     private static class NonceInfo {
+-        private volatile long count;
+         private volatile long timestamp;
+-        
+-        public void setCount(long l) {
+-            count = l;
++        private volatile boolean seen[];
++        private volatile int offset;
++        private volatile int count = 0;
++
++        public NonceInfo(long currentTime, int seenWindowSize) {
++            this.timestamp = currentTime;
++            seen = new boolean[seenWindowSize];
++            offset = seenWindowSize / 2;
+         }
+         
+-        public long getCount() {
+-            return count;
+-        }
+-        
+-        public void setTimestamp(long l) {
+-            timestamp = l;
++        public synchronized boolean nonceCountValid(long nonceCount) {
++            if ((count - offset) >= nonceCount ||
++                    (nonceCount > count - offset + seen.length)) {
++                return false;
++            }
++            int checkIndex = (int) ((nonceCount + offset) % seen.length);
++            if (seen[checkIndex]) {
++                return false;
++            } else {
++                seen[checkIndex] = true;
++                seen[count % seen.length] = false;
++                count++;
++                return true;
++            }
+         }
+         
+         public long getTimestamp() {
diff --git a/debian/patches/series b/debian/patches/series
index 7f918c6..fd7d743 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -8,3 +8,5 @@
 0008-add-OSGI-headers-to-jsp-api.patch
 0010-Use-java.security.policy-file-in-catalina.sh.patch
 0011-CVE-2012-0022-regression-fix.patch
+cve-2012-2733.patch
+cve-2012-3439.patch

-- 
tomcat6 packaging



More information about the pkg-java-commits mailing list