如何在Java中获取服务器证书链并验证其是否有效和可信

20

我需要创建与远程服务器的Https连接,然后检索和验证证书。

我的连接已经正常建立:

try {  
    url = new URL(this.SERVER_URL);  
    HttpURLConnection con = (HttpURLConnection) url.openConnection();   
    HttpsURLConnection secured = (HttpsURLConnection) con;  
    secured.connect(); 
}  

但是,似乎HttpsURLConnection类型未定义getServerCertificateChain()方法。

那么我该如何检索服务器证书链呢?我的理解是getServerCertificateChain()应该返回一个X509Certificate对象数组,而这个类有一些方法可以用来查询证书。

我需要验证以下内容:

  1. 证书的有效性和信任性
  2. 检查证书序列号是否与证书吊销列表分发点匹配
  3. 确保它没有过期
  4. 检查证书中的URL是否与另一个URL匹配(我已经检索到)。

我迷失了方向,真的很感激任何帮助!


你确定Java的https客户端代码没有已经为你完成这四件事情吗? - President James K. Polk
你得到解决方案了吗?证书是否受信任?有解决方案吗? - Manu
3个回答

34

你需要的方法是getServerCertificates,而不是getServerCertificateChain。这里有一些好的示例代码在这里


编辑

我自己添加了一些示例代码,这对你是个很好的起点。别忘了查看HttpsURLConnectionX509Certificate的Javadocs。

import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;

public class TestSecuredConnection {

    /**
     * @param args
     */
    public static void main(String[] args) {
        TestSecuredConnection tester = new TestSecuredConnection();
        try {
            tester.testConnectionTo("https://www.google.com");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public TestSecuredConnection() {
        super();
    }

    public void testConnectionTo(String aURL) throws Exception {
        URL destinationURL = new URL(aURL);
        HttpsURLConnection conn = (HttpsURLConnection) destinationURL
                .openConnection();
        conn.connect();
        Certificate[] certs = conn.getServerCertificates();
        for (Certificate cert : certs) {
            System.out.println("Certificate is: " + cert);
            if(cert instanceof X509Certificate) {
                try {
                    ( (X509Certificate) cert).checkValidity();
                    System.out.println("Certificate is active for current date");
                } catch(CertificateExpiredException cee) {
                    System.out.println("Certificate is expired");
                }
            }
        }
    }
}

谢谢 - 我正在按照大公司手册的规范编写代码,但我开始怀疑撰写此部分的人是否出错了。然而,当涉及到Java网络编程时,我是个新手,所以我花了几个小时来弄清楚getServerCertificateChain和getServerCertificates之间的区别。 - Marc H
我如何根据我上面列出的四个要求来查询证书呢? - Marc H
哇..不知怎么的,当我发表那个评论时我没有看到你写的示例代码。看来我需要补觉了 :) 谢谢!!! - Marc H
3
警告:上述代码并未完全验证证书链,它仅检查证书是否在有效期内。 - Maarten Bodewes
这段代码只允许您检查已接受的证书。如果证书不被信任,调用getServerCertificates将返回null。 - Matt__C
显示剩余5条评论

2

3
博客中的代码格式不正确。这是源代码 https://svn.apache.org/repos/asf/cxf/tags/cxf-2.4.1/distribution/src/main/release/samples/sts_issue_operation/src/main/java/demo/sts/provider/cert/ - arulraj.net

1

Kirby和arulraj.net提到的此示例代码已于2011年从Apache CXF中删除,并不支持OCSP。 Apache PDFBox项目“复活”了这段代码,并添加了OCSP支持和更多在原始代码中缺失的功能,例如CRL签名检查。自2.0.13版本发布以来,改进后的源代码在示例子项目中的CertificateVerifier类中可用。它也可以通过在线方式获取,带有小的改进。

该代码并不声称完美,并且尚未检查根是否受信任。开发在JIRA问题PDFBOX-3017中跟踪。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接