2014-04-17 16 views
8

Uygulamamın yerel ağda kullanmak için güvenilir kendinden imzalı sertifikalar içeren kişisel bir anahtar deposu var: - mykeystore.jks. Yerel ağda bulunan yerel web sitelerinin yanı sıra yerel sitelere bağlanmış kendinden imzalı sertifikalar kullanarak herkese açık sitelere (google.com) bağlanmayı diliyorum.Bir TrustManagerFactory'yi birden çok güven kaynağıyla nasıl başlatırım?

sorun burada https://google.com bağlandığınızda kendi deposunu ayarı

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 

Ancak istisna raporlama, JRE ile birlikte kök CA'larını içeren varsayılan anahtar deposunu kıldığından, yol bina, eğer başarısız olmasıdır Kendi anahtar depomuma (mykeystore.jks) bir CA sertifikası alıyorum, iyi çalışıyor. Her ikisini de destekleyecek bir yolu var mı? Bu amaçla kendi TrustManger var

,

public class CustomX509TrustManager implements X509TrustManager { 

     X509TrustManager defaultTrustManager; 

     public MyX509TrustManager(KeyStore keystore) { 
       TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
       trustMgrFactory.init(keystore); 
       TrustManager trustManagers[] = trustMgrFactory.getTrustManagers(); 
       for (int i = 0; i < trustManagers.length; i++) { 
        if (trustManagers[i] instanceof X509TrustManager) { 
         defaultTrustManager = (X509TrustManager) trustManagers[i]; 
         return; 
        } 
       } 

     public void checkServerTrusted(X509Certificate[] chain, String authType) 
       throws CertificateException { 
      try { 
       defaultTrustManager.checkServerTrusted(chain, authType); 
      } catch (CertificateException ce) { 
      /* Handle untrusted certificates */ 
      } 
     } 
    } 

Sonra SSLContext, TrustManager [] trustManagers = başlatmak yeni TrustManager [] {yeni CustomX509TrustManager (deposu)}; SSLContext customSSLContext = SSLContext.getInstance ("TLS"); customSSLContext.init (null, trustManagers, null); Kendi güven yöneticileri set yoksa

ve soket fabrika set

,

HttpsURLConnection.setDefaultSSLSocketFactory(customSSLContext.getSocketFactory()); 

ana program,

URL targetServer = new URL(url); 
HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection(); 

, gayet https://google.com bağlanır. Varsayılan anahtar deposuna işaret eden bir "varsayılan güven yöneticisi" nasıl alabilirim?

+0

Olası yinelenen (http://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm) – OrangeDog

cevap

-1

Bir SSLContext'i ilklendirdiğinizde, TrustManager'ın dizisini sağlayabilirsiniz. İki tedarikçiniz var: JRE truststore'u kullanan bir varsayılan ve sizinkini kullanan bir başka. Delegasyon modeli yanlış cevap burada.

+0

Ne yazık ki, JSSE tarafından kullanılan varsayılan güven yöneticisini (JRE CA'ları kullanan), sadece bir soket fabrikasını almanın bir yolu yoktur. JRE belgelerini arayan kendi güven yöneticimi uygulayabilirim, ancak bunun JRE'nin konumuna bağlı olduğundan temiz bir çözüm olduğunu düşünmüyorum. – varrunr

+1

Dizide yalnızca belirli bir anahtar ve/veya güven yöneticisi uygulama türünün ilk örneği kullanılır. (Örneğin, dizideki sadece ilk javax.net.ssl.X509KeyManager kullanılacaktır.) – Dale

14

trustMgrFactory.init(keystore); içinde, defaultTrustManager'ı sistem varsayılan anahtar deposu değil kendi kişisel anahtar deponuzla yapılandırıyorsunuz.

sun.security.ssl.TrustManagerFactoryImpl kaynak kodunu okuyarak dayanarak, trustMgrFactory.init((KeyStore) null); sen (sistem varsayılan anahtar deposunu yüklemek) gerek tam olarak ne yapmak ve hızlı testlere dayanmaktadır olur benziyor, benim için iş gibi görünüyor.

+1

Java 1.8 ile çalıştım (1.8.0_60-b27 yapıyorum). Ama benim için çalışmadı. Aynı hatayı aldım: PKIX yolu oluşturulamadı. –

+0

Ancak bu, sertifikalarınızı yalnızca özel bir anahtar deposunda kullanmanıza izin vermez, yalnızca sistemde yüklü olan CA sertifikaları. –

+0

Kaynak okunarak bunu anlamak için Kudos! Bu, çok sayıda cacerts yolunu ve isim işleme jugglery'ını basitleştirir! Ayrıca bana bunun için parola gereksinimi olmadığını da beni şaşırtıyor. – FUD

1

Commons HttpClient ile aynı sorunu yaşadım. Benim durumumda için çözüm Çalışma şu şekilde PKIX TrustManagers için heyet zincirini yaratmaktı:

public class TrustManagerDelegate implements X509TrustManager { 
    private final X509TrustManager mainTrustManager; 
    private final X509TrustManager trustManager; 
    private final TrustStrategy trustStrategy; 

    public TrustManagerDelegate(X509TrustManager mainTrustManager, X509TrustManager trustManager, TrustStrategy trustStrategy) { 
     this.mainTrustManager = mainTrustManager; 
     this.trustManager = trustManager; 
     this.trustStrategy = trustStrategy; 
    } 

    @Override 
    public void checkClientTrusted(
      final X509Certificate[] chain, final String authType) throws CertificateException { 
     this.trustManager.checkClientTrusted(chain, authType); 
    } 

    @Override 
    public void checkServerTrusted(
      final X509Certificate[] chain, final String authType) throws CertificateException { 
     if (!this.trustStrategy.isTrusted(chain, authType)) { 
      try { 
       mainTrustManager.checkServerTrusted(chain, authType); 
      } catch (CertificateException ex) { 
       this.trustManager.checkServerTrusted(chain, authType); 
      } 
     } 
    } 

    @Override 
    public X509Certificate[] getAcceptedIssuers() { 
     return this.trustManager.getAcceptedIssuers(); 
    } 

} 

Ve bu arada aşağıdaki HttpClient başlatmak (evet o çirkin): Basit HttpsURLConnection ile durumda

final SSLContext sslContext; 
try { 
    sslContext = SSLContext.getInstance("TLS"); 
    final TrustManagerFactory javaDefaultTrustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    javaDefaultTrustManager.init((KeyStore)null); 
    final TrustManagerFactory customCaTrustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    customCaTrustManager.init(getKeyStore()); 

    sslContext.init(
     null, 
     new TrustManager[]{ 
      new TrustManagerDelegate(
        (X509TrustManager)customCaTrustManager.getTrustManagers()[0], 
        (X509TrustManager)javaDefaultTrustManager.getTrustManagers()[0], 
        new TrustSelfSignedStrategy() 
      ) 
     }, 
     secureRandom 
    ); 

} catch (final NoSuchAlgorithmException ex) { 
    throw new SSLInitializationException(ex.getMessage(), ex); 
} catch (final KeyManagementException ex) { 
    throw new SSLInitializationException(ex.getMessage(), ex); 
} 

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext); 

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
     RegistryBuilder.<ConnectionSocketFactory>create() 
       .register("http", PlainConnectionSocketFactory.getSocketFactory()) 
       .register("https", sslSocketFactory) 
       .build() 
); 
//maximum parallel requests is 500 
cm.setMaxTotal(500); 
cm.setDefaultMaxPerRoute(500); 

CredentialsProvider cp = new BasicCredentialsProvider(); 
cp.setCredentials(
     new AuthScope(apiSettings.getIdcApiUrl(), 443), 
     new UsernamePasswordCredentials(apiSettings.getAgencyId(), apiSettings.getAgencyPassword()) 
); 

client = HttpClients.custom() 
        .setConnectionManager(cm) 
        .build(); 

sen delegating sınıfının basitleştirilmiş versiyonu ile tarafından alabilirsiniz:

public class TrustManagerDelegate implements X509TrustManager { 
    private final X509TrustManager mainTrustManager; 
    private final X509TrustManager trustManager; 

    public TrustManagerDelegate(X509TrustManager mainTrustManager, X509TrustManager trustManager) { 
     this.mainTrustManager = mainTrustManager; 
     this.trustManager = trustManager; 
    } 

    @Override 
    public void checkClientTrusted(
      final X509Certificate[] chain, final String authType) throws CertificateException { 
     this.trustManager.checkClientTrusted(chain, authType); 
    } 

    @Override 
    public void checkServerTrusted(
      final X509Certificate[] chain, final String authType) throws CertificateException { 
     try { 
      mainTrustManager.checkServerTrusted(chain, authType); 
     } catch (CertificateException ex) { 
      this.trustManager.checkServerTrusted(chain, authType); 
     } 
    } 

    @Override 
    public X509Certificate[] getAcceptedIssuers() { 
     return this.trustManager.getAcceptedIssuers(); 
    } 

} 
+0

için çözüm daha fazla ayrıntıda açıklanmıştır: http://blog.novoj.net/2016/02/29/how-to-make-apache-httpclient-trust- lets-encrypt-certificate-otorite/ – Novoj

6

cevap here ben bunun nasıl anlaşılması nasıl geldi.Sistem CA sertifikalarını ve ayrıca özel bir anahtar deposu anahtarını kabul etmek istiyorsanız, bazı kolaylık yöntemleriyle tek bir sınıfa basitleştirdim. Mevcut burada Tam kodu: [JVM birden anahtar depolarını kaydedilmesi] arasında

https://gist.github.com/HughJeffner/6eac419b18c6001aeadb

KeyStore keystore; // Get your own keystore here 
    SSLContext sslContext = SSLContext.getInstance("TLS"); 
    TrustManager[] tm = CompositeX509TrustManager.getTrustManagers(keystore); 
    sslContext.init(null, tm, null); 
+0

Kompozit güven yöneticisi gerçekten yararlı bir çözümdür. – Kane

İlgili konular