Follow-up to #764 / PR #766.
Context
PR #766 generates a combined CA bundle (system roots + clawpatrol MITM CA) so clawpatrol run no longer breaks TLS to passthrough hosts. On macOS the system-roots source is obtained by dumping Apple's curated root store:
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain
This was deliberately narrowed to the SystemRoot keychain only (not System.keychain) to avoid promoting un-trust-evaluated certs to anchors.
Gap
security find-certificate -a -p exports certificate objects without evaluating trust:
- It does not apply admin/user distrust overrides ("Never Trust"), trust domains, or SSL-purpose constraints, so a built-in root the operator/admin has explicitly distrusted would still land in the bundle.
- It does not reflect Apple policy-layer constraints on built-in roots.
- Roots the user trusted in the login keychain are omitted (under-trust) — those passthrough hosts still fail, though fail-closed (visible TLS error, never a silent MITM).
Proposed work
Derive the trusted set using Security.framework trust-settings semantics rather than a raw keychain dump — e.g. SecTrustSettingsCopyCertificates across the user/admin/system domains plus SecTrustSettingsCopyTrustSettings to honor deny/SSL-purpose, or an equivalent trust-evaluation pass — then emit the surviving roots as PEM. This needs cgo/Security.framework.
Also worth revisiting: the Darwin reader test currently runs locally only; the macOS CI job's -run 'Sandbox|Dial|Nosy|Plugin|ExternalCredential' filter excludes it.
Non-goals / current behavior
Until then, the current fail-closed behavior stands: an un-trusted or missing root is simply absent from the bundle, so verification fails visibly rather than silently trusting the wrong anchor.
Follow-up to #764 / PR #766.
Context
PR #766 generates a combined CA bundle (system roots + clawpatrol MITM CA) so
clawpatrol runno longer breaks TLS to passthrough hosts. On macOS the system-roots source is obtained by dumping Apple's curated root store:This was deliberately narrowed to the SystemRoot keychain only (not
System.keychain) to avoid promoting un-trust-evaluated certs to anchors.Gap
security find-certificate -a -pexports certificate objects without evaluating trust:Proposed work
Derive the trusted set using Security.framework trust-settings semantics rather than a raw keychain dump — e.g.
SecTrustSettingsCopyCertificatesacross the user/admin/system domains plusSecTrustSettingsCopyTrustSettingsto honor deny/SSL-purpose, or an equivalent trust-evaluation pass — then emit the surviving roots as PEM. This needs cgo/Security.framework.Also worth revisiting: the Darwin reader test currently runs locally only; the macOS CI job's
-run 'Sandbox|Dial|Nosy|Plugin|ExternalCredential'filter excludes it.Non-goals / current behavior
Until then, the current fail-closed behavior stands: an un-trusted or missing root is simply absent from the bundle, so verification fails visibly rather than silently trusting the wrong anchor.