How to use System KeyChain along with AccessGroup? - swift

I want to have my keys stored in System Keychain and a couple of apps(keySharing and AppGroup enabled) to access them
My current approach
I am using
 let path:String = "/Library/Keychains/System.keychain"
 var keychain: SecKeychain?
 SecKeychainOpen(path, &keychain)
For options in SecItemAdd() ,I added
[kSecUseKeychain as String: keychain! ]
with this approach, I am able to write to System keyChain but only the current app is able to access this KeyChainItem,
kSecAttrAccessGroup
is completely ignored for this keychain item.
After some digging I found
kSecUseDataProtectionKeychain = true
is mandatory to use AccessGroup
When I included this in the options of SecAddItem(), Yes I am able to utilize access groups after this, but it is ignoring kSecUseKeychain now. Though my app is running in root and kSecUseKeychain is set, SecAddtem() is writing to login KeyChain (and apps inside my access are able to access them) instead of System Keychain
Is there a way to write to System KeyChain and allow a set of apps to modify them?
In short
[kSecUseKeychain as String: keychain! ]
is ignored when
kSecUseDataProtectionKeychain = true
Thanks
Any alternatives related to having keys in System Context is much appreciated
Xcode -12.2
macOS :10.15

Related

Swift - Keychain Services SecKeychainSetDefault fails as root - Will not set default

I want to store something in the system keychain, but am seeing some weird behavior. In my app's scheme, I have Debug Process As set to root. However, when I check the default keychain via SecKeychainCopyDefault, it returns the login keychain for my current user.
As far as I know, the only way to write a keychain item to a specific keychain is to first set it as the default keychain using SecKeychainSetDefault and then perform the write. Obviously, since the default is set to my login chain in my debug environment, I'd need to set the default to the system keychain before attempting to write. I am doing the following to accomplish this:
// Store original default so we can restore it after we are done
var defaultKeychain: SecKeychain? = nil
SecKeychainCopyDefault(&defaultKeychain)
// Open System keychain
let cs = ("/Library/Keychains/System.keychain" as NSString).utf8String
var buffer = UnsafeMutablePointer<Int8>(mutating: cs)!
var systemKeychain: SecKeychain? = nil
SecKeychainOpen(buffer, &systemKeychain)
// Set System keychain to default
var status = SecKeychainSetDefault(systemKeychain)
NSLog(SecCopyErrorMessageString(status, nil) as String? ?? "")
// Ensure default keychain gets reset at end of scope
defer {
SecKeychainSetDefault(defaultKeychain)
}
// Add item to keychain below
...
However, I get the following output:
Will not set default: UID=0 does not own directory /Users/myuser
2019-12-11 09:54:31.262285-0700 App[99920:12060617] Write permissions error.
It seems as though even though my app is running as root, I don't have write access to the login keychain for some reason. The strange thing is, when I deploy my app as a background launch daemon, the default keychain is already the System keychain, not the login keychain, and things work properly. Obviously though I would like this behavior in my development environment as well.
How can I get around this issue? I need my keychain item to be in the System keychain, but even running the app as root doesn't seem to help when running in a debug environment.
The following workaround worked for me (on Mac OS 10.15) :
In your app's scheme set the "HOME" environment variable to a folder owned by root (e.g. '/' or '/var/root')

How to detect keystrokes globally in Swift on macOS?

Here is what I tried:
NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]) { (event) in
print(event.keyCode)
}
Unfortunately, it does not print anything.
And no, it's not a duplicate of this, that question is about modifier keys, my question is about keystrokes.
Looks like the "duplicate" mark got removed, but so has the answer that I kludged into the comments section. So, for posterity:
The reason this doesn't work is because global monitors for .keyDown events require more permissions than some of the other event handlers, including the one that somebody thought this was a duplicate of. This is mainly because global .keyDown monitors can be used for nefarious purposes, such as keyloggers. So there are additional security measures in place to make sure we're legit:
1) Your app needs to be code-signed.
2) Your app needs to not have the App Sandbox enabled, and:
3) Your app needs to be registered in the Security and Privacy preference pane, under Accessibility.
The third one of these things has to be enabled by the user, but you can nudge them in that direction with this code:
let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String : true]
let accessEnabled = AXIsProcessTrustedWithOptions(options)
if !accessEnabled {
print("Access Not Enabled")
}
This will prompt the user, giving him/her the option to automatically open the appropriate preference pane where the user can allow your app to control the computer via the Accessibility API, which, assuming your app is signed and not sandboxed, will allow your global .keyDown monitor to work.
if you only want global hotkey support all this is unnecessary (and not all random key or mouse events) you can do that easily with the hotkey API. look at e.g. PTHotkey :)
or a newer api .. seee also: How to implement shortcut key input in Mac Cocoa App?

Swift 3 osx - Popup every time I use SecIdentitySetPreferred

I am editing a lot of identity preferences in a swift 3 app. For every single domain, there is an annoying popup: "[app name] wants to access key "[domain]" in your keychain. Do you want to allow access to this item?".
How do I get rid of this popup / automatically give my app the right access any keys in my keychain?
Edit: my question is not the same as this question because I need a programmatic solution. How do I change that setting programmatically with either Swift or AppleScript? Thanks.

Storing app parameters like secret key

I'm working on a little SDK which has a configFile.plist file to store things like secret key.
Developer who implement this SDK in his app, and other users will download the app, they will be able to go into the app binary and change anything in the .plist file.
Is there any way to store this info without letting users modifing the parameters easily? I don't want users to have the ability to change the parametes in the .plist file.
Thanks in advance for any help!
When it comes to plist storage, it's easily accessible either way. Your best option is to provide a class file for configuration, and not a plist. Example below..
//Config.h
#define SHARED_SECRET #"2390849028349829384"
#define SOME_OTHER_VALUE 1
..and so on, this way, the class file is compiled with the App, and not visible to the user but accessible by the developer. Once you #import "Config.h", you can use SHARED_SECRET and SOME_OTHER_VALUE in place of the value itself within the code. If this suffices as a solution to your question, mark it as the answer. Hope it helps..
Keeping in mind that people are going to be able to see/change almost anything with the right tools, you can't prevent people from hacking this.
If the key is going to be different for each user of the SDK, then you might want to make it the Developer's responsibility and have them provide the private key to you using a delegate method. That will make it their problem, and it will make it easier for them to compile the key directly into code, which is going to be less obvious for the end-user to access.

Using Xcode for multiple developer IDs

I am quite new all this iPhone stuff. I have no such clear IDea yet about provisioning profile etc.
I will be using my mac machine for two different developer IDs,one for my own and other for the startup where I am working in. Now,how can I use xCode to submit my apps in two different IDs?
thanks
You can explicitly specify a signing identity (as long as they have different names) and a provisioning profile GUID.
EDIT: CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer: John Doe (ABCDEF) and PROVISIONING_PROFILE[sdk=iphoneos*] = provisioning-profile-guid in the config (or on the command line). Or in the project settings, search for "sign" and use the nice GUI menu.
Alternatively, use a different user account for your work builds.
EDIT: System Preferences → Accounts and add a new user. It also helps if you enable fast user-switching under "Login Options".