2009-08-13 15 views
30

Ho un client Java che sta chiamando un'operazione di servizio Web che accetta un certificato "identificazione personale" come parametro. Credo che l'identificazione personale sia una sorta di hash SHA1, in formato stringa esadecimale, della chiave pubblica del certificato, ma non ne sono sicuro.Come recuperare/calcolare l'identificazione personale di un certificato X509 in Java?

Il framework .NET sembra includere un modo semplice per ottenere questo valore (proprietà X509Certificate2.Thumbprint). Visualizzazione delle proprietà di un file con estensione cer in Windows visualizza anche l'identificazione personale, che assomiglia a:

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

La mia domanda è quindi: Qualcuno sa come recuperare o calcolare questa stringa identificazione personale all'interno di Java, se ho un'istanza di una java.security.cert.X509Certificate?

+0

Questa demo Java programma di oogle (URLConnection) si connette a un URL HTTPS e stampe/calcola tutti i tipi di impronte digitali, tra cui pin-sha256, SCI e impronte digitali: https://github.com/ecki/JavaCryptoTest/ blob/master/src/main/java/net/eckenfels/test/ssl/UrlInspect.java – eckes

risposta

64

L'hash SHA-1 dello DER encoding del certificato è ciò che .NET sta ottenendo con X509Certificate2.Thumbprint.

come indicato sul remarks on MSDN:

L'identificazione personale viene generata dinamicamente utilizzando l'algoritmo SHA1 e non esiste fisicamente nel certificato. Poiché l'identificazione digitale è un valore univoco per il certificato, viene comunemente utilizzata per trovare un determinato certificato in un archivio certificati.

libreria standard di Java non prevede l'identificazione personale direttamente, ma si può ottenere in questo modo:

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

Ecco un esempio completo lavorato utilizzando un file PEM facilmente accessibile:

  1. Crea 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. Crea 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. Compilare il programma con Java 8:

    javac X509.java 
    

    o Java 9 - a causa di JDK/JPMS modulari - DataTypeConverter non è in java.base, ma java.xml.bind, quindi è necessario dipendere esplicitamente da esso durante la compilazione :

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

    In caso contrario, su Java 9, si ottiene questo quando si cerca di costruirlo:

    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. eseguirlo con Java 8:

    java X509 stackoverflow.crt.pem 
    

    In Java 9 - a causa per modulare JDK/JPMS - DataTypeConverter non è in java.base, ma java.xml.legare, quindi è necessario dipendono esplicitamente da esso durante l'esecuzione del programma:

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

    In caso contrario, su Java 9, si ottiene questo quando si tenta di eseguirlo:

    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. Prendi il previsto uscita:

    47adb03649a2eb18f63ffa29790818349a99cab7 
    
+5

Grazie per la risposta! Cercando su Google ho scoperto che l'identificazione personale è comunemente usata come identificatore univoco per un certificato, quindi non sembra essere specifica di .NET. Il servizio web che sto chiamando lo sta usando per trovare il certificato nel loro negozio. –

+0

Il servizio Web deve essere un server .NET. Non ho visto nessun altro server che utilizza l'identificazione personale per archiviare il certificato cliente. .NET ha creato così tante estensioni relative alla sicurezza, potresti incontrare anche altri problemi. A meno che il tuo client non abbia bisogno di essere multipiattaforma, sarebbe molto più facile scrivere client in .NET. –

+10

Le thumbprint non sono .Net esclusivo. Hai provato a connetterti a un server usando SSH a cui non ti sei mai connesso? Vedrai la sua impronta digitale. Anche l'archivio certificati includerà le impronte digitali. – Henrik

5

È possibile generare l'identificazione personale utilizzando il comando openssl, quindi ad esempio se avete il formato PEM del certificato in un file (file.txt)

poi:

cat file.txt | openssl x509 -sha1 -fingerprint - si realizzerebbe la stessa identificazione personale

+3

In che modo questo aiuta con Java? – Hiro2k

-9

Ecco un modo più semplice:

using System.Security.Cryptography.X509Certificates;  

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

Non è Java :-) So che è facile entrare in .NET –

36

Usando Apache Commons Codec puoi fare:

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

nice one-liner! – user882209

1

One-liner con G Guava

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

Per completezza - comunemente SHA-1 ('Hashing.sha1()') viene usato come identificazione personale (come visto nelle altre risposte). –

Problemi correlati