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  }