[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