From 72e86431b59c466673214d330bbd9baa295449cf Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 4 Nov 2016 09:51:26 +0100 Subject: add hostname validation to httpclient 3.1, which is assumed by openSAML 2.x --- .../utils/MOAHttpProtocolSocketFactory.java | 140 +++++++++++++++++---- 1 file changed, 115 insertions(+), 25 deletions(-) (limited to 'id/server/moa-id-commons/src/main/java') diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/MOAHttpProtocolSocketFactory.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/MOAHttpProtocolSocketFactory.java index 84743b8c7..5bcf915e8 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/MOAHttpProtocolSocketFactory.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/MOAHttpProtocolSocketFactory.java @@ -27,7 +27,12 @@ import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.GeneralSecurityException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -35,6 +40,7 @@ import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; import org.apache.commons.lang3.StringUtils; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException; import at.gv.egovernment.moa.id.commons.utils.ssl.SSLConfigurationException; @@ -51,34 +57,57 @@ public class MOAHttpProtocolSocketFactory implements SecureProtocolSocketFactory private SSLSocketFactory sslfactory = null; + private boolean verifyHostName = true; + /** + * SSL Protocol socket factory + * + * @param url + * @param trustStoreURL + * @param acceptedServerCertURL + * @param chainingMode Specifies the ChainingMode for SSL certificate trust validation + * @param checkRevocation Enables / Disables certificate revocation checks + * @param revocationMethodOrder + * @param verifyHostName Enables / Disables hostName verfication + * @throws MOAHttpProtocolSocketFactoryException + */ public MOAHttpProtocolSocketFactory ( String url, String trustStoreURL, String acceptedServerCertURL, String chainingMode, boolean checkRevocation, - String[] revocationMethodOrder) throws MOAHttpProtocolSocketFactoryException { + String[] revocationMethodOrder, + boolean verifyHostName) throws MOAHttpProtocolSocketFactoryException { internalInitialize(url, null, trustStoreURL, acceptedServerCertURL, chainingMode, checkRevocation, revocationMethodOrder); + this.verifyHostName = verifyHostName; + } /** - * @param string - * @param certStoreDirectory - * @param trustStoreDirectory - * @param object - * @param string2 - * @param b - * @param strings + * SSL Protocol socket factory + * + * @param url + * @param certStoreDirectory + * @param trustStoreURL + * @param acceptedServerCertURL + * @param chainingMode Specifies the ChainingMode for SSL certificate trust validation + * @param checkRevocation Enables / Disables certificate revocation checks + * @param revocationMethodOrder + * @param verifyHostName Enables / Disables hostName verfication + * @throws MOAHttpProtocolSocketFactoryException */ public MOAHttpProtocolSocketFactory(String url, String certStoreDirectory, String trustStoreURL, String acceptedServerCertURL, String chainingMode, boolean checkRevocation, - String[] revocationMethodOrder) throws MOAHttpProtocolSocketFactoryException { + String[] revocationMethodOrder, + boolean verifyHostName) throws MOAHttpProtocolSocketFactoryException { internalInitialize(url, certStoreDirectory, trustStoreURL, acceptedServerCertURL, chainingMode, checkRevocation, revocationMethodOrder); + this.verifyHostName = verifyHostName; + } private void internalInitialize(String url, String certStoreDirectory, String trustStoreURL, @@ -120,7 +149,7 @@ public class MOAHttpProtocolSocketFactory implements SecureProtocolSocketFactory */ public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException, UnknownHostException { - return setEnabledSslCiphers(this.sslfactory.createSocket(host, port, + return setSecurityRequirements(this.sslfactory.createSocket(host, port, localAddress, localPort)); } @@ -130,7 +159,7 @@ public class MOAHttpProtocolSocketFactory implements SecureProtocolSocketFactory public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { - return setEnabledSslCiphers(this.sslfactory.createSocket(host, port, + return setSecurityRequirements(this.sslfactory.createSocket(host, port, localAddress, localPort)); } @@ -139,7 +168,7 @@ public class MOAHttpProtocolSocketFactory implements SecureProtocolSocketFactory */ public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return setEnabledSslCiphers(this.sslfactory.createSocket(host, port)); + return setSecurityRequirements(this.sslfactory.createSocket(host, port)); } /* (non-Javadoc) @@ -147,10 +176,73 @@ public class MOAHttpProtocolSocketFactory implements SecureProtocolSocketFactory */ public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { - return setEnabledSslCiphers(this.sslfactory.createSocket(socket, host, + return setSecurityRequirements(this.sslfactory.createSocket(socket, host, port, autoClose)); } + + private Socket setSecurityRequirements(Socket socket) throws SSLException { + if (socket instanceof SSLSocket) { + SSLSocket sslSocket = (SSLSocket)socket; + + //verify Hostname + verifyHostName(sslSocket); + + //set allowed SSL ciphers + sslSocket = setEnabledSslCiphers(sslSocket); + + return sslSocket; + } + + return socket; + } + + /** + * Verify hostname against SSL server certificate + * + * @param sslSocket + * @throws SSLPeerUnverifiedException + */ + private void verifyHostName(SSLSocket sslSocket) throws SSLException{ + if (verifyHostName) { + SSLSession session = sslSocket.getSession(); + String hostName = session.getPeerHost(); + Certificate[] certs = null; + + try { + certs = session.getPeerCertificates(); + if (certs == null || certs.length < 1) + throw new SSLPeerUnverifiedException("No server certificates found!"); + + X509Certificate x509 = (X509Certificate)certs[0]; + DefaultHostnameVerifier hostNameVerifier = new DefaultHostnameVerifier(); + hostNameVerifier.verify(hostName, x509); + + } catch (SSLPeerUnverifiedException e) { + Logger.error("Host:" + hostName + " sends no certificates for validation.", e); + throw e; + + } catch (SSLException e) { + Logger.error("Hostname validation FAILED:" + hostName + " validation ", e); + + //log certificates in case of Debug + if (Logger.isDebugEnabled() && certs != null) { + Logger.debug("Server certificate chain:"); + for (int i = 0; i < certs.length; i++) { + Logger.debug("X509Certificate[" + i + "]=" + certs[i]); + } + + } + + throw e; + + } + + } + + } + + /** * Enable only a specific subset of TLS cipher suites * This subset can be set by 'https.cipherSuites' SystemProperty (z.B. -Dhttps.cipherSuites=...) @@ -158,19 +250,17 @@ public class MOAHttpProtocolSocketFactory implements SecureProtocolSocketFactory * @param sslSocket {@link SSLSocket} * @return {@link SSLSocket} with Ciphersuites */ - private Socket setEnabledSslCiphers(Socket sslSocket) { - if (sslSocket instanceof SSLSocket) { - String systemProp = System.getProperty("https.cipherSuites"); - if (MiscUtil.isNotEmpty(systemProp)) { - ((SSLSocket) sslSocket).setEnabledCipherSuites(systemProp.split(",")); - - } + private SSLSocket setEnabledSslCiphers(SSLSocket sslSocket) { + String systemProp = System.getProperty("https.cipherSuites"); + if (MiscUtil.isNotEmpty(systemProp)) { + sslSocket.setEnabledCipherSuites(systemProp.split(",")); + + } - try { - Logger.trace("Enabled SSL-Cipher: " + StringUtils.join(((SSLSocket) sslSocket).getEnabledCipherSuites(), ",")); - } catch (Exception e) { - Logger.error(e); - } + try { + Logger.trace("Enabled SSL-Cipher: " + StringUtils.join(((SSLSocket) sslSocket).getEnabledCipherSuites(), ",")); + } catch (Exception e) { + Logger.error(e); } return sslSocket; -- cgit v1.2.3