4

I got a string represents PEM certificate:

-----BEGIN CERTIFICATE-----
MIICUTCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADBXMQswCQYDVQQGEwJDTjEL
MAkGA1UECBMCUE4xCzAJBgNVBAcTAkNOMQswCQYDVQQKEwJPTjELMAkGA1UECxMC
VU4xFDASBgNVBAMTC0hlcm9uZyBZYW5nMB4XDTA1MDcxNTIxMTk0N1oXDTA1MDgx
NDIxMTk0N1owVzELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAlBOMQswCQYDVQQHEwJD
TjELMAkGA1UEChMCT04xCzAJBgNVBAsTAlVOMRQwEgYDVQQDEwtIZXJvbmcgWWFu
ZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCp5hnG7ogBhtlynpOS21cBewKE/B7j
V14qeyslnr26xZUsSVko36ZnhiaO/zbMOoRcKK9vEcgMtcLFuQTWDl3RAgMBAAGj
gbEwga4wHQYDVR0OBBYEFFXI70krXeQDxZgbaCQoR4jUDncEMH8GA1UdIwR4MHaA
FFXI70krXeQDxZgbaCQoR4jUDncEoVukWTBXMQswCQYDVQQGEwJDTjELMAkGA1UE
CBMCUE4xCzAJBgNVBAcTAkNOMQswCQYDVQQKEwJPTjELMAkGA1UECxMCVU4xFDAS
BgNVBAMTC0hlcm9uZyBZYW5nggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEE
BQADQQA/ugzBrjjK9jcWnDVfGHlk3icNRq0oV7Ri32z/+HQX67aRfgZu7KWdI+Ju
Wm7DCfrPNGVwFWUQOmsPue9rZBgO
-----END CERTIFICATE-----

I assigned the above string to String variable String myCertStr.

What is the proper way to convert myCertStr to DER encoded byte[]?

(I am using Java 7, and I am not interested to use 3rd party library for this, I am seeking for a JDK7 way of doing it.)

Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • would you mind to update your certificate body (Base64) to match the header (i.e. to a full certificate, not just an RSA public key), as otherwise, it can be rather confusing for those who stumble upon this question and decide to experiment with it. – zeppelin Nov 06 '16 at 18:39
  • The certificate text still looks a broken to me, due to that column of "..". – zeppelin Nov 07 '16 at 11:11
  • @zeppelin, I updated it, please have a look, thanks ! – Leem.fin Nov 09 '16 at 18:36
  • Looks good now ! I've been able to decode this certificate with both CertificateFactory, Base64 and ASN.1 Decoder w/o any issues. Have you succeeded with doing that in your environment ? – zeppelin Nov 09 '16 at 21:40

1 Answers1

4

IMPORTANT

As @dave_thompson_085 has pointed out in the comments, SunJCE CertificateFactory is indeed capable of parsing PEM files.

So you can just use that to get the Certificate object as detailed at How to load public certificate from pem file..? (which is an earlier answer by @dave on the same topic, so please upvote it, instead of this one, if you find this useful !), and then access its encoded (DER) form.

However, if your PEM file is a raw "RSA PUBLIC KEY" (like the one that was attached to this question), or some other entity which SunJCE implementation can not parse directly, you can still parse and decode it manually, as detailed below.


Technically what you have here is not a certificate, but just a public key.

You can decode it to DER bytes as simple as that:

byte[] derBytes = Base64.getDecoder().decode(
    pemText.replaceAll("-----(BEGIN|END) RSA PUBLIC KEY-----", "").replaceAll("\n", "")
);

Note, that what you will get will be a raw RSA (PKCS#1) key:

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e
}

You can use the same technique to decode X.509 certificates or private keys.

E.g. the code to decode the X.509 certificate:

byte[] certificateBytes = Base64.getDecoder().decode(
    pemText.replaceAll("-----(BEGIN|END) CERTIFICATE-----", "").replaceAll("\n", "").getBytes("UTF-8")
);

CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    X509Certificate certificate = (X509Certificate)(certificateFactory.generateCertificate(
        new ByteArrayInputStream(certificateBytes)
    )
);

UPDATE

The code above uses Java 8 Base64 decoder. As question has been updated asking for a Java 7 solution, here is a link to an excellent thread, discussing various options available: Base64 Java encode and decode a string.

E.g. java.xml.bind method described there does not require any extra libraries on Java 7 (which seems to match what OP wants)

Community
  • 1
  • 1
zeppelin
  • 8,947
  • 2
  • 24
  • 30
  • >Sorry, I corrected it to certificate Hmm, if what you have is a public key (which seems to be the case), you can not convert it to certificate by simply changing the header, as certificate is more than just a public key (it also includes the subject, signature e.t.c.) – zeppelin Nov 05 '16 at 21:45
  • No, I mean I have a certificate not public key, I just mistakenly copy pasted another public key to my question, but I do have a certificate. Please forget about public key. – Leem.fin Nov 06 '16 at 07:20
  • But this needs Java 8, I mean the Base64 class. My project is based on Java 7. I am not interested in 3rd party library. This is not the answer I need. But thanks. – Leem.fin Nov 06 '16 at 13:13
  • AFAIK there is no ready to use PEM parser provided with JDK, so you will have to decode Base64 this way or another (or use some security framework, which will parse PEM for you). In Java 7 you may use Google Guava or Jakarta Commons Base64 decoder, or just copy some Base64 implementation into your code if you really can not afford using a library. – zeppelin Nov 06 '16 at 14:21
  • `CertificateFactory` handles either DER or PEM input, since at least Java 6 (oldest I can check). 7 up even handles PEM with 'comments' (text before the dases-BEGIN line) that OpenSSL likes to create. But that creates a `Certificate` object, not a DER-encoded `byte[]` as asked -- although you can convert back with `.getEncoded()`. – dave_thompson_085 Nov 06 '16 at 16:56
  • @dave_thompson_085 It is true, thanks for pointing this out ! My guess is that this is just what OP wants. However, there is still no public PEM Parser API, so if you want to parse something like "RSA PUBLIC KEY" (which was an original sample attached to this question), you still have to do it manually. (Please correct me if I'm wrong on this !). – zeppelin Nov 06 '16 at 18:19
  • I saw your update to your answer, and the link "how to load public certificate from PEM" but I still don't get how to convert my PEM certificate string to DER byte array??? Can you please be more specific? – Leem.fin Nov 07 '16 at 09:38
  • Since I am developing an Android project, I can use this Base64 class https://developer.android.com/reference/android/util/Base64.html#decode(byte[],%20int) , I tried your code (with slight changes to fits this class requirement), but the `decode` function needs a flag as parameter, I tried `DEFAULT` flag, however, it seems the final byte array is not DER format. Could you please provide a code snippet which uses this Base64 class from Android? – Leem.fin Nov 07 '16 at 09:47
  • AFAIK Android CertificateFactory does support PEM too (https://developer.android.com/reference/java/security/cert/CertificateFactory.html), so you can still apply @dave's method: `byte derBytes = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(myCertStr.getBytes())).getEncoded();` Regarding the Base64 issue, the DEFAULT flag should do, you can try to run your data through the ASN.1 decoder at https://holtstrom.com/michael/tools/asn1decoder.php, to see if they are correct (it will accept your Base64 string as an input) – zeppelin Nov 07 '16 at 11:15