7 Replies Latest reply: Jul 27, 2011 2:28 PM by safarmer RSS

    "Invalid DER-encoded certificate data" while loading KeyStore

    843811
      Hello,

      Using JDK 1.6.0_20 on WinXP, I am attempting to create a KeyStore object containing a single trusted certificate, but keep running into the following error when running the program:

      java.security.cert.CertificateParsingException: invalid DER-encoded certificate data

      I have tested several different root certificates (e.g. Verisign Class 3) to populate the keystore, and both keytool and OpenSSL seem to recognize them as DER-encoded and handle them fine. Keytool importcert and verbose list commands work fine, as does an OpenSSL list (openssl x509 -text -noout -inform DER -in certificate.cer).

      I originally was using the sample code from the KeyStore API almost verbatim to attempt to load the KeyStore contents from a keystore file, just replacing a couple of placeholder items with command-line args:
      try
              {
                  // Create/load the keystore to use in the PKIXParameters
                  KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
      
                  // get user password and file input stream
                  char[] password = args[1].toCharArray();
      
                  FileInputStream fis = null;
                  try {
                      fis = new FileInputStream(args[0]);
                      ks.load(fis, password);            }
                  finally {
                      if (fis != null) {
                          fis.close();
                      }
                  }
      I also tested loading an empty keystore and then adding the certificate within the code:
      try
              {
                  CertificateFactory cf = CertificateFactory.getInstance("X.509");
      
                  // Create/load the keystore to use in the PKIXParameters
                  KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
      
                  // get user password and file input stream
                  char[] password = args[1].toCharArray();
      
                  FileInputStream fis = null;
                  try {
                      ks.load(fis, password);
      
                      FileInputStream trustedCertStream = new FileInputStream(args[0]);
                      X509Certificate trustedCert = (X509Certificate) cf.generateCertificate(trustedCertStream);
      
                      ks.setCertificateEntry("trustroot",trustedCert);
                  }
                  finally {
                      if (fis != null) {
                          fis.close();
                      }
                  }
      Both code blocks give me that same "invalid DER-encoded certificate data" error.

      If I just load a null FileInputStream, the code continues along fine until the point where you'd expect it to fail (when it's looking for trust anchors in the keystore and there are none).

      To rule out issues with the command-line args being passed in, I tested passing a bogus keystore file (
      yielding a FileNotFound error as expected), a straight X.509 cert to the code expecting a keystore file (got an IOException - Invalid keystore format - as expected), and an incorrect password (“There was an error parsing the truststore file: java.io.IOException: Keystore was tampered with, or password was incorrect” - as expected).

      Any ideas what could be causing this error and/or how to fix it?

      Thanks,

      Julia
        • 1. Re: "Invalid DER-encoded certificate data" while loading KeyStore
          EJP
          I am attempting to create a KeyStore object containing a single trusted certificate,
          Why? It should contain all the root certs shipped in the JDK trustore plus the one you want to add.

          If you got that error in the first block you must be trying to load the certificate file as a keystore. It isn't.

          In the second block there must be something wrong with the certificate you are loading.
          • 2. Re: "Invalid DER-encoded certificate data" while loading KeyStore
            843811
            ".cer" files are not simple X509 certificates or key stores. Possible approaches -

            1) Since you can read it with openssl, use openssl to convert it to an x509 file certificate.
            2) Try to load the file using 'keytool' .
            3) Since it only contains a public key, post it here (I would expect it to already be base64 encoded) then forum members can investigate. If you do so then please enclose it in \
            \
            tags because the forum markup can 'interpret' some of the base64 characters.
            • 3. Re: "Invalid DER-encoded certificate data" while loading KeyStore
              843811
              ejp -
              It should contain all the root certs shipped in the JDK trustore plus the one you want to add.
              That's not actually true - just because Sun includes a standard list of common PKI roots in the default cacerts truststore for convenience does not mean you always want to trust all of the PKIs they include in that store. For example, many corporations run their own PKIs. If they're running Java-based servers (Tomcat, Weblogic, WebSphere, etc) and using certificate-based authentication, they don't want to let just any Joe off the street who went out and bought a Verisign cert authenticate to their app with his certificate by treating the full contents of the cacerts keystore as their truststore. They would only want to trust their own PKI's root (which they would probably implement by creating a new custom keystore containing just their own root as a trusted certificate).
              If you got that error in the first block you must be trying to load the certificate file as a keystore. It isn't.
              I assure you that I am aware that a certificate file and a keystore are not the same thing, and was passing (as I initially indicated) a keystore file as args[0] to the first implementation, and a certificate file to the second implementation.

              The keytool listing for (for example) the keystore containing the Verisign root cert is:
              keytool -list -v -keystore verisign.jks
              Enter keystore password:
              
              Keystore type: JKS
              Keystore provider: SUN
              
              Your keystore contains 1 entry
              
              Alias name: verisign_class3
              Creation date: May 12, 2010
              Entry type: trustedCertEntry
              
              Owner: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized u
              se only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign, I
              nc.", C=US
              Issuer: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized
              use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,
              Inc.", C=US
              Serial number: 7dd9fe07cfa81eb7107967fba78934c6
              Valid from: Sun May 17 20:00:00 EDT 1998 until: Tue Aug 01 19:59:59 EDT 2028
              Certificate fingerprints:
                       MD5:  A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9
                       SHA1: 85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F
                       Signature algorithm name: SHA1withRSA
                       Version: 1
              
              
              *******************************************
              *******************************************
              sabre150 -
              ".cer" files are not simple X509 certificates or key stores. Possible approaches -
              
              1) Since you can read it with openssl, use openssl to convert it to an x509 file certificate.
              2) Try to load the file using 'keytool' . 
              3) Since it only contains a public key, post it here (I would expect it to already be base64 encoded) then forum members can investigate.
              Keytool both imports and lists the certificate fine, as I indicated in my initial post. The fact that the openssl x509 command works on the certificate file also suggests that the certificate is in fact an X509 certificate.

              Here is the openssl listing for the Verisign cert:
              openssl.exe x509 -text -noout -inform DER -in verisign_class3.cer
              
              Certificate:
                  Data:
                      Version: 1 (0x0)
                      Serial Number:
                          7d:d9:fe:07:cf:a8:1e:b7:10:79:67:fb:a7:89:34:c6
                      Signature Algorithm: sha1WithRSAEncryption
                      Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification
              Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSig
              n Trust Network
                      Validity
                          Not Before: May 18 00:00:00 1998 GMT
                          Not After : Aug  1 23:59:59 2028 GMT
                      Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification
               Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSi
              gn Trust Network
                      Subject Public Key Info:
                          Public Key Algorithm: rsaEncryption
                          RSA Public Key: (1024 bit)
                              Modulus (1024 bit):
                                  00:cc:5e:d1:11:5d:5c:69:d0:ab:d3:b9:6a:4c:99:
                                  1f:59:98:30:8e:16:85:20:46:6d:47:3f:d4:85:20:
                                  84:e1:6d:b3:f8:a4:ed:0c:f1:17:0f:3b:f9:a7:f9:
                                  25:d7:c1:cf:84:63:f2:7c:63:cf:a2:47:f2:c6:5b:
                                  33:8e:64:40:04:68:c1:80:b9:64:1c:45:77:c7:d8:
                                  6e:f5:95:29:3c:50:e8:34:d7:78:1f:a8:ba:6d:43:
                                  91:95:8f:45:57:5e:7e:c5:fb:ca:a4:04:eb:ea:97:
                                  37:54:30:6f:bb:01:47:32:33:cd:dc:57:9b:64:69:
                                  61:f8:9b:1d:1c:89:4f:5c:67
                              Exponent: 65537 (0x10001)
                  Signature Algorithm: sha1WithRSAEncryption
                      51:4d:cd:be:5c:cb:98:19:9c:15:b2:01:39:78:2e:4d:0f:67:
                      70:70:99:c6:10:5a:94:a4:53:4d:54:6d:2b:af:0d:5d:40:8b:
                      64:d3:d7:ee:de:56:61:92:5f:a6:c4:1d:10:61:36:d3:2c:27:
                      3c:e8:29:09:b9:11:64:74:cc:b5:73:9f:1c:48:a9:bc:61:01:
                      ee:e2:17:a6:0c:e3:40:08:3b:0e:e7:eb:44:73:2a:9a:f1:69:
                      92:ef:71:14:c3:39:ac:71:a7:91:09:6f:e4:71:06:b3:ba:59:
                      57:26:79:00:f6:f8:0d:a2:33:30:28:d4:aa:58:a0:9d:9d:69:
                      91:fd
              The cert is in DER format (as I understand is required for the KeyStore load), not PEM (Base64). However, when converted to PEM via OpenSSL, the cert blob is:
              -----BEGIN CERTIFICATE-----
              MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
              BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
              c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
              MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
              emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
              DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
              FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
              UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
              YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
              MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
              AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
              pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
              13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
              AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
              U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
              F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
              oJ2daZH9
              -----END CERTIFICATE-----
              As always, any ideas as to what could be causing the issue are appreciated.
              • 4. Re: "Invalid DER-encoded certificate data" while loading KeyStore
                843811
                Sorry, I misread the OP so misunderstood the problem. I don't know whether or not I still misunderstand the problem but the following code reads the PEM file you posted into a keystore and lists the store content. I lashed this code together from a couple of my examples and have not refined it. If any of the code is of any use then you can extract the bits you want and refine them. If you use the DER file directly then you can get rid of my code to convert pem to der and you won't need the method that fully reads a file. Best of luck.
                import java.io.ByteArrayInputStream;
                import java.io.DataInputStream;
                import java.io.IOException;
                import me.grm.library.codec.Base64Decoder;
                
                import java.io.File;
                import java.io.FileInputStream;
                import java.io.FileOutputStream;
                import java.io.InputStream;
                import java.io.OutputStream;
                import java.security.KeyStore;
                import java.security.cert.CertificateFactory;
                import java.security.cert.X509Certificate;
                import java.security.interfaces.RSAPublicKey;
                import java.util.Enumeration;
                
                public class Sabre20100513
                {
                    static final Base64Decoder base64Decoder = new Base64Decoder();
                
                    private static byte[] fullyReadFile(final File file) throws IOException
                    {
                        final DataInputStream dis = new DataInputStream(new FileInputStream(file));
                        final byte[] bytes = new byte[(int) file.length()];
                        dis.readFully(bytes);
                        dis.close();
                        return bytes;
                    }
                
                    static private byte[] pemToDer(byte[] pemBytes) throws IOException
                    {
                        pemBytes = pemBytes.clone();
                        int oIndex = 0;
                        int iIndex = 0;
                        while (pemBytes[iIndex] == '-')
                            iIndex++;
                        while (pemBytes[iIndex] != '-')
                            iIndex++;
                        while (pemBytes[iIndex] == '-')
                            iIndex++;
                        while (pemBytes[iIndex] != '-')
                        {
                            if ((pemBytes[iIndex] == '\r') || (pemBytes[iIndex] == '\n') || (pemBytes[iIndex] == ' ') || (pemBytes[iIndex] == '\t'))
                                iIndex++;
                            else
                                pemBytes[oIndex++] = pemBytes[iIndex++];
                        }
                
                        return base64Decoder.decode(pemBytes, 0, oIndex);
                    }
                
                    public static void main(String[] args) throws Exception
                    {
                        File publicKeyFilePEM = new File(System.getProperty("user.home") + "/certificate.pem");
                        File keystoreFile = new File(System.getProperty("user.home") + "/keystore");
                        byte[] pem = fullyReadFile(publicKeyFilePEM);
                        System.out.write(pem);
                        byte[] der = pemToDer(pem);
                        InputStream trustedCertStream = new ByteArrayInputStream(der);
                        CertificateFactory cf = CertificateFactory.getInstance("X.509");
                
                        X509Certificate trustedCert = (X509Certificate) cf.generateCertificate(trustedCertStream);
                        trustedCert.checkValidity();
                        RSAPublicKey pk = (RSAPublicKey) trustedCert.getPublicKey();
                        System.out.println("Modulus  : " + pk.getModulus());
                        System.out.println("Exponent : " + pk.getPublicExponent());
                        char[] password = "password".toCharArray();
                        {
                            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
                            ks.load(null);
                            ks.setCertificateEntry("fred", trustedCert);
                
                            OutputStream os = new FileOutputStream(keystoreFile);
                            ks.store(os, password);
                            os.close();
                        }
                        {
                            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
                            InputStream is = new FileInputStream(keystoreFile);
                            ks.load(is, password);
                            is.close();
                
                            System.out.println("Type\t: " + ks.getType());
                            for (Enumeration<String> en = ks.aliases(); en.hasMoreElements();)
                            {
                                final String alias = en.nextElement();
                                System.out.println("  Alias\t:" + alias);
                                KeyStore.Entry entry = null;
                                try
                                {
                                    entry = ks.getEntry(alias, new KeyStore.PasswordProtection(password));
                                } catch (UnsupportedOperationException e)
                                {
                                    entry = ks.getEntry(alias, null);
                                }
                                if (entry instanceof KeyStore.TrustedCertificateEntry)
                                {
                                    System.out.println("    Certificate");
                                    final KeyStore.TrustedCertificateEntry certEntry = (KeyStore.TrustedCertificateEntry) entry;
                                    final java.security.cert.Certificate certificate = certEntry.getTrustedCertificate();
                                    System.out.println("      type\t: " + certificate.getType());
                                    System.out.println("      Public key\t: " + certificate.getPublicKey().getAlgorithm());
                                }
                            }
                        }
                
                    }
                }
                Edited by: sabre150 on May 13, 2010 9:21 PM
                • 5. Re: "Invalid DER-encoded certificate data" while loading KeyStore
                  843811
                  I've resolved the issue and have to call a "my bad" on this one - the error was actually being thrown by an X509CertPath constructor call further down in the code, and since NetBeans wasn't yelling at me for not coding a CertificateException catch/throw for that line, I didn't consider that it could be coming from there. The keystore was in fact loading fine.

                  Thanks for looking, and sorry about the misdirection.
                  • 6. Re: "Invalid DER-encoded certificate data" while loading KeyStore
                    343303
                    Where can I find the classes:
                    me.grm.library.codec.Base64Decoder
                    and me.grm.library.codec.Base64Encoder

                    Have they been replaced by some other classes?

                    Janeen

                    Edited by: janeenmj on Jul 27, 2011 12:23 PM
                    • 7. Re: "Invalid DER-encoded certificate data" while loading KeyStore
                      safarmer
                      Hi,

                      This is an old thread from the Sun forums so the OP will not reply to this.

                      I am not sure what library that class comes from, but there are many Base64 implementations out the (BouncyCastle, MiGBase64 etc) that you can use to achieve the same result.

                      Cheers,
                      Shane