Hello community, here is the log from the commit of package jakarta-commons-httpclient for openSUSE:12.3 checked in at 2013-02-14 21:00:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:12.3/jakarta-commons-httpclient (Old) and /work/SRC/openSUSE:12.3/.jakarta-commons-httpclient.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "jakarta-commons-httpclient", Maintainer is "" Changes: -------- --- /work/SRC/openSUSE:12.3/jakarta-commons-httpclient/jakarta-commons-httpclient.changes 2013-01-31 01:20:33.000000000 +0100 +++ /work/SRC/openSUSE:12.3/.jakarta-commons-httpclient.new/jakarta-commons-httpclient.changes 2013-02-14 21:00:25.000000000 +0100 @@ -1,0 +2,6 @@ +Thu Feb 14 09:10:48 UTC 2013 - mvysko...@suse.com + +- fix bnc#8033332: no ssl certificate hostname checking (CVE-2012-5783) + * commons-httpclient-CVE-2012-5783.patch + +------------------------------------------------------------------- New: ---- commons-httpclient-CVE-2012-5783.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ jakarta-commons-httpclient.spec ++++++ --- /var/tmp/diff_new_pack.jZUyB8/_old 2013-02-14 21:00:25.000000000 +0100 +++ /var/tmp/diff_new_pack.jZUyB8/_new 2013-02-14 21:00:25.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package jakarta-commons-httpclient # -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -32,6 +32,9 @@ # Add OSGi MANIFEST.MF bits Patch1: %{name}-addosgimanifest.patch Patch2: %{name}-encoding.patch +#PATCH-FIX-UPSTREAM: bnc#803332 +#http://svn.apache.org/viewvc?view=revision&revision=483925 +Patch3: commons-httpclient-CVE-2012-5783.patch BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -111,6 +114,7 @@ popd %patch2 +%patch3 -p1 # Use javax classes, not com.sun ones # assume no filename contains spaces ++++++ commons-httpclient-CVE-2012-5783.patch ++++++ Index: commons-httpclient-3.1/src/java/org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.java =================================================================== --- commons-httpclient-3.1.orig/src/java/org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.java +++ commons-httpclient-3.1/src/java/org/apache/commons/httpclient/protocol/SSLProtocolSocketFactory.java @@ -31,10 +31,17 @@ package org.apache.commons.httpclient.protocol; import java.io.IOException; +import java.io.InputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import org.apache.commons.httpclient.ConnectTimeoutException; @@ -79,12 +86,17 @@ public class SSLProtocolSocketFactory im InetAddress clientHost, int clientPort) throws IOException, UnknownHostException { - return SSLSocketFactory.getDefault().createSocket( + SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket( host, port, clientHost, clientPort ); + + verifyHostName( host, (SSLSocket) socket ); + + // verifyHostName() didn't blowup - good! + return socket; } /** @@ -124,15 +136,18 @@ public class SSLProtocolSocketFactory im } int timeout = params.getConnectionTimeout(); if (timeout == 0) { - return createSocket(host, port, localAddress, localPort); + SSLSocket socket = (SSLSocket) createSocket(host, port, localAddress, localPort); + verifyHostName(host, (SSLSocket) socket); + return socket; } else { // To be eventually deprecated when migrated to Java 1.4 or above - Socket socket = ReflectionSocketFactory.createSocket( + SSLSocket socket =(SSLSocket) ReflectionSocketFactory.createSocket( "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort, timeout); if (socket == null) { - socket = ControllerThreadSocketFactory.createSocket( + socket = (SSLSocket) ControllerThreadSocketFactory.createSocket( this, host, port, localAddress, localPort, timeout); } + verifyHostName(host, (SSLSocket) socket); return socket; } } @@ -142,10 +157,12 @@ public class SSLProtocolSocketFactory im */ public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return SSLSocketFactory.getDefault().createSocket( + SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket( host, port ); + verifyHostName( host, (SSLSocket) socket ); + return socket; } /** @@ -157,14 +174,133 @@ public class SSLProtocolSocketFactory im int port, boolean autoClose) throws IOException, UnknownHostException { - return ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket( + SSLSocket s = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket( socket, host, port, autoClose ); + verifyHostName( host, (SSLSocket) socket ); + + // verifyHostName() didn't blowup - good! + return s; + } + + private static void verifyHostName( String host, SSLSocket ssl ) + throws IOException { + if ( host == null ) { + throw new NullPointerException( "host to verify was null" ); + } + + SSLSession session = ssl.getSession(); + if ( session == null ) { + // In our experience this only happens under IBM 1.4.x when + // spurious (unrelated) certificates show up in the server's chain. + // Hopefully this will unearth the real problem: + InputStream in = ssl.getInputStream(); + in.available(); + /* + If you're looking at the 2 lines of code above because you're + running into a problem, you probably have two options: + + #1. Clean up the certificate chain that your server + is presenting (e.g. edit "/etc/apache2/server.crt" or + wherever it is your server's certificate chain is + defined). + + OR + + #2. Upgrade to an IBM 1.5.x or greater JVM, or switch to a + non-IBM JVM. + */ + + // If ssl.getInputStream().available() didn't cause an exception, + // maybe at least now the session is available? + session = ssl.getSession(); + if ( session == null ) { + // If it's still null, probably a startHandshake() will + // unearth the real problem. + ssl.startHandshake(); + + // Okay, if we still haven't managed to cause an exception, + // might as well go for the NPE. Or maybe we're okay now? + session = ssl.getSession(); + } + } + + Certificate[] certs = session.getPeerCertificates(); + X509Certificate x509 = (X509Certificate) certs[ 0 ]; + String cn = getCN( x509 ); + if ( cn == null ) { + String subject = x509.getSubjectX500Principal().toString(); + String msg = "certificate doesn't contain CN: " + subject; + throw new SSLException( msg ); + } + // I'm okay with being case-insensitive when comparing the host we used + // to establish the socket to the hostname in the certificate. + // Don't trim the CN, though. + cn = cn.toLowerCase(); + host = host.trim().toLowerCase(); + boolean doWildcard = false; + if ( cn.startsWith( "*." ) ) { + // The CN better have at least two dots if it wants wildcard action, + // but can't be [*.co.uk] or [*.co.jp] or [*.org.uk], etc... + String withoutCountryCode = ""; + if ( cn.length() >= 7 && cn.length() <= 9 ) { + withoutCountryCode = cn.substring( 2, cn.length() - 2 ); + } + doWildcard = cn.lastIndexOf( '.' ) >= 0 && + !"ac.".equals( withoutCountryCode ) && + !"co.".equals( withoutCountryCode ) && + !"com.".equals( withoutCountryCode ) && + !"ed.".equals( withoutCountryCode ) && + !"edu.".equals( withoutCountryCode ) && + !"go.".equals( withoutCountryCode ) && + !"gouv.".equals( withoutCountryCode ) && + !"gov.".equals( withoutCountryCode ) && + !"info.".equals( withoutCountryCode ) && + !"lg.".equals( withoutCountryCode ) && + !"ne.".equals( withoutCountryCode ) && + !"net.".equals( withoutCountryCode ) && + !"or.".equals( withoutCountryCode ) && + !"org.".equals( withoutCountryCode ); + + // The [*.co.uk] problem is an interesting one. Should we just + // hope that CA's would never foolishly allow such a + // certificate to happen? + } + + boolean match; + if ( doWildcard ) { + match = host.endsWith( cn.substring( 1 ) ); + } else { + match = host.equals( cn ); + } + if ( !match ) { + throw new SSLException( "hostname in certificate didn't match: <" + host + "> != <" + cn + ">" ); + } } + private static String getCN( X509Certificate cert ) { + // Note: toString() seems to do a better job than getName() + // + // For example, getName() gives me this: + // 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d + // + // whereas toString() gives me this: + // EMAILADDRESS=juliusdav...@cucbc.com + String subjectPrincipal = cert.getSubjectX500Principal().toString(); + int x = subjectPrincipal.indexOf( "CN=" ); + if ( x >= 0 ) { + int y = subjectPrincipal.indexOf( ',', x ); + // If there are no more commas, then CN= is the last entry. + y = ( y >= 0 ) ? y : subjectPrincipal.length(); + return subjectPrincipal.substring( x + 3, y ); + } else { + return null; + } + } + /** * All instances of SSLProtocolSocketFactory are the same. */ -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org