2009-08-13 2 views
30

У меня есть java-клиент, который вызывает операцию веб-службы, которая берет сертификат «отпечаток пальца» в качестве параметра. Я считаю, что отпечаток - это своего рода хэш SHA1 в шестнадцатеричном строчном формате открытого ключа cert, но я не уверен.Как получить/вычислить отпечаток сертификата X509 в Java?

.NET framework, кажется, включает в себя простой способ получить это значение (X509Certificate2.Thumbprint). Просмотр свойств .CER файла в Windows, также отображает отпечаток, который выглядит как:

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, SKI и отпечатки пальцев: https://github.com/ecki/JavaCryptoTest/ blob/master/src/main/java/net/eckenfels/test/ssl/UrlInspect.java – eckes

ответ

64

Хеш SHA-1 DER encoding сертификата - это то, что .NET получает с X509Certificate2.Thumbprint.

Как было отмечено на remarks on MSDN:

Отпечаток динамически генерируется с использованием алгоритма SHA1 и физически не существует в сертификате. Поскольку отпечаток является уникальным значением для сертификата, он обычно используется для поиска конкретного сертификата в хранилище сертификатов.

стандартная библиотека Java не предоставляет отпечаток напрямую, но вы можете получить его, как это:

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

Вот полный обработанный пример использования удобно доступный PEM файла:

  1. Создать 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 - 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 
    
  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. Веб-сервис, который я звоню, использует его, чтобы найти сертификат в своем магазине. –

+0

Веб-служба должна быть .NET-сервером. Я не видел других серверов, использующих отпечаток пальца для хранения сертификата клиента. .NET сделал так много связанных с безопасностью расширений, вы можете столкнуться и с другими проблемами. Если ваш клиент не должен быть кросс-платформенным, было бы намного проще писать клиент в .NET тоже. –

+10

Отпечатки пальцев не являются .Net эксклюзивными. Вы пытались подключиться к серверу с помощью SSH, с которым вы ранее не подключались? Вы увидите его отпечаток. В хранилище сертификатов также будут указаны отпечатки пальцев. – Henrik

5

Вы можете создать отпечаток с помощью команды OpenSSL, так например, если у вас есть формат PEM сертификата в файле (file.txt)

затем:

cat file.txt | openssl x509 -sha1 -fingerprint - это дало бы тот же отпечаток

+3

Как это помогает с Java? – Hiro2k

-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 –

36

Используя Apache Commons Codec вы можете сделать:

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

приятный однострочный! – user882209

1

Однострочный лоток с использованием G Программа oogle в Guava

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

Для полноты - обычно SHA-1 ('Hashing.sha1()') используется как отпечаток (как видно из других ответов). –

Смежные вопросы