如何获取服务器证书链,然后验证它在 Java 中是不是有效且受信任

Posted

技术标签:

【中文标题】如何获取服务器证书链,然后验证它在 Java 中是不是有效且受信任【英文标题】:How to get server certificate chain then verify it's valid and trusted in Java如何获取服务器证书链,然后验证它在 Java 中是否有效且受信任 【发布时间】:2011-11-04 04:12:46 【问题描述】:

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

我已经建立了良好的连接:

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

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

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

我需要验证:

    证书有效且受信任, 根据证书序列号检查证书吊销列表分发点 确保它没有过期并且 检查证书中的 URL 是否匹配另一个(我已经检索到)。

我迷路了,非常感谢任何帮助!

【问题讨论】:

您确定 Java 的 https 客户端代码还没有为您完成所有四件事吗? 您找到解决方案了吗?证书是否可信?任何解决方案 【参考方案1】:

Kirby 和 arulraj.net 提到的这个示例代码已于 2011 年从 Apache CXF 中删除,并且不支持 OCSP。 Apache PDFBox 项目“复活”了此代码并添加了 OCSP 支持和原始代码中缺少的更多功能,例如CRL 签名检查。从 2.0.13 版开始,改进的源代码可在示例子项目的 CertificateVerifier 类中获得。它也是available online,有一些小改进。

代码并没有声称是完美的,并且还没有检查根是否可信。在 JIRA 问题PDFBOX-3017 中跟踪开发。

【讨论】:

【参考方案2】:

快速谷歌搜索将我带到了这个使用 BouncyCastle 的示例。我认为它更好地回答了这个问题。 http://www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-chain-and-verify-clr-with-bouncy-castle/

【讨论】:

该博客中的代码格式不正确.. 这是源代码svn.apache.org/repos/asf/cxf/tags/cxf-2.4.1/distribution/src/…【参考方案3】:

你想要的方法是getServerCertificates,而不是getServerCertificateChain。有一些很好的示例代码here。


编辑

添加了一些我自己的示例代码。对你来说很好的起点。不要忘记查看HttpsURLConnection 和X509Certificate 的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 之间到底有什么区别。 我如何根据上面列出的四个要求来查询证书? 您必须将证书转换为 X509Certificates 并使用该类的方法。 如何获取证书中的url?如何检查它是否有效且受信任且未过期?我是网络新手,我在网上找到的大多数资源只会让我更加困惑。 警告:上面的代码没有完全验证链,它只检查证书是否在其有效期内。

以上是关于如何获取服务器证书链,然后验证它在 Java 中是不是有效且受信任的主要内容,如果未能解决你的问题,请参考以下文章

强制 Chrome 在 TLS 期间发送链中的所有证书

证书链和TLS Pinning

OCSP查询没有颁发者证书的中间证书

Java 11:获取“空 [客户端] 证书链”而不是“空 [服务器] 证书链”

收到的 WCF 服务器证书的部分链验证失败

数字证书的相关专业名词(中)---根证书和CRL,以及java中CRL的获取和验证方法