Search code examples
objective-cmacoscocoakeychain

SecKeychain load item


I want to store SMTP-Data from my Mac OSX application using the keychain. I read the Keychain Services Programming Guide of Apple and wrote this method to store the data:

    - (BOOL)saveSMPTData
{
    OSStatus err;
    SecKeychainItemRef item = nil;
    SecProtocolType protocol = kSecProtocolTypeSMTP;
    const char *accessLabelUTF8 = [KEYCHAIN_NAME UTF8String];
    const char *serverNameUTF8 = [self.serverName UTF8String];
    const char *usernameUTF8 = [self.username UTF8String];
    const char *passwordUTF8 = [self.password UTF8String];

    SecAccessRef access = createAccess(KEYCHAIN_NAME);

    SecKeychainAttribute attrs[] = {
        { kSecLabelItemAttr, (int)strlen(accessLabelUTF8), (char *)accessLabelUTF8 },
        { kSecAccountItemAttr, (int)strlen(usernameUTF8), (char *)usernameUTF8 },
        { kSecServerItemAttr, (int)strlen(serverNameUTF8), (char *)serverNameUTF8 },
        { kSecProtocolItemAttr, sizeof(SecProtocolType), (SecProtocolType *)&protocol }
    };
    SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
    err = SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass,
                                           &attributes,
                                           (int)strlen(passwordUTF8),
                                           passwordUTF8,
                                           NULL,
                                           access,
                                           &item);
    if (access) CFRelease(access);
    if (item) CFRelease(item);
    return (err == noErr);
}

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

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

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

    if (err) return nil;
    return access;
}

Of course I also want to load them. My first try looks like this:

- (BOOL)loadDataFromKeychain
{
    uint32_t serverNameLength = 0;
    const char *serverName = NULL;

    uint32_t usernameLength = 0;
    const char *username = NULL;

    uint32_t passwordLength = 0;
    void **password = NULL;

    OSStatus err = SecKeychainFindInternetPassword(NULL,
                                                   serverNameLength, serverName,
                                                   0, NULL,
                                                   usernameLength, username,
                                                   0, NULL,
                                                   0, 0,
                                                   0,
                                                   &passwordLength, password,
                                                   NULL); // How do I get the ItemRef?

    return (err == noErr);
}

But this does not work, and I think I know why not. I don’t know how to get the SecKeychainItemRef for the SecKeychainFindInternetPassword method.

Maybe anyone can help me?


Solution

  • Instead of declaring password a void **, declare it a void * and pass &password for the second-to-last parameter.

    You probably don't need the SecKeychainItemRef for what you're trying to accomplish.

    By the way, have you tried using Keychain Access to verify the items are getting into the keychain?