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//go:build darwin
6
7package macOS
8
9import (
10	"errors"
11	"internal/abi"
12	"strconv"
13	"unsafe"
14)
15
16// Security.framework linker flags for the external linker. See Issue 42459.
17//
18//go:cgo_ldflag "-framework"
19//go:cgo_ldflag "Security"
20
21// Based on https://opensource.apple.com/source/Security/Security-59306.41.2/base/Security.h
22
23type SecTrustSettingsResult int32
24
25const (
26	SecTrustSettingsResultInvalid SecTrustSettingsResult = iota
27	SecTrustSettingsResultTrustRoot
28	SecTrustSettingsResultTrustAsRoot
29	SecTrustSettingsResultDeny
30	SecTrustSettingsResultUnspecified
31)
32
33type SecTrustResultType int32
34
35const (
36	SecTrustResultInvalid SecTrustResultType = iota
37	SecTrustResultProceed
38	SecTrustResultConfirm // deprecated
39	SecTrustResultDeny
40	SecTrustResultUnspecified
41	SecTrustResultRecoverableTrustFailure
42	SecTrustResultFatalTrustFailure
43	SecTrustResultOtherError
44)
45
46type SecTrustSettingsDomain int32
47
48const (
49	SecTrustSettingsDomainUser SecTrustSettingsDomain = iota
50	SecTrustSettingsDomainAdmin
51	SecTrustSettingsDomainSystem
52)
53
54const (
55	// various macOS error codes that can be returned from
56	// SecTrustEvaluateWithError that we can map to Go cert
57	// verification error types.
58	ErrSecCertificateExpired = -67818
59	ErrSecHostNameMismatch   = -67602
60	ErrSecNotTrusted         = -67843
61)
62
63type OSStatus struct {
64	call   string
65	status int32
66}
67
68func (s OSStatus) Error() string {
69	return s.call + " error: " + strconv.Itoa(int(s.status))
70}
71
72// Dictionary keys are defined as build-time strings with CFSTR, but the Go
73// linker's internal linking mode can't handle CFSTR relocations. Create our
74// own dynamic strings instead and just never release them.
75//
76// Note that this might be the only thing that can break over time if
77// these values change, as the ABI arguably requires using the strings
78// pointed to by the symbols, not values that happen to be equal to them.
79
80var SecTrustSettingsResultKey = StringToCFString("kSecTrustSettingsResult")
81var SecTrustSettingsPolicy = StringToCFString("kSecTrustSettingsPolicy")
82var SecTrustSettingsPolicyString = StringToCFString("kSecTrustSettingsPolicyString")
83var SecPolicyOid = StringToCFString("SecPolicyOid")
84var SecPolicyAppleSSL = StringToCFString("1.2.840.113635.100.1.3") // defined by POLICYMACRO
85
86var ErrNoTrustSettings = errors.New("no trust settings found")
87
88const errSecNoTrustSettings = -25263
89
90//go:cgo_import_dynamic x509_SecTrustSettingsCopyCertificates SecTrustSettingsCopyCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security"
91
92func SecTrustSettingsCopyCertificates(domain SecTrustSettingsDomain) (certArray CFRef, err error) {
93	ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyCertificates_trampoline), uintptr(domain),
94		uintptr(unsafe.Pointer(&certArray)), 0, 0, 0, 0)
95	if int32(ret) == errSecNoTrustSettings {
96		return 0, ErrNoTrustSettings
97	} else if ret != 0 {
98		return 0, OSStatus{"SecTrustSettingsCopyCertificates", int32(ret)}
99	}
100	return certArray, nil
101}
102func x509_SecTrustSettingsCopyCertificates_trampoline()
103
104const errSecItemNotFound = -25300
105
106//go:cgo_import_dynamic x509_SecTrustSettingsCopyTrustSettings SecTrustSettingsCopyTrustSettings "/System/Library/Frameworks/Security.framework/Versions/A/Security"
107
108func SecTrustSettingsCopyTrustSettings(cert CFRef, domain SecTrustSettingsDomain) (trustSettings CFRef, err error) {
109	ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyTrustSettings_trampoline), uintptr(cert), uintptr(domain),
110		uintptr(unsafe.Pointer(&trustSettings)), 0, 0, 0)
111	if int32(ret) == errSecItemNotFound {
112		return 0, ErrNoTrustSettings
113	} else if ret != 0 {
114		return 0, OSStatus{"SecTrustSettingsCopyTrustSettings", int32(ret)}
115	}
116	return trustSettings, nil
117}
118func x509_SecTrustSettingsCopyTrustSettings_trampoline()
119
120//go:cgo_import_dynamic x509_SecTrustCreateWithCertificates SecTrustCreateWithCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security"
121
122func SecTrustCreateWithCertificates(certs CFRef, policies CFRef) (CFRef, error) {
123	var trustObj CFRef
124	ret := syscall(abi.FuncPCABI0(x509_SecTrustCreateWithCertificates_trampoline), uintptr(certs), uintptr(policies),
125		uintptr(unsafe.Pointer(&trustObj)), 0, 0, 0)
126	if int32(ret) != 0 {
127		return 0, OSStatus{"SecTrustCreateWithCertificates", int32(ret)}
128	}
129	return trustObj, nil
130}
131func x509_SecTrustCreateWithCertificates_trampoline()
132
133//go:cgo_import_dynamic x509_SecCertificateCreateWithData SecCertificateCreateWithData "/System/Library/Frameworks/Security.framework/Versions/A/Security"
134
135func SecCertificateCreateWithData(b []byte) (CFRef, error) {
136	data := BytesToCFData(b)
137	defer CFRelease(data)
138	ret := syscall(abi.FuncPCABI0(x509_SecCertificateCreateWithData_trampoline), kCFAllocatorDefault, uintptr(data), 0, 0, 0, 0)
139	// Returns NULL if the data passed in the data parameter is not a valid
140	// DER-encoded X.509 certificate.
141	if ret == 0 {
142		return 0, errors.New("SecCertificateCreateWithData: invalid certificate")
143	}
144	return CFRef(ret), nil
145}
146func x509_SecCertificateCreateWithData_trampoline()
147
148//go:cgo_import_dynamic x509_SecPolicyCreateSSL SecPolicyCreateSSL "/System/Library/Frameworks/Security.framework/Versions/A/Security"
149
150func SecPolicyCreateSSL(name string) (CFRef, error) {
151	var hostname CFString
152	if name != "" {
153		hostname = StringToCFString(name)
154		defer CFRelease(CFRef(hostname))
155	}
156	ret := syscall(abi.FuncPCABI0(x509_SecPolicyCreateSSL_trampoline), 1 /* true */, uintptr(hostname), 0, 0, 0, 0)
157	if ret == 0 {
158		return 0, OSStatus{"SecPolicyCreateSSL", int32(ret)}
159	}
160	return CFRef(ret), nil
161}
162func x509_SecPolicyCreateSSL_trampoline()
163
164//go:cgo_import_dynamic x509_SecTrustSetVerifyDate SecTrustSetVerifyDate "/System/Library/Frameworks/Security.framework/Versions/A/Security"
165
166func SecTrustSetVerifyDate(trustObj CFRef, dateRef CFRef) error {
167	ret := syscall(abi.FuncPCABI0(x509_SecTrustSetVerifyDate_trampoline), uintptr(trustObj), uintptr(dateRef), 0, 0, 0, 0)
168	if int32(ret) != 0 {
169		return OSStatus{"SecTrustSetVerifyDate", int32(ret)}
170	}
171	return nil
172}
173func x509_SecTrustSetVerifyDate_trampoline()
174
175//go:cgo_import_dynamic x509_SecTrustEvaluate SecTrustEvaluate "/System/Library/Frameworks/Security.framework/Versions/A/Security"
176
177func SecTrustEvaluate(trustObj CFRef) (CFRef, error) {
178	var result CFRef
179	ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluate_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)), 0, 0, 0, 0)
180	if int32(ret) != 0 {
181		return 0, OSStatus{"SecTrustEvaluate", int32(ret)}
182	}
183	return CFRef(result), nil
184}
185func x509_SecTrustEvaluate_trampoline()
186
187//go:cgo_import_dynamic x509_SecTrustGetResult SecTrustGetResult "/System/Library/Frameworks/Security.framework/Versions/A/Security"
188
189func SecTrustGetResult(trustObj CFRef, result CFRef) (CFRef, CFRef, error) {
190	var chain, info CFRef
191	ret := syscall(abi.FuncPCABI0(x509_SecTrustGetResult_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)),
192		uintptr(unsafe.Pointer(&chain)), uintptr(unsafe.Pointer(&info)), 0, 0)
193	if int32(ret) != 0 {
194		return 0, 0, OSStatus{"SecTrustGetResult", int32(ret)}
195	}
196	return chain, info, nil
197}
198func x509_SecTrustGetResult_trampoline()
199
200//go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security"
201
202func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
203	var errRef CFRef
204	ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluateWithError_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&errRef)), 0, 0, 0, 0)
205	if int32(ret) != 1 {
206		errStr := CFErrorCopyDescription(errRef)
207		err := errors.New(CFStringToString(errStr))
208		errCode := CFErrorGetCode(errRef)
209		CFRelease(errRef)
210		CFRelease(errStr)
211		return errCode, err
212	}
213	return 0, nil
214}
215func x509_SecTrustEvaluateWithError_trampoline()
216
217//go:cgo_import_dynamic x509_SecTrustGetCertificateCount SecTrustGetCertificateCount "/System/Library/Frameworks/Security.framework/Versions/A/Security"
218
219func SecTrustGetCertificateCount(trustObj CFRef) int {
220	ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateCount_trampoline), uintptr(trustObj), 0, 0, 0, 0, 0)
221	return int(ret)
222}
223func x509_SecTrustGetCertificateCount_trampoline()
224
225//go:cgo_import_dynamic x509_SecTrustGetCertificateAtIndex SecTrustGetCertificateAtIndex "/System/Library/Frameworks/Security.framework/Versions/A/Security"
226
227func SecTrustGetCertificateAtIndex(trustObj CFRef, i int) (CFRef, error) {
228	ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateAtIndex_trampoline), uintptr(trustObj), uintptr(i), 0, 0, 0, 0)
229	if ret == 0 {
230		return 0, OSStatus{"SecTrustGetCertificateAtIndex", int32(ret)}
231	}
232	return CFRef(ret), nil
233}
234func x509_SecTrustGetCertificateAtIndex_trampoline()
235
236//go:cgo_import_dynamic x509_SecCertificateCopyData SecCertificateCopyData "/System/Library/Frameworks/Security.framework/Versions/A/Security"
237
238func SecCertificateCopyData(cert CFRef) ([]byte, error) {
239	ret := syscall(abi.FuncPCABI0(x509_SecCertificateCopyData_trampoline), uintptr(cert), 0, 0, 0, 0, 0)
240	if ret == 0 {
241		return nil, errors.New("x509: invalid certificate object")
242	}
243	b := CFDataToSlice(CFRef(ret))
244	CFRelease(CFRef(ret))
245	return b, nil
246}
247func x509_SecCertificateCopyData_trampoline()
248