Home > Uncategorized > Reading X.509 Certificate in Java: How to Handle Format Issue

Reading X.509 Certificate in Java: How to Handle Format Issue

March 16th, 2014 Leave a comment Go to comments

I got into a very interesting problem while writing code to read a X.509 certificate. It’s a standard PEM encoded certificate (shown below) as you would find anywhere else.

-----BEGIN CERTIFICATE-----IBAgIJAKMIIDRTCCAi2gAwlwrFcAdHQtMA0GCSqGSIb3DQEBBQUAMCAxHjAcBgNVBAMTFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjAeFw0xNDAyMjExMzM4NTBaFw0yNDAyMTkxMzM4NTBaMCAxHjAcBgNVBAMTFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPFUHIMCZdvngHxBhSPf2LezpXTzQ7cOsfv2G0xVBJjkYKfffLxKmm0S3/ZEeGoXz1x/kQUoohYMf4ormOZwO+XL/9aVvj569t8siykGa0u15vAl2JASbHdGtzccD7V/3sz9rW5lLGq+ZsdU4n9r0opwSwlr6dSkWmv2OC8joSxwGWVbZREWi5j0vf/F76WjTSNHIruJpeST476UFBVrh633cwRoJoyDkuvM2lpze1WGBLKqk/kmGcnpBsjdDLGDKHgxlou3BstBjuq6nYaFAV1zHCc9SyM0KmZs8UJ5TX/3vnpxCyCMbcz9mGYU8Z+6eKVLG3xT7iWQsf1JZZMVwPUCAwEAAaOBgTB/MB0GA1UdDgQWBBRQc0tKrMgUvO6ne29Yfvp7U/28iDBQBgNVHSMESTBHgBRQc0tKrMgUvO6ne29Yfvp7U/28iKEkpCIwIDEeMBwGA1UEAxMVbG9jYWxob3N0LmxvY2FsZG9tYWluggkAqXCsVwB0dC0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAVn+5vniECIvs4IdW+Ix556daxP7mu7Xu1AoUxtMCXkwGovkuQvguabd+WAV2nQKVEdCC9b61mGQAueCHWaONGV2ZkMIHh5uoheiX8QAkbxjYijXlqS7bPbFW9faF8icrXg1rKuRTW/rt7WVL7FER/88zU65b5HCzyXfRrb48E4xBBpSc/QE/zgtHWqxeFG/+FJvJBRlXtxDZRWbLCy0HhZf0SvcPoQ1JqHI0lJC43RQzXrfo9GGVS34wb7Pi+6lYHVnh71zfypXXDrfzKzEJM+zwri6KX+BpSMV9pMqgqeew+Bp95+uKYTY4bnOixW/3X80t+2zMnJqPJ62UhHuKzw==-----END CERTIFICATE-----

Time to learn how to "Google" and manage your VMware and clouds in a fast and secure

HTML5 App

The exception is as follows. It’s pretty clear, but also confusing because the certificate string has included both BEGIN and END. It seems to me very complete. Of course, the program does not lie and we have to trust it most of the time unless there is a bug.

java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Incomplete data
	at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:104)
	at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
...

I understand there could be special characters that cannot be displayed in a normal editor. So I used HEX viewer in Notepad++ to check the string and didn’t find much unusual. Instead of further guessing, I decided to search for the source code of the X509Factory.java and see what is taken as incomplete by the API.

Quite luckily, I found the following code at github (full source is here)

            // Read BASE64 encoded data, might skip info at the beginning
            char[] data = new char[2048];
            int pos = 0;
 
            // Step 1: Read until header is found
            int hyphen = (c=='-') ? 1: 0; // count of consequent hyphens
            int last = (c=='-') ? -1: c; // the char before hyphen
            while (true) {
                int next = is.read();
                if (next == -1) {
                    // We accept useless data after the last block,
                    // say, empty lines.
                    return null;
                }
                if (next == '-') {
                    hyphen++;
                } else {
                    hyphen = 0;
                    last = next;
                }
                if (hyphen == 5 && (last==-1 || last=='\r' || last=='\n')) {
                    break;
                }
            }
 
            // Step 2: Read the rest of header, determine the line end
            int end;
            StringBuffer header = new StringBuffer("-----");
            while (true) {
                int next = is.read();
                if (next == -1) {
                    throw new IOException("Incomplete data");
                }

With the source code, it becomes quite clear that the API expects the certificate to have CR or/and LF after the begin mark. In other words, the certificate must have two lines. But my certificate string does not have CR or LF after the begin mark, therefore it continues to look for data with no luck.

The solution to the problem is pretty straight forward – just add one CR or LF (both are OK too, “\r\n” in Java and other languages) after the “—–BEGIN CERTIFICATE—–“.

If you read the string from some sources that do not have CRLF, you must insert one (which is a trivial work) to make the Java API happy.

Categories: Uncategorized Tags: , , ,
  1. Joe Bloe
    May 12th, 2015 at 17:55 | #1

    Thank you! There is no sign of this quirk in the official documentation for these APIs. Your post saved me a lot of time.

  2. May 12th, 2015 at 18:27 | #2

    Thanks for letting me know Joe,
    Glad you find it helpful.
    Steve

  3. bond
    August 16th, 2015 at 12:31 | #3

    Thanks a lot buddy.

  4. October 6th, 2015 at 15:12 | #4

    Now that’s an “interesting” feature. Spent quite some time on trying to figure out why my perfectly fine certificate string did not work with the CertificateFactory, before Google led me here. Thank you for your post!

  5. October 6th, 2015 at 17:43 | #5

    You are very welcome Erko, glad that it helped.

    -Steve

  6. laura
    October 26th, 2015 at 13:58 | #6

    you share the pem string, the error and the source code for the methods you used, would it be possible to see the actual code was trying to make the cert?

    public static X509Certificate fromStringToX509Certificate(String str) throws CertificateException {
    byte[] bytes =str.getBytes();
    CertificateFactory certFactory = CertificateFactory.getInstance(“X.509”);
    InputStream in = new ByteArrayInputStream(bytes);
    X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
    return cert;
    }

    I tried this with my own Pem encoded cert and got the error you described then put in the \r\n and started getting a different error. I threw your Pem encoded cert in (with \r\n) and got a new error , it would be great to see the code. thanks!

  7. Girma Mamuye
    June 6th, 2016 at 04:16 | #7

    Thank you very much, you saved my day!

  8. June 6th, 2016 at 17:55 | #8

    You are very welcome Girma, glad it helped.
    -Steve

  9. August 8th, 2016 at 12:44 | #9

    I am also facing java.io.IOException: Incomplete data, for actual cert content. Not sure how to solve it, since its not working when added CR or LF after BEGIN CERT as follows.
    -----BEGIN CERTIFICATE-----CR\r\n
    Is it possible to post complete cert data to test.

  10. August 23rd, 2016 at 13:03 | #10

    Hi Paramesh,

    It’s a while back and I could not find the cert file. You may want to generate one which is quite fast to do.

    -Steve

  11. Aleksandra
    September 20th, 2016 at 04:33 | #11

    Saved my day as will, good work! Keep it up.

  12. Pistol Pete
    December 13th, 2016 at 04:50 | #12

    Thanks man

  13. November 13th, 2017 at 12:12 | #13

    Oh my – thank you so much! Funnily enough, I did think to try that so I’d like to imagine that I would have got there in the end. Not sure I would have though!

  1. March 20th, 2014 at 00:02 | #1