[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