Calling SecIdentitySetPreferred fails with 'permission denied'

I am working in Go code that manages x509 certs on the user's behalf. When I install or renew a cert in the user's login keychain, I want to set an identity preference so Safari will automatically select the cert for my domain.

I am writing CGO to use the Security framework to interact with the keychain. Basic functions such as searching, installing, and deleting work for me. But when I try to call SecIdentitySetPreferred, my application reports could not set identity preference for cert: code: 100013, message: UNIX[Permission denied].

The command-line security tool to set-identity-preference succeeds, and my code currently makes a system call to run that application as a workaround. I would really like to know why I cannot use the framework to set an identity preference.

Here's an example of my code:
Code Block go
// this is a method that searches the keychain and returns a C.SecCertificateRef if it finds an item that matches
certRef, err := k.findCertMatchingKey([]byte(commonName), matchCertSubjectCommonName)
if err != nil {
return err
}
if certRef == 0 {
return fmt.Errorf("could not find a cert matching subject CN '%s'; cannot set identity preference", commonName)
}
defer C.CFRelease(C.CFTypeRef(certRef))
var idRef C.SecIdentityRef
status := C.SecIdentityCreateWithCertificate((C.CFTypeRef)(k.impl), certRef, &idRef)
if status != C.errSecSuccess {
return fmt.Errorf("could not retrieve identity for cert: %s", getErrorMsg(status))
}
defer C.CFRelease(C.CFTypeRef(idRef))
cnStrRef, err := toCFString(commonName)
if err != nil {
return err
}
status = C.SecIdentitySetPreferred(idRef, cnStrRef, 0)
if status != C.errSecSuccess {
return fmt.Errorf("could not set identity preference for cert: %s", getErrorMsg(status))
}

UPDATE: problem still exists, even after I realized I was not correctly associating the identity (cert) with the website URL. I also wondered if the problem was passing '0' for the null keyUsage CFArrayRef, so I modified my call as follows:
Code Block language
svcURLStrRef, err := toCFString(serviceURL)
if err != nil {
return err
}
keyUsage := arrayToCFArray([]C.CFTypeRef{(C.CFTypeRef)(C.kSecAttrCanDecrypt),(C.CFTypeRef)(C.kSecAttrCanSign)})
status = C.SecIdentitySetPreferred(idRef, svcURLStrRef, keyUsage)

In addition, I've tried adding the application to Full Disk Access (via the Security & Privacy pane in Settings). The call still fails with the same permissions error.
Calling SecIdentitySetPreferred fails with 'permission denied'
 
 
Q