Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retrieve/compute an X509 certificate's thumbprint in Java?

I have a java client that is calling a web service operation which takes a certificate "thumbprint" as a parameter. I believe the thumbprint is some kind of SHA1 hash, in hexadecimal string format, of the cert's public key, but I'm not sure.

The .NET framework seems to include a simple way to get this value (X509Certificate2.Thumbprint property). Viewing a .cer file's properties in Windows also displays the thumbprint, which looks like:

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

My question is therefore: Does anybody know how to retrieve or compute this thumbprint string within Java, if I have an instance of a java.security.cert.X509Certificate?

like image 836
Matt Z Avatar asked Aug 13 '09 08:08

Matt Z


People also ask

How do I find the thumbprint of a certificate?

Go to Tools > Internet Options. Click Content tab > Certificates. In the Certificates window, click on the tab for the certificate you want to examine (Personal, Other People, Intermediate Certification Authorities, Trusted Root Certification Authorities) Locate the certificate or root in the list.

What is X509Certificate in Java?

public abstract class X509Certificate extends Certificate. Abstract class for X. 509 v1 certificates. This provides a standard way to access all the version 1 attributes of an X.


1 Answers

The SHA-1 hash of the DER encoding of the certificate is what .NET is getting with X509Certificate2.Thumbprint.

As noted on the remarks on MSDN:

The thumbprint is dynamically generated using the SHA1 algorithm and does not physically exist in the certificate. Since the thumbprint is a unique value for the certificate, it is commonly used to find a particular certificate in a certificate store.

Java's standard library doesn't provide the thumbprint directly, but you can get it like this:

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

Here's a full worked example using a conveniently accessible PEM file:

  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. Create 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. Compile the program with Java 8:

    javac X509.java 

    Or Java 9 - due to modular JDK/JPMS - DataTypeConverter is not in java.base, but java.xml.bind, so you need to explicitly depend on it during your build:

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

    Otherwise, on Java 9, you get this when you try to build it:

    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. Run it with Java 8:

    java X509 stackoverflow.crt.pem 

    In Java 9 - due to modular JDK/JPMS - DataTypeConverter is not in java.base, but java.xml.bind, so you need to explicitly depend on it when running your program:

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

    Otherwise, on Java 9, you get this when you try to run it:

    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. Get the expected output:

    47adb03649a2eb18f63ffa29790818349a99cab7 
like image 111
ZZ Coder Avatar answered Sep 17 '22 17:09

ZZ Coder