Skip to content

Commit 42bb476

Browse files
committed
crypto/x509: include roots with empty or multiple policies on macOS
To a fifth reading of the relevant docs, it looks like 1) a constraint dictionary with no policy applies to all of them; 2) multiple applying constraint dictionaries should have their results OR'd; 3) untrusted certificates in the keychain should be used for chain building. This fixes 1), approximates 2) and punts on 3). Fixes #30672 Fixes #30471 Change-Id: Ibbaabf0b77d267377c0b5de07abca3445c2c2302 Reviewed-on: https://go-review.googlesource.com/c/go/+/178539 Reviewed-by: Adam Langley <[email protected]>
1 parent 2326a66 commit 42bb476

File tree

1 file changed

+20
-9
lines changed

1 file changed

+20
-9
lines changed

src/crypto/x509/root_cgo_darwin.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static SInt32 sslTrustSettingsResult(SecCertificateRef cert) {
5151
}
5252
5353
// > no trust settings [...] means "this certificate must be verified to a known trusted certificate”
54+
// (Should this cause a fallback from user to admin domain? It's unclear.)
5455
if (err != errSecSuccess || trustSettings == NULL) {
5556
if (trustSettings != NULL) CFRelease(trustSettings);
5657
return kSecTrustSettingsResultUnspecified;
@@ -77,16 +78,12 @@ static SInt32 sslTrustSettingsResult(SecCertificateRef cert) {
7778
for (m = 0; m < CFArrayGetCount(trustSettings); m++) {
7879
CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, m);
7980
80-
// First, check if this trust setting applies to our policy. We assume
81-
// only one will. The docs suggest that there might be multiple applying
82-
// but don't explain how to combine them.
81+
// First, check if this trust setting is constrained to a non-SSL policy.
8382
SecPolicyRef policyRef;
8483
if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsPolicy, (const void**)&policyRef)) {
8584
if (!isSSLPolicy(policyRef)) {
8685
continue;
8786
}
88-
} else {
89-
continue;
9087
}
9188
9289
if (CFDictionaryContainsKey(tSetting, _kSecTrustSettingsPolicyString)) {
@@ -98,13 +95,23 @@ static SInt32 sslTrustSettingsResult(SecCertificateRef cert) {
9895
if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsResult, (const void**)&cfNum)) {
9996
CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
10097
} else {
101-
// > If the value of the kSecTrustSettingsResult component is not
102-
// > kSecTrustSettingsResultUnspecified for a usage constraints dictionary that has
103-
// > no constraints, the default value kSecTrustSettingsResultTrustRoot is assumed.
98+
// > If this key is not present, a default value of
99+
// > kSecTrustSettingsResultTrustRoot is assumed.
104100
result = kSecTrustSettingsResultTrustRoot;
105101
}
106102
107-
break;
103+
// If multiple dictionaries match, we are supposed to "OR" them,
104+
// the semantics of which are not clear. Since TrustRoot and TrustAsRoot
105+
// are mutually exclusive, Deny should probably override, and Invalid and
106+
// Unspecified be overridden, approximate this by stopping at the first
107+
// TrustRoot, TrustAsRoot or Deny.
108+
if (result == kSecTrustSettingsResultTrustRoot) {
109+
break;
110+
} else if (result == kSecTrustSettingsResultTrustAsRoot) {
111+
break;
112+
} else if (result == kSecTrustSettingsResultDeny) {
113+
break;
114+
}
108115
}
109116
110117
// If trust settings are present, but none of them match the policy...
@@ -244,6 +251,10 @@ int CopyPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots, bool debugDa
244251
} else if (result == kSecTrustSettingsResultDeny) {
245252
appendTo = combinedUntrustedData;
246253
} else if (result == kSecTrustSettingsResultUnspecified) {
254+
// Certificates with unspecified trust should probably be added to a pool of
255+
// intermediates for chain building, or checked for transitive trust and
256+
// added to the root pool (which is an imprecise approximation because it
257+
// cuts chains short) but we don't support either at the moment. TODO.
247258
continue;
248259
} else {
249260
continue;

0 commit comments

Comments
 (0)