cert-manager icon indicating copy to clipboard operation
cert-manager copied to clipboard

cert-manager produces invalid (per RFC5280) certificates when `cert sign` usage is set along with another usage

Open solidDoWant opened this issue 9 months ago • 2 comments

Describe the bug:

When a certificate resource contains both cert sign and another non-CA usage (such as server auth), the x509 certificate produced by cert-manager splits the usage between X509v3 Key Usage and X509v3 Extended Key Usage fields. Per RFC5280 4.2.1.12,

If a certificate contains both a key usage extension and an extended key usage extension, then both extensions MUST be processed independently and the certificate MUST only be used for a purpose consistent with both extensions. If there is no purpose consistent with both extensions, then the certificate MUST NOT be used for any purpose.

Because the usages are split between the key usage and extended key usage fields, the produced certificates are not valid for any of the usages.

Expected behaviour: There key usage and extended key usage fields should have the same values set, or one of them should have no values set at all.

Steps to reproduce the bug:

  1. Deploy a certificate with cert sign and server auth usage:

    ---
    # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cert-manager.io/certificate_v1.json
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: example-cert
    spec:
      isCA: true # Self-signed cert must be a CA
      commonName: Self signed cert
      dnsNames: &domain_names
        - some-domain.com
      usages:
        - server auth
        # Self-signed cert must be able to sign itself
        - cert sign
        - crl sign
      # Allow only signing for the license domain name
      nameConstraints:
        critical: true
        permitted:
          dnsDomains: *domain_names
      issuerRef:
        name: self-signed-issuer
        kind: ClusterIssuer
        group: cert-manager.io
      secretName: example-cert
    
  2. Get the signed cert and check the key usage via openssl:

    $ kubectl get secrets -n monitoring example-cert -o json | jq -r '.data["tls.crt"]' | base64 -d | openssl x509 -noout -text | grep -A4 'X509v3 extensions'
        X509v3 extensions:
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
    

If deployed to a basic webserver (i.e. nginx with bare minimum config), openssl reject this certificate due to 26 (unsupported certificate purpose)

$ echo | openssl s_client -connect some-domain.com:443
... # Unrelated lines omitted
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1567 bytes and written 443 bytes
Verification error: unsupported certificate purpose
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 26 (unsupported certificate purpose)
---
DONE

Anything else we need to know?:

Environment details:

  • Kubernetes version: N/A
  • Cloud-provider/provisioner: N/A
  • cert-manager version: 1.17.1
  • Install method: e.g. helm/static manifests Helm

/kind bug

solidDoWant avatar Apr 04 '25 18:04 solidDoWant

@solidDoWant is this still happening on the latest patch of cert manager? if yes I can take a look at it and work on it

hjoshi123 avatar May 14 '25 03:05 hjoshi123

Issues go stale after 6 months of inactivity. Mark the issue as fresh with /remove-lifecycle stale. Stale issues remain open for an additional 3 months of inactivity and then close. If this issue is safe to close now please do so with /close. /lifecycle stale

cert-manager-bot avatar Nov 12 '25 03:11 cert-manager-bot