2

Here's my code:

import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;

class LoadKey {
    public static void main(String[] args)
    throws InvalidKeySpecException, UnsupportedEncodingException, NoSuchAlgorithmException
    {
        String cert = "-----BEGIN CERTIFICATE-----\n" +
                      "MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM\n" +
                      "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n" +
                      "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x\n" +
                      "MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n" +
                      "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n" +
                      "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n" +
                      "gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy\n" +
                      "wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B\n" +
                      "d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM\n" +
                      "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n" +
                      "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n" +
                      "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n" +
                      "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n" +
                      "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n" +
                      "AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp\n" +
                      "ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le\n" +
                      "IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==\n" +
                      "-----END CERTIFICATE-----\n";
        System.out.println(cert);
        byte[] encodedCert = cert.getBytes();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedCert);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
    }
}

OpenSSL is able to decode the X509 cert via the command line so I know it's a valid cert. But Java doesn't seem to like it, all the same.

I've tired it with and without the trailing \n to no avail.

Any ideas?

neubert
  • 15,947
  • 24
  • 120
  • 212
  • you have a certificate as a PEM text, you get the bytes of that string in the default charset of your computer, you pass these bytes that have no relation to crypto stuff to *key*-related factory, and what exactly do you expect to happen? – Oleg Estekhin Dec 31 '15 at 16:23
  • Perhaps it's expecting an `\r\n`? Have you tried reading it from a file first? – Zymus Dec 31 '15 at 16:24
  • @OlegEstekhin - well `cert.getBytes("UTF-8")` doesn't help either. And how can you say that the bytes have no relation to crypto stuff when, as I said in my post, OpenSSL (`openssl x509 -in mycert.pem -noout -text`) can read those bytes just fine? If these bytes don't have any relation to crypto stuff than what sequence of bytes does? If Java just decided to throw out all the IETF RFCs and to make up it's own standards it's a pretty gosh darned useless language. – neubert Dec 31 '15 at 16:36
  • 2
    @neubert It didn't man, and it isn't. You're just missing a few things. PEM is encoded to Base64, you'll need to decode the string first. See the examples here http://stackoverflow.com/questions/11787571/how-to-read-pem-file-to-get-private-and-public-key – 11thdimension Dec 31 '15 at 16:49

1 Answers1

17

---Update

As mentioned by dave_thompson_085 in the comments, only thing wrong with OP's solution is that OP is using KeyFactory used for keys and not CertificateFactory used for certificates.

Here's the code without Base64 conversion as CertificateFactory can read PEM files itself (It looks for BEGIN/END CERTIFICATE blocks itself to know that it's reading PEM file).

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;


class LoadKey {
    public static void main(String[] args)
    throws Exception
    {
        String cert = "-----BEGIN CERTIFICATE-----\n" +
                      "MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM\n" +
                      "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n" +
                      "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x\n" +
                      "MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n" +
                      "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n" +
                      "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n" +
                      "gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy\n" +
                      "wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B\n" +
                      "d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM\n" +
                      "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n" +
                      "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n" +
                      "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n" +
                      "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n" +
                      "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n" +
                      "AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp\n" +
                      "ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le\n" +
                      "IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==\n" +
                      "-----END CERTIFICATE-----\n";

        System.out.println(cert);

        byte[] certBytes = cert.getBytes(java.nio.charset.StandardCharsets.UTF_8);

        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(certBytes);
        X509Certificate certificate = (X509Certificate)certFactory.generateCertificate(in);

        System.out.println("Subject DN : " + certificate.getSubjectDN().getName());
        System.out.println("Issuer : " + certificate.getIssuerDN().getName());
        System.out.println("Not After: " + certificate.getNotAfter());
        System.out.println("Not Before: " + certificate.getNotBefore());
        System.out.println("version: " + certificate.getVersion());
        System.out.println("serial number : " + certificate.getSerialNumber());

        PublicKey publicKey = certificate.getPublicKey();
        System.out.println("PublicKey : \n" + publicKey);
    }
}

You were missing the base64 decoding part. See the comment above

Here's working code, you'll need Apache Commons Codec library for Base64 class.

Note: Check the code above, base64 steps above are done automatically by CertificateFactory, there's no need to do it manually.

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import org.apache.commons.codec.binary.Base64;

class LoadKey {
    public static void main(String[] args)
    throws Exception
    {
        String cert = "-----BEGIN CERTIFICATE-----\n" +
                      "MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM\n" +
                      "MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg\n" +
                      "THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x\n" +
                      "MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n" +
                      "MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw\n" +
                      "FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n" +
                      "gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy\n" +
                      "wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B\n" +
                      "d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM\n" +
                      "BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl\n" +
                      "LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF\n" +
                      "BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw\n" +
                      "Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0\n" +
                      "ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF\n" +
                      "AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp\n" +
                      "ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le\n" +
                      "IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==\n" +
                      "-----END CERTIFICATE-----\n";

        cert = cert.replace("-----BEGIN CERTIFICATE-----\n", "");
        cert = cert.replace("-----END CERTIFICATE-----\n", "");
        System.out.println(cert);

        byte[] encodedCert = cert.getBytes("UTF-8");
        byte[] decodedCert = Base64.decodeBase64(encodedCert);
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(decodedCert);
        X509Certificate certificate = (X509Certificate)certFactory.generateCertificate(in);

        System.out.println("Subject DN : " + certificate.getSubjectDN().getName());
        System.out.println("Issuer : " + certificate.getIssuerDN().getName());
        System.out.println("Not After: " + certificate.getNotAfter());
        System.out.println("Not Before: " + certificate.getNotBefore());
        System.out.println("version: " + certificate.getVersion());
        System.out.println("serial number : " + certificate.getSerialNumber());

        PublicKey publicKey = certificate.getPublicKey();
        System.out.println("PublicKey : \n" + publicKey);
    }
}

Output

MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM
MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x
MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy
wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B
d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM
BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp
ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le
IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==

Subject DN : CN=www.google.com, O=Google Inc, L=Mountain View, ST=California, C=US
Issuer : CN=Thawte SGC CA, O=Thawte Consulting (Pty) Ltd., C=ZA
Not After: Mon Sep 30 19:59:59 EDT 2013
Not Before: Tue Oct 25 20:00:00 EDT 2011
version: 3
serial number : 105827261859531100510423749949966875981
PublicKey : 
Sun RSA public key, 1024 bits
  modulus: 156396091895984667473837837332877995558144703880815901117439532534031286131520903863087599986938779606924811933611903716377206837300122262900786662124968110191717844999183338594373129421417536020806373385428322642107305024162536996222164292639147591878860587271770855626780464602884552232097424473091745159379
  public exponent: 65537
11thdimension
  • 10,333
  • 4
  • 33
  • 71
  • 3
    With Java 8 you can also use `java.util.Base64().getDecoder().decode()` to avoid Apache commons dependency – ChocolateAndCheese Jul 12 '18 at 17:39
  • 1
    Actually the OP's only problem, which you changed without saying so, was using `KeyFactory` instead of `CertificateFactory` for a certificate. `CertificateFactory` _can_ read either PEM or DER, so you don't need to decode at all, and thus didn't need commons _or_ j8: just pass the (PEM) data as a stream. – dave_thompson_085 May 01 '20 at 20:01