{"record":{"id":"360b9c7146800221","repo":"quarkusio/quarkus","slug":"signing-certificate-must-have-keycertsign-as-key","errorCode":null,"errorMessage":"Signing certificate must have 'keyCertSign' as key usage: ${subjectX500Principal}","messagePattern":"Signing certificate must have 'keyCertSign' as key usage: (.+?)","errorType":"exception","errorClass":"SpiffeConnectionException","httpStatus":null,"severity":"error","filePath":"extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java","lineNumber":51,"sourceCode":"            throw new SpiffeConnectionException(\"Leaf certificate must not have 'keyCertSign' as key usage\");\n        }\n        if (keyUsage.length > 6 && keyUsage[6]) {\n            throw new SpiffeConnectionException(\"Leaf certificate must not have 'cRLSign' as key usage\");\n        }\n\n        return extractAndValidateUriSan(leaf);\n    }\n\n    // X.509-SVID 3.2 SHOULD: signing cert SHOULD itself be an SVID (not enforced — upstream CA may not be SPIFFE-aware)\n    // 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)\n    static void validateIntermediate(X509Certificate cert) throws SpiffeConnectionException {\n        if (cert.getBasicConstraints() < 0) {\n            throw new SpiffeConnectionException(\n                    \"Signing certificate must have CA flag set to true: \" + cert.getSubjectX500Principal());\n        }\n        boolean[] keyUsage = cert.getKeyUsage();\n        if (keyUsage == null || keyUsage.length <= 5 || !keyUsage[5]) {\n            throw new SpiffeConnectionException(\n                    \"Signing certificate must have 'keyCertSign' as key usage: \" + cert.getSubjectX500Principal());\n        }\n        // X.509-SVID 3.2 MUST: if signing cert has a SPIFFE ID, it must not have a path component\n        String uriSan = extractOptionalUriSan(cert);\n        if (uriSan != null && uriSan.startsWith(SPIFFE_URI_PREFIX)) {\n            URI uri = URI.create(uriSan);\n            String path = uri.getPath();\n            if (path != null && !path.isEmpty() && !\"/\".equals(path)) {\n                throw new SpiffeConnectionException(\n                        \"Signing certificate SPIFFE ID must not have a path component: \" + uriSan);\n            }\n        }\n    }\n\n    static void validateSpiffeId(String spiffeId) throws SpiffeConnectionException {\n        if (spiffeId == null || spiffeId.isEmpty()) {\n            throw new SpiffeConnectionException(\"SPIFFE ID must not be empty\");\n        }","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java#L33-L69","documentation":"A CA certificate in the SVID chain must have the keyCertSign key usage bit (index 5) set, since it signs other certificates. SpiffeValidator.validateIntermediate throws SpiffeConnectionException when keyUsage is absent, too short, or does not include keyCertSign.","triggerScenarios":"Validating a chain whose signing certificate either has no KeyUsage extension at all, or has a KeyUsage that does not include keyCertSign (e.g. only cRLSign or digitalSignature).","commonSituations":"Intermediate CA issued by an internal PKI with restrictive/incorrect key usage templates; hand-crafted test CAs generated without -keyUsage extensions; legacy CAs predating strict profile enforcement.","solutions":["Reissue the signing certificate with keyUsage = critical, keyCertSign (plus digitalSignature and cRLSign if needed for CRLs).","Fix the CA template used by the upstream PKI to include keyCertSign for CA certs.","Regenerate local test CAs with: openssl req -x509 -addext keyUsage=critical,keyCertSign,cRLSign."],"exampleFix":"// before (openssl config for intermediate)\nkeyUsage = digitalSignature\n// after\nkeyUsage = critical, digitalSignature, keyCertSign, cRLSign","handlingStrategy":"validation","validationCode":"boolean[] ku = cert.getKeyUsage();\nif (ku == null || ku.length <= 5 || !ku[5]) {\n    throw new IllegalArgumentException(\"CA cert lacks keyCertSign usage\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    connection.establish();\n} catch (SpiffeConnectionException e) {\n    if (e.getMessage().contains(\"keyCertSign\")) {\n        log.error(\"Signing certificate has invalid key usage; reissue\", e);\n    }\n    throw e;\n}","preventionTips":["Generate CAs with keyUsage=critical,keyCertSign,cRLSign","Include keyCertSign in all intermediate-CA PKI templates","Test chains with openssl verify before deployment"],"tags":["x509","certificate-chain","keyusage","spiffe"],"backgroundTag":"certificate-key-usage-violation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}