javajwtcertificatepublic-key-encryptionder

Create PEM certificate from Java PublicKey created with Nimbus


I have an integration where I validate a JSON created by another service. They provide a public endpoint to fetch the public certificates to validate against.

But I am setting up a test for this and would like to create the same JWT with Nimbus to sign it with my own private key. So I do this like this (it's a nested and encrypted JWT): https://connect2id.com/products/nimbus-jose-jwt/examples/signed-and-encrypted-jwt

Then I would like to simulate the public endpoint with a MockServer (https://www.mock-server.com/) endpoint in tests. The problem is that I try to create a PEM certificate from the public key from the senderJWK from the example like this:

var encoded = senderJWK.toPublicKey().getEncoded();
var base64Encoded = Base64.getEncoder().encode(encoded);
return new String(base64Encoded, StandardCharsets.UTF_8);

(I have also tested senderJWK.toRSAPublicKey().getEncoded().)

The code that works with the real certificate does not work to parse it. The code to parse it look like this:

private static RSAPublicKey readPublicKey(String publicKey) throws CertificateException {
    var bytes = Base64.getDecoder().decode(publicKey);
    var inStream = new ByteArrayInputStream(bytes);
    var certificateFactory = CertificateFactory.getInstance(X_509_CERTIFICATE_FACTORY);
    var certificate = (X509Certificate) certificateFactory.generateCertificate(inStream);
    return (RSAPublicKey) certificate.getPublicKey();
}

The error I am getting is:

    java.io.IOException: Too short
        at java.base/sun.security.util.DerValue.<init>(DerValue.java:333)
        at java.base/sun.security.util.DerInputStream.getDerValue(DerInputStream.java:109)
        at java.base/sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1771)
        at java.base/sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:183)
        ... 100 common frames omitted
    Wrapped by: java.security.cert.CertificateException: Unable to initialize, java.io.IOException: Too short
        at java.base/sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:186)
        at java.base/sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:105)
        at java.base/java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:355)
        ... 95 common frames omitted

Solution

  • Ok, I think what I need to do is create a X509 certificate from java, and then use the private and public keys from that in the signing and verification.

    Found these resources on how to use bouncy castle to do that: Self signed X509 Certificate with Bouncy Castle in Java How to create a X509 certificate using Java?

    Edit: I got it working fine with that.