OktaClient fails build when private key is set instead of PEM file

I’m building a service app integration with Okta using the OAuth client assertion with a private key.

Using the Java Okta SDK, I’m able to build the OktaClient by setting the private key to be a path to an unencrypted PEM file. However, the build always seems to fail whenever I pass a PrivateKey type instead with the error:

Cannot invoke “org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getEncoded()” because the return value of “org.bouncycastle.openssl.PEMKeyPair.getPublicKeyInfo()” is null

I have tried the following:

  • Extracting KeyPair from Java KeyStore (.jks) in PKCS#12 fomat [generated using keytool]
  • Extracting PrivateKey from PKCS#8 file [generated using openssl] via BouncyCastle
  • Extracting PrivateKey from PEM (.pem) file [generated using openssl] via BouncyCastle
  • Sending the PrivateKey directly from Jwts.SIG.ES512.keyPair().build() via io.jsonwebtoken:jjwt

In all cases, it seems like the extracted PrivateKey does not have enough information to construct the PublicKeyInfo.
This block of code seems to be the culprit, as I’m not sure why the PrivateKey couldn’t be accepted “as is” so that the future code block doesn’t assume it’s a PEMKeyPair. I’m not sure that the else block is ever hit in this case:

public ClientBuilder setPrivateKey(PrivateKey privateKey) {
    else if(algorithm.equals("EC")) {
            String encodedString = ConfigUtil.EC_PRIVATE_KEY_HEADER + "\n"
                + Base64.getEncoder().encodeToString(privateKey.getEncoded()) + "\n"
                + ConfigUtil.EC_PRIVATE_KEY_FOOTER;
            this.clientConfig.setPrivateKey(encodedString);
PrivateKey getPrivateKeyFromPEM(Reader reader) throws IOException {
    if (pemContent instanceof PEMKeyPair) {
                PEMKeyPair pemKeyPair = (PEMKeyPair) pemContent;
                KeyPair keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair);
                privateKey = keyPair.getPrivate();
            } else if (pemContent instanceof PrivateKeyInfo) {
                PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) pemContent;
                privateKey = jcaPEMKeyConverter.getPrivateKey(privateKeyInfo);
            }

It seems like this may be related specifically to Elliptic Curve Digital Signature Algorithm (ECDSA).

This builds just fine: Clients.builder().setPrivateKey(Jwts.SIG.RS256.keyPair().build().private).build()
This fails to build: Clients.builder().setPrivateKey(Jwts.SIG.ES256.keyPair().build().private).build()

What’s weird is that passing an unencrypted PEM file path whose private key is ES512 also seems to work…

openssl genpkey -out unencrypted.key -algorithm EC -pkeyopt ec_paramgen_curve:P-521
Clients.builder().setPrivateKey("unencrypted.key").build()