Przeglądaj źródła

https client certificate handler refactoring and enforce certificate name verification

jrivard@gmail.com 6 lat temu
rodzic
commit
b000838dee

+ 1 - 0
server/src/main/java/password/pwm/AppProperty.java

@@ -128,6 +128,7 @@ public enum AppProperty
     HTTP_CLIENT_SOCKET_TIMEOUT_MS                   ( "http.client.socketTimeoutMs" ),
     HTTP_CLIENT_CONNECT_TIMEOUT_MS                  ( "http.client.connectTimeoutMs" ),
     HTTP_CLIENT_REQUEST_TIMEOUT_MS                  ( "http.client.requestTimeoutMs" ),
+    HTTP_CLIENT_ENABLE_HOSTNAME_VERIFICATION        ( "http.client.enableHostnameVerification" ),
     HTTP_CLIENT_PROMISCUOUS_WORDLIST_ENABLE         ( "http.client.promiscuous.wordlist.enable" ),
     HTTP_ENABLE_GZIP                                ( "http.gzip.enable" ),
     HTTP_ERRORS_ALLOW_HTML                          ( "http.errors.allowHtml" ),

+ 1 - 1
server/src/main/java/password/pwm/health/ApplianceStatusChecker.java

@@ -91,7 +91,7 @@ public class ApplianceStatusChecker implements HealthChecker
         final Map<String, String> requestHeaders = Collections.singletonMap( "sspr-authorization-token", getApplianceAccessToken( pwmApplication ) );
 
         final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
-                .trustManager( new X509Utils.PromiscuousTrustManager() )
+                .trustManager( new X509Utils.PromiscuousTrustManager( SessionLabel.HEALTH_SESSION_LABEL ) )
                 .build();
 
         final PwmHttpClient pwmHttpClient = new PwmHttpClient( pwmApplication, SessionLabel.HEALTH_SESSION_LABEL, pwmHttpClientConfiguration );

+ 186 - 0
server/src/main/java/password/pwm/http/client/HttpTrustManagerHelper.java

@@ -0,0 +1,186 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2018 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.http.client;
+
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import password.pwm.AppProperty;
+import password.pwm.bean.SessionLabel;
+import password.pwm.config.Configuration;
+import password.pwm.error.PwmError;
+import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.util.java.JavaHelper;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.X509Utils;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.TrustManager;
+import java.security.cert.X509Certificate;
+import java.util.Iterator;
+
+class HttpTrustManagerHelper
+{
+    private final Configuration configuration;
+    private final SessionLabel sessionLabel;
+    private final PwmHttpClientConfiguration pwmHttpClientConfiguration;
+    private final TrustManagerType trustManagerType;
+
+    enum TrustManagerType
+    {
+        promiscuous,
+        supplied,
+        configuredCertificates,
+        defaultJava,
+    }
+
+    HttpTrustManagerHelper(
+            final Configuration configuration,
+            final SessionLabel sessionLabel,
+            final PwmHttpClientConfiguration pwmHttpClientConfiguration
+    )
+    {
+        this.configuration = configuration;
+        this.sessionLabel = sessionLabel;
+        this.pwmHttpClientConfiguration = pwmHttpClientConfiguration;
+        this.trustManagerType = figureType();
+    }
+
+    TrustManagerType getTrustManagerType()
+    {
+        return trustManagerType;
+    }
+
+    private TrustManagerType figureType()
+    {
+
+        final boolean configPromiscuousEnabled = Boolean.parseBoolean( configuration.readAppProperty( AppProperty.SECURITY_HTTP_PROMISCUOUS_ENABLE ) );
+        final boolean promiscuousTrustMgrSet = pwmHttpClientConfiguration != null
+                && pwmHttpClientConfiguration.getTrustManager() != null
+                && X509Utils.PromiscuousTrustManager.class.equals( pwmHttpClientConfiguration.getTrustManager().getClass() );
+
+        if ( configPromiscuousEnabled || promiscuousTrustMgrSet )
+        {
+            return TrustManagerType.promiscuous;
+        }
+
+        // use the client supplied TrustManager
+        if ( pwmHttpClientConfiguration.getTrustManager() != null )
+        {
+            return TrustManagerType.supplied;
+        }
+
+        // using configured certificates
+        if ( !JavaHelper.isEmpty( pwmHttpClientConfiguration.getCertificates() ) )
+        {
+            return TrustManagerType.configuredCertificates;
+        }
+
+        // use default trust manager
+        return TrustManagerType.defaultJava;
+    }
+
+    HostnameVerifier hostnameVerifier()
+    {
+        final TrustManagerType trustManagerType = getTrustManagerType();
+        if ( trustManagerType == TrustManagerType.promiscuous )
+        {
+            return NoopHostnameVerifier.INSTANCE;
+        }
+
+        if ( !Boolean.parseBoolean( configuration.readAppProperty( AppProperty.HTTP_CLIENT_ENABLE_HOSTNAME_VERIFICATION ) ) )
+        {
+            return NoopHostnameVerifier.INSTANCE;
+        }
+
+        return new DefaultHostnameVerifier();
+    }
+
+    TrustManager[] makeTrustManager(
+    )
+            throws PwmUnrecoverableException
+    {
+        final TrustManagerType trustManagerType = getTrustManagerType();
+
+        switch ( trustManagerType )
+        {
+            case promiscuous:
+                return new TrustManager[]
+                        {
+                                new X509Utils.PromiscuousTrustManager( sessionLabel ),
+                        };
+
+            case supplied:
+            {
+                return new TrustManager[]
+                        {
+                                pwmHttpClientConfiguration.getTrustManager(),
+                        };
+            }
+
+            case configuredCertificates:
+            {
+                return new TrustManager[]
+                        {
+                                new X509Utils.CertMatchingTrustManager( configuration, pwmHttpClientConfiguration.getCertificates() ),
+                        };
+            }
+
+            case defaultJava:
+            {
+                return X509Utils.getDefaultJavaTrustManager( configuration );
+            }
+
+            default:
+                JavaHelper.unhandledSwitchStatement( trustManagerType );
+
+        }
+
+        throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "unknown trust manager type" );
+    }
+
+    String debugText() throws PwmUnrecoverableException
+    {
+        final TrustManagerType type = getTrustManagerType();
+        final StringBuilder value = new StringBuilder( "trust manager [" + type );
+        if ( TrustManagerType.supplied == type )
+        {
+            value.append( "=" );
+            value.append( pwmHttpClientConfiguration.getTrustManager().getClass().getSimpleName() );
+        }
+        else if ( TrustManagerType.configuredCertificates == type )
+        {
+            value.append( "=" );
+            for ( final Iterator<X509Certificate> iterator = pwmHttpClientConfiguration.getCertificates().iterator(); iterator.hasNext(); )
+            {
+                final X509Certificate certificate = iterator.next();
+                value.append( X509Utils.hash( certificate, PwmHashAlgorithm.SHA1 ) );
+                if ( iterator.hasNext() )
+                {
+                    value.append( "," );
+                }
+            }
+        }
+        value.append( "]" );
+        return value.toString();
+    }
+}

+ 33 - 54
server/src/main/java/password/pwm/http/client/PwmHttpClient.java

@@ -45,7 +45,6 @@ import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.conn.routing.HttpRoutePlanner;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.BasicCredentialsProvider;
@@ -53,8 +52,6 @@ import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.ProxyAuthenticationStrategy;
 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
 import org.apache.http.protocol.HttpContext;
-import org.apache.http.ssl.SSLContextBuilder;
-import org.apache.http.ssl.TrustStrategy;
 import org.apache.http.util.EntityUtils;
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
@@ -70,22 +67,16 @@ import password.pwm.http.HttpMethod;
 import password.pwm.http.PwmURL;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
+import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogger;
-import password.pwm.util.secure.X509Utils;
 
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
 import java.time.Instant;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -131,40 +122,25 @@ public class PwmHttpClient
     {
         final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
         clientBuilder.setUserAgent( PwmConstants.PWM_APP_NAME + " " + PwmConstants.SERVLET_VERSION );
-        final boolean configPromiscuousEnabled = Boolean.parseBoolean( configuration.readAppProperty( AppProperty.SECURITY_HTTP_PROMISCUOUS_ENABLE ) );
-        final boolean promiscuousTrustMgrSet = pwmHttpClientConfiguration != null
-                && pwmHttpClientConfiguration.getTrustManager() != null
-                && X509Utils.PromiscuousTrustManager.class.equals( pwmHttpClientConfiguration.getTrustManager().getClass() );
 
         try
         {
-            if ( configPromiscuousEnabled || promiscuousTrustMgrSet )
-            {
-                clientBuilder.setSSLContext( promiscuousSSLContext() );
-                clientBuilder.setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE );
-            }
-            else if ( pwmHttpClientConfiguration != null && ( pwmHttpClientConfiguration.getCertificates() != null || pwmHttpClientConfiguration.getTrustManager() != null ) )
-            {
-                final SSLContext sslContext = SSLContext.getInstance( "TLS" );
-                final TrustManager trustManager = pwmHttpClientConfiguration.getTrustManager() != null
-                        ? pwmHttpClientConfiguration.getTrustManager()
-                        : new X509Utils.CertMatchingTrustManager( configuration, pwmHttpClientConfiguration.getCertificates() );
-                sslContext.init( null, new TrustManager[]
-                                {
-                                        trustManager,
-                                },
-                        new SecureRandom() );
-
-                final SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory( sslContext, NoopHostnameVerifier.INSTANCE );
-                final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
-                        .register( "https", sslConnectionFactory )
-                        .register( "http", PlainConnectionSocketFactory.INSTANCE )
-                        .build();
-                final HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager( registry );
-                clientBuilder.setSSLContext( sslContext );
-                clientBuilder.setSSLSocketFactory( sslConnectionFactory );
-                clientBuilder.setConnectionManager( ccm );
-            }
+            final SSLContext sslContext = SSLContext.getInstance( "TLS" );
+            final HttpTrustManagerHelper httpTrustManagerHelper = new HttpTrustManagerHelper( configuration, sessionLabel, pwmHttpClientConfiguration );
+            sslContext.init(
+                    null,
+                    httpTrustManagerHelper.makeTrustManager(),
+                    new SecureRandom() );
+            final SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory( sslContext, httpTrustManagerHelper.hostnameVerifier() );
+            final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+                    .register( "https", sslConnectionFactory )
+                    .register( "http", PlainConnectionSocketFactory.INSTANCE )
+                    .build();
+            final HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager( registry );
+            clientBuilder.setSSLHostnameVerifier( httpTrustManagerHelper.hostnameVerifier() );
+            clientBuilder.setSSLContext( sslContext );
+            clientBuilder.setSSLSocketFactory( sslConnectionFactory );
+            clientBuilder.setConnectionManager( ccm );
         }
         catch ( Exception e )
         {
@@ -281,8 +257,22 @@ public class PwmHttpClient
         final Instant startTime = Instant.now();
         final int counter = REQUEST_COUNTER.getAndIncrement();
 
-        LOGGER.trace( sessionLabel, () -> "preparing to send (id=" + counter + ") "
-                + clientRequest.toDebugString( this ) );
+        if ( LOGGER.isEnabled( PwmLogLevel.TRACE ) )
+        {
+            final String sslDebugText;
+            if ( clientRequest.isHttps() )
+            {
+                final HttpTrustManagerHelper httpTrustManagerHelper = new HttpTrustManagerHelper( pwmApplication.getConfig(), sessionLabel, pwmHttpClientConfiguration );
+                sslDebugText = "using " + httpTrustManagerHelper.debugText();
+            }
+            else
+            {
+                sslDebugText = "";
+            }
+
+            LOGGER.trace( sessionLabel, () -> "preparing to send (id=" + counter + ") "
+                    + clientRequest.toDebugString( this, sslDebugText ) );
+        }
 
         final HttpResponse httpResponse = executeRequest( clientRequest );
         final String responseBody = EntityUtils.toString( httpResponse.getEntity() );
@@ -375,17 +365,6 @@ public class PwmHttpClient
         return httpClient.execute( httpRequest );
     }
 
-    private static SSLContext promiscuousSSLContext( ) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException
-    {
-        return new SSLContextBuilder().loadTrustMaterial( null, new TrustStrategy()
-        {
-            public boolean isTrusted( final X509Certificate[] arg0, final String arg1 ) throws CertificateException
-            {
-                return true;
-            }
-        } ).build();
-    }
-
     public InputStream streamForUrl( final String inputUrl )
             throws IOException, PwmUnrecoverableException
     {

+ 13 - 2
server/src/main/java/password/pwm/http/client/PwmHttpClientRequest.java

@@ -24,8 +24,10 @@ package password.pwm.http.client;
 
 import lombok.Value;
 import password.pwm.http.HttpMethod;
+import password.pwm.util.java.StringUtil;
 
 import java.io.Serializable;
+import java.net.URI;
 import java.util.Map;
 
 @Value
@@ -36,8 +38,17 @@ public class PwmHttpClientRequest implements Serializable
     private final String body;
     private final Map<String, String> headers;
 
-    public String toDebugString( final PwmHttpClient pwmHttpClient )
+    public String toDebugString( final PwmHttpClient pwmHttpClient, final String additionalText )
     {
-        return pwmHttpClient.entityToDebugString( "HTTP " + method + " request to " + url, headers, body );
+        final String topLine = "HTTP " + method + " request to " + url
+                + ( StringUtil.isEmpty( additionalText )
+                ? ""
+                : " " + additionalText );
+        return pwmHttpClient.entityToDebugString( topLine, headers, body );
+    }
+
+    public boolean isHttps()
+    {
+        return "https".equals( URI.create( getUrl() ).getScheme() );
     }
 }

+ 1 - 1
server/src/main/java/password/pwm/svc/telemetry/HttpTelemetrySender.java

@@ -63,7 +63,7 @@ public class HttpTelemetrySender implements TelemetrySender
             throws PwmUnrecoverableException
     {
         final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
-                .trustManager( new X509Utils.PromiscuousTrustManager() )
+                .trustManager( new X509Utils.PromiscuousTrustManager( SessionLabel.TELEMETRY_SESSION_LABEL ) )
                 .build();
         final PwmHttpClient pwmHttpClient = new PwmHttpClient( pwmApplication, SessionLabel.TELEMETRY_SESSION_LABEL, pwmHttpClientConfiguration );
         final String body = JsonUtil.serialize( statsPublishBean );

+ 1 - 1
server/src/main/java/password/pwm/svc/wordlist/WordlistSource.java

@@ -82,7 +82,7 @@ class WordlistSource
             {
                 final boolean promiscuous = Boolean.parseBoolean( pwmApplication.getConfig().readAppProperty( AppProperty.HTTP_CLIENT_PROMISCUOUS_WORDLIST_ENABLE ) );
                 final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
-                        .trustManager( promiscuous ? new X509Utils.PromiscuousTrustManager() : null )
+                        .trustManager( promiscuous ? new X509Utils.PromiscuousTrustManager( null ) : null )
                         .build();
                 final PwmHttpClient client = new PwmHttpClient( pwmApplication, null, pwmHttpClientConfiguration );
                 return client.streamForUrl( wordlistConfiguration.getAutoImportUrl() );

+ 15 - 4
server/src/main/java/password/pwm/util/queue/SmsQueueManager.java

@@ -47,6 +47,7 @@ import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsManager;
 import password.pwm.util.BasicAuthInfo;
 import password.pwm.util.PasswordData;
+import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
@@ -498,11 +499,21 @@ public class SmsQueueManager implements PwmService
 
             final PwmHttpClientRequest pwmHttpClientRequest = makeRequest( requestData );
 
-            final PwmHttpClientConfiguration pwmHttpClientConfiguration = PwmHttpClientConfiguration.builder()
-                    .certificates( config.readSettingAsCertificate( PwmSetting.SMS_GATEWAY_CERTIFICATES ) )
-                    .build();
+            final PwmHttpClient pwmHttpClient;
+            {
+                if ( JavaHelper.isEmpty( config.readSettingAsCertificate( PwmSetting.SMS_GATEWAY_CERTIFICATES ) ) )
+                {
+                    pwmHttpClient = new PwmHttpClient( pwmApplication, sessionLabel );
+                }
+                else
+                {
+                    final PwmHttpClientConfiguration clientConfiguration = PwmHttpClientConfiguration.builder()
+                            .certificates( config.readSettingAsCertificate( PwmSetting.SMS_GATEWAY_CERTIFICATES ) )
+                            .build();
 
-            final PwmHttpClient pwmHttpClient = new PwmHttpClient( pwmApplication, sessionLabel, pwmHttpClientConfiguration );
+                    pwmHttpClient = new PwmHttpClient( pwmApplication, sessionLabel, clientConfiguration );
+                }
+            }
 
             try
             {

+ 49 - 12
server/src/main/java/password/pwm/util/secure/X509Utils.java

@@ -47,11 +47,14 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
 import java.security.cert.CertificateEncodingException;
@@ -269,6 +272,13 @@ public abstract class X509Utils
 
     public static class PromiscuousTrustManager implements X509TrustManager
     {
+        private final SessionLabel sessionLabel;
+
+        public PromiscuousTrustManager( final SessionLabel sessionLabel )
+        {
+            this.sessionLabel = sessionLabel;
+        }
+
         public X509Certificate[] getAcceptedIssuers( )
         {
             return new X509Certificate[ 0 ];
@@ -284,7 +294,7 @@ public abstract class X509Utils
             logMsg( certs, authType );
         }
 
-        private static void logMsg( final X509Certificate[] certs, final String authType )
+        private void logMsg( final X509Certificate[] certs, final String authType )
         {
             if ( certs != null )
             {
@@ -292,7 +302,7 @@ public abstract class X509Utils
                 {
                     try
                     {
-                        LOGGER.warn( "blind trusting certificate during authType=" + authType + ", subject=" + cert.getSubjectDN().toString() );
+                        LOGGER.warn( sessionLabel, "blind trusting certificate during authType=" + authType + ", subject=" + cert.getSubjectDN().toString() );
                     }
                     catch ( Exception e )
                     {
@@ -414,12 +424,10 @@ public abstract class X509Utils
             throws CertificateEncodingException, PwmUnrecoverableException
     {
         return x509Certificate.toString()
-                + "\n:MD5 checksum: " + SecureEngine.hash( new ByteArrayInputStream( x509Certificate.getEncoded() ), PwmHashAlgorithm.MD5 )
-                + "\n:SHA1 checksum: " + SecureEngine.hash( new ByteArrayInputStream( x509Certificate.getEncoded() ), PwmHashAlgorithm.SHA1 )
-                + "\n:SHA2-256 checksum: " + SecureEngine.hash( new ByteArrayInputStream( x509Certificate.getEncoded() ), PwmHashAlgorithm.SHA256 )
-                + "\n:SHA2-512 checksum: " + SecureEngine.hash( new ByteArrayInputStream( x509Certificate.getEncoded() ), PwmHashAlgorithm.SHA512 );
-
-
+                + "\n:MD5 checksum: " + hash( x509Certificate, PwmHashAlgorithm.MD5 )
+                + "\n:SHA1 checksum: " + hash( x509Certificate, PwmHashAlgorithm.SHA1 )
+                + "\n:SHA2-256 checksum: " + hash( x509Certificate, PwmHashAlgorithm.SHA256 )
+                + "\n:SHA2-512 checksum: " + hash( x509Certificate, PwmHashAlgorithm.SHA512 );
     }
 
     public static String makeDebugText( final X509Certificate x509Certificate )
@@ -473,10 +481,9 @@ public abstract class X509Utils
         returnMap.put( CertDebugInfoKey.expireDate.toString(), JavaHelper.toIsoDate( cert.getNotAfter() ) );
         try
         {
-            returnMap.put( CertDebugInfoKey.md5Hash.toString(), SecureEngine.hash( new ByteArrayInputStream( cert.getEncoded() ), PwmHashAlgorithm.MD5 ) );
-            returnMap.put( CertDebugInfoKey.sha1Hash.toString(), SecureEngine.hash( new ByteArrayInputStream( cert.getEncoded() ), PwmHashAlgorithm.SHA1 ) );
-            returnMap.put( CertDebugInfoKey.sha512Hash.toString(), SecureEngine.hash( new ByteArrayInputStream( cert.getEncoded() ),
-                    PwmHashAlgorithm.SHA512 ) );
+            returnMap.put( CertDebugInfoKey.md5Hash.toString(), hash( cert, PwmHashAlgorithm.MD5 ) );
+            returnMap.put( CertDebugInfoKey.sha1Hash.toString(), hash( cert, PwmHashAlgorithm.SHA1 ) );
+            returnMap.put( CertDebugInfoKey.sha512Hash.toString(), hash( cert, PwmHashAlgorithm.SHA512 ) );
             if ( JavaHelper.enumArrayContainsValue( flags, DebugInfoFlag.IncludeCertificateDetail ) )
             {
                 returnMap.put( CertDebugInfoKey.detail.toString(), X509Utils.makeDetailText( cert ) );
@@ -533,4 +540,34 @@ public abstract class X509Utils
         }
         return Collections.emptyList();
     }
+
+    public static TrustManager[] getDefaultJavaTrustManager( final Configuration configuration )
+            throws PwmUnrecoverableException
+    {
+        try
+        {
+            final TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
+            tmf.init( (KeyStore) null );
+            return tmf.getTrustManagers();
+        }
+        catch ( GeneralSecurityException e )
+        {
+            final String errorMsg = "unexpected error loading default java TrustManager: " + e.getMessage();
+            final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, errorMsg );
+            throw new PwmUnrecoverableException( errorInformation );
+        }
+    }
+
+    public static String hash( final X509Certificate certificate, final PwmHashAlgorithm pwmHashAlgorithm )
+            throws PwmUnrecoverableException
+    {
+        try
+        {
+            return SecureEngine.hash( new ByteArrayInputStream( certificate.getEncoded() ), pwmHashAlgorithm );
+        }
+        catch ( CertificateEncodingException e )
+        {
+            throw PwmUnrecoverableException.newException( PwmError.ERROR_INTERNAL, "unexpected error encoding certificate: " + e.getMessage() );
+        }
+    }
 }

+ 1 - 0
server/src/main/resources/password/pwm/AppProperty.properties

@@ -123,6 +123,7 @@ http.client.alwaysLogEntities=false
 http.client.socketTimeoutMs=60000
 http.client.connectTimeoutMs=60000
 http.client.requestTimeoutMs=60000
+http.client.enableHostnameVerification=true
 http.client.promiscuous.wordlist.enable=true
 http.header.server=@PwmAppName@
 http.header.sendContentLanguage=true

+ 4 - 2
server/src/test/java/password/pwm/http/client/PwmHttpClientTest.java

@@ -29,7 +29,6 @@ import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
-
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
@@ -157,7 +156,10 @@ public class PwmHttpClientTest
                 .certificates( getWireMockSelfSignedCertificate() )
                 .build();
 
-        final HttpClient httpClient = PwmHttpClient.getHttpClient( configuration, pwmHttpClientConfiguration, null );
+        Mockito.when( configuration.readAppProperty( AppProperty.HTTP_CLIENT_ENABLE_HOSTNAME_VERIFICATION ) ).thenReturn( "false" );
+
+
+        final HttpClient httpClient = PwmHttpClient.getHttpClient( configuration, pwmHttpClientConfiguration, null  );
 
         final HttpGet httpGet = new HttpGet( String.format( "https://localhost:%d/simpleHello", wireMockRule.httpsPort() ) );
         final HttpResponse response = httpClient.execute( httpGet );