如何在 Java 中以编程方式检查 SSL 证书到期日期

Posted

技术标签:

【中文标题】如何在 Java 中以编程方式检查 SSL 证书到期日期【英文标题】:how to check SSL certificate expiration date programmatically in Java 【发布时间】:2012-10-19 03:36:50 【问题描述】:

我需要从Java网站上的SSL证书中提取到期日期,应该同时支持 受信任和自签名证书,例如: 1.信任 https://github.com 2.自签 https://mms.nw.ru/

我已经复制了一些代码:

import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLTest 

    public static void main(String [] args) throws Exception 
        // configure the SSLContext with a TrustManager
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] new DefaultTrustManager(), new SecureRandom());
        SSLContext.setDefault(ctx);

        URL url = new URL("https://github.com");//https://mms.nw.ru
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setHostnameVerifier(new HostnameVerifier() 
            @Override
            public boolean verify(String arg0, SSLSession arg1) 
                return true;
            
        );
        System.out.println(conn.getResponseCode());
        Certificate[] certs = conn.getServerCertificates();
        for (Certificate cert :certs)
            System.out.println(cert.getType());
            System.out.println(cert);
        

        conn.disconnect();
    

    private static class DefaultTrustManager implements X509TrustManager 

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException 

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException 

        @Override
        public X509Certificate[] getAcceptedIssuers() 
            return null;
        
    

问题是:

    如何从证书中解析过期日期,在我的代码中,toString() 确实输出了日期,但是很难解析。

    如何确定证书链,例如链3的github证书,我怎么知道从哪个证书获取到期日期?

【问题讨论】:

尽管我要求使用 .NET,但 Google 仍会指向此处,因此我将在 C# 答案中添加 this link。 我必须在 for 循环之前添加 conn.connect(); 才能使此代码正常工作并停止接收 java.lang.IllegalStateException: connection not yet open 【参考方案1】:

如何从证书中解析过期日期

将其发送至X509Certificate 并调用getNotAfter()

如何确定证书链,例如github证书有链

你明白了。这就是Certificate[] 数组,正如它在Javadoc 中所说的那样。

我怎么知道从哪个证书获取到期日期?

阅读Javadoc。 “对等方自己的证书首先是任何证书颁发机构”。

但是我不知道你为什么要这样做。 Java 应该已经为您完成了这一切。

请丢弃不安全且不正确的 TrustManager 实现。处理自签名证书的正确方法是将它们导入客户端信任库。还请扔掉不安全的 HostnameVerifier,并使用默认的或安全的。如果您不希望 HTTPS 安全,为什么还要使用它?

【讨论】:

我的应用程序是一个监控工具,具有监控 SSL 到期日期的功能,以便在到期时通知客户。所以我不在乎HTTPS是否安全,我只关心它什么时候到期。 “Java 应该已经为你做这一切”是什么意思? @Grace 我的意思是如果证书已经过期,它会抛出一个SSLHandshakeException。很难相信一个简单的日历条目根本不编写任何 Java 代码就无法实现这一目的。 感谢您的快速回复。我可以从 Certificate 转换为 X509Certificate。无论如何,我们的程序旨在自动监控一个证书的到期日期,并在它即将到期时通知管理员。我们的应用程序是一个监控系统,就像 nagios 等一样。就是这样。你确实帮了大忙:) @Grace 我明白了,玩得开心。【参考方案2】:

确保将 Begin/End 行附加到 PEM 格式,否则 java 无法理解它。

public class CertTest 

    public static final String cert = "-----BEGIN CERTIFICATE-----\n<CERT_DATA>\n-----END CERTIFICATE-----";

    public static void main(String[] args)
        try 
            X509Certificate myCert = (X509Certificate)CertificateFactory
                     .getInstance("X509")
                     .generateCertificate(
                                       // string encoded with default charset
                    new ByteArrayInputStream(cert.getBytes())
                     );
            System.out.println(myCert.getNotAfter());

         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        

    

【讨论】:

问题中没有任何内容表明 Java 不理解证书格式。 这对我帮助很大【参考方案3】:

在 Kotlin 方式中,它应该看起来像这样:

fun certInformation(aURL: String) 
    val destinationURL = URL(aURL)
    val conn = destinationURL.openConnection() as HttpsURLConnection
    conn.connect()
    val certs = conn.serverCertificates
    for (cert in certs) 
        println("Certificate is: $cert")
        if (cert is X509Certificate) 
            println(cert.issuerDN.name)
            println(cert.notAfter)
            println(cert.notBefore)
        
    

【讨论】:

以上是关于如何在 Java 中以编程方式检查 SSL 证书到期日期的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式在 couchbase android 中添加 ssl 证书

来自 Java 客户端的 SSL 错误,但在 Firefox 中以 POSTER 形式工作

如何在 Python 中以编程方式传递密码

在 OpenJDK 11 中启用 SSL 证书吊销检查

如何在 Objective-C 中以编程方式检查协议是不是包含某些方法?

ssl时如何忽略证书检查