|
| 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 | +// +build darwin,amd64 |
| 6 | + |
| 7 | +// Package macOS provides cgo-less wrappers for Core Foundation and |
| 8 | +// Security.framework, similarly to how package syscall provides access to |
| 9 | +// libSystem.dylib. |
| 10 | +package macOS |
| 11 | + |
| 12 | +import ( |
| 13 | + "errors" |
| 14 | + "reflect" |
| 15 | + "runtime" |
| 16 | + "unsafe" |
| 17 | +) |
| 18 | + |
| 19 | +// CFRef is an opaque reference to a Core Foundation object. It is a pointer, |
| 20 | +// but to memory not owned by Go, so not an unsafe.Pointer. |
| 21 | +type CFRef uintptr |
| 22 | + |
| 23 | +// CFDataToSlice returns a copy of the contents of data as a bytes slice. |
| 24 | +func CFDataToSlice(data CFRef) []byte { |
| 25 | + length := CFDataGetLength(data) |
| 26 | + ptr := CFDataGetBytePtr(data) |
| 27 | + src := (*[1 << 20]byte)(unsafe.Pointer(ptr))[:length:length] |
| 28 | + out := make([]byte, length) |
| 29 | + copy(out, src) |
| 30 | + return out |
| 31 | +} |
| 32 | + |
| 33 | +type CFString CFRef |
| 34 | + |
| 35 | +const kCFAllocatorDefault = 0 |
| 36 | +const kCFStringEncodingUTF8 = 0x08000100 |
| 37 | + |
| 38 | +//go:linkname x509_CFStringCreateWithBytes x509_CFStringCreateWithBytes |
| 39 | +//go:cgo_import_dynamic x509_CFStringCreateWithBytes CFStringCreateWithBytes "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 40 | + |
| 41 | +// StringToCFString returns a copy of the UTF-8 contents of s as a new CFString. |
| 42 | +func StringToCFString(s string) CFString { |
| 43 | + p := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s)).Data) |
| 44 | + ret := syscall(funcPC(x509_CFStringCreateWithBytes_trampoline), kCFAllocatorDefault, uintptr(p), |
| 45 | + uintptr(len(s)), uintptr(kCFStringEncodingUTF8), 0 /* isExternalRepresentation */, 0) |
| 46 | + runtime.KeepAlive(p) |
| 47 | + return CFString(ret) |
| 48 | +} |
| 49 | +func x509_CFStringCreateWithBytes_trampoline() |
| 50 | + |
| 51 | +//go:linkname x509_CFDictionaryGetValueIfPresent x509_CFDictionaryGetValueIfPresent |
| 52 | +//go:cgo_import_dynamic x509_CFDictionaryGetValueIfPresent CFDictionaryGetValueIfPresent "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 53 | + |
| 54 | +func CFDictionaryGetValueIfPresent(dict CFRef, key CFString) (value CFRef, ok bool) { |
| 55 | + ret := syscall(funcPC(x509_CFDictionaryGetValueIfPresent_trampoline), uintptr(dict), uintptr(key), |
| 56 | + uintptr(unsafe.Pointer(&value)), 0, 0, 0) |
| 57 | + if ret == 0 { |
| 58 | + return 0, false |
| 59 | + } |
| 60 | + return value, true |
| 61 | +} |
| 62 | +func x509_CFDictionaryGetValueIfPresent_trampoline() |
| 63 | + |
| 64 | +const kCFNumberSInt32Type = 3 |
| 65 | + |
| 66 | +//go:linkname x509_CFNumberGetValue x509_CFNumberGetValue |
| 67 | +//go:cgo_import_dynamic x509_CFNumberGetValue CFNumberGetValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 68 | + |
| 69 | +func CFNumberGetValue(num CFRef) (int32, error) { |
| 70 | + var value int32 |
| 71 | + ret := syscall(funcPC(x509_CFNumberGetValue_trampoline), uintptr(num), uintptr(kCFNumberSInt32Type), |
| 72 | + uintptr(unsafe.Pointer(&value)), 0, 0, 0) |
| 73 | + if ret == 0 { |
| 74 | + return 0, errors.New("CFNumberGetValue call failed") |
| 75 | + } |
| 76 | + return value, nil |
| 77 | +} |
| 78 | +func x509_CFNumberGetValue_trampoline() |
| 79 | + |
| 80 | +//go:linkname x509_CFDataGetLength x509_CFDataGetLength |
| 81 | +//go:cgo_import_dynamic x509_CFDataGetLength CFDataGetLength "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 82 | + |
| 83 | +func CFDataGetLength(data CFRef) int { |
| 84 | + ret := syscall(funcPC(x509_CFDataGetLength_trampoline), uintptr(data), 0, 0, 0, 0, 0) |
| 85 | + return int(ret) |
| 86 | +} |
| 87 | +func x509_CFDataGetLength_trampoline() |
| 88 | + |
| 89 | +//go:linkname x509_CFDataGetBytePtr x509_CFDataGetBytePtr |
| 90 | +//go:cgo_import_dynamic x509_CFDataGetBytePtr CFDataGetBytePtr "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 91 | + |
| 92 | +func CFDataGetBytePtr(data CFRef) uintptr { |
| 93 | + ret := syscall(funcPC(x509_CFDataGetBytePtr_trampoline), uintptr(data), 0, 0, 0, 0, 0) |
| 94 | + return ret |
| 95 | +} |
| 96 | +func x509_CFDataGetBytePtr_trampoline() |
| 97 | + |
| 98 | +//go:linkname x509_CFArrayGetCount x509_CFArrayGetCount |
| 99 | +//go:cgo_import_dynamic x509_CFArrayGetCount CFArrayGetCount "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 100 | + |
| 101 | +func CFArrayGetCount(array CFRef) int { |
| 102 | + ret := syscall(funcPC(x509_CFArrayGetCount_trampoline), uintptr(array), 0, 0, 0, 0, 0) |
| 103 | + return int(ret) |
| 104 | +} |
| 105 | +func x509_CFArrayGetCount_trampoline() |
| 106 | + |
| 107 | +//go:linkname x509_CFArrayGetValueAtIndex x509_CFArrayGetValueAtIndex |
| 108 | +//go:cgo_import_dynamic x509_CFArrayGetValueAtIndex CFArrayGetValueAtIndex "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 109 | + |
| 110 | +func CFArrayGetValueAtIndex(array CFRef, index int) CFRef { |
| 111 | + ret := syscall(funcPC(x509_CFArrayGetValueAtIndex_trampoline), uintptr(array), uintptr(index), 0, 0, 0, 0) |
| 112 | + return CFRef(ret) |
| 113 | +} |
| 114 | +func x509_CFArrayGetValueAtIndex_trampoline() |
| 115 | + |
| 116 | +//go:linkname x509_CFEqual x509_CFEqual |
| 117 | +//go:cgo_import_dynamic x509_CFEqual CFEqual "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 118 | + |
| 119 | +func CFEqual(a, b CFRef) bool { |
| 120 | + ret := syscall(funcPC(x509_CFEqual_trampoline), uintptr(a), uintptr(b), 0, 0, 0, 0) |
| 121 | + return ret == 1 |
| 122 | +} |
| 123 | +func x509_CFEqual_trampoline() |
| 124 | + |
| 125 | +//go:linkname x509_CFRelease x509_CFRelease |
| 126 | +//go:cgo_import_dynamic x509_CFRelease CFRelease "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" |
| 127 | + |
| 128 | +func CFRelease(ref CFRef) { |
| 129 | + syscall(funcPC(x509_CFRelease_trampoline), uintptr(ref), 0, 0, 0, 0, 0) |
| 130 | +} |
| 131 | +func x509_CFRelease_trampoline() |
| 132 | + |
| 133 | +// syscall is implemented in the runtime package (runtime/sys_darwin.go) |
| 134 | +func syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr |
| 135 | + |
| 136 | +// funcPC returns the entry point for f. See comments in runtime/proc.go |
| 137 | +// for the function of the same name. |
| 138 | +//go:nosplit |
| 139 | +func funcPC(f func()) uintptr { |
| 140 | + return **(**uintptr)(unsafe.Pointer(&f)) |
| 141 | +} |
0 commit comments