quarkusio/quarkus · error · RuntimeException

Failure to create a private key

Error message

Failure to create a private key

What it means

LetsEncryptHelpers.getPrivateKey() base64-decodes the key material and reconstructs a PrivateKey via KeyFactory with a PKCS8EncodedKeySpec, choosing RSA unless the algorithm is explicitly EC. Any decoding or key-generation failure is wrapped in this RuntimeException. It means the stored ACME account/order private key could not be parsed.

Source

Thrown at extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java:270

    private static X509Certificate getCertificate(String encodedCert) {
        try {
            byte[] encodedBytes = Base64.getDecoder().decode(encodedCert);
            return (X509Certificate) CertificateFactory.getInstance("X.509")
                    .generateCertificate(new ByteArrayInputStream(encodedBytes));
        } catch (Exception ex) {
            throw new RuntimeException("Failure to create a certificate", ex);
        }
    }

    private static PrivateKey getPrivateKey(String encodedKey, String keyAlgorithm) {
        try {
            KeyFactory f = KeyFactory.getInstance((keyAlgorithm == null || "RSA".equals(keyAlgorithm) ? "RSA" : "EC"));
            byte[] encodedBytes = Base64.getDecoder().decode(encodedKey);
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedBytes);
            return f.generatePrivate(spec);
        } catch (Exception ex) {
            throw new RuntimeException("Failure to create a private key", ex);
        }
    }

    public static void renewCertificate(AcmeClient acmeClient,
            File letsEncryptPath,
            boolean staging,
            String domain,
            File certChainPemLoc,
            File privateKeyPemLoc,
            String acmeServerUrl,
            String acmeStagingServerUrl) {
        LOGGER.infof("\uD83D\uDD35 Renewing %s ACME certificate chain and private key",
                (staging ? "staging" : "production"));
        issueCertificate(acmeClient, letsEncryptPath, staging, domain, certChainPemLoc, privateKeyPemLoc,
                acmeServerUrl, acmeStagingServerUrl);
    }

    public static void deactivateAccount(AcmeClient acmeClient, File letsEncryptPath, boolean staging,

View on GitHub (pinned to e1c734241f)

Solutions

  1. Regenerate the key by deleting the letsencrypt directory and letting the tooling issue a new order/key
  2. Convert PKCS#1 keys to PKCS#8 (openssl pkcs8 -topk8) before storing
  3. Ensure keyAlgorithm matches the actual key ('RSA' or 'EC'); pass null for RSA default
  4. Verify the base64 payload has no PEM headers or whitespace before calling

Example fix

// before
PrivateKey key = LetsEncryptHelpers.getPrivateKey(pkcs1KeyBody, "EC");
// after
// convert to PKCS#8 first: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key.pkcs8.pem
PrivateKey key = LetsEncryptHelpers.getPrivateKey(pkcs8KeyBody, "EC");
Defensive patterns

Strategy: validation

Validate before calling

static boolean isParseablePkcs8Key(String b64, String alg) {
    try {
        byte[] der = Base64.getDecoder().decode(b64.replaceAll("-----[A-Z ]+-----|\\s", ""));
        KeyFactory f = KeyFactory.getInstance(alg == null || "RSA".equals(alg) ? "RSA" : "EC");
        f.generatePrivate(new PKCS8EncodedKeySpec(der));
        return true;
    } catch (Exception e) { return false;
    }
}

Type guard

if (keyAlg != null && !keyAlg.equals("RSA") && !keyAlg.equals("EC")) throw new IllegalArgumentException("Unsupported keyAlgorithm: " + keyAlg);

Try / catch

try {
    PrivateKey key = LetsEncryptHelpers.getPrivateKey(encoded, alg);
} catch (RuntimeException e) {
    LOGGER.error("Stored private key unreadable (wrong format?); regenerate key", e);
    deleteKeyAndRenew();
}

Prevention

When it happens

Trigger: getPrivateKey(encodedKey, keyAlgorithm) throws when the string is not valid base64, the decoded bytes are not a PKCS#8 structure, or the key algorithm mismatch (e.g. an EC key parsed with the RSA KeyFactory, or a non-RSA/non-EC keyAlgorithm passed).

Common situations: Key file regenerated by another tool in PKCS#1 ('BEGIN RSA PRIVATE KEY') instead of PKCS#8, key truncated or corrupted on disk, keyAlgorithm config changed to EC while the stored key is RSA.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/9d51ad05ec43931c. Report an issue: GitHub.