Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Adding Simple Keychain Services to Your Application

Most applications need to use Keychain Services only to add a new password to a keychain or retrieve a password when needed. Keychain Services provides the following pairs of functions for accomplishing these tasks:

You use Internet passwords for accessing servers and websites over the Internet, and generic passwords for any other password-protected service (such as a database or scheduling application). AppleShare passwords (that is, keychain items with a class code of kSecAppleSharePasswordItemClass) are stored as generic passwords.

Note: AppleShare passwords created with the legacy Keychain Manager function KCAddAppleSharePassword are stored as Internet password items. You can use the SecKeychainAddInternetPassword function to store an AppleShare password, but it will appear in the Keychain Access utility as an Internet password. To create a keychain item with a class code of kSecAppleSharePasswordItemClass, you must use the lower-level API described in Keychain Services Reference.

The “find” functions retrieve information (attributes or secure data) from an item in the keychain. The “add” functions add an item to a keychain. These functions call other Keychain Services functions to accomplish their tasks. Because Keychain Services allocates the buffers in which the item data and attributes are returned, you must call SecKeychainItemFreeContent to free these buffers after using one of the find functions to retrieve attributes or secure data from a keychain item. (If Keychain Services does not find the item or fails to return any data for some other reason, it does not allocate any buffers and you should not call the SecKeychainItemFreeContent function.)

Figure 2-1 shows a flowchart of how an application might use these functions to gain access to an Internet FTP server.


Figure 2-1  Accessing an Internet server using Keychain Services

Accessing an Internet server using Keychain Services

The user starts by selecting a File Transfer Protocol (FTP) server. The application calls SecKeychainFindInternetPassword, passing it attributes that identify the service and the user to seek. If the password is on the keychain, the function returns the password to the application, which sends it to the FTP server to authenticate the user. The application then calls SecKeychainItemFreeContent to free the data buffer allocated for the password (note that you should not call this function if no data is returned). If the authentication succeeds, the routine is finished. If the authentication fails, the application displays a dialog to request the user name and password.

If the password is not on the keychain, then SecKeychainFindInternetPassword returns the errSecItemNotFound result code. In this case as well, the application displays a dialog to request the user name and password. (This dialog should also include a Cancel button, but that choice was omitted from the figure to keep the flowchart from becoming overly complex.)

Having obtained the password from the user, the application proceeds to authenticate the user. When the authentication has succeeded, the application can assume that the information entered by the user was valid. The application then displays another dialog asking the user whether to save the password on the keychain. If the user selects No, then the routine is finished. If the user selects Yes, then the application calls the SecKeychainAddInternetPassword function (if this is a new keychain item), or the SecKeychainItemModifyAttributesAndData function (to update an existing keychain item) before ending the routine.

If there is no keychain, the SecKeychainFindInternetPassword or SecKeychainAddInternetPassword function displays a dialog allowing the user to “reset to defaults” (see Figure 1-5), which creates a new keychain named login.keychain with the user’s login account password. If the keychain is locked, the function displays a dialog requesting the user to enter a password to unlock the keychain (Figure 1-6). The user can cancel the operation at this time as well.

“Getting and setting passwords” shows how a typical application might use Keychain Services functions to get and set passwords for generic items. You can get and set keychain item attributes (such as user name or service name) using these same functions; see Listing 2-2 for an example.

Listing 2-1  Getting and setting passwords

#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <CoreServices/CoreServices.h>
 
//Call SecKeychainAddGenericPassword to add a new password to the keychain:
OSStatus StorePasswordKeychain (void* password,UInt32 passwordLength)
{
 OSStatus status;
 status = SecKeychainAddGenericPassword (
                NULL,            // default keychain
                10,              // length of service name
                "SurfWriter",    // service name
                10,              // length of account name
                "MyUserAcct",    // account name
                passwordLength,  // length of password
                password,        // pointer to password data
                NULL             // the item reference
    );
    return (status);
 }
 
//Call SecKeychainFindGenericPassword to get a password from the keychain:
OSStatus GetPasswordKeychain (void *passwordData,UInt32 *passwordLength,
                                                SecKeychainItemRef *itemRef)
{
 OSStatus status1 ;
 
 
 status1 = SecKeychainFindGenericPassword (
                 NULL,           // default keychain
                 10,             // length of service name
                 "SurfWriter",   // service name
                 10,             // length of account name
                 "MyUserAcct",   // account name
                 passwordLength,  // length of password
                 passwordData,   // pointer to password data
                 itemRef         // the item reference
    );
     return (status1);
 }
 
//Call SecKeychainItemModifyAttributesAndData to change the password for
// an item already in the keychain:
OSStatus ChangePasswordKeychain (SecKeychainItemRef itemRef)
{
    OSStatus status;
    void * password = "myNewP4sSw0rD";
    UInt32 passwordLength = strlen(password);
 
 status = SecKeychainItemModifyAttributesAndData (
                 itemRef,         // the item reference
                 NULL,            // no change to attributes
                 passwordLength,  // length of password
                 password         // pointer to password data
    );
     return (status);
 }
 
 
/* ********************************************************************** */
 
int main (int argc, const char * argv[]) {
    OSStatus status;
    OSStatus status1;
 
     void * myPassword = "myP4sSw0rD";
     UInt32 myPasswordLength = strlen(myPassword);
 
     void *passwordData = nil; // will be allocated and filled in by
                               //SecKeychainFindGenericPassword
     SecKeychainItemRef itemRef = nil;
     UInt32 passwordLength = nil;
 
    status1 = GetPasswordKeychain (&passwordData,&passwordLength,&itemRef);  //Call
                                                //SecKeychainFindGenericPassword
        if (status1 == noErr)       //If call was successful, authenticate user
                                    //and continue.
        {
        //Free the data allocated by SecKeychainFindGenericPassword:
    status = SecKeychainItemFreeContent (
                 NULL,           //No attribute data to release
                 passwordData    //Release data buffer allocated by
                 //SecKeychainFindGenericPassword
    );
 }
 
    if (status1 == errSecItemNotFound) { //Is password on keychain?
    /*
    If password is not on keychain, display dialog to prompt user for
    name and password.
    Authenticate user.  If unsuccessful, prompt user again for name and password.
    If successful, ask user whether to store new password on keychain; if no, return.
    If yes, store password:
    */
    status = StorePasswordKeychain (myPassword,myPasswordLength); //Call
                                                      // SecKeychainAddGenericPassword
    return (status);
    }
 
    /*
    If password is on keychain, authenticate user.
    If authentication succeeds, return.
    If authentication fails, prompt user for new user name and password and
     authenticate again.
    If unsuccessful, prompt again.
    If successful, ask whether to update keychain with new information.  If no, return.
    If yes, store new information:
    */
    status = ChangePasswordKeychain (itemRef);  //Call
                                            // SecKeychainItemModifyAttributesAndData
    if (itemRef) CFRelease(itemRef);
    return (status);
 
 }

This example follows the same general sequence that was shown in Figure 2-1; however, unlike the figure, the example illustrates the use of generic passwords rather than Internet passwords.

Important: You should not cache passwords, because the user can change them using Keychain Access or another program and the data may no longer be valid. In addition, the long-term storage of passwords by applications negates the value of the keychain.

Although the example in “Getting and setting passwords” is written in procedural C, you can call these same functions using Objective C. Listing 2-2 shows how you might create an Internet password item if you wanted some custom attribute values. Note that attribute strings should all be encoded in UTF-8 format.



< Previous PageNext Page > Hide TOC


Last updated: 2007-01-08




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice