当前位置:  开发笔记 > 编程语言 > 正文

如何在Java中检索/计算X509证书的指纹?

如何解决《如何在Java中检索/计算X509证书的指纹?》经验,为你挑选了2个好方法。

我有一个调用Web服务操作的java客户端,它将证书"thumbprint"作为参数.我相信指纹是某种SHA1哈希值,采用十六进制字符串格式,是cert的公钥,但我不确定.

.NET框架似乎包含一种获取此值的简单方法(X509Certificate2.Thumbprint属性).在Windows中查看.cer文件的属性还会显示指纹,如下所示:

a6 9c fd b0 58 0d a4 ee ae 9a 47 75 24 c3 0b 9f 5d b6 1c 77

因此,我的问题是:如果我有一个java.security.cert.X509Certificate的实例,有人知道如何在Java中检索或计算这个指纹字符串吗?



1> ZZ Coder..:

证书的DER编码的SHA-1哈希是.NET通过X509Certificate2.Thumbprint获得的.

正如MSDN上的评论所述:

指纹是使用SHA1算法动态生成的,并且在证书中不存在.由于指纹是证书的唯一值,因此通常用于在证书库中查找特定证书.

Java的标准库不直接提供指纹,但你可以这样得到它:

DatatypeConverter.printHexBinary(
        MessageDigest.getInstance("SHA-1").digest(
                cert.getEncoded())).toLowerCase();

这是一个使用方便访问的PEM文件的完整工作示例:

    创建stackoverflow.crt.pem:

    -----BEGIN CERTIFICATE-----
    MIIHHjCCBgagAwIBAgIQDhG71w1UtxDQxvVAtrUspDANBgkqhkiG9w0BAQsFADBw
    MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
    d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
    dXJhbmNlIFNlcnZlciBDQTAeFw0xNjA1MjEwMDAwMDBaFw0xOTA4MTQxMjAwMDBa
    MGoxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJOWTERMA8GA1UEBxMITmV3IFlvcmsx
    HTAbBgNVBAoTFFN0YWNrIEV4Y2hhbmdlLCBJbmMuMRwwGgYDVQQDDBMqLnN0YWNr
    ZXhjaGFuZ2UuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr0YD
    zscT5i6T2FaRsTGNCiLB8OtPXu8N9iAyuaROh/nS0kRRsN8wUMk1TmgZhPuYM6oF
    S377V8W2LqhLBMrPXi7lnhvKt2DFWCyw38RrDbEsM5dzVGErmhux3F0QqcTI92zj
    VW61DmE7NSQLiR4yonVpTpdAaO4jSPJxn8d+4p1sIlU2JGSk8LZSWFqaROc7KtXt
    lWP4HahNRZtdwvL5dIEGGNWx+7B+XVAfY1ygc/UisldkA+a3D2+3WAtXgFZRZZ/1
    CWFjKWJNMAI6ZBAtlbgSNgRYxdcdleIhPLCzkzWysfltfiBmsmgz6VCoFR4KgJo8
    Gd3MeTWojBthM10SLwIDAQABo4IDuDCCA7QwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
    zNllZGKiErhZcjswHQYDVR0OBBYEFFrBQmPCYhOznZSEqjIeF8tto4Z7MIIB6AYD
    VR0RBIIB3zCCAduCEyouc3RhY2tleGNoYW5nZS5jb22CEXN0YWNrb3ZlcmZsb3cu
    Y29tghMqLnN0YWNrb3ZlcmZsb3cuY29tgg1zdGFja2F1dGguY29tggtzc3RhdGlj
    Lm5ldIINKi5zc3RhdGljLm5ldIIPc2VydmVyZmF1bHQuY29tghEqLnNlcnZlcmZh
    dWx0LmNvbYINc3VwZXJ1c2VyLmNvbYIPKi5zdXBlcnVzZXIuY29tgg1zdGFja2Fw
    cHMuY29tghRvcGVuaWQuc3RhY2thdXRoLmNvbYIRc3RhY2tleGNoYW5nZS5jb22C
    GCoubWV0YS5zdGFja2V4Y2hhbmdlLmNvbYIWbWV0YS5zdGFja2V4Y2hhbmdlLmNv
    bYIQbWF0aG92ZXJmbG93Lm5ldIISKi5tYXRob3ZlcmZsb3cubmV0gg1hc2t1YnVu
    dHUuY29tgg8qLmFza3VidW50dS5jb22CEXN0YWNrc25pcHBldHMubmV0ghIqLmJs
    b2dvdmVyZmxvdy5jb22CEGJsb2dvdmVyZmxvdy5jb22CGCoubWV0YS5zdGFja292
    ZXJmbG93LmNvbYIVKi5zdGFja292ZXJmbG93LmVtYWlsghNzdGFja292ZXJmbG93
    LmVtYWlsMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
    BQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29t
    L3NoYTItaGEtc2VydmVyLWc1LmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNl
    cnQuY29tL3NoYTItaGEtc2VydmVyLWc1LmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
    /WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
    MAgGBmeBDAECAjCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8v
    b2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRzLmRp
    Z2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0EuY3J0
    MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAAzJAMGSdKoX1frdqNlN
    iXu8Gcbsm/DxWMXpcTXlZn8s+/qQQoc+/3o0CK3C8/j9n5DmsYa88P6Ntt5ysDs+
    b0ynXFva4CAEyKaoPM4SIpOjwfWBRSUOqAIkQO2/LhKBwT/EnpaIHIKGnI0UdXLQ
    oDfkMDg6mgJsEBsKdKF5EfEX7iU3NO5xVJPJE8/R0btLAdYwxB9S6fSpCXGe2HqQ
    D101O/7/4MWNdFSbfdDSFcn5oEm+idimrqiNrF5knmuJy4qPBkL7thNuGK6rvYCF
    ZJM03ZEZhkQmn2jG/7LgjfwZmvfcITeADCpylf88bL+lf+vxe6cCl9CyqWgBDpsI
    xpE=
    -----END CERTIFICATE-----
    

    创建X509.java:

    import javax.xml.bind.DatatypeConverter;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateEncodingException;
    import java.security.cert.CertificateException;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    
    public final class X509 {
        public static void main(String[] args)
                throws FileNotFoundException, CertificateException, NoSuchAlgorithmException {
            FileInputStream is = new FileInputStream(args[0]);
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(is);
            String thumbprint = getThumbprint(cert);
            System.out.println(thumbprint);
        }
    
        private static String getThumbprint(X509Certificate cert)
                throws NoSuchAlgorithmException, CertificateEncodingException {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] der = cert.getEncoded();
            md.update(der);
            byte[] digest = md.digest();
            String digestHex = DatatypeConverter.printHexBinary(digest);
            return digestHex.toLowerCase();
        }
    }
    

    使用Java 8编译程序:

    javac X509.java
    

    或Java 9 - 由于模块化JDK/JPMS - DataTypeConverter不在java.base中,而是在java.xml.bind中,因此您需要在构建期间明确依赖它:

    javac --add-modules java.xml.bind X509.java
    

    否则,在Java 9上,当您尝试构建它时会得到:

    X509.java:3: error: package javax.xml.bind is not visible
            import javax.xml.bind.DatatypeConverter;
            ^
            (package javax.xml.bind is declared in module java.xml.bind, which is not in the module graph)
            1 error
    

    使用Java 8运行它:

    java X509 stackoverflow.crt.pem
    

    在Java 9中 - 由于模块化JDK/JPMS - DataTypeConverter不在java.base中,而是在java.xml.bind中,因此在运行程序时需要明确依赖它:

    java --add-modules java.xml.bind X509 stackoverflow.crt.pem
    

    否则,在Java 9上,当您尝试运行它时会得到此信息:

    Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
        at X509.getThumbPrint(X509.java:29)
        at X509.main(X509.java:19)
        Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
        ... 2 more
    

    获得预期的输出:

    47adb03649a2eb18f63ffa29790818349a99cab7
    


Thumbprints不是.Net独家.您是否尝试使用之前未连接的SSH连接到服务器?你会看到它的指纹.证书商店也会列出指纹.
"为什么你需要用Java?" - 他可能在固定证书.它比信任数百个CA和从属CA和DNS中的任何一个更安全.
谢谢你的回答!谷歌搜索我发现指纹通常用作证书的唯一标识符,因此它似乎不是特定于.NET的.我正在调用的Web服务正在使用它来查找商店中的证书.

2> Martin Ždila..:

使用Apache Commons Codec,您可以:

DigestUtils.sha1Hex(cert.getEncoded())

推荐阅读
围脖上的博博_771
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有