2
votes

I read a bit about the known issue of transforming keys from PEM to DER so Java can read them, and I ran up this article. When followed through, this works OK - generated RSA key pair with openssl, keys are loaded fine, and what is encrypted with public key is successfully decoded with the private key.

Now, here's the unclear part.
Not so long ago, I generated PKI using Easy-RSA utility, while setting up OpenVPN server. Here, a self-signed cert was created. Output files, among others are:

server.csr ------ // certificate request
server.key ------// private key
server.crt -------// self-signed certificate/public-key/whatever this is..?

Just for the reference, easy-RSA is documented (on the bottom of the page are the scripts explained, and we can see openssl commands actually used in the process).

So, I tried the above logic on these files, using server.key as my private key file, and server.crt as my public key file, both previously transformed to Java-readable DER format:

openssl pkcs8 -topk8 -inform PEM -outform DER -in server.key -out server_private_key.der -nocrypt openssl x509 -inform PEM -outform DER -text -in server.crt -out server.der

Private key, not so strangely, works OK, i.e. it is successfully loaded in Java.
Public key (again, probably not so strangely) won't load, but I don't know the reason, since I'm not really familiar with all these things. My guess is that this has something to do with certificate being signed, and I wonder how to deal with this in those cases. I get the following exception:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException:IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
  at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:188)
  at java.security.KeyFactory.generatePublic(KeyFactory.java:304)
  at aes.utils.KeyReaderUtil.getPublicKeyFromFile(KeyReaderUtil.java:57)
  at aes.utils.Main.main(Main.java:69)
Caused by: java.security.InvalidKeyException: IOException: ObjectIdentifier() -- data
isn't an object ID (tag = -96)
  at sun.security.x509.X509Key.decode(X509Key.java:380)
  at sun.security.x509.X509Key.decode(X509Key.java:386)
  at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:66)
  at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:281)
  at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:184)
  ... 3 more

Furthermore, when I "export" the public key from the existing server.key private key file, like this (as in the above article):

openssl rsa -in server.key -pubout -outform DER -out server_public_key.der

it all works fine again.

So, my question is: what is the right way, and why server.crt won't load as public key ?

1

1 Answers

8
votes

The Java code in the article you linked is expecting a public key file, not an X509 Certificate, which is what you have in server.crt.

An X509 certificate contains the public key as well as identity information that is bound to that key via the signature.

From Java's X509Certificate documentation, you can find this code:

 InputStream inStream = null;
 try {
     inStream = new FileInputStream("fileName-of-cert");
     CertificateFactory cf = CertificateFactory.getInstance("X.509");
     X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
 } finally {
     if (inStream != null) {
         inStream.close();
     }
 }

And once you have an X509 certificate object, you can easily get the PublicKey like this:

PublicKey myPubKey = cert.getPublicKey();