quarkusio/quarkus · critical · SpiffeConnectionException

Leaf certificate must not have 'keyCertSign' as key usage

Error message

Leaf certificate must not have 'keyCertSign' as key usage

What it means

A leaf workload certificate must not be able to sign other certificates. If KeyUsage includes the keyCertSign bit, the certificate could act as a CA and the validator rejects it to enforce the SPIFFE X.509-SVID profile. This protects against privilege escalation if the workload's key is compromised.

Source

Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java:33

    private static final int MAX_TRUST_DOMAIN_LENGTH = 255;

    private SpiffeValidator() {
    }

    static String validateLeaf(X509Certificate leaf) throws SpiffeConnectionException {
        if (leaf.getBasicConstraints() != -1) {
            throw new SpiffeConnectionException("Leaf certificate must not have CA flag set to true");
        }

        boolean[] keyUsage = leaf.getKeyUsage();
        if (keyUsage == null) {
            throw new SpiffeConnectionException("Leaf certificate is missing the key usage extension");
        }
        if (keyUsage.length < 1 || !keyUsage[0]) {
            throw new SpiffeConnectionException("Leaf certificate must have 'digitalSignature' as key usage");
        }
        if (keyUsage.length > 5 && keyUsage[5]) {
            throw new SpiffeConnectionException("Leaf certificate must not have 'keyCertSign' as key usage");
        }
        if (keyUsage.length > 6 && keyUsage[6]) {
            throw new SpiffeConnectionException("Leaf certificate must not have 'cRLSign' as key usage");
        }

        return extractAndValidateUriSan(leaf);
    }

    // X.509-SVID 3.2 SHOULD: signing cert SHOULD itself be an SVID (not enforced — upstream CA may not be SPIFFE-aware)
    // X.509-SVID 3.2 SHOULD: signing cert SHOULD reside in the trust domain of leaf SVIDs it issues (not enforced — cross-domain signing is allowed)
    static void validateIntermediate(X509Certificate cert) throws SpiffeConnectionException {
        if (cert.getBasicConstraints() < 0) {
            throw new SpiffeConnectionException(
                    "Signing certificate must have CA flag set to true: " + cert.getSubjectX500Principal());
        }
        boolean[] keyUsage = cert.getKeyUsage();
        if (keyUsage == null || keyUsage.length <= 5 || !keyUsage[5]) {
            throw new SpiffeConnectionException(

View on GitHub (pinned to e1c734241f)

Solutions

  1. Serve a proper end-entity SVID without CA flags or CA usages from the SPIRE agent.
  2. Check the leaf: openssl x509 -noout -ext keyUsage — remove keyCertSign from workload cert templates.
  3. Separate your CA chain (trust bundle) from the leaf chain in custom code paths.
  4. Verify SPIRE server registration entries map to workload profiles, not CA profiles.

Example fix

// before
-addext "keyUsage=digitalSignature,keyCertSign"
// after
-addext "keyUsage=digitalSignature,keyEncipherment"
Defensive patterns

Strategy: validation

Validate before calling

static boolean lacksKeyCertSign(X509Certificate leaf) {
    boolean[] ku = leaf.getKeyUsage();
    return ku == null || ku.length <= 5 || !ku[5];
}

Type guard

static boolean isNotCaCapable(X509Certificate cert) {
    boolean[] ku = cert.getKeyUsage();
    return cert.getBasicConstraints() == -1 && (ku == null || ku.length <= 5 || !ku[5]);
}

Try / catch

try {
    SpiffeValidator.validateLeaf(leaf);
} catch (SpiffeConnectionException e) {
    throw new SecurityException("Leaf must not have keyCertSign usage: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Validation encountering a leaf whose KeyUsage asserts keyCertSign (bit 5), e.g. a self-signed CA certificate or an intermediate passed in as the leaf.

Common situations: Testing with self-signed CA certs as if they were SVIDs; upstream CA templates leaking CA usages into workload certs; accidentally passing a bundle/intermediate where a leaf is expected.

Understand the failure class

Related errors


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