quarkusio/quarkus · error · SpiffeConnectionException

Signing certificate must have CA flag set to true: ${subject

Error message

Signing certificate must have CA flag set to true: ${subjectX500Principal}

What it means

Signing (CA) certificates in the SVID chain must have the BasicConstraints CA flag set to true. Quarkus SPIFFE client validates this in SpiffeValidator.validateIntermediate; if getBasicConstraints() returns -1 (not a CA), the chain cannot be trusted to sign leaf SVIDs and a SpiffeConnectionException is thrown.

Source

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

        }
        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(
                    "Signing certificate must have 'keyCertSign' as key usage: " + cert.getSubjectX500Principal());
        }
        // X.509-SVID 3.2 MUST: if signing cert has a SPIFFE ID, it must not have a path component
        String uriSan = extractOptionalUriSan(cert);
        if (uriSan != null && uriSan.startsWith(SPIFFE_URI_PREFIX)) {
            URI uri = URI.create(uriSan);
            String path = uri.getPath();
            if (path != null && !path.isEmpty() && !"/".equals(path)) {
                throw new SpiffeConnectionException(
                        "Signing certificate SPIFFE ID must not have a path component: " + uriSan);
            }
        }
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Replace the offending certificate in the trust bundle with a genuine CA certificate (BasicConstraints critical, cA=TRUE).
  2. Regenerate the signing certificate with basicConstraints=critical,CA:TRUE.
  3. Verify trust-bundle contents with `openssl x509 -text` and remove any non-CA certs.

Example fix

// before (openssl ca config for signing cert)
basicConstraints = CA:false
// after
basicConstraints = critical, CA:true
Defensive patterns

Strategy: validation

Validate before calling

if (cert.getBasicConstraints() < 0) {
    throw new IllegalArgumentException("Not a CA certificate: " + cert.getSubjectX500Principal());
}

Try / catch

try {
    connection.establish();
} catch (SpiffeConnectionException e) {
    if (e.getMessage().contains("CA flag")) {
        log.error("Trust bundle contains a non-CA certificate", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Presenting a trust bundle / intermediate chain where one of the signing certificates lacks the BasicConstraints extension or has cA=false; detected during intermediate validation after leaf validation.

Common situations: The trust bundle was assembled with a leaf or end-entity certificate mistakenly included as an intermediate; a self-signed server cert was pasted into the trust store; CA cert was regenerated without the CA:TRUE constraint.

Understand the failure class

Related errors


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