diff options
Diffstat (limited to 'src/crypto/x509/internal/macos/security.go')
-rw-r--r-- | src/crypto/x509/internal/macos/security.go | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go new file mode 100644 index 0000000..cf9df2b --- /dev/null +++ b/src/crypto/x509/internal/macos/security.go @@ -0,0 +1,249 @@ +// 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. + +//go:build darwin + +package macOS + +import ( + "errors" + "internal/abi" + "strconv" + "unsafe" +) + +// Security.framework linker flags for the external linker. See Issue 42459. +// +//go:cgo_ldflag "-framework" +//go:cgo_ldflag "Security" + +// Based on https://opensource.apple.com/source/Security/Security-59306.41.2/base/Security.h + +type SecTrustSettingsResult int32 + +const ( + SecTrustSettingsResultInvalid SecTrustSettingsResult = iota + SecTrustSettingsResultTrustRoot + SecTrustSettingsResultTrustAsRoot + SecTrustSettingsResultDeny + SecTrustSettingsResultUnspecified +) + +type SecTrustResultType int32 + +const ( + SecTrustResultInvalid SecTrustResultType = iota + SecTrustResultProceed + SecTrustResultConfirm // deprecated + SecTrustResultDeny + SecTrustResultUnspecified + SecTrustResultRecoverableTrustFailure + SecTrustResultFatalTrustFailure + SecTrustResultOtherError +) + +type SecTrustSettingsDomain int32 + +const ( + SecTrustSettingsDomainUser SecTrustSettingsDomain = iota + SecTrustSettingsDomainAdmin + SecTrustSettingsDomainSystem +) + +const ( + // various macOS error codes that can be returned from + // SecTrustEvaluateWithError that we can map to Go cert + // verification error types. + ErrSecCertificateExpired = -67818 + ErrSecHostNameMismatch = -67602 + ErrSecNotTrusted = -67843 +) + +type OSStatus struct { + call string + status int32 +} + +func (s OSStatus) Error() string { + return s.call + " error: " + strconv.Itoa(int(s.status)) +} + +// Dictionary keys are defined as build-time strings with CFSTR, but the Go +// linker's internal linking mode can't handle CFSTR relocations. Create our +// own dynamic strings instead and just never release them. +// +// Note that this might be the only thing that can break over time if +// these values change, as the ABI arguably requires using the strings +// pointed to by the symbols, not values that happen to be equal to them. + +var SecTrustSettingsResultKey = StringToCFString("kSecTrustSettingsResult") +var SecTrustSettingsPolicy = StringToCFString("kSecTrustSettingsPolicy") +var SecTrustSettingsPolicyString = StringToCFString("kSecTrustSettingsPolicyString") +var SecPolicyOid = StringToCFString("SecPolicyOid") +var SecPolicyAppleSSL = StringToCFString("1.2.840.113635.100.1.3") // defined by POLICYMACRO + +var ErrNoTrustSettings = errors.New("no trust settings found") + +const errSecNoTrustSettings = -25263 + +//go:cgo_import_dynamic x509_SecTrustSettingsCopyCertificates SecTrustSettingsCopyCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustSettingsCopyCertificates(domain SecTrustSettingsDomain) (certArray CFRef, err error) { + ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyCertificates_trampoline), uintptr(domain), + uintptr(unsafe.Pointer(&certArray)), 0, 0, 0, 0) + if int32(ret) == errSecNoTrustSettings { + return 0, ErrNoTrustSettings + } else if ret != 0 { + return 0, OSStatus{"SecTrustSettingsCopyCertificates", int32(ret)} + } + return certArray, nil +} +func x509_SecTrustSettingsCopyCertificates_trampoline() + +const errSecItemNotFound = -25300 + +//go:cgo_import_dynamic x509_SecTrustSettingsCopyTrustSettings SecTrustSettingsCopyTrustSettings "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustSettingsCopyTrustSettings(cert CFRef, domain SecTrustSettingsDomain) (trustSettings CFRef, err error) { + ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyTrustSettings_trampoline), uintptr(cert), uintptr(domain), + uintptr(unsafe.Pointer(&trustSettings)), 0, 0, 0) + if int32(ret) == errSecItemNotFound { + return 0, ErrNoTrustSettings + } else if ret != 0 { + return 0, OSStatus{"SecTrustSettingsCopyTrustSettings", int32(ret)} + } + return trustSettings, nil +} +func x509_SecTrustSettingsCopyTrustSettings_trampoline() + +//go:cgo_import_dynamic x509_SecPolicyCopyProperties SecPolicyCopyProperties "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecPolicyCopyProperties(policy CFRef) CFRef { + ret := syscall(abi.FuncPCABI0(x509_SecPolicyCopyProperties_trampoline), uintptr(policy), 0, 0, 0, 0, 0) + return CFRef(ret) +} +func x509_SecPolicyCopyProperties_trampoline() + +//go:cgo_import_dynamic x509_SecTrustCreateWithCertificates SecTrustCreateWithCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustCreateWithCertificates(certs CFRef, policies CFRef) (CFRef, error) { + var trustObj CFRef + ret := syscall(abi.FuncPCABI0(x509_SecTrustCreateWithCertificates_trampoline), uintptr(certs), uintptr(policies), + uintptr(unsafe.Pointer(&trustObj)), 0, 0, 0) + if int32(ret) != 0 { + return 0, OSStatus{"SecTrustCreateWithCertificates", int32(ret)} + } + return trustObj, nil +} +func x509_SecTrustCreateWithCertificates_trampoline() + +//go:cgo_import_dynamic x509_SecCertificateCreateWithData SecCertificateCreateWithData "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecCertificateCreateWithData(b []byte) (CFRef, error) { + data := BytesToCFData(b) + defer CFRelease(data) + ret := syscall(abi.FuncPCABI0(x509_SecCertificateCreateWithData_trampoline), kCFAllocatorDefault, uintptr(data), 0, 0, 0, 0) + // Returns NULL if the data passed in the data parameter is not a valid + // DER-encoded X.509 certificate. + if ret == 0 { + return 0, errors.New("SecCertificateCreateWithData: invalid certificate") + } + return CFRef(ret), nil +} +func x509_SecCertificateCreateWithData_trampoline() + +//go:cgo_import_dynamic x509_SecPolicyCreateSSL SecPolicyCreateSSL "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecPolicyCreateSSL(name string) CFRef { + var hostname CFString + if name != "" { + hostname = StringToCFString(name) + defer CFRelease(CFRef(hostname)) + } + ret := syscall(abi.FuncPCABI0(x509_SecPolicyCreateSSL_trampoline), 1 /* true */, uintptr(hostname), 0, 0, 0, 0) + return CFRef(ret) +} +func x509_SecPolicyCreateSSL_trampoline() + +//go:cgo_import_dynamic x509_SecTrustSetVerifyDate SecTrustSetVerifyDate "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustSetVerifyDate(trustObj CFRef, dateRef CFRef) error { + ret := syscall(abi.FuncPCABI0(x509_SecTrustSetVerifyDate_trampoline), uintptr(trustObj), uintptr(dateRef), 0, 0, 0, 0) + if int32(ret) != 0 { + return OSStatus{"SecTrustSetVerifyDate", int32(ret)} + } + return nil +} +func x509_SecTrustSetVerifyDate_trampoline() + +//go:cgo_import_dynamic x509_SecTrustEvaluate SecTrustEvaluate "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustEvaluate(trustObj CFRef) (CFRef, error) { + var result CFRef + ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluate_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)), 0, 0, 0, 0) + if int32(ret) != 0 { + return 0, OSStatus{"SecTrustEvaluate", int32(ret)} + } + return CFRef(result), nil +} +func x509_SecTrustEvaluate_trampoline() + +//go:cgo_import_dynamic x509_SecTrustGetResult SecTrustGetResult "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustGetResult(trustObj CFRef, result CFRef) (CFRef, CFRef, error) { + var chain, info CFRef + ret := syscall(abi.FuncPCABI0(x509_SecTrustGetResult_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)), + uintptr(unsafe.Pointer(&chain)), uintptr(unsafe.Pointer(&info)), 0, 0) + if int32(ret) != 0 { + return 0, 0, OSStatus{"SecTrustGetResult", int32(ret)} + } + return chain, info, nil +} +func x509_SecTrustGetResult_trampoline() + +//go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustEvaluateWithError(trustObj CFRef) (int, error) { + var errRef CFRef + ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluateWithError_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&errRef)), 0, 0, 0, 0) + if int32(ret) != 1 { + errStr := CFErrorCopyDescription(errRef) + err := errors.New(CFStringToString(errStr)) + errCode := CFErrorGetCode(errRef) + CFRelease(errRef) + CFRelease(errStr) + return errCode, err + } + return 0, nil +} +func x509_SecTrustEvaluateWithError_trampoline() + +//go:cgo_import_dynamic x509_SecTrustGetCertificateCount SecTrustGetCertificateCount "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustGetCertificateCount(trustObj CFRef) int { + ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateCount_trampoline), uintptr(trustObj), 0, 0, 0, 0, 0) + return int(ret) +} +func x509_SecTrustGetCertificateCount_trampoline() + +//go:cgo_import_dynamic x509_SecTrustGetCertificateAtIndex SecTrustGetCertificateAtIndex "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecTrustGetCertificateAtIndex(trustObj CFRef, i int) CFRef { + ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateAtIndex_trampoline), uintptr(trustObj), uintptr(i), 0, 0, 0, 0) + return CFRef(ret) +} +func x509_SecTrustGetCertificateAtIndex_trampoline() + +//go:cgo_import_dynamic x509_SecCertificateCopyData SecCertificateCopyData "/System/Library/Frameworks/Security.framework/Versions/A/Security" + +func SecCertificateCopyData(cert CFRef) ([]byte, error) { + ret := syscall(abi.FuncPCABI0(x509_SecCertificateCopyData_trampoline), uintptr(cert), 0, 0, 0, 0, 0) + if ret == 0 { + return nil, errors.New("x509: invalid certificate object") + } + b := CFDataToSlice(CFRef(ret)) + CFRelease(CFRef(ret)) + return b, nil +} +func x509_SecCertificateCopyData_trampoline() |