如何使用jax-ws / SSLSocket不受信任时获取远程TLS / SSL证书

时间:2018-01-16 08:31:09

标签: java ssl https cxf jax-ws

我们正在使用基于HTTPS的JAX-WS客户端来发送消息(由CXF支持,我认为它使用SSLSocket)。 如果远程证书不可信/无效,我们希望记录远程证书详细信息以及消息详细信息。

最初我希望我们能得到一个有用的异常,但堆栈跟踪中有趣的异常是内部的(比如sun.security.validator.ValidatorException和sun.security.provider.certpath.SunCertPathBuilderException),所以不应该这样做。真的被使用了,而且似乎没有拿着远程证书。

所以我的问题是,在我还有消息详细信息(JAX-WS调用之外)的级别上,获取证书最为整洁的方式是什么?

到目前为止,我最好的猜测是添加我自己的javax.net.ssl.X509TrustManager,它包装当前使用的那个,并将证书放在ThreadLocal上,调用者可以在最近接收它。它看起来不是很整洁,但到目前为止它似乎是最好的:)

非常感谢任何建议!

1 个答案:

答案 0 :(得分:0)

重点是JSSE在您的问题中正在做并隐藏您正在寻找的所有内容。但幸运的是,CXF似乎允许一些定制。 我们的想法是使用您自己的实现自定义SSLSocketFactory(http://cxf.apache.org/docs/tls-configuration.html#TLSConfiguration-ClientTLSParameters),并且必须创建自己Sockets附带的HandshakeCompletedListener。这是最后一个将转储您要查找的信息的对象,我给出了一个实现示例:

class CustomHandshakeCompletedListener implements HandshakeCompletedListener {
  private HandshakeCompletedEvent hce;
  private String cipher;
  private Certificate[] peerCertificates = null;
  private Principal peerPrincipal = null;

  public void handshakeCompleted(HandshakeCompletedEvent hce) {
    this.hce = hce;

    // only cipersuites different from DH_anon* will return a server certificate
    if(!cipher.toLowerCase().contains("dh_anon")) {
      try {
        cipher = hce.getCipherSuite();
        peerCertificates = hce.getPeerCertificates();
        peerPrincipal = hce.getPeerPrincipal();
        // do anything you want with these certificates and ciphersuite
      }
      catch(SSLPeerUnverifiedException spue) {
        System.err.println("unexpected exception :");
        spue.printStackTrace();
      }
    }
  }

仍然有一些工作要实现你的目标,如果这条线索运作良好,请告诉我们。