你如何写OSX系统钥匙串?

时间:2012-03-23 10:40:02

标签: macos cocoa keychain

作为在OSX中以编程方式创建VPN连接的过程的一部分,使用Cocoa,我需要将PPP密码存储在System keychain中。当我尝试使用keychain API执行此操作时,由于调用SecKeychainAddGenericPassword而出现以下错误:

“无法写入文件。它可能是在访问权限不足的情况下打开的。”

以下是我正在使用的代码:

- (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));
    }
}

讨论How to write to the System.keychain?使得我似乎需要从我的程序中对/ usr / bin / security进行命令行调用,但Keychain API的重点似乎是避免这种hackery 。

有人能指出我在系统钥匙串中存储新密码的正确方向吗?谢谢。

4 个答案:

答案 0 :(得分:1)

当您向系统密钥链写入内容时,您需要root权限。 对于xcode调试,只需“EditScheme”(从菜单按“Product-> EditScheme ...-> Run-> Info-> Debug process as-> root”)。好吧,我的xcode版本是6.1,也许在不同的xcode版本中有一些区别。 或者只是通过sudo你的应用程序使用命令行。 希望这会有所帮助。

答案 1 :(得分:1)

确实,凭据需要进入系统密钥链而不是用户密钥链。你不需要SMJobBless来做到这一点。

解锁钥匙串后,创建一个SecAccessRef,如下所示:

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

然后构建您的钥匙串项目

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},
};

最后将它存储到钥匙串中:

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

Github上有一个项目可以做到这一点。查看VPNKeychain.m文件以查看整个实现。 https://github.com/halo/macosvpn

答案 2 :(得分:0)

当然是VPN用户名&密码属于特定用户,您真的是指系统密钥链而不是用户密钥链吗?

尝试放弃对SecKeychainCopyDomainDefault& SecKeychainUnlock只是将NULL作为SecKeychainAddGenericPassword的第一个参数传递 - 这应该将项目添加到默认的钥匙串。

答案 3 :(得分:0)

Apple目前推荐的特权访问是使用Service Management API。他们有一个示例项目:SMJobBless。如果您定位到Mac App Store,我不确定沙盒是否允许系统密钥链访问。

您指出的另一个问题似乎是推荐服务管理所取代的Authorization Services API(在10.6中),并明确声明在沙箱时根本不允许。