Ejemplo n.º 1
0
func CGImageCreateWithImage(img image.Image) (cgimg C.CGImageRef, err error) {
	var data imageData

	if data, err = extractImageData(img); err != nil {
		return
	}

	memory := C.CFDataCreate(
		nil,
		(*C.UInt8)(unsafe.Pointer(&data.pixels[0])),
		C.CFIndex(len(data.pixels)),
	)

	provider := C.CGDataProviderCreateWithCFData(memory)

	cgimg = C.CGImageCreate(
		C.size_t(data.width),
		C.size_t(data.height),
		C.size_t(data.bpc),
		C.size_t(data.bpp),
		C.size_t(data.stride),
		data.colors,
		data.info,
		provider,
		nil,
		false,
		C.kCGRenderingIntentDefault,
	)

	C.CFRelease(provider)
	C.CFRelease(memory)
	C.CFRelease(data.colors)
	return
}
Ejemplo n.º 2
0
// ===== CFData =====
func convertBytesToCFData(data []byte) C.CFDataRef {
	var ptr *C.UInt8
	if len(data) > 0 {
		ptr = (*C.UInt8)((&data[0]))
	}
	return C.CFDataCreate(nil, ptr, C.CFIndex(len(data)))
}
Ejemplo n.º 3
0
func (c osx16Collator) Compare(a, b Input) int {
	sa := C.CFStringCreateWithCharactersNoCopy(
		nil,
		osxCharP(a.UTF16),
		C.CFIndex(len(a.UTF16)),
		nil,
	)
	sb := C.CFStringCreateWithCharactersNoCopy(
		nil,
		osxCharP(b.UTF16),
		C.CFIndex(len(b.UTF16)),
		nil,
	)
	_range := C.CFRangeMake(0, C.CFStringGetLength(sa))
	return int(C.CFStringCompareWithOptionsAndLocale(sa, sb, _range, c.opt, c.loc))
}
Ejemplo n.º 4
0
// The returned CFDataRef, if non-nil, must be released via CFRelease.
func bytesToCFData(b []byte) C.CFDataRef {
	var p *C.UInt8
	if len(b) > 0 {
		p = (*C.UInt8)(&b[0])
	}
	return C.CFDataCreate(nil, p, C.CFIndex(len(b)))
}
Ejemplo n.º 5
0
func convertSliceToCFArrayHelper(slice reflect.Value, helper func(reflect.Value) (cfTypeRef, error)) (C.CFArrayRef, error) {
	if slice.Len() == 0 {
		// short-circuit 0, so we can assume plists[0] is valid later
		return C.CFArrayCreate(nil, nil, 0, nil), nil
	}
	// assume slice is a slice/array, because our caller already checked
	plists := make([]cfTypeRef, slice.Len())
	// defer the release
	defer func() {
		for _, cfObj := range plists {
			cfRelease(cfObj)
		}
	}()
	// convert the slice
	for i := 0; i < slice.Len(); i++ {
		cfType, err := helper(slice.Index(i))
		if err != nil {
			return nil, err
		}
		plists[i] = cfType
	}

	// create the array
	callbacks := (*C.CFArrayCallBacks)(&C.kCFTypeArrayCallBacks)
	return C.CFArrayCreate(nil, (*unsafe.Pointer)(&plists[0]), C.CFIndex(len(plists)), callbacks), nil
}
Ejemplo n.º 6
0
// ExportFromKeychain ...
func ExportFromKeychain(itemRefsToExport []C.CFTypeRef, outputFilePath string, isAskForPassword bool) error {
	passphraseCString := C.CString("")
	defer C.free(unsafe.Pointer(passphraseCString))

	var exportedData C.CFDataRef
	var exportParams C.SecItemImportExportKeyParameters
	exportParams.keyUsage = nil
	exportParams.keyAttributes = nil
	exportParams.version = C.SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
	if isAskForPassword {
		exportParams.flags = C.kSecKeySecurePassphrase
		exportParams.passphrase = nil
		exportParams.alertTitle = nil

		promptText := C.CString("Enter a password which will be used to protect the exported items")
		defer C.free(unsafe.Pointer(promptText))
		exportParams.alertPrompt = convertCStringToCFString(promptText)
	} else {
		exportParams.flags = 0
		exportParams.passphrase = (C.CFTypeRef)(convertCStringToCFString(passphraseCString))
		exportParams.alertTitle = nil
		exportParams.alertPrompt = nil
	}

	// create a C array from the input
	ptr := (*unsafe.Pointer)(&itemRefsToExport[0])
	cfArrayForExport := C.CFArrayCreate(
		C.kCFAllocatorDefault,
		ptr,
		C.CFIndex(len(itemRefsToExport)),
		&C.kCFTypeArrayCallBacks)

	// do the export!
	status := C.SecItemExport(C.CFTypeRef(cfArrayForExport),
		C.kSecFormatPKCS12,
		0, //C.kSecItemPemArmour, // Use kSecItemPemArmour to add PEM armour - the .p12 generated by Keychain Access.app does NOT have PEM armour
		&exportParams,
		&exportedData)

	if status != C.errSecSuccess {
		return fmt.Errorf("SecItemExport: error (OSStatus): %d", status)
	}
	// exportedData now contains your PKCS12 data
	//  make sure it'll be released properly!
	defer C.CFRelease(C.CFTypeRef(exportedData))

	dataBytes := convertCFDataRefToGoBytes(exportedData)
	if dataBytes == nil || len(dataBytes) < 1 {
		return errors.New("ExportFromKeychain: failed to convert export data - nil or empty")
	}

	if err := fileutil.WriteBytesToFile(outputFilePath, dataBytes); err != nil {
		return fmt.Errorf("ExportFromKeychain: failed to write into file: %s", err)
	}

	log.Debug("Export - success")

	return nil
}
Ejemplo n.º 7
0
func NewCFString(s string) C.CFStringRef {
	s_ := C.CString(s)
	defer C.free(unsafe.Pointer(s_))
	retval := C.CFStringCreateWithBytes(
		C.CFAllocatorRef(nil), (*C.UInt8)(unsafe.Pointer(s_)), C.CFIndex(len(s)), C.kCFStringEncodingUTF8, C.Boolean(0),
	)
	return retval
}
Ejemplo n.º 8
0
// cfstringGo creates a Go string for a CoreFoundation string using the CoreFoundation UTF-8 converter.
// For short strings this is an efficiency nightmare! In this package this function is not currently used
// in any critical path.
func cfstringGo(cfs C.CFStringRef) string {
	var usedBufLen C.CFIndex
	n := C.cfstring_utf8_length(cfs, &usedBufLen)
	if n <= 0 {
		return ""
	}
	rng := C.CFRange{location: C.CFIndex(0), length: n}
	buf := make([]byte, int(usedBufLen))

	bufp := unsafe.Pointer(&buf[0])
	C.CFStringGetBytes(cfs, rng, C.kCFStringEncodingUTF8, 0, 0, (*C.UInt8)(bufp), C.CFIndex(len(buf)), &usedBufLen)

	sh := &reflect.StringHeader{
		Data: uintptr(bufp),
		Len:  int(usedBufLen),
	}
	return *(*string)(unsafe.Pointer(sh))
}
Ejemplo n.º 9
0
// Converts a go string to a C.CFStringRef. The content of the string is copied
// by the function so if the Go string gets garbage collected the returned object
// is still valid.
// The program needs to call C.CFRelease on the returned C.CFStringRef when it
// doesn't need it anymore to avoid any memory leak.
func GoStringToCFString(s string) C.CFStringRef {
	h := (*reflect.StringHeader)(unsafe.Pointer(&s))
	return C.CFStringCreateWithBytes(
		nil,
		(*C.UInt8)(unsafe.Pointer(h.Data)),
		C.CFIndex(len(s)),
		C.kCFStringEncodingUTF8,
		0,
	)
}
Ejemplo n.º 10
0
func CFNetServiceSetTXTData(cns *CFNetService, data []byte) bool {
	p := unsafe.Pointer(nil)
	if data != nil && len(data) > 0 {
		p = unsafe.Pointer(&data[0])
	}
	data_ := C.CFDataCreate(nil, (*C.UInt8)(p), C.CFIndex(len(data)))
	retval := C.CFNetServiceSetTXTData(cns.ref, data_)
	C.CFRelease((C.CFTypeRef)(data_))
	return retval != 0
}
Ejemplo n.º 11
0
func (c *osxCollator) init(locale string) {
	l := C.CFStringCreateWithBytes(
		nil,
		osxUInt8P([]byte(locale)),
		C.CFIndex(len(locale)),
		C.kCFStringEncodingUTF8,
		C.Boolean(0),
	)
	c.loc = C.CFLocaleCreate(nil, l)
}
Ejemplo n.º 12
0
func (c osx8Collator) Compare(a, b Input) int {
	sa := C.CFStringCreateWithBytesNoCopy(
		nil,
		osxUInt8P(a.UTF8),
		C.CFIndex(len(a.UTF8)),
		C.kCFStringEncodingUTF8,
		C.Boolean(0),
		nil,
	)
	sb := C.CFStringCreateWithBytesNoCopy(
		nil,
		osxUInt8P(b.UTF8),
		C.CFIndex(len(b.UTF8)),
		C.kCFStringEncodingUTF8,
		C.Boolean(0),
		nil,
	)
	_range := C.CFRangeMake(0, C.CFStringGetLength(sa))
	return int(C.CFStringCompareWithOptionsAndLocale(sa, sb, _range, c.opt, c.loc))
}
Ejemplo n.º 13
0
// ArrayToCFArray will return a CFArrayRef and if non-nil, must be released with
// Release(ref).
func ArrayToCFArray(a []C.CFTypeRef) C.CFArrayRef {
	var values []unsafe.Pointer
	for _, value := range a {
		values = append(values, unsafe.Pointer(value))
	}
	numValues := len(values)
	var valuesPointer *unsafe.Pointer
	if numValues > 0 {
		valuesPointer = &values[0]
	}
	return C.CFArrayCreate(nil, valuesPointer, C.CFIndex(numValues), &C.kCFTypeArrayCallBacks)
}
Ejemplo n.º 14
0
// The returned CFStringRef, if non-nil, must be released via CFRelease.
func _UTF8StringToCFString(s string) (C.CFStringRef, error) {
	if !utf8.ValidString(s) {
		return nil, errors.New("invalid UTF-8 string")
	}

	bytes := []byte(s)
	var p *C.UInt8
	if len(bytes) > 0 {
		p = (*C.UInt8)(&bytes[0])
	}
	return C.CFStringCreateWithBytes(nil, p, C.CFIndex(len(s)), C.kCFStringEncodingUTF8, C.false), nil
}
Ejemplo n.º 15
0
func buildFont(f C.CTFontRef) []byte {
	ctags := C.CTFontCopyAvailableTables(f, C.kCTFontTableOptionExcludeSynthetic)
	tagsCount := C.CFArrayGetCount(ctags)

	var tags []uint32
	var dataRefs []C.CFDataRef
	var dataLens []uint32

	for i := C.CFIndex(0); i < tagsCount; i++ {
		tag := (C.CTFontTableTag)((uintptr)(C.CFArrayGetValueAtIndex(ctags, i)))
		dataRef := C.CTFontCopyTable(f, tag, 0) // retained
		tags = append(tags, uint32(tag))
		dataRefs = append(dataRefs, dataRef)
		dataLens = append(dataLens, uint32(C.CFDataGetLength(dataRef)))
	}

	totalLen := 0
	for _, l := range dataLens {
		totalLen += int(l)
	}

	// Big-endian output.
	buf := make([]byte, 0, 12+16*len(tags)+totalLen)
	write16 := func(x uint16) { buf = append(buf, byte(x>>8), byte(x)) }
	write32 := func(x uint32) { buf = append(buf, byte(x>>24), byte(x>>16), byte(x>>8), byte(x)) }

	// File format description: http://www.microsoft.com/typography/otspec/otff.htm
	write32(0x00010000)        // version 1.0
	write16(uint16(len(tags))) // numTables
	write16(0)                 // searchRange
	write16(0)                 // entrySelector
	write16(0)                 // rangeShift

	// Table tags, includes offsets into following data segments.
	offset := uint32(12 + 16*len(tags)) // offset starts after table tags
	for i, tag := range tags {
		write32(tag)
		write32(0)
		write32(offset)
		write32(dataLens[i])
		offset += dataLens[i]
	}

	// Data segments.
	for i, dataRef := range dataRefs {
		data := (*[1<<31 - 2]byte)((unsafe.Pointer)(C.CFDataGetBytePtr(dataRef)))[:dataLens[i]]
		buf = append(buf, data...)
		C.CFRelease(C.CFTypeRef(dataRef))
	}

	return buf
}
Ejemplo n.º 16
0
// CFDictionaryToMap converts CFDictionaryRef to a map.
func CFDictionaryToMap(cfDict C.CFDictionaryRef) (m map[C.CFTypeRef]C.CFTypeRef) {
	count := C.CFDictionaryGetCount(cfDict)
	if count > 0 {
		keys := make([]C.CFTypeRef, count)
		values := make([]C.CFTypeRef, count)
		C.CFDictionaryGetKeysAndValues(cfDict, (*unsafe.Pointer)(&keys[0]), (*unsafe.Pointer)(&values[0]))
		m = make(map[C.CFTypeRef]C.CFTypeRef, count)
		for i := C.CFIndex(0); i < count; i++ {
			m[keys[i]] = values[i]
		}
	}
	return
}
Ejemplo n.º 17
0
// wrapper for C.CFDictionaryCreate, since referencing the callbacks in 2 separate files
// seems to be triggering some sort of "redefinition" error in cgo
func createCFDictionary(keys, values []cfTypeRef) C.CFDictionaryRef {
	if len(keys) != len(values) {
		panic("plist: unexpected length difference between keys and values")
	}
	var keyPtr, valPtr *unsafe.Pointer
	if len(keys) > 0 {
		keyPtr = (*unsafe.Pointer)(&keys[0])
		valPtr = (*unsafe.Pointer)(&values[0])
	}
	keyCallbacks := (*C.CFDictionaryKeyCallBacks)(&C.kCFTypeDictionaryKeyCallBacks)
	valCallbacks := (*C.CFDictionaryValueCallBacks)(&C.kCFTypeDictionaryValueCallBacks)
	return C.CFDictionaryCreate(nil, keyPtr, valPtr, C.CFIndex(len(keys)), keyCallbacks, valCallbacks)
}
Ejemplo n.º 18
0
// BytesToCFData will return a CFDataRef and if non-nil, must be released with
// Release(ref).
func BytesToCFData(b []byte) (C.CFDataRef, error) {
	if uint64(len(b)) > math.MaxUint32 {
		return nil, errors.New("Data is too large")
	}
	var p *C.UInt8
	if len(b) > 0 {
		p = (*C.UInt8)(&b[0])
	}
	cfData := C.CFDataCreate(nil, p, C.CFIndex(len(b)))
	if cfData == nil {
		return nil, fmt.Errorf("CFDataCreate failed")
	}
	return cfData, nil
}
Ejemplo n.º 19
0
// The returned CFDictionaryRef, if non-nil, must be released via CFRelease.
func mapToCFDictionary(m map[C.CFTypeRef]C.CFTypeRef) C.CFDictionaryRef {
	var keys, values []unsafe.Pointer
	for key, value := range m {
		keys = append(keys, unsafe.Pointer(key))
		values = append(values, unsafe.Pointer(value))
	}
	numValues := len(values)
	var keysPointer, valuesPointer *unsafe.Pointer
	if numValues > 0 {
		keysPointer = &keys[0]
		valuesPointer = &values[0]
	}
	return C.CFDictionaryCreate(nil, keysPointer, valuesPointer, C.CFIndex(numValues), &C.kCFTypeDictionaryKeyCallBacks, &C.kCFTypeDictionaryValueCallBacks)
}
Ejemplo n.º 20
0
// StringToCFString will return a CFStringRef and if non-nil, must be released with
// Release(ref).
func StringToCFString(s string) (C.CFStringRef, error) {
	if !utf8.ValidString(s) {
		return nil, errors.New("Invalid UTF-8 string")
	}
	if uint64(len(s)) > math.MaxUint32 {
		return nil, errors.New("String is too large")
	}

	bytes := []byte(s)
	var p *C.UInt8
	if len(bytes) > 0 {
		p = (*C.UInt8)(&bytes[0])
	}
	return C.CFStringCreateWithBytes(nil, p, C.CFIndex(len(s)), C.kCFStringEncodingUTF8, C.false), nil
}
Ejemplo n.º 21
0
// ===== CFString =====
// convertStringToCFString may return nil if the input string is not a valid UTF-8 string
func convertStringToCFString(str string) C.CFStringRef {
	var bytes *C.UInt8
	var byteCount C.CFIndex
	if len(str) > 0 {
		// check the string for invalid encodings
		// We could use unicode.ValidString() but we also want to count the desired buffer size
		// and there's no sense in iterating the string more than we have to
		var errorCount int
		for i, r := range str {
			if r == utf8.RuneError {
				// This may be a valid value in the string. Re-decode it
				_, size := utf8.DecodeRuneInString(str[i:])
				if size == 1 {
					errorCount++
				}
			}
		}
		if errorCount == 0 {
			// go through unsafe to get the string bytes directly without the copy
			header := (*reflect.StringHeader)(unsafe.Pointer(&str))
			bytes = (*C.UInt8)(unsafe.Pointer(header.Data))
			byteCount = C.CFIndex(header.Len)
		} else {
			// our desired buffer is the length of s, minus the invalid bytes, plus the
			// replacement bytes.
			buf := make([]byte, len(str)+(errorCount*(runeErrorLen-1)))
			i := 0
			for _, r := range str {
				i += utf8.EncodeRune(buf[i:], r)
			}
			bytes = (*C.UInt8)(unsafe.Pointer(&buf[0]))
			byteCount = C.CFIndex(len(buf))
		}
	}
	return C.CFStringCreateWithBytes(nil, bytes, byteCount, C.kCFStringEncodingUTF8, C.false)
}
Ejemplo n.º 22
0
func fromCFString(cstr C.CFStringRef) string {
	defer C.CFRelease(C.CFTypeRef(cstr))

	var (
		buf  []C.char
		ok   C.Boolean
		size uint = 1024
	)
	for ok == C.FALSE {
		buf = make([]C.char, size)
		ok = C.CFStringGetCString(cstr, &buf[0],
			C.CFIndex(len(buf)), C.kCFStringEncodingUTF8)
		size *= 2
	}
	return C.GoString(&buf[0])
}
Ejemplo n.º 23
0
// MapToCFDictionary will return a CFDictionaryRef and if non-nil, must be
// released with Release(ref).
func MapToCFDictionary(m map[C.CFTypeRef]C.CFTypeRef) (C.CFDictionaryRef, error) {
	var keys, values []unsafe.Pointer
	for key, value := range m {
		keys = append(keys, unsafe.Pointer(key))
		values = append(values, unsafe.Pointer(value))
	}
	numValues := len(values)
	var keysPointer, valuesPointer *unsafe.Pointer
	if numValues > 0 {
		keysPointer = &keys[0]
		valuesPointer = &values[0]
	}
	cfDict := C.CFDictionaryCreate(nil, keysPointer, valuesPointer, C.CFIndex(numValues), &C.kCFTypeDictionaryKeyCallBacks, &C.kCFTypeDictionaryValueCallBacks)
	if cfDict == nil {
		return nil, fmt.Errorf("CFDictionaryCreate failed")
	}
	return cfDict, nil
}
Ejemplo n.º 24
0
func (dev *osxDevice) setReport(typ C.IOHIDReportType, data []byte) error {
	var reportNo int32 = int32(data[0])
	if reportNo == 0 {
		data = data[1:]
	}

	if !dev.disconnected {
		res := C.IOHIDDeviceSetReport(dev.osDevice, typ, C.CFIndex(reportNo), (*C.uint8_t)(&data[0]), C.CFIndex(len(data)))

		if res == C.kIOReturnSuccess {
			return nil
		} else {
			return ioReturnToErr(res)
		}
	}

	return errors.New("device disconnected")
}
Ejemplo n.º 25
0
func NSStringToString(inString Object) string {
	cr := C.CFStringRef(unsafe.Pointer(inString))

	var usedBufLen C.CFIndex
	rng := C.CFRange{C.CFIndex(0), C.CFStringGetLength(cr)}
	n := int(C.CFStringGetBytes(cr, rng, C.kCFStringEncodingUTF8, 0, 0, nil, 0, &usedBufLen))
	if n <= 0 {
		return ""
	}

	buf := make([]byte, int(usedBufLen))
	C.CFStringGetBytes(cr, rng, C.kCFStringEncodingUTF8, 0, 0, (*C.UInt8)(unsafe.Pointer(&buf[0])), C.CFIndex(len(buf)), &usedBufLen)

	sh := &reflect.StringHeader{
		Data: uintptr(unsafe.Pointer(&buf[0])),
		Len:  int(usedBufLen),
	}
	return *(*string)(unsafe.Pointer(sh))
}
Ejemplo n.º 26
0
// Converts a CGStringRef object to a Go string.
func CFStringToGoString(s C.CFStringRef) string {
	ptr := C.CFStringGetCStringPtr(s, C.kCFStringEncodingUTF8)

	if ptr != nil {
		return C.GoString(ptr)
	}

	n := C.CFStringGetLength(s)
	b := make([]byte, int(4*n))
	C.CFStringGetBytes(
		s,
		C.CFRangeMake(0, n),
		C.kCFStringEncodingUTF8,
		'?',
		0,
		(*C.UInt8)(unsafe.Pointer(&b[0])),
		C.CFIndex(len(b)),
		&n,
	)

	return string(b[:n])
}
Ejemplo n.º 27
0
func NSString(inString string) Object {
	l := C.CFIndex(len(inString))
	ret := C.CFStringCreateWithBytes(nil, *(**C.UInt8)(unsafe.Pointer(&inString)),
		l, C.kCFStringEncodingUTF8, 0)
	return Object(unsafe.Pointer(ret))
}
Ejemplo n.º 28
0
// The function reads the content of the text reader given as argument and
// produces a C.CFAttributedStringRef object that most closely represtns the
// input.
// The program needs to call C.CFRelease on the returned C.CFAttributedStringRef
// when it doesn't need it anymore to avoid any memory leak.
func CFAttributedStringCreateWithTextReader(r text.Reader) C.CFAttributedStringRef {
	style := text.Style{}

	b := &bytes.Buffer{}
	b.Grow(1000)

	styles := make([]C.Style__, 0, 10)
	offset := 0

	for {
		c, err := r.ReadChar()
		if err != nil {
			break
		}

		s := text.StyleOf(c)
		s.Offset = 0

		if s != style {
			style = s
			s.Offset = offset

			font := C.CTFontRef(nil)

			switch f := s.Face.(type) {
			case *face:
				font = f.ref
			}

			styles = append(styles, C.Style__{
				_range:     C.CFRange{location: C.CFIndex(offset)},
				font:       font,
				foreground: makeRGBA__(imageColor(s.Foreground, color.Black)),
				background: makeRGBA__(imageColor(s.Background, color.Transparent)),
			})
		}

		b.WriteRune(c.Rune)
		offset++
	}

	if n := len(styles); n != 0 {
		n--
		styles[n]._range.length = C.CFIndex(offset) - styles[n]._range.location

		for i := range styles[:n] {
			s0 := &styles[i]
			s1 := &styles[i+1]
			s0._range.length = s1._range.location - s0._range.location
		}
	}

	d := b.Bytes()
	s := C.CFStringCreateWithBytesNoCopy(
		nil,
		(*C.UInt8)(&d[0]),
		C.CFIndex(len(d)),
		C.kCFStringEncodingUTF8,
		0,
		C.kCFAllocatorNull,
	)
	defer C.CFRelease(C.CFTypeRef(s))
	return C.CFAttributedStringCreateWithStyles__(nil, s, &styles[0], C.size_t(len(styles)))
}
Ejemplo n.º 29
0
func cfstring(s string) C.CFStringRef {
	n := C.CFIndex(len(s))
	return C.CFStringCreateWithBytes(nil, *(**C.UInt8)(unsafe.Pointer(&s)), n, C.kCFStringEncodingUTF8, 0)
}
Ejemplo n.º 30
0
// FindIdentity ...
//  IMPORTANT: you have to C.CFRelease the returned items (one-by-one)!!
//             you can use the ReleaseIdentityWithRefList method to do that
func FindIdentity(identityLabel string, isFullLabelMatch bool) ([]IdentityWithRefModel, error) {

	queryDict := C.CFDictionaryCreateMutable(nil, 0, nil, nil)
	defer C.CFRelease(C.CFTypeRef(queryDict))
	C.CFDictionaryAddValue(queryDict, unsafe.Pointer(C.kSecClass), unsafe.Pointer(C.kSecClassIdentity))
	C.CFDictionaryAddValue(queryDict, unsafe.Pointer(C.kSecMatchLimit), unsafe.Pointer(C.kSecMatchLimitAll))
	C.CFDictionaryAddValue(queryDict, unsafe.Pointer(C.kSecReturnAttributes), unsafe.Pointer(C.kCFBooleanTrue))
	C.CFDictionaryAddValue(queryDict, unsafe.Pointer(C.kSecReturnRef), unsafe.Pointer(C.kCFBooleanTrue))

	var resultRefs C.CFTypeRef
	osStatusCode := C.SecItemCopyMatching(queryDict, &resultRefs)
	if osStatusCode != C.errSecSuccess {
		return nil, fmt.Errorf("Failed to call SecItemCopyMatch - OSStatus: %d", osStatusCode)
	}
	defer C.CFRelease(C.CFTypeRef(resultRefs))

	identitiesArrRef := C.CFArrayRef(resultRefs)
	identitiesCount := C.CFArrayGetCount(identitiesArrRef)
	if identitiesCount < 1 {
		return nil, fmt.Errorf("No Identity (certificate + related private key) found in your Keychain!")
	}
	log.Debugf("identitiesCount: %d", identitiesCount)

	// filter the identities, by label
	retIdentityRefs := []IdentityWithRefModel{}
	for i := C.CFIndex(0); i < identitiesCount; i++ {
		aIdentityRef := C.CFArrayGetValueAtIndex(identitiesArrRef, i)
		log.Debugf("aIdentityRef: %#v", aIdentityRef)
		aIdentityDictRef := C.CFDictionaryRef(aIdentityRef)
		log.Debugf("aIdentityDictRef: %#v", aIdentityDictRef)

		lablCSting := C.CString("labl")
		defer C.free(unsafe.Pointer(lablCSting))
		vrefCSting := C.CString("v_Ref")
		defer C.free(unsafe.Pointer(vrefCSting))

		labl, err := getCFDictValueUTF8String(aIdentityDictRef, C.CFTypeRef(convertCStringToCFString(lablCSting)))
		if err != nil {
			return nil, fmt.Errorf("FindIdentity: failed to get 'labl' property: %s", err)
		}
		log.Debugf("labl: %#v", labl)
		if isFullLabelMatch {
			if labl != identityLabel {
				continue
			}
		} else {
			if !strings.Contains(labl, identityLabel) {
				continue
			}
		}
		log.Debugf("Found identity with label: %s", labl)

		vrefRef, err := getCFDictValueRef(aIdentityDictRef, C.CFTypeRef(convertCStringToCFString(vrefCSting)))
		if err != nil {
			return nil, fmt.Errorf("FindIdentity: failed to get 'v_Ref' property: %s", err)
		}
		log.Debugf("vrefRef: %#v", vrefRef)

		// retain the pointer
		vrefRef = C.CFRetain(vrefRef)
		// store it
		retIdentityRefs = append(retIdentityRefs, IdentityWithRefModel{
			KeychainRef: vrefRef,
			Label:       labl,
		})
	}

	return retIdentityRefs, nil
}