Search code examples
openssljwt

Convert public key (.pem) to a JWK


I have created a private/public key pair using openssl but I need to convert the public key, to a JWK.

Can I do this via openssl? or is it safe enough to do via an online converter?

This is only for testing purposes at the moment but I will need to do it for production at some point and using an online converter doesn't seem very safe for production.


Solution

  • Using online converter. The possible dangers are:

    1. malicious site substitutes their publickey for yours, in an attempt to trick you into accepting their (false) signatures or encrypting data they can read. To prevent this, just test the returned publickey before using it for production: it should verify a signature made with your privatekey or encrypt data that decrypts with your privatekey. For all asymmetric algorithms supported by JWK (and JOSE), if it works with your privatekey it doesn't work with any adversary privatekey.

    2. site becomes unavailable, either accidentally (server crash, network problem) or intentionally (sponsor ceases operation, or changes policy to make it unusable for you such as charging high fees). There isn't really any guarantee against this except the belief that the Internet is so "really really big" (like Doug Adams' space) that there will always be someone somewhere offering what you need.

    In case you thought disclosure of the publickey to the site or even to others on the network like your ISP is a danger, it isn't. The whole point of and reason for publickey cryptography is that a publickey can be known to anyone and everyone including even adversaries.

    However, this is not programming or development and is offtopic for SO.

    Doing it yourself. Generating Public Key from JWK gives you the second half -- if you have a key in Java's internal format (a JCA object) that nimbusds library can export it to JWK. (It can similarly import from JWK to JCA, but you don't need that. And it handles either public or private keys.) For the first half, reading from an OpenSSL file to JCA, it depends on which of the many OpenSSL formats you use(d), which your Q didn't specify or describe.

    If you use openssl to create a certificate containing the publickey, in either PEM or 'DER' (binary) format, Java's CertificateFactory can read that; see the javadoc. (What Java describes clumsily as base64 bounded by -----BEGIN/END CERTIFICATE----- lines is what OpenSSL and nearly everybody else in the world calls PEM.)

    If you use openssl to create a separate pubkey DER file with any of

    openssl rsa -in privrsa.pem -pubout -outform der -out pub.der 
    openssl ec -in privec.pem -pubout -outform der -out pub.der
    openssl pkey -in priv.pem -pubout -outform der -out pub.der
    

    (or a program that calls any i2d_*PUBKEY* API), Java can handle that directly with X509EncodedKeySpec containing the contents of the file (read as bytes not chars, e.g. java.nio.file.Files#readAllBytes) passed to .generatePublic on a KeyFactory for the relevant algorithm ("RSA" or "EC"); see the respective javadocs.

    If you use openssl to create a separate PEM file, such as the above with -outform der omitted, you need to handle the PEM part yourself, but it isn't hard: read the file, remove the -----(BEGIN|END) PUBLIC KEY----- lines, and base64-decode the rest except the linebreaks -- either remove the linebreaks and then decode, or use java.lang.Base64.getMimeDecoder() which ignores the linebreaks while decoding. Then proceed as for DER above. Alternatively if you have/get the third-party libraries from https://www.bouncycastle.org they can handle this format directly -- search for many existing Qs using PEMParser and JcaPEMKeyConverter -- but I consider Bouncy overkill for this case which is one of the simplest.

    If you use openssl to create (only) a privatekey file, it actually contains the information needed to create the publickey, but using it may be harder. First of all there are at least 7 and sometimes more formats OpenSSL can use, only 2 of which Java can easily read, and even if you can read it converting to public is easy for RSA (because OpenSSL uses the CRT-form key defined by PKCS1, and JCA also supports this) but hard for EC. Because the range of possibilities here is much larger and more complicated, I'm not going to try to cover it unless you specify that you need it, and exactly which part(s) of it.