2012-06-18 22 views
6

私は他の人々と同じ問題にぶつかると思いますが、私は多くの同様の問題と潜在的な解決策を見てきましたが、運がありません。Java SSL - InstallCertは証明書を認識しますが、引き続き「有効な証明書パスを見つけることができません」というエラーはありますか?

私が使用しているトラストストアはJava 1.6.0 JREのlib/securityにあります(ビルド1.6.0_20-b02 ...これが問題の根本かもしれません)。私もjssecacertsで試しました。

InstallCertを使用すると、証明書が実際にインストールされ、有効であることがわかります(証明書が削除され、再インポートされていることを確認してください) :

java InstallCert <my host name> 
Loading KeyStore jssecacerts... 
Opening connection to <my host name>:443... 
Starting SSL handshake... 
No errors, certificate is already trusted 

すでに下に存在していること」のkeytoolのチェックインとPortecle、証明書を再インポートするには、(私はなど、ブラウザからエクスポートし、それを超えるscp'ing、-showcertでのopensslから生成しようとした)私を与えますこの他のエイリアスはここの "メッセージのタイプです。したがって、証明書がツールにどのように反映されているかに問題はないようです。

コード内の明示的なトラストストアパスを強制しても差はありません。すべての場合、デバッグを有効にすると、最終的には(javax.net.debugのsetPropertyを介して「すべて」になります):

main, SEND TLSv1 ALERT: fatal, description = certificate_unknown 
main, WRITE: TLSv1 Alert, length = 2 [Raw write]: length = 7 0000: 15 
03 01 00 02 02 2E        ....... main, called 
closeSocket() main, handling exception: 
javax.net.ssl.SSLHandshakeException: 
sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to 
find valid certification path to requested target 

残念ながら、自分のTrustManagerを実装することでチェックを無効にすることはできません。実際にチェックする必要があります。

私がホストから取得した証明書には、いくつかの拡張機能があります(正確には9個)。

他に何かチェック/試用できますか?別のJREバージョンに変更しますか?

A)は、Webサーバー上でコードを実行します。

+0

あなた自身の 'TrustManager'を実装できないのはなぜですか?依然として、トラストマネージャーの証明書を使用してチェックを実行できます。 –

+0

@Vivin - 私が解決しようとしているコアの問題は、直接コントロールしていないアプリケーション層内です(この場合は、最近HTTPSになっているWebサービスを呼び出すGrailsアプリケーションです)。私自身のローカルシナリオでは、その使用を上流で強制することはできません。これは痛みですが、私は後でそれを扱います - 今、私がそれを最も細かいレベルで動作させることができるなら、少なくとも解決の連鎖のどこに行くべきかを私に教えてくれます。 – Bill

+0

GlassFishなどのアプリケーションサーバーでこれを実行していますか?プロセスが/usr/lib/jvm/java-1.6.0-sun-1.6.0.20.x86_64でJavaバイナリを実行しているかどうかを確認し、あなたのtrustStore(OpenJDK、等)。あなたが掲示したデバッグ出力は参考になります、もっと投稿できますか? – Brad

答えて

0

独自のトラストマネージャを実装して証明書を確認することはできます。私は同様の問題hereに遭遇した。私もcacertsに証明書を追加しようとしましたが、役に立たなかった。

トラストマネージャでは、証明書を明示的にロードする必要があります。このような基本的に私は何をしなければならなかったことだった何か:私はソケットファクトリを作成する必要がありました、このトラストマネージャを使用して、今すぐ

public class ValicertX509TrustManager implements X509TrustManager { 

    X509TrustManager pkixTrustManager; 

    ValicertX509TrustManager() throws Exception { 

     String valicertFile = "/certificates/ValicertRSAPublicRootCAv1.cer"; 
     String commwebDRFile = "/certificates/DR_10570.migs.mastercard.com.au.crt"; 
     String commwebPRODFile = "/certificates/PROD_10549.migs.mastercard.com.au.new.crt"; 

     Certificate valicert = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(valicertFile)); 
     Certificate commwebDR = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebDRFile)); 
     Certificate commwebPROD = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebPRODFile)); 

     KeyStore keyStore = KeyStore.getInstance("JKS"); 
     keyStore.load(null, "".toCharArray()); 
     keyStore.setCertificateEntry("valicert", valicert); 
     keyStore.setCertificateEntry("commwebDR", commwebDR); 
     keyStore.setCertificateEntry("commwebPROD", commwebPROD); 

     TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); 
     trustManagerFactory.init(keyStore); 

     TrustManager trustManagers[] = trustManagerFactory.getTrustManagers(); 

     for(TrustManager trustManager : trustManagers) { 
      if(trustManager instanceof X509TrustManager) { 
       pkixTrustManager = (X509TrustManager) trustManager; 
       return; 
      } 
     } 

     throw new Exception("Couldn't initialize"); 
    } 

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     pkixTrustManager.checkServerTrusted(chain, authType); 
    } 

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
     pkixTrustManager.checkServerTrusted(chain, authType); 
    } 

    public X509Certificate[] getAcceptedIssuers() { 
     return pkixTrustManager.getAcceptedIssuers(); 
    } 
} 

まず私は、実際の証明書ファイルを使用して、トラストマネージャを作成します。

Protocol.registerProtocol("vhttps", new Protocol("vhttps", new ValicertSSLProtocolSocketFactory(), 443)); 
PostMethod postMethod = new PostMethod(url); 
for (Map.Entry<String, String> entry : params.entrySet()) { 
    postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue())); 
} 

HttpClient client = new HttpClient(); 
int status = client.executeMethod(postMethod); 
if (status == 200) { 
    StringBuilder resultBuffer = new StringBuilder(); 
    resultBuffer.append(postMethod.getResponseBodyAsString()); 
    return new HttpResponse(resultBuffer.toString(), ""); 
} else { 
    throw new IOException("Invalid response code: " + status); 
} 

のみ:

public class ValicertSSLProtocolSocketFactory implements ProtocolSocketFactory { 

    private SSLContext sslContext = null; 

    public ValicertSSLProtocolSocketFactory() { 
     super(); 
    } 

    private static SSLContext createValicertSSLContext() { 
     try { 
      ValicertX509TrustManager valicertX509TrustManager = new ValicertX509TrustManager(); 
      SSLContext context = SSLContext.getInstance("TLS"); 
      context.init(null, new ValicertX509TrustManager[] { valicertX509TrustManager}, null); 
      return context; 
     } 

     catch(Exception e) { 
      Log.error(Log.Context.Net, e); 
      return null; 
     } 
    } 

    private SSLContext getSSLContext() { 
     if(this.sslContext == null) { 
      this.sslContext = createValicertSSLContext(); 
     } 

     return this.sslContext; 
    } 

    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException { 
     return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); 
    } 

    public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException { 
     if(params == null) { 
      throw new IllegalArgumentException("Parameters may not be null"); 
     } 

     int timeout = params.getConnectionTimeout(); 
     SocketFactory socketFactory = getSSLContext().getSocketFactory(); 

     if(timeout == 0) { 
      return socketFactory.createSocket(host, port, localAddress, localPort); 
     } 

     else { 
      Socket socket = socketFactory.createSocket(); 
      SocketAddress localAddr = new InetSocketAddress(localAddress, localPort); 
      SocketAddress remoteAddr = new InetSocketAddress(host, port); 
      socket.bind(localAddr); 
      socket.connect(remoteAddr, timeout); 
      return socket; 
     } 
    } 

    public Socket createSocket(String host, int port) throws IOException { 
     return getSSLContext().getSocketFactory().createSocket(host, port); 
    } 

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { 
     return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); 
    } 

    public boolean equals(Object obj) { 
     return ((obj != null) && obj.getClass().equals(ValicertSSLProtocolSocketFactory.class)); 
    } 

    public int hashCode() { 
     return ValicertSSLProtocolSocketFactory.class.hashCode(); 
    } 
} 

は、その後、私はちょうど新しいプロトコルを登録しましたこの特定の証明書に特定のプロトコル(vhttps)を作成しなければならないという欠点があります。

+0

本当に必要なすべてを信じるのは難しいです。これに関する根本的な問題を理解していないという明確な味があります。 – EJP

+0

@EJPあまりにもひいきにする必要はありません。私はこのソリューションが最適ではないことに痛感しています。より良い解決策があれば、私はそれを聞いてうれしいです。証明書を追加すること(私は信頼チェーンを一貫して追跡することができると確信していました)をサーバーのcacertsファイルに追加することを含めて、これを動作させるためにさまざまなことを試しました。何も動作していないようです。私は最終的にこのソリューションを使用する前に、この問題を多く研究しました。それは私の最初の選択ではなかった。 –

+0

@Vivin - 私はこのルートに行く必要はないと本当に望んでいるが、提案を感謝します。 :)私が直接制御しない他の多くのコードは変更する必要があるので、私の側やマシンの設定側のどこかに間違いがあることを期待しているシナリオの1つです。 – Bill

0

私の推測では、これらのもののいずれかが起こったのです。彼らはしばしば独自のトラストストアを使用します - あなたのコードが実行されるときに使用されているのはcacertsなのですか?

b)デフォルトでは、JavaはCRLをダウンロードして解釈することによって証明書の有効性をチェックしようとします。プロキシの背後にいる場合、ダウンロードは失敗し、その結果PKIX全体のチェックは失敗します。

+1

彼はサーバー証明書を直接インストールしているので、(b)は適用されません。そうでなければ良い答え。 – EJP

+0

@EJPあなたは正しいですが、代わりにルート証明書をインポートすることにしました。それを修正します。 – emboss

+0

最初はAはそれだと思っていたのですが、その後完全なデバッグを行って小さなサンプルコードに煮詰めても、それでも失敗しました。しかし、提案を感謝します。 – Bill

0

SSLデバッグトレースは、手動で手動でロードしない限り、どのcacertsファイルを使用しているかを表示します。明らかにあなたがあなたが思っているものを使用していません。

+0

「TrustStoreは/usr/lib/jvm/java-1.6.0-sun-1.6.0.20.x86_64/jre/lib/security/jssecacerts」であることを確認することをお勧めします。私が言及したように、私はjssecacertsとcacertsの両方でそれを試しました。これにはtrustStore設定を通るパスが含まれています。 – Bill

関連する問題