Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you write to the OSX System keychain?

As part of the process of creating a VPN connection programatically in OSX, using Cocoa, I need to store the PPP password in the System keychain. When I try to do this using the keychain API, I get the following error as a result of calling SecKeychainAddGenericPassword:

"Could not write to the file. It may have been opened with insufficient access privileges."

Here is the code I am using:

- (void)storePasswordInKeychain
{
    SecKeychainRef keychain = nil;
    err = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
    if (err != errSecSuccess) {
        NSLog(@"Error getting system keychain: %@", SecCopyErrorMessageString(err, NULL));
    } else {
        NSLog(@"Succeeded opening keychain: %@", SecCopyErrorMessageString(err, NULL));
        SecKeychainItemRef item = nil;        
        err = SecKeychainUnlock(keychain, 0, NULL, FALSE);
        NSLog(@"Keychain unlocked: %@", SecCopyErrorMessageString(err, NULL));

        err = SecKeychainAddGenericPassword (keychain, 
                                         3, "VPN", 
                                         8, "username",
                                         8, "password",
                                         &item);
        NSLog(@"Result of storing password: %@", SecCopyErrorMessageString(err, NULL));
    }
}

The discussion How to write to the System.keychain? makes it seem like I need to make a command line call to /usr/bin/security from within my program, but the point of the Keychain API seems to be to avoid that kind of hackery.

Can anybody point me in the right direction for storing a new password in the System keychain? Thanks.

like image 516
Kevin Avatar asked Dec 04 '25 21:12

Kevin


2 Answers

You need root privilege when you write something to system keychain. For xcode debugging, you just "EditScheme"(From Menu by "Product->EditScheme...->Run->Info->Debug process as->root"). Well,my xcode version is 6.1, maybe there is some difference in different xcode version. Or just use command line by sudo your app. Hope this helps.

like image 133
iPanda Avatar answered Dec 07 '25 15:12

iPanda


It is true that the credentials need to go into the system keychain and not the user keychain. You will not need the SMJobBless to do that.

After you unlocked the keychain, create an SecAccessRef like so:

SecAccessRef access = nil;
status = SecAccessCreate(CFSTR("Some VPN Test"), (__bridge CFArrayRef)(self.trustedApps), &access);

Then build your keychain item

SecKeychainAttribute attrs[] = {
  {kSecLabelItemAttr, (int)strlen(labelUTF8), (char *)labelUTF8},
  {kSecAccountItemAttr, (int)strlen(accountUTF8), (char *)accountUTF8},
  {kSecServiceItemAttr, (int)strlen(serviceUTF8), (char *)serviceUTF8},
  {kSecDescriptionItemAttr, (int)strlen(descriptionUTF8), (char *)descriptionUTF8},
};

And finally store it to the keychain:

  SecKeychainAttributeList attributes = {sizeof(attrs) / sizeof(attrs[0]), attrs};
  status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, (int)strlen(passwordUTF8), passwordUTF8, keychain, access, &item);

There is a project on Github which does just that. Have a look at the VPNKeychain.m file to see the whole implementation. https://github.com/halo/macosvpn

like image 25
halo Avatar answered Dec 07 '25 16:12

halo