cert-manager produces invalid (per RFC5280) certificates when `cert sign` usage is set along with another usage
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:
-
Deploy a certificate with
cert signandserver authusage:--- # 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 -
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 is this still happening on the latest patch of cert manager? if yes I can take a look at it and work on it
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