web-dev-qa-db-ja.com

X509TrustManagerの実装-検証の一部を既存の検証に渡す

PKIXパス構築例外を無視する必要があります

javax.net.ssl.SSLHandshakeException: Sun.security.validator.ValidatorException:
PKIX path building failed: Sun.security.provider.certpath.SunCertPathBuilderExc
ption: unable to find valid certification path to requested target

isServerTrustedから常にX509TrustManagerを実装するreturn trueを実装する独自のクラスを作成することで、これを行う方法を知っています。

ただし、すべてのサーバーとクライアントを信頼する必要はありません。

  • 現在行われているように、クライアントに対してすべてのデフォルトの検証を実行してください。
  • サーバーの場合、1つの特定の証明書についてのみサーバー証明書の検証を無視しますが、現在行われているように(たとえば、cacertsストアを使用して)検証します。

どうすればこのようなことを実現できますか?つまり、検証の一部を、X509TrustFactoryオブジェクトを置き換える前にX509TrustFactoryオブジェクトに渡します。

つまり、これは私がやりたいことです

public boolean isServerTrusted(X509Certificate[] chain)
{
    if(chain[0].getIssuerDN().getName().equals("MyTrustedServer") && chain[0].getSubjectDN().getName().equals("MyTrustedServer"))
        return true;

    // else I want to do whatever verification is normally done
}

また、既存のisClientTrusted検証を妨害したくありません。

これどうやってするの?

15
user93353

既存のデフォルトのトラストマネージャーを手に入れ、次のようなものを使用して独自にラップすることができます:

_TrustManagerFactory tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Using null here initialises the TMF with the default trust store.
tmf.init((KeyStore) null);

// Get hold of the default trust manager
X509TrustManager x509Tm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
    if (tm instanceof X509TrustManager) {
        x509Tm = (X509TrustManager) tm;
        break;
    }
}

// Wrap it in your own class.
final X509TrustManager finalTm = x509Tm;
X509TrustManager customTm = new X509TrustManager() {
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return finalTm.getAcceptedIssuers();
    }

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

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

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { customTm }, null);

// You don't have to set this as the default context,
// it depends on the library you're using.
SSLContext.setDefault(sslContext);
_

次に、finalTm.checkServerTrusted(chain, authType);の周りに独自のロジックを実装できます。

ただし、無視する特定の証明書を例外にしていることを確認する必要があります。

以下では、これらの発行者DNとサブジェクトDNを使用してany証明書を通過させています(偽造するのは難しくありません)。

_if(chain[0].getIssuerDN().getName().equals("MyTrustedServer") && chain[0].getSubjectDN().getName().equals("MyTrustedServer"))
    return true;
_

代わりに、既知の参照から_X509Certificate_インスタンスをロードして、チェーン内の実際の値を比較できます。

また、checkClientTrustedおよびcheckServerTrustedtrueまたはfalseを返すメソッドではなく、デフォルトでサイレントに成功するvoidメソッドです。期待する証明書に問題がある場合は、CertificateExceptionを明示的にスローします。

39
Bruno