Source file src/crypto/x509/root_darwin.go

     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  package x509
     6  
     7  import (
     8  	"crypto/x509/internal/macos"
     9  	"errors"
    10  	"fmt"
    11  )
    12  
    13  // macOS has no default SSL_CERT_{FILE,DIR} paths.
    14  var certFiles, certDirectories []string
    15  
    16  func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
    17  	certs := macos.CFArrayCreateMutable()
    18  	defer macos.ReleaseCFArray(certs)
    19  	leaf, err := macos.SecCertificateCreateWithData(c.Raw)
    20  	if err != nil {
    21  		return nil, errors.New("invalid leaf certificate")
    22  	}
    23  	macos.CFArrayAppendValue(certs, leaf)
    24  	if opts.Intermediates != nil {
    25  		for _, lc := range opts.Intermediates.lazyCerts {
    26  			c, err := lc.getCert()
    27  			if err != nil {
    28  				return nil, err
    29  			}
    30  			sc, err := macos.SecCertificateCreateWithData(c.Raw)
    31  			if err != nil {
    32  				return nil, err
    33  			}
    34  			macos.CFArrayAppendValue(certs, sc)
    35  		}
    36  	}
    37  
    38  	policies := macos.CFArrayCreateMutable()
    39  	defer macos.ReleaseCFArray(policies)
    40  	sslPolicy, err := macos.SecPolicyCreateSSL(opts.DNSName)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	macos.CFArrayAppendValue(policies, sslPolicy)
    45  
    46  	trustObj, err := macos.SecTrustCreateWithCertificates(certs, policies)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	defer macos.CFRelease(trustObj)
    51  
    52  	if !opts.CurrentTime.IsZero() {
    53  		dateRef := macos.TimeToCFDateRef(opts.CurrentTime)
    54  		defer macos.CFRelease(dateRef)
    55  		if err := macos.SecTrustSetVerifyDate(trustObj, dateRef); err != nil {
    56  			return nil, err
    57  		}
    58  	}
    59  
    60  	// TODO(roland): we may want to allow passing in SCTs via VerifyOptions and
    61  	// set them via SecTrustSetSignedCertificateTimestamps, since Apple will
    62  	// always enforce its SCT requirements, and there are still _some_ people
    63  	// using TLS or OCSP for that.
    64  
    65  	if ret, err := macos.SecTrustEvaluateWithError(trustObj); err != nil {
    66  		switch ret {
    67  		case macos.ErrSecCertificateExpired:
    68  			return nil, CertificateInvalidError{c, Expired, err.Error()}
    69  		case macos.ErrSecHostNameMismatch:
    70  			return nil, HostnameError{c, opts.DNSName}
    71  		case macos.ErrSecNotTrusted:
    72  			return nil, UnknownAuthorityError{Cert: c}
    73  		default:
    74  			return nil, fmt.Errorf("x509: %s", err)
    75  		}
    76  	}
    77  
    78  	chain := [][]*Certificate{{}}
    79  	chainRef, err := macos.SecTrustCopyCertificateChain(trustObj)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	defer macos.CFRelease(chainRef)
    84  	for i := 0; i < macos.CFArrayGetCount(chainRef); i++ {
    85  		certRef := macos.CFArrayGetValueAtIndex(chainRef, i)
    86  		cert, err := exportCertificate(certRef)
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  		chain[0] = append(chain[0], cert)
    91  	}
    92  	if len(chain[0]) == 0 {
    93  		// This should _never_ happen, but to be safe
    94  		return nil, errors.New("x509: macos certificate verification internal error")
    95  	}
    96  
    97  	if opts.DNSName != "" {
    98  		// If we have a DNS name, apply our own name verification
    99  		if err := chain[0][0].VerifyHostname(opts.DNSName); err != nil {
   100  			return nil, err
   101  		}
   102  	}
   103  
   104  	keyUsages := opts.KeyUsages
   105  	if len(keyUsages) == 0 {
   106  		keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
   107  	}
   108  
   109  	// If any key usage is acceptable then we're done.
   110  	for _, usage := range keyUsages {
   111  		if usage == ExtKeyUsageAny {
   112  			return chain, nil
   113  		}
   114  	}
   115  
   116  	if !checkChainForKeyUsage(chain[0], keyUsages) {
   117  		return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
   118  	}
   119  
   120  	return chain, nil
   121  }
   122  
   123  // exportCertificate returns a *Certificate for a SecCertificateRef.
   124  func exportCertificate(cert macos.CFRef) (*Certificate, error) {
   125  	data, err := macos.SecCertificateCopyData(cert)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	return ParseCertificate(data)
   130  }
   131  

View as plain text