Skip to content

Commit feb024f

Browse files
crypto/x509: use platform verifier on darwin
When VerifyOptions.Roots is nil, default to using the platform X.509 certificate verification APIs on darwin, rather than using the Go verifier. Since our oldest supported version of macOS is 10.12, we are able to use the modern verification APIs, and don't need to resort to the complex chain building trickery employed by chromium et al. Unfortunately there is not a clean way to programmatically add test roots to the system trust store that the builders would tolerate. The most obvious solution, using 'security add-trusted-cert' requires human interaction for authorization. We could also manually add anchors to the constructed SecTrustRef, but that would require adding a whole bunch of plumbing for test functionality, and would mean we weren't really testing the actual non-test path. The path I've chosen here is to just utilize existing valid, and purposefully invalid, trusted chains, from google.com and the badssl.com test suite. This requires external network access, but most accurately reflects real world contexts. This change removes the x509.SystemCertPool() functionality, which will be ammended in a follow-up change which supports the suggested hybrid pool approach described in #46287. Updates #46287 Fixes #42414 Fixes #38888 Fixes #35631 Fixes #19561 Change-Id: I17f0d6c5cb3ef8a1f2731ce3296478b28d30df46 Reviewed-on: https://go-review.googlesource.com/c/go/+/353132 Trust: Roland Shoemaker <[email protected]> Run-TryBot: Roland Shoemaker <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 8f923a4 commit feb024f

File tree

10 files changed

+409
-225
lines changed

10 files changed

+409
-225
lines changed

src/crypto/x509/cert_pool.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ func SystemCertPool() (*CertPool, error) {
106106
if runtime.GOOS == "windows" {
107107
// Issue 16736, 18609:
108108
return nil, errors.New("crypto/x509: system root pool is not available on Windows")
109+
} else if runtime.GOOS == "darwin" {
110+
return nil, errors.New("crypto/x509: system root pool is not available on macOS")
109111
}
110112

111113
if sysRoots := systemRootsPool(); sysRoots != nil {

src/crypto/x509/internal/macos/corefoundation.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"internal/abi"
1515
"reflect"
1616
"runtime"
17+
"time"
1718
"unsafe"
1819
)
1920

@@ -35,11 +36,37 @@ func CFDataToSlice(data CFRef) []byte {
3536
return out
3637
}
3738

39+
// CFStringToString returns a Go string representation of the passed
40+
// in CFString.
41+
func CFStringToString(ref CFRef) string {
42+
data := CFStringCreateExternalRepresentation(ref)
43+
b := CFDataToSlice(data)
44+
CFRelease(data)
45+
return string(b)
46+
}
47+
48+
// TimeToCFDateRef converts a time.Time into an apple CFDateRef
49+
func TimeToCFDateRef(t time.Time) CFRef {
50+
secs := t.Sub(time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)).Seconds()
51+
ref := CFDateCreate(int(secs))
52+
return ref
53+
}
54+
3855
type CFString CFRef
3956

4057
const kCFAllocatorDefault = 0
4158
const kCFStringEncodingUTF8 = 0x08000100
4259

60+
//go:cgo_import_dynamic x509_CFDataCreate CFDataCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
61+
62+
func BytesToCFData(b []byte) CFRef {
63+
p := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data)
64+
ret := syscall(abi.FuncPCABI0(x509_CFDataCreate_trampoline), kCFAllocatorDefault, uintptr(p), uintptr(len(b)), 0, 0, 0)
65+
runtime.KeepAlive(p)
66+
return CFRef(ret)
67+
}
68+
func x509_CFDataCreate_trampoline()
69+
4370
//go:cgo_import_dynamic x509_CFStringCreateWithBytes CFStringCreateWithBytes "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
4471

4572
// StringToCFString returns a copy of the UTF-8 contents of s as a new CFString.
@@ -126,5 +153,55 @@ func CFRelease(ref CFRef) {
126153
}
127154
func x509_CFRelease_trampoline()
128155

156+
//go:cgo_import_dynamic x509_CFArrayCreateMutable CFArrayCreateMutable "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
157+
158+
func CFArrayCreateMutable() CFRef {
159+
ret := syscall(abi.FuncPCABI0(x509_CFArrayCreateMutable_trampoline), kCFAllocatorDefault, 0, 0 /* kCFTypeArrayCallBacks */, 0, 0, 0)
160+
return CFRef(ret)
161+
}
162+
func x509_CFArrayCreateMutable_trampoline()
163+
164+
//go:cgo_import_dynamic x509_CFArrayAppendValue CFArrayAppendValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
165+
166+
func CFArrayAppendValue(array CFRef, val CFRef) {
167+
syscall(abi.FuncPCABI0(x509_CFArrayAppendValue_trampoline), uintptr(array), uintptr(val), 0, 0, 0, 0)
168+
}
169+
func x509_CFArrayAppendValue_trampoline()
170+
171+
//go:cgo_import_dynamic x509_CFDateCreate CFDateCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
172+
173+
func CFDateCreate(seconds int) CFRef {
174+
ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, uintptr(seconds), 0, 0, 0, 0)
175+
return CFRef(ret)
176+
}
177+
func x509_CFDateCreate_trampoline()
178+
179+
//go:cgo_import_dynamic x509_CFErrorCopyDescription CFErrorCopyDescription "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
180+
181+
func CFErrorCopyDescription(errRef CFRef) CFRef {
182+
ret := syscall(abi.FuncPCABI0(x509_CFErrorCopyDescription_trampoline), uintptr(errRef), 0, 0, 0, 0, 0)
183+
return CFRef(ret)
184+
}
185+
func x509_CFErrorCopyDescription_trampoline()
186+
187+
//go:cgo_import_dynamic x509_CFStringCreateExternalRepresentation CFStringCreateExternalRepresentation "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
188+
189+
func CFStringCreateExternalRepresentation(strRef CFRef) CFRef {
190+
ret := syscall(abi.FuncPCABI0(x509_CFStringCreateExternalRepresentation_trampoline), kCFAllocatorDefault, uintptr(strRef), kCFStringEncodingUTF8, 0, 0, 0)
191+
return CFRef(ret)
192+
}
193+
func x509_CFStringCreateExternalRepresentation_trampoline()
194+
129195
// syscall is implemented in the runtime package (runtime/sys_darwin.go)
130196
func syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr
197+
198+
// ReleaseCFArray iterates through an array, releasing its contents, and then
199+
// releases the array itself. This is necessary because we cannot, easily, set the
200+
// CFArrayCallBacks argument when creating CFArrays.
201+
func ReleaseCFArray(array CFRef) {
202+
for i := 0; i < CFArrayGetCount(array); i++ {
203+
ref := CFArrayGetValueAtIndex(array, i)
204+
CFRelease(ref)
205+
}
206+
CFRelease(array)
207+
}

src/crypto/x509/internal/macos/corefoundation.s

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,15 @@ TEXT ·x509_CFNumberGetValue_trampoline(SB),NOSPLIT,$0-0
2828
JMP x509_CFNumberGetValue(SB)
2929
TEXT ·x509_CFEqual_trampoline(SB),NOSPLIT,$0-0
3030
JMP x509_CFEqual(SB)
31+
TEXT ·x509_CFArrayCreateMutable_trampoline(SB),NOSPLIT,$0-0
32+
JMP x509_CFArrayCreateMutable(SB)
33+
TEXT ·x509_CFArrayAppendValue_trampoline(SB),NOSPLIT,$0-0
34+
JMP x509_CFArrayAppendValue(SB)
35+
TEXT ·x509_CFDateCreate_trampoline(SB),NOSPLIT,$0-0
36+
JMP x509_CFDateCreate(SB)
37+
TEXT ·x509_CFDataCreate_trampoline(SB),NOSPLIT,$0-0
38+
JMP x509_CFDataCreate(SB)
39+
TEXT ·x509_CFErrorCopyDescription_trampoline(SB),NOSPLIT,$0-0
40+
JMP x509_CFErrorCopyDescription(SB)
41+
TEXT ·x509_CFStringCreateExternalRepresentation_trampoline(SB),NOSPLIT,$0-0
42+
JMP x509_CFStringCreateExternalRepresentation(SB)

src/crypto/x509/internal/macos/security.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package macOS
88

99
import (
1010
"errors"
11+
"fmt"
1112
"internal/abi"
1213
"strconv"
1314
"unsafe"
@@ -29,6 +30,19 @@ const (
2930
SecTrustSettingsResultUnspecified
3031
)
3132

33+
type SecTrustResultType int32
34+
35+
const (
36+
SecTrustResultInvalid SecTrustResultType = iota
37+
SecTrustResultProceed
38+
SecTrustResultConfirm // deprecated
39+
SecTrustResultDeny
40+
SecTrustResultUnspecified
41+
SecTrustResultRecoverableTrustFailure
42+
SecTrustResultFatalTrustFailure
43+
SecTrustResultOtherError
44+
)
45+
3246
type SecTrustSettingsDomain int32
3347

3448
const (
@@ -115,3 +129,107 @@ func SecPolicyCopyProperties(policy CFRef) CFRef {
115129
return CFRef(ret)
116130
}
117131
func x509_SecPolicyCopyProperties_trampoline()
132+
133+
//go:cgo_import_dynamic x509_SecTrustCreateWithCertificates SecTrustCreateWithCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security"
134+
135+
func SecTrustCreateWithCertificates(certs CFRef, policies CFRef) (CFRef, error) {
136+
var trustObj CFRef
137+
ret := syscall(abi.FuncPCABI0(x509_SecTrustCreateWithCertificates_trampoline), uintptr(certs), uintptr(policies),
138+
uintptr(unsafe.Pointer(&trustObj)), 0, 0, 0)
139+
if int32(ret) != 0 {
140+
return 0, OSStatus{"SecTrustCreateWithCertificates", int32(ret)}
141+
}
142+
return trustObj, nil
143+
}
144+
func x509_SecTrustCreateWithCertificates_trampoline()
145+
146+
//go:cgo_import_dynamic x509_SecCertificateCreateWithData SecCertificateCreateWithData "/System/Library/Frameworks/Security.framework/Versions/A/Security"
147+
148+
func SecCertificateCreateWithData(b []byte) CFRef {
149+
data := BytesToCFData(b)
150+
ret := syscall(abi.FuncPCABI0(x509_SecCertificateCreateWithData_trampoline), kCFAllocatorDefault, uintptr(data), 0, 0, 0, 0)
151+
CFRelease(data)
152+
return CFRef(ret)
153+
}
154+
func x509_SecCertificateCreateWithData_trampoline()
155+
156+
//go:cgo_import_dynamic x509_SecPolicyCreateSSL SecPolicyCreateSSL "/System/Library/Frameworks/Security.framework/Versions/A/Security"
157+
158+
func SecPolicyCreateSSL(name string) CFRef {
159+
var hostname CFString
160+
if name != "" {
161+
hostname = StringToCFString(name)
162+
defer CFRelease(CFRef(hostname))
163+
}
164+
ret := syscall(abi.FuncPCABI0(x509_SecPolicyCreateSSL_trampoline), 1 /* true */, uintptr(hostname), 0, 0, 0, 0)
165+
return CFRef(ret)
166+
}
167+
func x509_SecPolicyCreateSSL_trampoline()
168+
169+
//go:cgo_import_dynamic x509_SecTrustSetVerifyDate SecTrustSetVerifyDate "/System/Library/Frameworks/Security.framework/Versions/A/Security"
170+
171+
func SecTrustSetVerifyDate(trustObj CFRef, dateRef CFRef) error {
172+
ret := syscall(abi.FuncPCABI0(x509_SecTrustSetVerifyDate_trampoline), uintptr(trustObj), uintptr(dateRef), 0, 0, 0, 0)
173+
if int32(ret) != 0 {
174+
return OSStatus{"SecTrustSetVerifyDate", int32(ret)}
175+
}
176+
return nil
177+
}
178+
func x509_SecTrustSetVerifyDate_trampoline()
179+
180+
//go:cgo_import_dynamic x509_SecTrustEvaluate SecTrustEvaluate "/System/Library/Frameworks/Security.framework/Versions/A/Security"
181+
182+
func SecTrustEvaluate(trustObj CFRef) (CFRef, error) {
183+
var result CFRef
184+
ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluate_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)), 0, 0, 0, 0)
185+
if int32(ret) != 0 {
186+
return 0, OSStatus{"SecTrustEvaluate", int32(ret)}
187+
}
188+
return CFRef(result), nil
189+
}
190+
func x509_SecTrustEvaluate_trampoline()
191+
192+
//go:cgo_import_dynamic x509_SecTrustGetResult SecTrustGetResult "/System/Library/Frameworks/Security.framework/Versions/A/Security"
193+
194+
func SecTrustGetResult(trustObj CFRef, result CFRef) (CFRef, CFRef, error) {
195+
var chain, info CFRef
196+
ret := syscall(abi.FuncPCABI0(x509_SecTrustGetResult_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)),
197+
uintptr(unsafe.Pointer(&chain)), uintptr(unsafe.Pointer(&info)), 0, 0)
198+
if int32(ret) != 0 {
199+
return 0, 0, OSStatus{"SecTrustGetResult", int32(ret)}
200+
}
201+
return chain, info, nil
202+
}
203+
func x509_SecTrustGetResult_trampoline()
204+
205+
//go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security"
206+
207+
func SecTrustEvaluateWithError(trustObj CFRef) error {
208+
var errRef CFRef
209+
ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluateWithError_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&errRef)), 0, 0, 0, 0)
210+
if int32(ret) != 1 {
211+
errStr := CFErrorCopyDescription(errRef)
212+
err := fmt.Errorf("x509: %s", CFStringToString(errStr))
213+
CFRelease(errRef)
214+
CFRelease(errStr)
215+
return err
216+
}
217+
return nil
218+
}
219+
func x509_SecTrustEvaluateWithError_trampoline()
220+
221+
//go:cgo_import_dynamic x509_SecTrustGetCertificateCount SecTrustGetCertificateCount "/System/Library/Frameworks/Security.framework/Versions/A/Security"
222+
223+
func SecTrustGetCertificateCount(trustObj CFRef) int {
224+
ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateCount_trampoline), uintptr(trustObj), 0, 0, 0, 0, 0)
225+
return int(ret)
226+
}
227+
func x509_SecTrustGetCertificateCount_trampoline()
228+
229+
//go:cgo_import_dynamic x509_SecTrustGetCertificateAtIndex SecTrustGetCertificateAtIndex "/System/Library/Frameworks/Security.framework/Versions/A/Security"
230+
231+
func SecTrustGetCertificateAtIndex(trustObj CFRef, i int) CFRef {
232+
ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateAtIndex_trampoline), uintptr(trustObj), uintptr(i), 0, 0, 0, 0)
233+
return CFRef(ret)
234+
}
235+
func x509_SecTrustGetCertificateAtIndex_trampoline()

src/crypto/x509/internal/macos/security.s

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,21 @@ TEXT ·x509_SecTrustSettingsCopyTrustSettings_trampoline(SB),NOSPLIT,$0-0
1818
JMP x509_SecTrustSettingsCopyTrustSettings(SB)
1919
TEXT ·x509_SecPolicyCopyProperties_trampoline(SB),NOSPLIT,$0-0
2020
JMP x509_SecPolicyCopyProperties(SB)
21+
TEXT ·x509_SecTrustCreateWithCertificates_trampoline(SB),NOSPLIT,$0-0
22+
JMP x509_SecTrustCreateWithCertificates(SB)
23+
TEXT ·x509_SecCertificateCreateWithData_trampoline(SB),NOSPLIT,$0-0
24+
JMP x509_SecCertificateCreateWithData(SB)
25+
TEXT ·x509_SecPolicyCreateSSL_trampoline(SB),NOSPLIT,$0-0
26+
JMP x509_SecPolicyCreateSSL(SB)
27+
TEXT ·x509_SecTrustSetVerifyDate_trampoline(SB),NOSPLIT,$0-0
28+
JMP x509_SecTrustSetVerifyDate(SB)
29+
TEXT ·x509_SecTrustEvaluate_trampoline(SB),NOSPLIT,$0-0
30+
JMP x509_SecTrustEvaluate(SB)
31+
TEXT ·x509_SecTrustGetResult_trampoline(SB),NOSPLIT,$0-0
32+
JMP x509_SecTrustGetResult(SB)
33+
TEXT ·x509_SecTrustEvaluateWithError_trampoline(SB),NOSPLIT,$0-0
34+
JMP x509_SecTrustEvaluateWithError(SB)
35+
TEXT ·x509_SecTrustGetCertificateCount_trampoline(SB),NOSPLIT,$0-0
36+
JMP x509_SecTrustGetCertificateCount(SB)
37+
TEXT ·x509_SecTrustGetCertificateAtIndex_trampoline(SB),NOSPLIT,$0-0
38+
JMP x509_SecTrustGetCertificateAtIndex(SB)

0 commit comments

Comments
 (0)