root_darwin.mx raw

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