This chapter describes and illustrates the use of basic Keychain Services functions in Mac OS X. For the use of Keychain Services in iPhone OS, see “iPhone OS Keychain Services Tasks.”
The functions described in this chapter enable you to:
Add a password to a keychain
Find a password in a keychain
Get the attributes and data in a keychain item
Change the attributes and data in a keychain item
Unlock a keychain
Lock a keychain
Suppress the automatic display of the create keychain or open keychain dialogs
Add trusted applications to a keychain item’s access control list
“Keychain Services Concepts” provides an introduction to the concepts and terminology of Keychain Services. For detailed information about all Keychain Services functions, see Keychain Services Reference.
Adding Simple Keychain Services to Your Application
Advanced Topics
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:
SecKeychainAddInternetPassword
and SecKeychainFindInternetPassword
(for Internet passwords)
SecKeychainAddGenericPassword
and SecKeychainFindGenericPassword
(for generic passwords
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 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.
The user of the application 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 to the FTP server. 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 in Mac OS X Keychain Services” 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 in Mac OS X Keychain Services
#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 in Mac OS X Keychain Services” 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.
Most applications need only the Keychain Services functions described in “Adding Simple Keychain Services to Your Application.” However, in certain circumstances you might want to use some of the other functions provided by Keychain Services. For example, you might want to display a custom label for your application in the Keychain Access utility. Or, if you are writing a server, you might want to disable the automatic display of dialogs and instead take care of unlocking the keychain within your application.
This section discusses how to create a keychain item if you want lower-level control than is provided by SecKeychainAddInternetPassword
or SecKeychainAddGenericPassword
. For example, you might want to have the Keychain Access application display a custom label for your keychain item or you might want to specify more than one trusted application that can access the item. Specifically, this section illustrates the use of the SecKeychainItemCreateFromContent
function to create a keychain item and the SecAccessCreate
function to set up an access list. For more details about these and other low-level functions, see Keychain Services Reference.
When you use SecKeychainAddInternetPassword
or SecKeychainAddGenericPassword
, the function creates a label for the keychain item automatically. For an Internet password, it uses the URL, minus the scheme name, colon, and leading slashes. For example, the label (displayed in the Name field in Keychain Access) for a new Internet password for the URL http://www.apple.com becomes www.apple.com. For a generic password, the function uses the service attribute for the label. In both cases, the Name and Where fields in Keychain access are identical. If you want a unique name for the keychain item that is different from the URL or service name, you can specify the label (kSecLabelItemAttr
) attribute when you call SecKeychainItemCreateFromContent
.
The SecKeychainAddInternetPassword
and SecKeychainAddGenericPassword
functions create an initial access list for you. This default access list includes only one trusted application (that is, one application that can access the keychain item whenever the keychain is unlocked), namely the application that created the keychain item. The SecKeychainItemCreateFromContent
function accepts an access list as input. However, if you pass NULL
, this function creates an access list consisting of the single application calling the function. Therefore, you must call the SecAccessCreate
function before calling the SecKeychainItemCreateFromContent
function if you want an access list with more than one trusted application. Alternatively, you can alter the access list of an existing keychain item; see “Modifying the Access List of an Existing Keychain Item.”
Listing 2-2 illustrates the creation of an Internet keychain item with a custom label and an access list that includes two trusted applications. This listing also illustrates the use of the Keychain Services API from an Objective-C application.
Listing 2-2 Creating a keychain item with custom attributes
#import <Cocoa/Cocoa.h> |
#include <Security/SecKeychain.h> |
#include <Security/SecKeychainItem.h> |
#include <Security/SecAccess.h> |
#include <Security/SecTrustedApplication.h> |
#include <Security/SecACL.h> |
SecAccessRef createAccess(NSString *accessLabel) |
{ |
OSStatus err; |
SecAccessRef access=nil; |
NSArray *trustedApplications=nil; |
//Make an exception list of trusted applications; that is, |
// applications that are allowed to access the item without |
// requiring user confirmation: |
SecTrustedApplicationRef myself, someOther; |
//Create trusted application references; see SecTrustedApplications.h: |
err = SecTrustedApplicationCreateFromPath(NULL, &myself); |
err = SecTrustedApplicationCreateFromPath("/Applications/Mail.app", |
&someOther); |
trustedApplications = [NSArray arrayWithObjects:(id)myself, |
(id)someOther, nil]; |
//Create an access object: |
err = SecAccessCreate((CFStringRef)accessLabel, |
(CFArrayRef)trustedApplications, &access); |
if (err) return nil; |
return access; |
} |
void addInternetPassword(NSString *password, NSString *account, |
NSString *server, NSString *itemLabel, NSString *path, |
SecProtocolType protocol, int port) |
{ |
OSStatus err; |
SecKeychainItemRef item = nil; |
const char *pathUTF8 = [path UTF8String]; |
const char *serverUTF8 = [server UTF8String]; |
const char *accountUTF8 = [account UTF8String]; |
const char *passwordUTF8 = [password UTF8String]; |
const char *itemLabelUTF8 = [itemLabel UTF8String]; |
//Create initial access control settings for the item: |
SecAccessRef access = createAccess(itemLabel); |
//Following is the lower-level equivalent to the |
// SecKeychainAddInternetPassword function: |
//Set up the attribute vector (each attribute consists |
// of {tag, length, pointer}): |
SecKeychainAttribute attrs[] = { |
{ kSecLabelItemAttr, strlen(itemLabelUTF8), (char *)itemLabelUTF8 }, |
{ kSecAccountItemAttr, strlen(accountUTF8), (char *)accountUTF8 }, |
{ kSecServerItemAttr, strlen(serverUTF8), (char *)serverUTF8 }, |
{ kSecPortItemAttr, sizeof(int), (int *)&port }, |
{ kSecProtocolItemAttr, sizeof(SecProtocolType), |
(SecProtocolType *)&protocol }, |
{ kSecPathItemAttr, strlen(pathUTF8), (char *)pathUTF8 } |
}; |
SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), |
attrs }; |
err = SecKeychainItemCreateFromContent( |
kSecInternetPasswordItemClass, |
&attributes, |
strlen(passwordUTF8), |
passwordUTF8, |
NULL, // use the default keychain |
access, |
&item); |
if (access) CFRelease(access); |
if (item) CFRelease(item); |
} |
int main(int argc, const char *argv[]) |
{ |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
//Add an example password to the keychain: |
addInternetPassword(@"sample password", @"sample account", |
@"samplehost.apple.com", @"sampleName", @"cgi-bin/bogus/testpath", |
kSecProtocolTypeHTTP, 8080); |
[pool release]; |
return 0; |
} |
By default, a keychain item’s access list contains only the application that created the keychain item. Listing 2-2 illustrates the creation of an Internet keychain item with an access list that includes two trusted applications. Listing 2-3 illustrates how to modify an existing keychain item. The listing finds a specific keychain item, extracts the access object, including the list of trusted applications, authorization tags, and other information (see “ACL Entries”), adds a trusted application to the list, reconstitutes the access object, and writes the new access object back to the keychain item. Although this sample illustrates modifying the list of trusted applications, you can use a similar sequence to modify any of the information in the access object—for example, to add or remove an authorization tag.
Listing 2-3 starts by calling the SecKeychainSearchCreateFromAttributes
function to create a search reference. In this example, the code looks for a keychain item by its label (as seen in the Keychain Access application); you can search for other attributes, however, such as modification date. Using this search reference, the sample calls SecKeychainSearchCopyNext
to find the keychain item.
The listing next calls SecKeychainItemCopyAccess
to retrieve the keychain item’s access object. As discussed in “Keychain Access Controls,” the access object includes one or more ACL entries. The listing calls the SecAccessCopySelectedACLList
function and passes it an authorization tag value of CSSM_ACL_AUTHORIZATION_DECRYPT
. This authorization tag is one of the tags normally associated with the access list used for sensitive operations and is the list displayed by the Keychain Access application. To retrieve all the ACL entries for an access object, use the SecAccessCopyACLList
function instead.
The SecAccessCopySelectedACLList
function returns a CFArrayRef object containing all of the ACL entries that meet the selection criteria. In this case, the code is assuming that there should be only one ACL entry that employs the CSSM_ACL_AUTHORIZATION_DECRYPT
tag. The listing calls the CFArrayGetValues
function to create a C array of SecACLRef
objects from the CFArrayRef and then calls the SecACLCopySimpleContents
function, passing it the first (and presumably only) item in the array. The SecACLCopySimpleContents
function also retrieves a CFArrayRef containing the list of trusted applications, the keychain item description string, and the prompt selector flag. These values are needed in order to reconstitute the ACL entry after adding a trusted application to the list.
Next, the listing uses the CFArrayGetValues
function again, this time to extract the array of trusted applications from the CFArrayRef. The listing calls the SecTrustedApplicationCreateFromPath
function to create a new trusted application object, appends the new application to the list, and calls CFArrayCreate
to create a new CFArrayRef.
Before adding a new ACL entry to the access object, the listing calls the SecACLGetAuthorizations
function to get the list of authorization tags from the old access object. Then, having extracted all the information from the old ACL entry, the code calls the SecACLRemove
function to remove the old ACL entry from the access object. The listing then calls the SecACLCreateFromSimpleContents
function to create a new ACL entry for the access object. This function automatically adds the entry to the access object; there is no separate call for that purpose. The new ACL entry has only the default authorization list, however, so the listing calls the SecACLSetAuthorizations
function, passing in the authorization list extracted from the old ACL entry.
The access object is now complete, with the new ACL entry containing all of the trusted applications in the old entry plus the new one added here. Only two steps remain: First, the listing calls the SecKeychainItemSetAccess
function to replace the access object in the keychain item with the new access object; then the listing calls the CFRelease
function for each core foundation object that is no longer needed, in order to release the memory.
Note that this sample routine causes the user to be prompted twice for permission: once when the old ACL entry is deleted from the access object, and once when the new access object is written to the keychain item.
Listing 2-3 Modifying a keychain item access list
#include <CoreFoundation/CoreFoundation.h> |
#include <Security/Security.h> |
#include <CoreServices/CoreServices.h> |
//Call SecKeychainSearchCreateFromAttributes to get a search reference: |
OSStatus GetSearchRef (SecKeychainAttributeList *attrList, |
SecKeychainSearchRef *searchReference) |
{ |
OSStatus status; |
status = SecKeychainSearchCreateFromAttributes ( |
NULL, // default keychain search list |
kSecInternetPasswordItemClass, // search for an Internet password |
attrList, // match attributes |
searchReference // search reference to return |
); |
return (status); |
} |
//Call SecKeychainSearchCopyNext to find an item on the keychain: |
OSStatus FindItem (SecKeychainSearchRef searchReference, |
SecKeychainItemRef *itemRef) |
{ |
OSStatus status1 ; |
status1 = SecKeychainSearchCopyNext ( |
searchReference, // search reference |
itemRef // the item reference |
); |
return (status1); |
} |
//Get an ACL out of a CFArray: |
SecACLRef GetACL (CFIndex numACLs, CFArrayRef ACLList, |
CFArrayRef *applicationList, CFStringRef *description, |
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector) |
{ |
OSStatus status; |
SecACLRef aclArray[numACLs]; |
CFRange aclRange; |
aclRange.location = (CFIndex) 0; |
aclRange.length = numACLs; |
CFArrayGetValues ( |
ACLList, // the CFArrayRef we got from the keychain item |
aclRange, // the size of the array |
(void *) aclArray // a SecACLRef containing the values from the |
// CFArrayRef |
); |
//Extract the application list from the ACL. |
//Because we limited our search to ACLs used for decryption, we |
// expect only one ACL for this item. Therefore, we extract the |
// application list from the first ACL in the array. |
status = SecACLCopySimpleContents ( |
aclArray[0], // the ACL from which to extract |
// the list of trusted apps |
applicationList, // the list of trusted apps |
description, // the description string |
promptSelector // the value of the prompt selector flag |
); |
return aclArray[0]; |
} |
int main (int argc, const char * argv[]) { |
OSStatus status; |
OSStatus status1; |
OSStatus status2; |
OSStatus status3; |
SecKeychainSearchRef searchReference = nil; |
SecKeychainItemRef itemRef = nil; |
SecAccessRef itemAccess = nil; |
SecACLRef oldACL, newACL; |
CFIndex arrayCount; |
CFRange arrayRange; |
SecTrustedApplicationRef trustedAppArray[10]; |
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector; |
CFStringRef description; |
CFArrayRef newTrustedAppArray; |
CSSM_ACL_AUTHORIZATION_TAG tags[20]; |
uint32 tagCount; |
tagCount = 20; |
const char *path = "/Applications/Mail.app"; //path to |
// trusted app to add to ACL |
SecTrustedApplicationRef trustedApp; |
SecKeychainAttributeList attrList; |
SecKeychainAttribute attrib; |
attrList.count = 1; |
attrib.tag = kSecLabelItemAttr; |
attrib.data = "www.TestItem.com"; //label of keychain item |
attrib.length = strlen(attrib.data); |
attrList.attr = &attrib; |
CFArrayRef aclList; |
CFIndex numACLs; |
CFArrayRef applicationList; |
CSSM_ACL_AUTHORIZATION_TAG authorizationTag = |
CSSM_ACL_AUTHORIZATION_DECRYPT; // the authorization tag |
// to search for. |
// Obtain a search reference object to use for finding the item |
// in the keychain. |
// This returns a SecKeychainSearchRef, which we must release when |
// we're finished using it. |
status = GetSearchRef (&attrList, &searchReference); |
// Find the keychain item and obtain a keychain item reference object. |
// This returns a SecKeychainItemRef, which we must release when |
// we're finished using it. |
status1 = FindItem (searchReference, &itemRef); |
if (status1 == noErr) |
{ |
// Obtain the access reference object for the keychain item. |
// This returns a SecAccessRef, which we must release when |
// we're finished using it. |
status2 = SecKeychainItemCopyAccess (itemRef, &itemAccess); |
// Obtain an array of ACL entry objects for the access object. |
// Limit the search to ACL entries with the specified |
// authorization tag. |
status3 = SecAccessCopySelectedACLList (itemAccess, |
authorizationTag, &aclList); |
numACLs = CFArrayGetCount (aclList); |
// Extract the ACL entry object from the array of ACL entries, |
// along with the ACL entry's list of trusted applications, |
// its description, and its prompt selector flag setting. |
// This returns a SecACLRef and a CFArrayRef, which we must |
// release we're finished using them. |
oldACL = GetACL (numACLs, aclList, &applicationList, |
&description, &promptSelector); |
arrayCount = CFArrayGetCount (applicationList); |
// The application list is a CFArray. Extract the list of |
// applications from the CFArray. |
arrayRange.location = (CFIndex) 0; |
arrayRange.length = arrayCount; |
CFArrayGetValues (applicationList, arrayRange, |
(void *) trustedAppArray); |
// Create a new trusted application reference object for |
// the application to be added to the list. |
status2 = SecTrustedApplicationCreateFromPath (path, &trustedApp); |
if (status2 == noErr) // the function fails if the application is |
// not found. |
{ |
// Append the new application to the array and create a |
// new CFArray. |
trustedAppArray[arrayCount] = trustedApp; |
newTrustedAppArray = CFArrayCreate (NULL, |
(void *)trustedAppArray, arrayCount+1, |
&kCFTypeArrayCallBacks); |
// Get the authorizations from the old ACL. |
status3 = SecACLGetAuthorizations (oldACL, tags, &tagCount); |
// Delete the old ACL from the access object. The user is |
// prompted for permission to alter the keychain item. |
status3 = SecACLRemove (oldACL); |
// Create a new ACL with the same attributes as the old |
// one, except use the new CFArray of trusted applications. |
status3 = SecACLCreateFromSimpleContents (itemAccess, |
newTrustedAppArray, description, &promptSelector, |
&newACL); |
// Set the authorizations for the new ACL to be the same as |
// those for the old ACL. |
status3 = SecACLSetAuthorizations (newACL, tags, tagCount); |
// Replace the access object in the keychain item with the |
// new access object. The user is prompted for permission |
// to alter the keychain item. |
status3 = SecKeychainItemSetAccess (itemRef, itemAccess); |
} |
else |
...; //Handle the error if the application was not found. |
// Release the objects we allocated or retrieved |
if (searchReference) |
CFRelease(searchReference); //SecKeychainSearchRef |
if (itemRef) |
CFRelease(itemRef); //SecKeychainItemRef |
if (itemAccess) |
CFRelease(itemAccess); //SecAccessRef |
if (oldACL) |
CFRelease(oldACL); //SecACLRef |
if (newACL) |
CFRelease(newACL); //SecACLRef |
if (description) |
CFRelease(description); //CFStringRef |
if (newTrustedAppArray) |
CFRelease(newTrustedAppArray); //CFArrayRef |
if (trustedApp) |
CFRelease(trustedApp); //SecTrustedApplicationRef |
if (aclList) |
CFRelease(aclList); //CFArrayRef |
if (applicationList) |
CFRelease(applicationList); //CFArrayRef |
} |
return (status3); |
} |
Several Keychain Services functions automatically display a dialog requesting that the user unlock the keychain or create a new keychain when necessary. Keychain Services also displays dialogs to confirm that the user wants the application to access the keychain (Figure 2-2) and for other reasons. If you are writing a server application that must run unattended, you might want to disable the automatic display of dialogs and programatically unlock or create keychains.
Use the SecKeychainSetUserInteractionAllowed
function to enable or disable the automatic display of dialogs. When you call this function with a value of FALSE
for the state
parameter, any Keychain Services functions that ordinarily open dialogs instead return immediately with the result errSecInteractionRequired
. You can use the SecKeychainGetStatus
function to find out whether the keychain exists and is unlocked. You can then use the SecKeychainUnlock
function to unlock the keychain, or the SecKeychainCreate
function to create a new keychain, as necessary.
Important: After you have disabled the automatic display of dialogs, no Keychain Services function called by any application displays dialogs until someone calls the SecKeychainSetUserInteractionAllowed
function to reenable dialogs, or until the system is restarted. Therefore, if there might be other applications operating on the same computer, you should be careful to reenable this feature once you are finished opening or creating a keychain.
© 2003, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-03-12)