Chris
Chris

Reputation: 389

Sign a JWT with a SHA cert using jose4j

New to using jose4j. I have found examples like this to set private key from cert:

JsonWebSignature jws = new JsonWebSignature();
PKCS8EncodedKeySpec spec =
new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pk = kf.generatePrivate(spec);
jws.setKey(kf.generatePrivate(spec));

But I get this error message

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format    

I think it is because the cert was created as SHA256 instead of RSA. Here is how I was told the cert was created:

openssl req -x509 -sha256 -nodes -days 730 -newkey rsa:2048 -keyout private.key -out certificate_pub.crt

Does anyone have any examples of how I could sign JWT with a SHA256 cert?

Upvotes: 2

Views: 1659

Answers (1)

dave_thompson_085
dave_thompson_085

Reputation: 38771

With additional info, that private key file is PEM but NOT PKCS#8, as a modern version of OpenSSL should have created for req -newkey. And the difference between PEM and "DER" (binary) which standard Java requires is not just removing (and adding) the BEGIN and END lines.

Your simplest solution if OpenSSL is available is to convert both of these, without encrypting:

openssl pkcs8 -topk8 -nocrypt -outform der -in private.pem -out good.der 

Then read good.der (use better name if you like) as bytes, and put that in PKCS8EncodedKeySpec and use it as you posted. Aside: you don't need to fiddle with DataInputStream, which isn't really intended for "plain old" bytes; java.nio.file.Files.readAllBytes can open, allocate, and read for you.

The next more complicated alternative is to convert to PKCS#8 but still PEM: same as about but omit -outform der (and use a file name that indicates PEM, to avoid confusion). Then in Java read that file as characters (with a Reader, usually BufferedReader, not a Stream), discard the BEGIN and END lines, concatenate all the lines between, and convert them from base64 to byte[]: in Java8 you have java.util.Base64, before that you can use javax.xml.bind.DatatypeConverter.

To read the file you have in standard Java is harder. You could read the PEM-armored PKCS#1 and convert to binary PKCS#1, then "wrap" the PKCS#1 into PKCS#8 by building the DER encoding, but that's a good bit more complicated than what you've demonstrated familiarity with. Or you could parse the PKCS#1 and use the components to construct your own implemenation of RSAPrivateCrtKey and use that directly (no factory), ditto.

The other alternative is to use the third-party library from http://www.BouncyCastle.org which has more flexible features for handling PEM files than standard Java. But you need to learn their API as well as the standard one, and if your program will run anywhere else you need to ensure BC is deployed with or as part of your program.

Upvotes: 2

Related Questions