I'm trying to develop a quick command line tool that will install a root CA into a MacOS System keychain. This is a chunk of the code that does the job.
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData);
SecKeychainRef keychain = nil;
OSStatus status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
if(status != errSecSuccess)
{
// log the error
return;
}
status = SecKeychainUnlock(keychain, 0, NULL, TRUE);
if(status != errSecSuccess)
{
// log the error
return;
}
status = SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainSystem, NULL);
NSDictionary * addCertificateQuery = @{(id)kSecValueRef: (__bridge id)certificate,
(id)kSecClass: (id)kSecClassCertificate,
(id)kSecAttrLabel: CERT_ATTRIBUTE_LABEL,
(id)kSecUseKeychain: (__bridge id)keychain,
(id)kSecReturnRef: @YES,
};
status = SecItemAdd((__bridge CFDictionaryRef)addCertificateQuery, NULL);
When using the XCode debugger as root, the certificate is correctly added to System Keychain, but when debugging as user (user has Admin privileges) and after getting prompted for a username and password of a user with Admin privileges for some reason SecItemAdd returns error -61: errSecWrPerm (No writing permissions for user).
I've been trying to find some documentation that explains why this happens but still haven't got a clue. So my question is: is there a particular reason why a user with admin privileges cannot add a certificate to System? Is writing on System only reserved to root?
I've also tried changing /Library/Keychains/System.keychain
permissions but had the same result.
A user with "admin" privileges is still only a normal, non-root user, but one which is allowed to perform certain operations as root, for example under 'sudo' or the MacOS authorization prompts (which would enable certificate additions, but would require a user prompt and registration with the database at /var/db/auth.db). Authorizations can be popped up using AuthorizationExecuteWithPrivileges, with a good example being "security execute-with-privileges", which pops up the authentication and uses /usr/libexec/security_authtrampoline - a Setuid root binary.
You're right about writing to System being reserved for root only, and the situation becomes even more complication with System Integrity Protection (SIP), and with MacOS's move (in 10.15) to a read-only mounted root filesystem. The former (SIP) adds protections such that, without the proper com.apple.rootless.* entitlement you won't be able to modify files, even as root, and the latter (r/o mount) means that nothing (short of remounting, and/or holding system installer entitlement) won't enable you to write anything.
The "direct" approach you specify, of modifying the files in /Library/keychains will fail because note that the keychain file ownership is root's.
Adding certificates programmatically will require either root, or the com.apple.private.system-keychain entitlement (or one of its siblings - I forget which - see http://newosxbook.com/ent.jl?ent=com.apple.private.system-keychain&osVer=MacOS13 for a full list of entitlements).
Also note, that messing with the keychain could have some serious impact. This is where everything that is secret and holy to macOS - root certs, passwords, Apple ID, etc - is held. Beware. Once a root CA is installed, it can be trusted for all sorts of applications (including, to some extents, code signing, website proxying, and even more sinister uses). So there's a pretty good reason it's not given too just any user - since a batch operation without a prompt could surreptitiously inject such a CA, and open up avenues for malware.
References: "*OS Internals, Volume III", which deals with this in Chapter 11 and the authorizations in chapter 6. Website: newosxbook.com