github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/crypto/x509/root_darwin.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !ios 6 7 package x509 8 9 import ( 10 "bytes" 11 macOS "crypto/x509/internal/macos" 12 "fmt" 13 "os" 14 "strings" 15 ) 16 17 var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1") 18 19 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { 20 return nil, nil 21 } 22 23 func loadSystemRoots() (*CertPool, error) { 24 var trustedRoots []*Certificate 25 untrustedRoots := make(map[string]bool) 26 27 // macOS has three trust domains: one for CAs added by users to their 28 // "login" keychain, one for CAs added by Admins to the "System" keychain, 29 // and one for the CAs that ship with the OS. 30 for _, domain := range []macOS.SecTrustSettingsDomain{ 31 macOS.SecTrustSettingsDomainUser, 32 macOS.SecTrustSettingsDomainAdmin, 33 macOS.SecTrustSettingsDomainSystem, 34 } { 35 certs, err := macOS.SecTrustSettingsCopyCertificates(domain) 36 if err == macOS.ErrNoTrustSettings { 37 continue 38 } else if err != nil { 39 return nil, err 40 } 41 defer macOS.CFRelease(certs) 42 43 for i := 0; i < macOS.CFArrayGetCount(certs); i++ { 44 c := macOS.CFArrayGetValueAtIndex(certs, i) 45 cert, err := exportCertificate(c) 46 if err != nil { 47 if debugDarwinRoots { 48 fmt.Fprintf(os.Stderr, "crypto/x509: domain %d, certificate #%d: %v\n", domain, i, err) 49 } 50 continue 51 } 52 53 var result macOS.SecTrustSettingsResult 54 if domain == macOS.SecTrustSettingsDomainSystem { 55 // Certs found in the system domain are always trusted. If the user 56 // configures "Never Trust" on such a cert, it will also be found in the 57 // admin or user domain, causing it to be added to untrustedRoots. 58 result = macOS.SecTrustSettingsResultTrustRoot 59 } else { 60 result, err = sslTrustSettingsResult(c) 61 if err != nil { 62 if debugDarwinRoots { 63 fmt.Fprintf(os.Stderr, "crypto/x509: trust settings for %v: %v\n", cert.Subject, err) 64 } 65 continue 66 } 67 if debugDarwinRoots { 68 fmt.Fprintf(os.Stderr, "crypto/x509: trust settings for %v: %d\n", cert.Subject, result) 69 } 70 } 71 72 switch result { 73 // "Note the distinction between the results kSecTrustSettingsResultTrustRoot 74 // and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to 75 // root (self-signed) certificates; the latter can only be applied to 76 // non-root certificates." 77 case macOS.SecTrustSettingsResultTrustRoot: 78 if isRootCertificate(cert) { 79 trustedRoots = append(trustedRoots, cert) 80 } 81 case macOS.SecTrustSettingsResultTrustAsRoot: 82 if !isRootCertificate(cert) { 83 trustedRoots = append(trustedRoots, cert) 84 } 85 86 case macOS.SecTrustSettingsResultDeny: 87 // Add this certificate to untrustedRoots, which are subtracted 88 // from trustedRoots, so that we don't have to evaluate policies 89 // for every root in the system domain, but still apply user and 90 // admin policies that override system roots. 91 untrustedRoots[string(cert.Raw)] = true 92 93 case macOS.SecTrustSettingsResultUnspecified: 94 // Certificates with unspecified trust should be added to a pool 95 // of intermediates for chain building, but we don't support it 96 // at the moment. This is Issue 35631. 97 98 default: 99 if debugDarwinRoots { 100 fmt.Fprintf(os.Stderr, "crypto/x509: unknown trust setting for %v: %d\n", cert.Subject, result) 101 } 102 } 103 } 104 } 105 106 pool := NewCertPool() 107 for _, cert := range trustedRoots { 108 if !untrustedRoots[string(cert.Raw)] { 109 pool.AddCert(cert) 110 } 111 } 112 return pool, nil 113 } 114 115 // exportCertificate returns a *Certificate for a SecCertificateRef. 116 func exportCertificate(cert macOS.CFRef) (*Certificate, error) { 117 data, err := macOS.SecItemExport(cert) 118 if err != nil { 119 return nil, err 120 } 121 defer macOS.CFRelease(data) 122 der := macOS.CFDataToSlice(data) 123 124 return ParseCertificate(der) 125 } 126 127 // isRootCertificate reports whether Subject and Issuer match. 128 func isRootCertificate(cert *Certificate) bool { 129 return bytes.Equal(cert.RawSubject, cert.RawIssuer) 130 } 131 132 // sslTrustSettingsResult obtains the final kSecTrustSettingsResult value for a 133 // certificate in the user or admin domain, combining usage constraints for the 134 // SSL SecTrustSettingsPolicy, 135 // 136 // It ignores SecTrustSettingsKeyUsage and kSecTrustSettingsAllowedError, and 137 // doesn't support kSecTrustSettingsDefaultRootCertSetting. 138 // 139 // https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting 140 func sslTrustSettingsResult(cert macOS.CFRef) (macOS.SecTrustSettingsResult, error) { 141 // In Apple's implementation user trust settings override admin trust settings 142 // (which themselves override system trust settings). If SecTrustSettingsCopyTrustSettings 143 // fails, or returns a NULL trust settings, when looking for the user trust 144 // settings then fallback to checking the admin trust settings. 145 // 146 // See Security-59306.41.2/trust/headers/SecTrustSettings.h for a description of 147 // the trust settings overrides, and SecLegacyAnchorSourceCopyUsageConstraints in 148 // Security-59306.41.2/trust/trustd/SecCertificateSource.c for a concrete example 149 // of how Apple applies the override in the case of NULL trust settings, or non 150 // success errors. 151 trustSettings, err := macOS.SecTrustSettingsCopyTrustSettings(cert, macOS.SecTrustSettingsDomainUser) 152 if err != nil || trustSettings == 0 { 153 if debugDarwinRoots && err != macOS.ErrNoTrustSettings { 154 fmt.Fprintf(os.Stderr, "crypto/x509: SecTrustSettingsCopyTrustSettings for SecTrustSettingsDomainUser failed: %s\n", err) 155 } 156 trustSettings, err = macOS.SecTrustSettingsCopyTrustSettings(cert, macOS.SecTrustSettingsDomainAdmin) 157 } 158 if err != nil || trustSettings == 0 { 159 // If there are neither user nor admin trust settings for a certificate returned 160 // from SecTrustSettingsCopyCertificates Apple returns kSecTrustSettingsResultInvalid, 161 // as this method is intended to return certificates _which have trust settings_. 162 // The most likely case for this being triggered is that the existing trust settings 163 // are invalid and cannot be properly parsed. In this case SecTrustSettingsCopyTrustSettings 164 // returns errSecInvalidTrustSettings. The existing cgo implementation returns 165 // kSecTrustSettingsResultUnspecified in this case, which mostly matches the Apple 166 // implementation because we don't do anything with certificates marked with this 167 // result. 168 // 169 // See SecPVCGetTrustSettingsResult in Security-59306.41.2/trust/trustd/SecPolicyServer.c 170 if debugDarwinRoots && err != macOS.ErrNoTrustSettings { 171 fmt.Fprintf(os.Stderr, "crypto/x509: SecTrustSettingsCopyTrustSettings for SecTrustSettingsDomainAdmin failed: %s\n", err) 172 } 173 return macOS.SecTrustSettingsResultUnspecified, nil 174 } 175 defer macOS.CFRelease(trustSettings) 176 177 // "An empty trust settings array means 'always trust this certificate' with an 178 // overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot." 179 if macOS.CFArrayGetCount(trustSettings) == 0 { 180 return macOS.SecTrustSettingsResultTrustRoot, nil 181 } 182 183 isSSLPolicy := func(policyRef macOS.CFRef) bool { 184 properties := macOS.SecPolicyCopyProperties(policyRef) 185 defer macOS.CFRelease(properties) 186 if v, ok := macOS.CFDictionaryGetValueIfPresent(properties, macOS.SecPolicyOid); ok { 187 return macOS.CFEqual(v, macOS.CFRef(macOS.SecPolicyAppleSSL)) 188 } 189 return false 190 } 191 192 for i := 0; i < macOS.CFArrayGetCount(trustSettings); i++ { 193 tSetting := macOS.CFArrayGetValueAtIndex(trustSettings, i) 194 195 // First, check if this trust setting is constrained to a non-SSL policy. 196 if policyRef, ok := macOS.CFDictionaryGetValueIfPresent(tSetting, macOS.SecTrustSettingsPolicy); ok { 197 if !isSSLPolicy(policyRef) { 198 continue 199 } 200 } 201 202 // Then check if it is restricted to a hostname, so not a root. 203 if _, ok := macOS.CFDictionaryGetValueIfPresent(tSetting, macOS.SecTrustSettingsPolicyString); ok { 204 continue 205 } 206 207 cfNum, ok := macOS.CFDictionaryGetValueIfPresent(tSetting, macOS.SecTrustSettingsResultKey) 208 // "If this key is not present, a default value of kSecTrustSettingsResultTrustRoot is assumed." 209 if !ok { 210 return macOS.SecTrustSettingsResultTrustRoot, nil 211 } 212 result, err := macOS.CFNumberGetValue(cfNum) 213 if err != nil { 214 return 0, err 215 } 216 217 // If multiple dictionaries match, we are supposed to "OR" them, 218 // the semantics of which are not clear. Since TrustRoot and TrustAsRoot 219 // are mutually exclusive, Deny should probably override, and Invalid and 220 // Unspecified be overridden, approximate this by stopping at the first 221 // TrustRoot, TrustAsRoot or Deny. 222 switch r := macOS.SecTrustSettingsResult(result); r { 223 case macOS.SecTrustSettingsResultTrustRoot, 224 macOS.SecTrustSettingsResultTrustAsRoot, 225 macOS.SecTrustSettingsResultDeny: 226 return r, nil 227 } 228 } 229 230 // If trust settings are present, but none of them match the policy... 231 // the docs don't tell us what to do. 232 // 233 // "Trust settings for a given use apply if any of the dictionaries in the 234 // certificate’s trust settings array satisfies the specified use." suggests 235 // that it's as if there were no trust settings at all, so we should maybe 236 // fallback to the admin trust settings? TODO(golang.org/issue/38888). 237 238 return macOS.SecTrustSettingsResultUnspecified, nil 239 }