2009-08-13 65 views
30

我有一個java客戶端調用一個Web服務操作,它將證書「指紋」作爲參數。我相信拇指印是某種SHA1哈希,以十六進制字符串格式,證書的公鑰,但我不確定。如何在Java中檢索/計算X509證書的指紋?

.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計算這個指紋字符串,如果我有一個實例java.security.cert.X509Certificate

+0

此Java演示(URLConnection的)程序連接到HTTPS URL和打印/計算各種指紋,包括引腳SHA256,滑雪和拇指指模:https://github.com/ecki/JavaCryptoTest/ blob/master/src/main/java/net/eckenfels/test/ssl/UrlInspect.java – eckes 2016-03-23 01:58:27

回答

64

證書的DER encoding的SHA-1散列是.NET正在獲得的內容X509Certificate2.Thumbprint

作爲對remarks on MSDN注意到:

指紋是使用SHA1算法動態地生成的,並且不與證書中物理存在。由於指紋是證書的唯一值,因此它通常用於在證書存儲中查找特定的證書。

Java的標準庫不直接提供指紋,但你可以這樣說:

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

下面是一個使用方便到達PEM文件一個完整的工作例如:

  1. Create 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----- 
    
  2. 創建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(); 
        } 
    } 
    
  3. 與Java 8編譯程序:

    javac X509.java 
    

    或Java 9 - 由於模塊化JDK/JPMS - DataTypeConverterjava.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 
    
  4. 與Java 8運行:

    java X509 stackoverflow.crt.pem 
    

    在Java 9 - 由於到模塊化JDK/JPMS - DataTypeConverter不在java.base,但是java.xml。結合,所以你需要運行您的程序時,明確依賴它:

    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 
    
  5. 得到預期輸出:

    47adb03649a2eb18f63ffa29790818349a99cab7 
    
+5

感謝您的回答!谷歌搜索我發現指紋通常用作證書的唯一標識符,所以它似乎並不是.NET特定的。我打電話的網絡服務正在使用它在商店中查找證書。 – 2009-08-14 17:28:49

+0

Web服務必須是.NET服務器。我還沒有看到其他服務器使用thumbprint來存儲客戶端證書。 .NET提供了很多與安全相關的擴展,您可能還會遇到其他問題。除非你的客戶需要跨平臺,否則在.NET中編寫客戶端也會容易得多。 – 2009-08-14 18:22:08

+10

指紋不是.Net獨佔的。您是否嘗試過使用SSH連接到您之前沒有連接過的服務器?你會看到它的指紋。證書商店也會列出指紋。 – Henrik 2012-09-15 13:18:09

5

可以使用openssl命令生成指紋,所以例如,如果你有證書的一個文件中PEM格式(file.txt的)

則:

cat file.txt | openssl x509 -sha1 -fingerprint - 這將產生相同的指紋

+3

這對Java有什麼幫助? – Hiro2k 2013-07-23 15:17:24

-9

這裏有一個簡單的方法:

using System.Security.Cryptography.X509Certificates;  

X509Certificate2 xcert = new X509Certificate2("C:\some_cert.cerpub"); 
string certSubject = xcert.Subject; 
string certThumbprint = xcert.Thumbprint; 
+2

這不是Java :-)我知道很容易就可以使用.NET – 2010-06-14 08:20:34

36

使用Apache Commons Codec你可以這樣做:

DigestUtils.sha1Hex(cert.getEncoded()) 
+1

。 – user882209 2013-10-16 14:09:03

1

單線程使用G oogle的Guava

String sha256AsHex = Hashing.sha256().hashBytes(x509Certificate.getEncoded()).toString(); 
+0

爲了完整性 - 通常使用SHA-1('Hashing.sha1()')作爲指紋(如其他答案中所見)。 – 2017-12-28 09:35:23