2

I create a custom keychain and then I save a password inside it this way:

SecKeychainRef someKeychain; //keychain reference
SecKeychainItemRef someItem; //keychain key item reference

SecKeychainCreate([keychainPath UTF8String], (UInt32)strlen(keychainPass), keychainPass, FALSE, NULL, &someKeychain);
SecKeychainAddGenericPassword(someKeychain, (UInt32)strlen(someServiceName), someServiceName, (UInt32)strlen(someAccountName), someAccountName, (UInt32)strlen(encryptedPass), encryptedPass, &someItem);

What I would like to do now is to make the added someItem accessible by any application that knows the keychainPass without prompting the user to allow. So I tried it this way:

SecACLRef aclList;
SecAccessRef itemAccessRef;
uid_t userid = 0;
gid_t groupid;
CFArrayRef aclListArr;
SecACLRef newAcl;

SecKeychainItemCopyAccess(someItem, &itemAccessRef);
SecAccessCopyOwnerAndACL(itemAccessRef, &userid, &groupid, (UInt32*)kSecUseOnlyUID, &aclListArr);

SecACLCreateWithSimpleContents(itemAccessRef, NULL, (__bridge CFStringRef)@"someTagName", kSecKeychainPromptInvalid, &newAcl);

But:

  1. I don't know if the function SecACLCreateWithSimpleContents is the right way to achieve this at all
  2. If it is, I don't know how to write the ACLlist created with it back to someItem
  3. I don't know how to work with these CFArrays it returns (I'm an objective-c beginner)

I know that this has to be possible, because when I import the newly created keychain into the Keychain Access OS X app and I mark the properties of someItem to be accessible by any application, the prompt is gone and everything works. What I don't know is how to achieve this programatically. I realize this might be a silly question, but I don't know what to do.

Michał Siwek
  • 794
  • 1
  • 10
  • 25

3 Answers3

0

I'm coming from iOS but according to the reference docs it should be roughly the same.

You need to use SecItemAdd with the option [kSecAttrAccessGroup)(https://developer.apple.com/library/mac/documentation/security/Reference/keychainservices/Reference/reference.html#//apple_ref/c/data/kSecAttrAccessGroup). Take a look at the reference docs for SecItemAdd

Here's a post that walks has some example code on how to use SecItemAdd.

Community
  • 1
  • 1
Todd Anderson
  • 1,138
  • 9
  • 21
  • That's not exactly what I need - I'd like to simply drop the access restrictions like the Keychain Access app does with GUI, not to allow group access. – Michał Siwek Jun 10 '14 at 19:32
  • Why? If two applications can have the same password to access encrypted data, they should be able to access the same kSecAttrAccessGroup. If you do not wish to store encrypted data, and you want any application to have access to it, without security, you should be using [NSUserDefaults addSuiteNamed:]. The only limitation is that the apps cannot be sandboxed. – Todd Anderson Jun 10 '14 at 19:49
  • There is one thing I don't quite get about `SecItemAdd ` yet - where do I provide it the reference to the keychain I'm creating? I've been looking for an answer, but I'm afraid it only works for the default system keychain. – Michał Siwek Jun 10 '14 at 21:09
  • SecItemAdd is a convenience function to use the default keychain. If you are using a different one you should use SecKeychainItemCreateFromContent or SecKeychainItemCreatePersistentReference depending on your needs. – Todd Anderson Jun 10 '14 at 21:30
  • 3
    @ToddAnderson Access Group on macOS works only when you set `kSecAttrSynchronizable` to `kCFBooleanTrue` and this automatically makes this entry sent to iCloud which could be undesired behaviour for some. – solgar Jan 25 '17 at 16:45
0

What you need to do is setup an access control list for the item and the keychain

Here is the code to create the access reference

#pragma mark - Keychain Access Methods

+ (SecAccessRef)createAccess:(NSString *)accessLabel
{
    OSStatus err;
    SecAccessRef access = nil;
    NSArray *trustedApplications = nil;

    SecTrustedApplicationRef myself;
    err = SecTrustedApplicationCreateFromPath(NULL, &myself);

    if (err)
        return nil;

    trustedApplications = [NSArray arrayWithObjects:(__bridge id)myself, nil];
    err = SecAccessCreate((__bridge CFStringRef)accessLabel,(__bridge CFArrayRef)trustedApplications, &access);

    if (err)
        return nil;

    return access;
}

You Didn't specify if your application creates the keychain but if it does you can allow your application when you create it using this code.

// Create Keychain
SecKeychainCreate(name, (UInt32)[password length], [password cStringUsingEncoding:NSUTF8StringEncoding], false, [self createAccess:keychainKey], NULL);

This would give your application access to any items in that keychain. You can also pass in the access control ref when you create the individual items.

Douglas Cobb
  • 193
  • 1
  • 9
0

You can achieve "Allow all applications to access this item" access for your new keychain items (Under macOS) by using the older Security API methods that accept a SecAccessRef parameter:

  • SecKeychainItemCreateFromContent()
  • SecKeyCreatePair() (deprecated in OS X 10.7 but still works)

Namely:

  • Create an SecAccessRef using SecAccessCreate() or SecAccessCreateWithOwnerAndACL()
  • Add a single ACL entry to the SecAccessRef with Any authorization, no prompt behavior (SecKeychainPromptSelector = 0) and a NULL trusted application list using SecACLCreateWithSimpleContents()
  • Pass the SecAccessRef when creating the keychain item(s) with the above APIs

I added a longer winded answer to this (dupe?) question: How to allow all applications to access keychain item without prompt

Mike C.
  • 621
  • 8
  • 13