[tomcat6/f16] CVE-2011-1138 rhbz 741407

Dave Knox dknox at fedoraproject.org
Wed Oct 19 19:27:21 UTC 2011


commit ad676423ffbc5a5f9ebf15aa6ab8aebfb507ce9e
Author: David Knox <dknox at dknox-laptop.(none)>
Date:   Wed Oct 19 13:27:49 2011 -0600

    CVE-2011-1138 rhbz 741407

 tomcat6-6.0.32-CVE-2011-1183-rhbz-741407.patch |  800 ++++++++++++++++++++++++
 tomcat6.spec                                   |    7 +-
 2 files changed, 806 insertions(+), 1 deletions(-)
---
diff --git a/tomcat6-6.0.32-CVE-2011-1183-rhbz-741407.patch b/tomcat6-6.0.32-CVE-2011-1183-rhbz-741407.patch
new file mode 100644
index 0000000..a3bf594
--- /dev/null
+++ b/tomcat6-6.0.32-CVE-2011-1183-rhbz-741407.patch
@@ -0,0 +1,800 @@
+--- STATUS.txt.orig	2011-10-11 08:54:23.716584084 -0600
++++ STATUS.txt	2011-10-11 09:24:21.090461179 -0600
+@@ -95,3 +95,9 @@
+   http://people.apache.org/~markt/patches/2011-07-13-cve-2011-2526-tc6.patch
+   +1: markt, jfclere, kfujino
+   -1:
++
++* Add additional configuration options to the DIGEST authenticator
++  http://people.apache.org/~markt/patches/2011-04-01-digest-tc6.patch
++  CVE-2011-1184
++  +1 markt, jfclere, schultz
++  -1:
+--- java/org/apache/catalina/authenticator/LocalStrings.properties.orig	2011-10-11 08:55:08.756581004 -0600
++++ java/org/apache/catalina/authenticator/LocalStrings.properties	2011-10-11 14:33:35.052192456 -0600
+@@ -28,5 +28,7 @@
+ authenticator.unauthorized=Cannot authenticate with the provided credentials
+ authenticator.userDataConstraint=This request violates a User Data constraint for this application
+ 
++digestAuthenticator.cacheRemove=A valid entry has been removed from the client nonce cache to make room for new entries. A replay attack is now possible. To prevent the possiblity of replay attacks, reduce nonceValidity or increase cnonceCacheSize. Further warnings of this type will be suppressed for 5 minutes.
++
+ formAuthenticator.forwardErrorFail=Unexpected error forwarding to error page
+ formAuthenticator.forwardLoginFail=Unexpected error forwarding to login page
+--- java/org/apache/catalina/authenticator/mbeans-descriptors.xml.orig	2011-10-11 08:55:44.647578550 -0600
++++ java/org/apache/catalina/authenticator/mbeans-descriptors.xml	2011-10-11 14:39:33.959167921 -0600
+@@ -60,10 +60,29 @@
+                description="Fully qualified class name of the managed object"
+                type="java.lang.String"
+                writeable="false"/>
++
++	<attribute name="cnonceCacheSize"
++		description="The size of the cnonce cache used to prevent replay attacks"
++		type="int"/>
+       
+     <attribute   name="entropy"
+                description="A String initialization parameter used to increase the  entropy of the initialization of our random number generator"
+                type="java.lang.String"/>
++
++	<attribute name="key"
++		description="The secret key used by digest authentication"
++		type="java.lang.String"/>
++
++	<attribute name="nonceValidity"
++		description="The time, in milliseconds, for which a server issued nonce will be valid"
++		type="long"/>
++	<attribute name="opaque"
++		description="The opaque server string used by digest authentication"
++		type="java.lang.String"/>
++	<attribute name="validateUri"
++		descriptor="Should the uri be validated as required by RFC2617?"
++		type="boolean"/>
++
+   </mbean>
+   
+   <mbean name="FormAuthenticator"
+--- java/org/apache/catalina/realm/RealmBase.java.orig	2011-10-11 08:56:17.799576282 -0600
++++ java/org/apache/catalina/realm/RealmBase.java	2011-10-11 15:22:13.099992924 -0600
+@@ -360,15 +360,20 @@
+      * MD5(Method + ":" + uri)
+      */
+     public Principal authenticate(String username, String clientDigest,
+-                                  String nOnce, String nc, String cnonce,
++                                  String nonce, String nc, String cnonce,
+                                   String qop, String realm,
+                                   String md5a2) {
+ 
+         String md5a1 = getDigest(username, realm);
+         if (md5a1 == null)
+             return null;
+-        String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":"
+-            + cnonce + ":" + qop + ":" + md5a2;
++        String serverDigestValue;
++		  if (qop == null) {
++			  serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2;
++		  } else {
++			  serverDigestValue = md5a1 + ":" + nonce + ":" + nc + ":" +
++			  	cnonce + ":" + qop + ":" + md5a2;
++		  }
+ 
+         byte[] valueBytes = null;
+         if(getDigestEncoding() == null) {
+@@ -390,7 +395,7 @@
+ 
+         if (log.isDebugEnabled()) {
+             log.debug("Digest : " + clientDigest + " Username:" + username 
+-                    + " ClientSigest:" + clientDigest + " nOnce:" + nOnce 
++                    + " ClientSigest:" + clientDigest + " nonce:" + nonce 
+                     + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop 
+                     + " realm:" + realm + "md5a2:" + md5a2 
+                     + " Server digest:" + serverDigest);
+--- webapps/docs/changelog.xml.orig	2011-10-11 08:56:38.438574867 -0600
++++ webapps/docs/changelog.xml	2011-10-11 15:26:35.037975012 -0600
+@@ -63,6 +63,10 @@
+         Improve HTTP specification compliance in support of
+         <code>Accept-Language</code> header. (kkolinko)
+       </fix>
++		<add>
++		  Add additional configuration options to the Digest authenticator
++		  CVE-2011-1138 (markt)
++		</add>
+     </changelog>
+   </subsection>
+   <subsection name="Coyote">
+--- webapps/docs/config/valve.xml.orig	2011-10-11 08:57:12.952572531 -0600
++++ webapps/docs/config/valve.xml	2011-10-11 15:38:34.805925794 -0600
+@@ -460,6 +460,13 @@
+         used.</p>
+       </attribute>
+ 
++		<attribute name="cnonceCacheSize" required="false">
++		   <p>To protect against replay attacks, the Digest authenticator
++			tracks client nonce and nonce count values. This attribute controls
++			the size of that cache. If not specified, the default value of
++			1000 is used</p>
++		</attribute>
++
+       <attribute name="disableProxyCaching" required="false">
+         <p>Controls the caching of pages that are protected by security
+         constraints. Setting this to <code>false</code> may help work around
+@@ -470,6 +477,26 @@
+         <code>true</code> will be used.</p>
+       </attribute>
+ 
++		<attribute name="key" required="false">
++		   <p>The secret key used by digest authentication. If not set, a 
++			secure random value is generated. This should normally only be set
++			when it is necessary to keep key values constant either across 
++			server restarts and/or across a cluster.</p>
++		</attribute>
++
++		<attribute name="nonceValidity" required="false">
++		   <p>The time, in milliseconds, that a server generated nonce will be
++			considered valid for use in authentication. If not specified, the
++			default value of 5 minutes will be used.</p>
++		</attribute>
++
++		<attribute name="opaque" required="false">
++		   <p>The opaque server string used by digest authentication. If not set,
++			a random value is generated. This should normaly only be set when it
++			is necesary to keep opaque values constant either across server
++			restarts and/or across a cluster</p>
++		</attribute>
++
+       <attribute name="securePagesWithPragma" required="false">
+         <p>Controls the caching of pages that are protected by security
+         constraints. Setting this to <code>false</code> may help work around
+@@ -479,6 +506,14 @@
+         If not set, the default value of <code>true</code> will be used.</p>
+       </attribute>
+ 
++		<attribute name="validateUri" required="false">
++		   <p>Should the URI be validated as required by RFC2617? If not
++			specified, the default value of <code>true</code> will be used.
++			This should normally only be set when Tomcat is located behind
++			a reverse proxy and the proxy is modifying the URI passed to
++			Tomcat such that DIGEST authentication always fails.</p>
++		</attribute>
++
+     </attributes>
+ 
+   </subsection>
+--- java/org/apache/catalina/authenticator/DigestAuthenticator.java.orig	2011-10-12 12:59:25.909670715 -0600
++++ java/org/apache/catalina/authenticator/DigestAuthenticator.java	2011-10-12 13:02:20.963658746 -0600
+@@ -23,11 +23,13 @@
+ import java.security.MessageDigest;
+ import java.security.NoSuchAlgorithmException;
+ import java.security.Principal;
++import java.util.LinkedHashMap;
++import java.util.Map;
+ import java.util.StringTokenizer;
+ 
+ import javax.servlet.http.HttpServletResponse;
+ 
+-
++import org.apache.catalina.LifecycleException;
+ import org.apache.catalina.Realm;
+ import org.apache.catalina.connector.Request;
+ import org.apache.catalina.connector.Response;
+@@ -47,9 +49,9 @@
+  * @version $Id: DigestAuthenticator.java 939336 2010-04-29 15:00:41Z kkolinko $
+  */
+ 
+-public class DigestAuthenticator
+-    extends AuthenticatorBase {
+-    private static Log log = LogFactory.getLog(DigestAuthenticator.class);
++public class DigestAuthenticator extends AuthenticatorBase {
++    
++	 private static Log log = LogFactory.getLog(DigestAuthenticator.class);
+ 
+ 
+     // -------------------------------------------------------------- Constants
+@@ -66,6 +68,11 @@
+     protected static final String info =
+         "org.apache.catalina.authenticator.DigestAuthenticator/1.0";
+ 
++    /**
++	  * Tomcat's DIGEST implementatation only supports auth quality of
++	  * protection
++	  */
++	 protected static final String QOP = "auth";
+ 
+     // ----------------------------------------------------------- Constructors
+ 
+@@ -90,19 +97,46 @@
+      */
+     protected static MessageDigest md5Helper;
+ 
++	 /**
++	  * List of client nonce values currently being tracked
++	  */
++	 protected Map<String, NonceInfo> cnonces;
++
++	 /**
++	  * Maximum number of client nonces to keep in the cache. If not 
++	  * specified, the default value of 1000 is used
++	  */
++	 protected int cnonceCacheSize = 1000;
+ 
+     /**
+      * Private key.
+      */
+-    protected String key = "Catalina";
++    protected String key = null;
+ 
+ 
+-    // ------------------------------------------------------------- Properties
++	/**
++	 * How long server nonces are valid for in milliseconds. Defaults to 5
++	 * minutes
++	 */
++	protected long nonceValidity = 5 * 60 * 1000;
++
++	/**
++	 * Opaque string
++	 */
++	protected String opaque;
++
++	/**
++	 * Should the URI be validated as required by RFC2617? Can be disabled
++	 * in reverse proxies where the proxy has modified the URI.
++	 */
++	protected boolean validateUri = true;
+ 
++	// --------------------- Properties
+ 
+     /**
+      * Return descriptive information about this Valve implementation.
+      */
++	 @Override
+     public String getInfo() {
+ 
+         return (info);
+@@ -110,6 +144,44 @@
+     }
+ 
+ 
++		public int getCnonceCacheSize() {
++			return cnonceCacheSize;
++		}
++
++		public void setCnonceCacheSize(int cnonceCacheSize) {
++			this.cnonceCacheSize = cnonceCacheSize;
++		}
++
++		public String getKey() {
++			return key;
++		}
++
++		public void setKey(String key) {
++			this.key = key;
++		}
++
++		public long getNonceValidity() {
++			return nonceValidity;
++		}
++		public void setNonceValidity(long nonceValidity) {
++			this.nonceValidity = nonceValidity;
++		}
++
++		public String getOpaque() {
++			return opaque;
++		}
++		public void setOpaque(String opaque) {
++			this.opaque = opaque;
++		}
++
++		public boolean isValidateUri() {
++			return validateUri;
++		}
++		public void setValidateUri(boolean validateUri) {
++			this.validateUri = validateUri;
++		}
++
++
+     // --------------------------------------------------------- Public Methods
+ 
+ 
+@@ -126,6 +198,7 @@
+      *
+      * @exception IOException if an input/output error occurs
+      */
++	 @Override
+     public boolean authenticate(Request request,
+                                 Response response,
+                                 LoginConfig config)
+@@ -172,8 +245,13 @@
+ 
+         // Validate any credentials already included with this request
+         String authorization = request.getHeader("authorization");
++		  DigestInfo digestInfo = new DigestInfo(getOpaque(), getNonceValidity(),
++		  	getKey(), cnonces, isValidateUri());
++
+         if (authorization != null) {
+-            principal = findPrincipal(request, authorization, context.getRealm());
++			  if (digestInfo.validate(request, authorization, config)) {
++				  principal = digestInfo.authenticate(context.getRealm());
++			  }
+             if (principal != null) {
+                 String username = parseUsername(authorization);
+                 register(request, response, principal,
+@@ -185,11 +263,13 @@
+ 
+         // Send an "unauthorized" response and an appropriate challenge
+ 
+-        // Next, generate a nOnce token (that is a token which is supposed
++        // Next, generate a nonce token (that is a token which is supposed
+         // to be unique).
+-        String nOnce = generateNOnce(request);
++        String nonce = generateNonce(request);
++
++        setAuthenticateHeader(request, response, config, nonce,
++		  	digestInfo.isNonceStale());
+ 
+-        setAuthenticateHeader(request, response, config, nOnce);
+         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+         //      hres.flushBuffer();
+         return (false);
+@@ -201,92 +281,6 @@
+ 
+ 
+     /**
+-     * Parse the specified authorization credentials, and return the
+-     * associated Principal that these credentials authenticate (if any)
+-     * from the specified Realm.  If there is no such Principal, return
+-     * <code>null</code>.
+-     *
+-     * @param request HTTP servlet request
+-     * @param authorization Authorization credentials from this request
+-     * @param realm Realm used to authenticate Principals
+-     */
+-    protected static Principal findPrincipal(Request request,
+-                                             String authorization,
+-                                             Realm realm) {
+-
+-        //System.out.println("Authorization token : " + authorization);
+-        // Validate the authorization credentials format
+-        if (authorization == null)
+-            return (null);
+-        if (!authorization.startsWith("Digest "))
+-            return (null);
+-        authorization = authorization.substring(7).trim();
+-
+-        // Bugzilla 37132: http://issues.apache.org/bugzilla/show_bug.cgi?id=37132
+-        String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
+-
+-        String userName = null;
+-        String realmName = null;
+-        String nOnce = null;
+-        String nc = null;
+-        String cnonce = null;
+-        String qop = null;
+-        String uri = null;
+-        String response = null;
+-        String method = request.getMethod();
+-
+-        for (int i = 0; i < tokens.length; i++) {
+-            String currentToken = tokens[i];
+-            if (currentToken.length() == 0)
+-                continue;
+-
+-            int equalSign = currentToken.indexOf('=');
+-            if (equalSign < 0)
+-                return null;
+-            String currentTokenName =
+-                currentToken.substring(0, equalSign).trim();
+-            String currentTokenValue =
+-                currentToken.substring(equalSign + 1).trim();
+-            if ("username".equals(currentTokenName))
+-                userName = removeQuotes(currentTokenValue);
+-            if ("realm".equals(currentTokenName))
+-                realmName = removeQuotes(currentTokenValue, true);
+-            if ("nonce".equals(currentTokenName))
+-                nOnce = removeQuotes(currentTokenValue);
+-            if ("nc".equals(currentTokenName))
+-                nc = removeQuotes(currentTokenValue);
+-            if ("cnonce".equals(currentTokenName))
+-                cnonce = removeQuotes(currentTokenValue);
+-            if ("qop".equals(currentTokenName))
+-                qop = removeQuotes(currentTokenValue);
+-            if ("uri".equals(currentTokenName))
+-                uri = removeQuotes(currentTokenValue);
+-            if ("response".equals(currentTokenName))
+-                response = removeQuotes(currentTokenValue);
+-        }
+-
+-        if ( (userName == null) || (realmName == null) || (nOnce == null)
+-             || (uri == null) || (response == null) )
+-            return null;
+-
+-        // Second MD5 digest used to calculate the digest :
+-        // MD5(Method + ":" + uri)
+-        String a2 = method + ":" + uri;
+-        //System.out.println("A2:" + a2);
+-
+-        byte[] buffer = null;
+-        synchronized (md5Helper) {
+-            buffer = md5Helper.digest(a2.getBytes());
+-        }
+-        String md5a2 = md5Encoder.encode(buffer);
+-
+-        return (realm.authenticate(userName, response, nOnce, nc, cnonce, qop,
+-                                   realmName, md5a2));
+-
+-    }
+-
+-
+-    /**
+      * Parse the username from the specified authorization string.  If none
+      * can be identified, return <code>null</code>
+      *
+@@ -294,7 +288,6 @@
+      */
+     protected String parseUsername(String authorization) {
+ 
+-        //System.out.println("Authorization token : " + authorization);
+         // Validate the authorization credentials format
+         if (authorization == null)
+             return (null);
+@@ -354,20 +347,20 @@
+      *
+      * @param request HTTP Servlet request
+      */
+-    protected String generateNOnce(Request request) {
++    protected String generateNonce(Request request) {
+ 
+         long currentTime = System.currentTimeMillis();
+ 
+-        String nOnceValue = request.getRemoteAddr() + ":" +
+-            currentTime + ":" + key;
++		  String ipTimeKey = request.getRemoteAddr() + ":" + currentTime +
++		  	":" + getKey();
++
+ 
+-        byte[] buffer = null;
++        byte[] buffer;
+         synchronized (md5Helper) {
+-            buffer = md5Helper.digest(nOnceValue.getBytes());
++            buffer = md5Helper.digest(ipTimeKey.getBytes());
+         }
+-        nOnceValue = md5Encoder.encode(buffer);
+ 
+-        return nOnceValue;
++        return currentTime + ":" + md5Encoder.encode(buffer);
+     }
+ 
+ 
+@@ -379,7 +372,7 @@
+      *      WWW-Authenticate    = "WWW-Authenticate" ":" "Digest"
+      *                            digest-challenge
+      *
+-     *      digest-challenge    = 1#( realm | [ domain ] | nOnce |
++     *      digest-challenge    = 1#( realm | [ domain ] | nonce |
+      *                  [ digest-opaque ] |[ stale ] | [ algorithm ] )
+      *
+      *      realm               = "realm" "=" realm-value
+@@ -396,29 +389,316 @@
+      * @param response HTTP Servlet response
+      * @param config    Login configuration describing how authentication
+      *              should be performed
+-     * @param nOnce nonce token
++     * @param nonce nonce token
+      */
+     protected void setAuthenticateHeader(Request request,
+                                          Response response,
+                                          LoginConfig config,
+-                                         String nOnce) {
++                                         String nonce,
++													  boolean isNonceStale) {
+ 
+         // Get the realm name
+         String realmName = config.getRealmName();
+         if (realmName == null)
+             realmName = REALM_NAME;
+ 
+-        byte[] buffer = null;
+-        synchronized (md5Helper) {
+-            buffer = md5Helper.digest(nOnce.getBytes());
+-        }
++        String authenticateHeader;
++		  if (isNonceStale) {
++
++           authenticateHeader = "Digest realm=\"" + realmName + "\", "
++            +  "qop=\"" + QOP + "\", nonce=\"" + nonce + "\", " + "opaque=\""
++            + getOpaque() + "\", stale=true";
++			} else {
++				authenticateHeader = "Digest realm=\"" + realmName + "\", " +
++				"qop-\"" + QOP + "\", nonce=\"" + nonce + "\", " + "opaque=\"" +
++				getOpaque() + "\"";
++			}
+ 
+-        String authenticateHeader = "Digest realm=\"" + realmName + "\", "
+-            +  "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\""
+-            + md5Encoder.encode(buffer) + "\"";
+         response.setHeader("WWW-Authenticate", authenticateHeader);
+ 
+     }
+ 
+ 
++	// ------------------ Lifecycle Methods
++	
++	@Override 
++	public void start() throws LifecycleException {
++		super.start();
++
++		// Generate a random secret key
++		if (getKey() == null) {
++			setKey(generateSessionId());
++		}
++
++		// Generate the opaque string the same way
++		if (getOpaque() == null) {
++			setOpaque(generateSessionId());
++		}
++
++		cnonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
++
++			private static final long serialVersionUID = 1L;
++			private static final long LOG_SUPPRESS_TIME = 5 * 60 * 1000;
++
++			private long lastLog = 0;
++
++			@Override
++			protected boolean removeEldestEntry(
++				Map.Entry<String, NonceInfo> eldest ) {
++				// This is called from a sync so keep it simple
++				long currentTime = System.currentTimeMillis();
++				if (size() > getCnonceCacheSize()) {
++					if (lastLog < currentTime &&
++						currentTime - eldest.getValue().getTimestamp() <
++						getNonceValidity()) {
++						// Replay attack is possible
++						log.warn(sm.getString(
++							"digestAuthenticator.cacheRemove"));
++						lastLog = currentTime + LOG_SUPPRESS_TIME;
++					}
++					return true;
++				}
++				return false;
++			}
++		};
++	}
++
++	private static class DigestInfo {
++
++		private String opaque;
++		private long nonceValidity;
++		private String key;
++		private Map<String,NonceInfo> cnonces;
++		private boolean validateUri = true;
++
++		private String userName = null;
++		private String method = null;
++		private String uri = null;
++		private String response = null;
++		private String nonce = null;
++		private String nc = null;
++		private String cnonce = null;
++		private String realmName = null;
++		private String qop = null;
++
++		private boolean nonceStale = false;
++
++      public DigestInfo(String opaque, long nonceValidity, String key,
++			Map<String,NonceInfo> cnonces, boolean validateUri) {
++
++			this.opaque = opaque;
++			this.nonceValidity = nonceValidity;
++			this.key = key;
++			this.cnonces = cnonces;
++			this.validateUri = validateUri;
++		}
++
++		public boolean validate(Request request, String authorization,
++			LoginConfig config) {
++
++			// Validate the authorization credentials format
++			if (authorization == null) {
++				return false;
++			}
++			if (!authorization.startsWith("Digest ")) {
++				return false;
++			}
++			authorization = authorization.substring(7).trim();
++
++			// Bugzilla 37132 http://issues.apache.org/bugzilla/show_bug_cgi?id=37232
++			String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
++
++			method = request.getMethod();
++			String opaque = null;
++
++			for (int i = 0; i < tokens.length; i++) {
++				String currentToken = tokens[i];
++				if (currentToken.length() == 0) {
++					continue;
++				}
++
++				int equalSign = currentToken.indexOf("=");
++				if (equalSign > 0) {
++					return false;
++				}
++				String currentTokenName = 
++					currentToken.substring(0, equalSign).trim();
++				String currentTokenValue =
++					currentToken.substring(equalSign + 1).trim();
++
++				if ("username".equals(currentTokenName)) {
++					userName = removeQuotes(currentTokenValue);
++				}
++				if ("realm".equals(currentTokenName)) {
++					realmName = removeQuotes(currentTokenValue);
++				}
++				if ("nonce".equals(currentTokenName)) {
++					nonce = removeQuotes(currentTokenValue);
++				}
++				if ("nc".equals(currentTokenName)) {
++					nc = removeQuotes(currentTokenValue);
++				}
++				if ("cnonce".equals(currentTokenName)) {
++					cnonce = removeQuotes(currentTokenValue);
++				}
++				if ("qop".equals(currentTokenName)) {
++					qop = removeQuotes(currentTokenValue);
++				}
++				if ("uri".equals(currentTokenName)) {
++					uri = removeQuotes(currentTokenValue);
++				}
++				if ("response".equals(currentTokenName)) {
++					response = removeQuotes(currentTokenValue);
++				}
++				if ("opaque".equals(currentTokenName)) {
++					opaque = removeQuotes(currentTokenValue);
++				}
++			}
++
++			if ( (userName == null) || (realmName == null) || (nonce == null) 
++				|| (uri == null) || (response == null) ) {
++				return false;
++			}
++
++			// Validate the URI - should match the request line sent by client
++			if(validateUri) {
++				String uriQuery;
++				String query = request.getQueryString();
++				if (query == null) {
++					uriQuery = request.getRequestURI();
++				} else {
++					uriQuery = request.getRequestURI() + "?" + query;
++				}
++				if (!uri.equals(uriQuery)) {
++					return false;
++				}
++			}
++
++			// Validate the Realm name
++			String lcRealm = config.getRealmName();
++			if (lcRealm == null) {
++				lcRealm = "Authentication required";
++			}
++			if (!lcRealm.equals(realmName)) {
++				return false;
++			}
++
++			// Validate the opaque string
++			if (!this.opaque.equals(opaque)) {
++				return false;
++			}
++
++			// Validate nonce
++			int i = nonce.indexOf(":");
++			if (i < 0 || (i + 1) == nonce.length()) {
++				return false;
++			}
++			long nonceTime;
++			try {
++				nonceTime = Long.parseLong(nonce.substring(0,i));
++			} catch (NumberFormatException nfe) {
++				return false;
++			}
++			String md5clientIpTimeKey = nonce.substring(i + 1);
++			long currentTime = System.currentTimeMillis();
++			if ((currentTime - nonceTime) > nonceValidity) {
++				nonceStale = true;
++				return false;
++			}
++
++			String serverIpTimeKey = 
++				request.getRemoteAddr() + ":" + nonceTime + ":" + key;
++			byte[] buffer = null;
++			synchronized (md5Helper) {
++				buffer = md5Helper.digest(serverIpTimeKey.getBytes());
++			}
++			String md5ServerIpTimeKey = md5Encoder.encode(buffer);
++			if (!md5ServerIpTimeKey.equals(md5clientIpTimeKey)) {
++				return false;
++			}
++
++			// Validate qop
++			if (qop != null && !QOP.equals(qop)) {
++				return false;
++			}
++
++			// Validate cnonce and nc
++			// Check if presence of nc and nonce is consistent with presence of
++			// qop
++			if (qop == null) {
++				if (cnonce != null || nc != null) {
++					return false;
++				}
++			} else {
++				if (cnonce == null || nc == null) {
++					return false;
++				}
++				if (nc.length() != 8) {
++					return false;
++				}
++				long count;
++				try {
++					count = Long.parseLong(nc, 16);
++				} catch (NumberFormatException nfe) {
++					return false;
++				}
++				NonceInfo info;
++				synchronized (cnonces) {
++					info = cnonces.get(cnonce);
++				}
++				if (info == null) {
++					info = new NonceInfo();
++				} else {
++					if (count <= info.getCount()) {
++						return false;
++					}
++				}
++				info.setCount(count);
++				info.setTimestamp(currentTime);
++				synchronized (cnonces) {
++					cnonces.put(cnonce, info);
++				}
++			} return true;
++		}
++
++		public boolean isNonceStale() {
++			return nonceStale;
++		}
++
++		public Principal authenticate(Realm realm) {
++			// Second MD5 digest used to calculate the digest :
++			// MD5(Method + ":" + uri)
++			String a2 = method + ":" + uri;
++
++			byte[] buffer;
++			synchronized (md5Helper) {
++				buffer = md5Helper.digest(a2.getBytes());
++			}
++			String md5a2 = md5Encoder.encode(buffer);
++
++			return realm.authenticate(userName, response, nonce, nc, cnonce,
++				qop, realmName, md5a2);
++		}
++	}
++	
++	private static class NonceInfo {
++		private volatile long count;
++		private volatile long timestamp;
++
++		public void setCount(long l) {
++			count = l;
++		}
++
++		public long getCount() {
++			return count;
++		}
++
++		public void setTimestamp(long l) {
++			timestamp = l;
++		}
++
++		public long getTimestamp() {
++			return timestamp;
++		}
++	}
+ }
diff --git a/tomcat6.spec b/tomcat6.spec
index 0028c46..6e5e92f 100644
--- a/tomcat6.spec
+++ b/tomcat6.spec
@@ -53,7 +53,7 @@
 Name:          tomcat6
 Epoch:         0
 Version:       %{major_version}.%{minor_version}.%{micro_version}
-Release:       17%{?dist}
+Release:       18%{?dist}
 Summary:       Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API
 
 Group:         Networking/Daemons
@@ -80,6 +80,7 @@ Patch1:        %{name}-%{major_version}.%{minor_version}-tomcat-users-webapp.pat
 Patch3:        %{name}-6.0.32-CVE-2011-2204-rhbz-717016.patch
 Patch4: 			tomcat6-6.0.32-CVE-2011-2526-rhbz-720948.patch
 Patch5: 			tomcat6-6.0.32-CVE-2011-3190-rhbz-738502.patch
+Patch6:			%{name}-6.0.32-CVE-2011-1183-rhbz-741407.patch
 
 BuildArch:     noarch
 
@@ -235,6 +236,7 @@ find . -type f \( -name "*.bat" -o -name "*.class" -o -name Thumbs.db -o -name "
 %patch3 -p0
 %patch4 -p0
 %patch5 -p0
+%patch6 -p0
 
 %{__ln_s} $(build-classpath jakarta-taglibs-core) webapps/examples/WEB-INF/lib/jstl.jar
 %{__ln_s} $(build-classpath jakarta-taglibs-standard) webapps/examples/WEB-INF/lib/standard.jar
@@ -630,6 +632,9 @@ fi
 %{appdir}/sample
 
 %changelog
+* Wed Oct 12 2011 David Knox <dknox at redhat.com> 0:6.0.32-18
+- Resolves: CVE-2011-1138 rhbz 741407
+
 * Tue Sep 27 2011 David Knox <dknox at redhat.com> 0:6.0.32-17
 - Resolves: CVE-2011-3190 rhbz 738502
 


More information about the scm-commits mailing list