Why macOS Rejects Your ACME Certificate With an Empty Subject (and curl Won’t Warn You)
A walkthrough of the RFC 5280 violation behind Infisical’s internal CA bug, how to detect empty-subject certificates rejected on macOS and iOS, and reissue them after upgrading to v0.162.2.
TL;DR
Infisical’s internal CA issued RFC 5280-invalid certificates whenever a client’s CSR omitted a Common Name, the default behavior for Caddy, certbot, lego, and acme.sh. macOS and iOS reject these certs; openssl, curl, and Go don't, so the problem hides from routine testing. Fixed in v0.162.2. If you're on an earlier version, upgrade and reissue.
If you run Infisical’s internal Certificate Authority with ACME, EST, or SCEP enabled, and your macOS or iOS clients suddenly started failing TLS handshakes against certificates that pass curl and openssl without complaint, you've likely hit an empty subject certificate rejected on macOS a real standards violation, not a flaky network issue. This walks through why it happens, how to confirm your own certificates are affected, and the exact steps to upgrade and reissue them.
Why macOS rejects it but curl doesn’t
The internal CA’s certificate-signing code hardcoded the Subject Alternative Name (SAN) extension’s critical flag to false on every issuance path, regardless of whether the certificate's Subject field was empty. RFC 5280 §4.1.2.6 requires the SAN extension to be marked critical whenever the Subject is empty. Because that check never existed, every certificate issued from a CN-less CSR came out non-compliant.
This matters because omitting the Subject Common Name is the default behavior for standards-compliant ACME clients, Caddy (via certmagic), certbot, lego, and acme.sh all do it. So this isn’t an edge case; it’s the default path.
Apple’s Security framework, used by macOS and iOS, enforces RFC 5280 strictly and rejects the resulting certificate. The client-visible error is CSSMERR_TP_INVALID_CERTIFICATE, reported as "Invalid empty SubjectName." openssl, curl, and Go's TLS stack validate the connection using the SAN directly and accept the same certificate without complaint which is exactly why most CLI-based testing misses it, and why the defect surfaced only when macOS and iOS clients started failing in production.
A community member confirmed the same failure pattern using certbot and lego: their working certificate, issued before their lego client upgraded and stopped sending a CN, had a populated Subject field and validated normally everywhere. Their broken certificate, issued after the CN-less CSR became the default, had an empty Subject and failed the same way. A linked lego issue on EnableCommonName confirms lego v5 stopped setting a CN by default which is why this specifically started showing up for lego users around that version.
Check whether your own certificates are affected
Run this against any leaf certificate issued by your internal CA:
echo | openssl s_client -connect <host>:443 -servername <name> 2>/dev/null \
| openssl x509 -noout -subject -ext subjectAltNameYou’re affected if the output shows an empty subject= line paired with a SAN extension that does not say critical:
subject=
X509v3 Subject Alternative Name:
DNS:svc.exampleA fixed, correctly issued certificate shows the critical marker next to the SAN line:
X509v3 Subject Alternative Name: critical
DNS:svc.exampleWhere the bug actually lived
The root cause sits in internal-certificate-authority-service.ts, inside the signCertFromCa function. When a CSR has no CN, the subjectOverride variable resolves to an empty string, and the leaf gets built with that empty Subject. Separately, the SAN extension is constructed with new x509.SubjectAlternativeNameExtension(altNamesArray, false), the false critical flag hardcoded on every path, with no check for whether the Subject was empty.
Get FOLAKE SOWONOYE’s stories in your inbox
Join Medium for free to get updates from this writer.
This isn’t a novel bug class. The step-ca project hit the identical defect and fixed it by adding a Critical: subjectIsEmpty check before constructing the SAN extension. Go's standard library crypto/x509 doesn't set this flag automatically, so any CA built on it or on a library wrapping it has to implement the check itself. Infisical's internal CA hadn't, until now.
The fix, tracked as Infisical issue #6899 and shipped via PR #6900, adds exactly that check: when the Subject is empty, the SAN extension is now built with the critical flag set to true.
Fix it: upgrade and reissue
- Confirm exposure. Check whether your deployment issues certificates via ACME, EST, or SCEP from the internal CA, and whether your clients send CN-less CSRs — Caddy, certbot, lego, and acme.sh all do this by default.
- Audit existing leaf certificates using the
opensslcommand above. An emptysubject=line without acriticalSAN marker means that certificate is affected. - Upgrade Infisical to v0.162.2 or later. The fix only changes issuance going forward — it does not retroactively correct certificates already issued.
- Reissue every affected certificate you identified in step 2.
- If you installed via a
.debpackage, verify directly with Infisical's release channel that your package build includes the fix, this was still unconfirmed in the public thread as of this writing. - Retest against an RFC 5280-strict client — macOS Safari or an iOS device to confirm the reissued certificate is now accepted.
FAQ
Is there a CVE for this? No CVE identifier appears in the GitHub issue or its linked pull requests.
Do I need to reissue certificates I already have? Yes. The v0.162.2 fix changes how new certificates are issued; certificates issued before you upgrade keep their empty Subject and non-critical SAN until you reissue them.
Why didn’t my own testing catch this? If you tested with openssl s_client, curl, or a Go-based TLS client, none of them enforce the RFC 5280 rule requiring a critical SAN when the Subject is empty, they validate against the SAN directly and accept the certificate regardless. Only clients that enforce the rule strictly, like Apple's Security framework, will show you the problem.
Key Takeaways
- If your Infisical internal CA issues certs over ACME/EST/SCEP and your clients omit the CSR’s Common Name (the default for Caddy, certbot, lego, and acme.sh), certificates issued before v0.162.2 are RFC 5280-invalid.
- The failure is invisible to
openssl,curl, and Go, it only shows up on macOS and iOS, asCSSMERR_TP_INVALID_CERTIFICATE/ "Invalid empty SubjectName." - Upgrading to v0.162.2 fixes issuance going forward only. You still have to find and reissue every certificate issued before the upgrade.
Source: Infisical/infisical#6899, fixed via PR #6900, RFC 5280 §4.1.2.6 and §4.2.1.6.








