diff options
Diffstat (limited to 'src/crypto/x509/root_darwin.go')
-rw-r--r-- | src/crypto/x509/root_darwin.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go new file mode 100644 index 0000000..c35885a --- /dev/null +++ b/src/crypto/x509/root_darwin.go @@ -0,0 +1,123 @@ +// 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. + +package x509 + +import ( + macOS "crypto/x509/internal/macos" + "errors" + "fmt" +) + +func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { + certs := macOS.CFArrayCreateMutable() + defer macOS.ReleaseCFArray(certs) + leaf := macOS.SecCertificateCreateWithData(c.Raw) + if leaf == 0 { + return nil, errors.New("invalid leaf certificate") + } + macOS.CFArrayAppendValue(certs, leaf) + if opts.Intermediates != nil { + for _, lc := range opts.Intermediates.lazyCerts { + c, err := lc.getCert() + if err != nil { + return nil, err + } + sc := macOS.SecCertificateCreateWithData(c.Raw) + if sc != 0 { + macOS.CFArrayAppendValue(certs, sc) + } + } + } + + policies := macOS.CFArrayCreateMutable() + defer macOS.ReleaseCFArray(policies) + sslPolicy := macOS.SecPolicyCreateSSL(opts.DNSName) + macOS.CFArrayAppendValue(policies, sslPolicy) + + trustObj, err := macOS.SecTrustCreateWithCertificates(certs, policies) + if err != nil { + return nil, err + } + defer macOS.CFRelease(trustObj) + + if !opts.CurrentTime.IsZero() { + dateRef := macOS.TimeToCFDateRef(opts.CurrentTime) + defer macOS.CFRelease(dateRef) + if err := macOS.SecTrustSetVerifyDate(trustObj, dateRef); err != nil { + return nil, err + } + } + + // TODO(roland): we may want to allow passing in SCTs via VerifyOptions and + // set them via SecTrustSetSignedCertificateTimestamps, since Apple will + // always enforce its SCT requirements, and there are still _some_ people + // using TLS or OCSP for that. + + if ret, err := macOS.SecTrustEvaluateWithError(trustObj); err != nil { + switch ret { + case macOS.ErrSecCertificateExpired: + return nil, CertificateInvalidError{c, Expired, err.Error()} + case macOS.ErrSecHostNameMismatch: + return nil, HostnameError{c, opts.DNSName} + case macOS.ErrSecNotTrusted: + return nil, UnknownAuthorityError{Cert: c} + default: + return nil, fmt.Errorf("x509: %s", err) + } + } + + chain := [][]*Certificate{{}} + numCerts := macOS.SecTrustGetCertificateCount(trustObj) + for i := 0; i < numCerts; i++ { + certRef := macOS.SecTrustGetCertificateAtIndex(trustObj, i) + cert, err := exportCertificate(certRef) + if err != nil { + return nil, err + } + chain[0] = append(chain[0], cert) + } + if len(chain[0]) == 0 { + // This should _never_ happen, but to be safe + return nil, errors.New("x509: macOS certificate verification internal error") + } + + if opts.DNSName != "" { + // If we have a DNS name, apply our own name verification + if err := chain[0][0].VerifyHostname(opts.DNSName); err != nil { + return nil, err + } + } + + keyUsages := opts.KeyUsages + if len(keyUsages) == 0 { + keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} + } + + // If any key usage is acceptable then we're done. + for _, usage := range keyUsages { + if usage == ExtKeyUsageAny { + return chain, nil + } + } + + if !checkChainForKeyUsage(chain[0], keyUsages) { + return nil, CertificateInvalidError{c, IncompatibleUsage, ""} + } + + return chain, nil +} + +// exportCertificate returns a *Certificate for a SecCertificateRef. +func exportCertificate(cert macOS.CFRef) (*Certificate, error) { + data, err := macOS.SecCertificateCopyData(cert) + if err != nil { + return nil, err + } + return ParseCertificate(data) +} + +func loadSystemRoots() (*CertPool, error) { + return &CertPool{systemPool: true}, nil +} |