grpc/grpc-java · error · InvalidKeySpecException

Neither RSA nor EC worked

Error message

Neither RSA nor EC worked

What it means

CertificateUtils.getPrivateKey tries to build a PKCS#8 private key first with the RSA KeyFactory and then with the EC KeyFactory. If both generatePrivate calls reject the key spec, it rethrows as an InvalidKeySpecException with this message, chaining the EC failure. It means the encoded key is neither a valid RSA nor EC private key for the loaded providers.

Source

Thrown at util/src/main/java/io/grpc/util/CertificateUtils.java:90

        break;
      }
    }
    StringBuilder keyContent = new StringBuilder();
    while ((line = reader.readLine()) != null) {
      if ("-----END PRIVATE KEY-----".equals(line)) {
        break;
      }
      keyContent.append(line);
    }
    byte[] decodedKeyBytes = BaseEncoding.base64().decode(keyContent.toString());
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKeyBytes);
    try {
      return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
    } catch (InvalidKeySpecException ignore) {
      try {
        return KeyFactory.getInstance("EC").generatePrivate(keySpec);
      } catch (InvalidKeySpecException e) {
        throw new InvalidKeySpecException("Neither RSA nor EC worked", e);
      }
    }
  }
}

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Convert the key to PKCS#8: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem and load that
  2. If the key is RSA and in PKCS#1 format, convert first (openssl rsa -traditional vs -pkcs8) before parsing
  3. Check the key algorithm — DSA/Ed25519 keys are not handled by this utility; generate an RSA or EC key or use a different loader
  4. Strip PEM headers and decode the Base64 body exactly once; verify the DER parses (e.g. openssl asn1parse)
  5. Regenerate the key pair if the encoding is corrupted

Example fix

// before
byte[] der = base64Decode(pemBodyOfRsaPkcs1Key); // 'BEGIN RSA PRIVATE KEY'
PrivateKey key = CertificateUtils.getPrivateKey(der); // InvalidKeySpecException
// after
// $ openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem
byte[] der = base64Decode(pemBodyOf("key_pkcs8.pem"));
PrivateKey key = CertificateUtils.getPrivateKey(der);
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean isPkcs8RsaOrEc(byte[] der) {
  // PKCS#8 PrivateKeyInfo starts with SEQUENCE; quick sanity via ASN.1 parse
  try {
    new PKCS8EncodedKeySpec(der);
    return der.length > 8 && der[0] == 0x30; // SEQUENCE tag
  } catch (IllegalArgumentException e) {
    return false;
  }
}

Type guard

static boolean looksLikePemPkcs8(String pem) {
  return pem.contains("BEGIN PRIVATE KEY"); // vs 'BEGIN RSA PRIVATE KEY' (PKCS#1) or 'BEGIN EC PRIVATE KEY' (SEC1)
}

Try / catch

try {
  privateKey = CertificateUtils.getPrivateKey(keyBytes);
} catch (InvalidKeySpecException e) {
  throw new IllegalArgumentException(
      "Key must be PKCS#8-encoded RSA or EC; got neither. Convert with: openssl pkcs8 -topk8 -nocrypt", e);
}

Prevention

When it happens

Trigger: Calling CertificateUtils.getPrivateKey with a byte array/PKCS8EncodedKeySpec that neither the RSA nor the EC KeyFactory can parse — e.g. a DSA/Ed25519 key, a corrupted or truncated DER encoding, a key encoded in a format other than PKCS#8 (PKCS#1 'BEGIN RSA PRIVATE KEY', SEC1 'BEGIN EC PRIVATE KEY', or a raw public key), or a PEM file whose Base64 body was passed raw.

Common situations: Loading keys generated with modern algorithms (Ed25519) unsupported by the two hardcoded factories; pasting the inner Base64 of a PKCS#1 header into PKCS8EncodedKeySpec; keys double-Base64-encoded or with headers/whitespace included; converting certificates/keys between formats with tools like OpenSSL incorrectly.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/b068651677f434b5. Report an issue: GitHub.