// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !ios

package x509

import (
	
	macOS 
	
	
	
)

var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")

func ( *Certificate) ( *VerifyOptions) ( [][]*Certificate,  error) {
	return nil, nil
}

func () (*CertPool, error) {
	var  []*Certificate
	 := make(map[string]bool)

	// macOS has three trust domains: one for CAs added by users to their
	// "login" keychain, one for CAs added by Admins to the "System" keychain,
	// and one for the CAs that ship with the OS.
	for ,  := range []macOS.SecTrustSettingsDomain{
		macOS.SecTrustSettingsDomainUser,
		macOS.SecTrustSettingsDomainAdmin,
		macOS.SecTrustSettingsDomainSystem,
	} {
		,  := macOS.SecTrustSettingsCopyCertificates()
		if  == macOS.ErrNoTrustSettings {
			continue
		} else if  != nil {
			return nil, 
		}
		defer macOS.CFRelease()

		for  := 0;  < macOS.CFArrayGetCount(); ++ {
			 := macOS.CFArrayGetValueAtIndex(, )
			,  := exportCertificate()
			if  != nil {
				if debugDarwinRoots {
					fmt.Fprintf(os.Stderr, "crypto/x509: domain %d, certificate #%d: %v\n", , , )
				}
				continue
			}

			var  macOS.SecTrustSettingsResult
			if  == macOS.SecTrustSettingsDomainSystem {
				// Certs found in the system domain are always trusted. If the user
				// configures "Never Trust" on such a cert, it will also be found in the
				// admin or user domain, causing it to be added to untrustedRoots.
				 = macOS.SecTrustSettingsResultTrustRoot
			} else {
				,  = sslTrustSettingsResult()
				if  != nil {
					if debugDarwinRoots {
						fmt.Fprintf(os.Stderr, "crypto/x509: trust settings for %v: %v\n", .Subject, )
					}
					continue
				}
				if debugDarwinRoots {
					fmt.Fprintf(os.Stderr, "crypto/x509: trust settings for %v: %d\n", .Subject, )
				}
			}

			switch  {
			// "Note the distinction between the results kSecTrustSettingsResultTrustRoot
			// and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to
			// root (self-signed) certificates; the latter can only be applied to
			// non-root certificates."
			case macOS.SecTrustSettingsResultTrustRoot:
				if isRootCertificate() {
					 = append(, )
				}
			case macOS.SecTrustSettingsResultTrustAsRoot:
				if !isRootCertificate() {
					 = append(, )
				}

			case macOS.SecTrustSettingsResultDeny:
				// Add this certificate to untrustedRoots, which are subtracted
				// from trustedRoots, so that we don't have to evaluate policies
				// for every root in the system domain, but still apply user and
				// admin policies that override system roots.
				[string(.Raw)] = true

			case macOS.SecTrustSettingsResultUnspecified:
				// Certificates with unspecified trust should be added to a pool
				// of intermediates for chain building, but we don't support it
				// at the moment. This is Issue 35631.

			default:
				if debugDarwinRoots {
					fmt.Fprintf(os.Stderr, "crypto/x509: unknown trust setting for %v: %d\n", .Subject, )
				}
			}
		}
	}

	 := NewCertPool()
	for ,  := range  {
		if ![string(.Raw)] {
			.AddCert()
		}
	}
	return , nil
}

// exportCertificate returns a *Certificate for a SecCertificateRef.
func ( macOS.CFRef) (*Certificate, error) {
	,  := macOS.SecItemExport()
	if  != nil {
		return nil, 
	}
	defer macOS.CFRelease()
	 := macOS.CFDataToSlice()

	return ParseCertificate()
}

// isRootCertificate reports whether Subject and Issuer match.
func ( *Certificate) bool {
	return bytes.Equal(.RawSubject, .RawIssuer)
}

// sslTrustSettingsResult obtains the final kSecTrustSettingsResult value for a
// certificate in the user or admin domain, combining usage constraints for the
// SSL SecTrustSettingsPolicy,
//
// It ignores SecTrustSettingsKeyUsage and kSecTrustSettingsAllowedError, and
// doesn't support kSecTrustSettingsDefaultRootCertSetting.
//
// https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting
func ( macOS.CFRef) (macOS.SecTrustSettingsResult, error) {
	// In Apple's implementation user trust settings override admin trust settings
	// (which themselves override system trust settings). If SecTrustSettingsCopyTrustSettings
	// fails, or returns a NULL trust settings, when looking for the user trust
	// settings then fallback to checking the admin trust settings.
	//
	// See Security-59306.41.2/trust/headers/SecTrustSettings.h for a description of
	// the trust settings overrides, and SecLegacyAnchorSourceCopyUsageConstraints in
	// Security-59306.41.2/trust/trustd/SecCertificateSource.c for a concrete example
	// of how Apple applies the override in the case of NULL trust settings, or non
	// success errors.
	,  := macOS.SecTrustSettingsCopyTrustSettings(, macOS.SecTrustSettingsDomainUser)
	if  != nil ||  == 0 {
		if debugDarwinRoots &&  != macOS.ErrNoTrustSettings {
			fmt.Fprintf(os.Stderr, "crypto/x509: SecTrustSettingsCopyTrustSettings for SecTrustSettingsDomainUser failed: %s\n", )
		}
		,  = macOS.SecTrustSettingsCopyTrustSettings(, macOS.SecTrustSettingsDomainAdmin)
	}
	if  != nil ||  == 0 {
		// If there are neither user nor admin trust settings for a certificate returned
		// from SecTrustSettingsCopyCertificates Apple returns kSecTrustSettingsResultInvalid,
		// as this method is intended to return certificates _which have trust settings_.
		// The most likely case for this being triggered is that the existing trust settings
		// are invalid and cannot be properly parsed. In this case SecTrustSettingsCopyTrustSettings
		// returns errSecInvalidTrustSettings. The existing cgo implementation returns
		// kSecTrustSettingsResultUnspecified in this case, which mostly matches the Apple
		// implementation because we don't do anything with certificates marked with this
		// result.
		//
		// See SecPVCGetTrustSettingsResult in Security-59306.41.2/trust/trustd/SecPolicyServer.c
		if debugDarwinRoots &&  != macOS.ErrNoTrustSettings {
			fmt.Fprintf(os.Stderr, "crypto/x509: SecTrustSettingsCopyTrustSettings for SecTrustSettingsDomainAdmin failed: %s\n", )
		}
		return macOS.SecTrustSettingsResultUnspecified, nil
	}
	defer macOS.CFRelease()

	// "An empty trust settings array means 'always trust this certificate' with an
	// overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot."
	if macOS.CFArrayGetCount() == 0 {
		return macOS.SecTrustSettingsResultTrustRoot, nil
	}

	 := func( macOS.CFRef) bool {
		 := macOS.SecPolicyCopyProperties()
		defer macOS.CFRelease()
		if ,  := macOS.CFDictionaryGetValueIfPresent(, macOS.SecPolicyOid);  {
			return macOS.CFEqual(, macOS.CFRef(macOS.SecPolicyAppleSSL))
		}
		return false
	}

	for  := 0;  < macOS.CFArrayGetCount(); ++ {
		 := macOS.CFArrayGetValueAtIndex(, )

		// First, check if this trust setting is constrained to a non-SSL policy.
		if ,  := macOS.CFDictionaryGetValueIfPresent(, macOS.SecTrustSettingsPolicy);  {
			if !() {
				continue
			}
		}

		// Then check if it is restricted to a hostname, so not a root.
		if ,  := macOS.CFDictionaryGetValueIfPresent(, macOS.SecTrustSettingsPolicyString);  {
			continue
		}

		,  := macOS.CFDictionaryGetValueIfPresent(, macOS.SecTrustSettingsResultKey)
		// "If this key is not present, a default value of kSecTrustSettingsResultTrustRoot is assumed."
		if ! {
			return macOS.SecTrustSettingsResultTrustRoot, nil
		}
		,  := macOS.CFNumberGetValue()
		if  != nil {
			return 0, 
		}

		// If multiple dictionaries match, we are supposed to "OR" them,
		// the semantics of which are not clear. Since TrustRoot and TrustAsRoot
		// are mutually exclusive, Deny should probably override, and Invalid and
		// Unspecified be overridden, approximate this by stopping at the first
		// TrustRoot, TrustAsRoot or Deny.
		switch  := macOS.SecTrustSettingsResult();  {
		case macOS.SecTrustSettingsResultTrustRoot,
			macOS.SecTrustSettingsResultTrustAsRoot,
			macOS.SecTrustSettingsResultDeny:
			return , nil
		}
	}

	// If trust settings are present, but none of them match the policy...
	// the docs don't tell us what to do.
	//
	// "Trust settings for a given use apply if any of the dictionaries in the
	// certificate’s trust settings array satisfies the specified use." suggests
	// that it's as if there were no trust settings at all, so we should maybe
	// fallback to the admin trust settings? TODO(golang.org/issue/38888).

	return macOS.SecTrustSettingsResultUnspecified, nil
}