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  	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  

View as plain text