Keychain Services Concepts

Computer users typically have to manage multiple accounts that require logins with user IDs and passwords. Secure FTP servers, AppleShare servers, database servers, secure websites, instant messaging accounts, and many other services require authentication before they can be used. Users often respond to this situation by making up very simple, easily remembered passwords, by using the same password over and over, or by writing passwords down where they can be easily found. Any of these cases compromises security.

The Keychain Services API provides a solution to this problem. By making a single call to this API, an application can store login information on a keychain where the application can retrieve the information—also with a single call—when needed. A keychain is an encrypted container that holds passwords for multiple applications and secure services. Keychains are secure storage containers, which means that when the keychain is locked, no one can access its protected contents. In OS X, users can unlock a keychain—thus providing trusted applications access to the contents—by entering a single master password. In iOS, each application always has access to its own keychain items; the user is never asked to unlock the keychain. Whereas in OS X any application can access any keychain item provided the user gives permission, in iOS an application can access only its own keychain items.

From the user’s point of view, a keychain provides transparent authentication; that is, (after unlocking the keychain if in OS X) the user does not have to log in separately to any services whose passwords are stored in the keychain. In OS X, the user has only to enter one password once to access any number of applications, servers, websites, and so on. In iOS, the user need not even enter the keychain password. Figure 1-1 shows the relationship between the user, the keychain, and the password-protected services. For iOS the first step (unlocking the keychain) is omitted. In iOS, an application can always access its own keychain items, but not items created by any other application.

Figure 1-1  Accessing password-protected services using a keychain in OS X
Accessing password-protected services using a keychain

By default, in OS X each login account has one keychain (for a new login on OS X v10.3, this keychain is named login.keychain); however, a user or application can create as many keychains as desired. The login keychain is automatically unlocked during login if it has the same password as the user’s login account password. When first created, the login keychain is also the default keychain. The default keychain is used to store newly created keychain items unless a different keychain is specified in the function call; certain other Keychain Services functions also use the default keychain when no other keychain is specified. The user can use the Keychain Access utility to designate another keychain as the default; however, the login keychain doesn’t change. In iOS, the situation is simpler: There is a single keychain accessible to applications. Although it stores the keychain items of all the applications on the system, an application can access only its own keychain items (with the possible exception of a keychain item for which the application that created it obtained a persistent reference).

Keychain Services and CDSA

In OS X, Keychain Services and other security APIs are built on the open source Common Data Security Architecture (CDSA) and its programming interface, Common Security Services Manager (CSSM).

The OS X Keychain Services API provides functions to perform most of the operations needed by applications, including creating, deleting, and modifying keychains and keychain items, controlling access to keychain items, finding keychain items, and retrieving attributes and data from items. However, the underlying CSSM API provides more capabilities that might be of interest to specialty applications, such as applications designed to administer the security of a computer or network. For this reason, the Keychain Services API includes a number of functions that return or create CSSM structures so that, if you are familiar with the CSSM API, you can move freely back and forth between Keychain Services and CSSM.

For more information about the CSSM API, see Common Security: CDSA and CSSM, version 2 (with corrigenda) from The Open Group (http://www.opengroup.org/security/cdsa.htm).

In iOS, the Keychain Services API provides all the functions available to manipulate keychain items.

Structure of a Keychain

Each keychain can contain any number of keychain items. Each keychain item contains data plus a set of attributes. For a keychain item that needs protection, such as a password or private key (a string of bytes used to encrypt or decrypt data), the data is encrypted and protected by the keychain. For keychain items that do not need protection, such as certificates, the data is not encrypted.

The attributes associated with a keychain item depend on the class of the item; the item classes most used by applications (other than the Finder and the Keychain Access application in OS X) are Internet passwords and generic passwords. As you might expect, Internet passwords include attributes for such things as security domain, protocol type, and path. The passwords or other secrets stored as keychain items are encrypted. In OS X, encrypted items are inaccessible when the keychain is locked; if you try to access the item while the keychain is locked, Keychain Services displays a dialog prompting the user for the keychain password. The attributes are not encrypted, however, and can be read at any time, even when the keychain is locked. In iOS, your application always has access to its own keychain items.

In OS X, each protected keychain item (and the keychain itself) contains access control information in the form of an opaque data structure called an access object. The access object contains one or more access control list (ACL) entries for that item. Each ACL entry has a list of one or more authorization tags specifying operations that can be done with that item, such as decrypting or authenticating. In addition, each ACL entry has a list of trusted applications that can perform the specified operations without authorization from the user.

Keychain Access Controls

When an OS X application attempts to access a keychain item for a particular purpose (such as to sign a document), the system looks at each ACL entry for that item to determine whether the application should be allowed access. If there is no ACL entry for that operation, then access is denied and it is up to the calling application to try something else or to notify the user. If there are any ACL entries for the operation, then the system looks at the list of trusted applications of each ACL entry to see if the calling application is in the list. If it is—or if the ACL specifies that all applications are allowed access—then access is permitted without confirmation from the user (as long as the keychain is unlocked). If there is an ACL entry for the operation but the calling application is not in the list of trusted applications, then the system prompts the user for the keychain password before permitting the application to access the item.

The Keychain Services API provides functions to create, delete, read, and modify ACL entries. Because an ACL entry is always associated with an access object, when you modify an ACL entry, you are modifying the access object as well. Therefore, there is no need for a separate function to write a modified ACL entry back into the access object.

There can be any number of ACL entries in an access object. If two or more of the ACL entries are for the same operation, there is no way to predict the order in which they will be evaluated.

Although the Keychain Services API lets you create ACL entries and add them to access objects, it is limited in the ways you can configure the authorizations and lists of trusted applications. If you want to implement access controls that go beyond the complexity and structure supported by Keychain Services, you can use the CSSM API to create a set of CSSM data structures and then call the SecAccessCreateFromOwnerAndACL function. Although you can’t use Keychain Services functions to extract information from or modify an access object made in this way, Keychain Services recognizes the access object as a CSSM data structure and uses it directly in its underlying calls to CSSM.

Trusted Applications

An ACL entry either permits all applications to perform the operations specified by its list of authorization tags or it contains a list of trusted applications. The trusted application list is actually a list of trusted application objects (objects with the opaque type SecTrustedApplicationRef). In addition to serving as a reference to the application, a trusted application object includes data that uniquely identifies the application, such as a cryptographic hash. The system can use this data to verify that the application has not been altered since the trusted application object was created. For example, when a trusted application requests access to an item in the keychain, the system checks this data before granting access. Although you can extract this data from the trusted application object for storage or for transmittal to another location (such as over a network), this data is in a private format; there is no supported way to read or interpret it.

You can use the SecTrustedApplicationCreateFromPath function to create a trusted application object. The trusted application is the binary form of the application that’s on the disk at the moment the trusted application object is created. If an application listed as a trusted application for a keychain item is modified in any way, the system does not recognize it as a trusted application. Instead, the user is prompted for confirmation when that application attempts to access the keychain item.

When a program attempts to access a keychain item for which it is not recognized as a trusted application, the system displays a confirmation dialog (Figure 1-2). The confirmation dialog has three buttons: Deny, Allow Once, and Always Allow. If the user clicks Always Allow, the system creates a trusted application object for the application and adds it to the access object for that keychain item.

Figure 1-2  Application access confirmation dialog
Application access confirmation dialog

To make the launching of programs more efficient, the system prebinds executables to dynamically loaded libraries (DLLs). When a user updates a DLL, the system automatically changes the executables of all the programs that use that library, a process referred to as reprebinding. Reprebinding a trusted application therefore causes the application to no longer match the version represented in the application hash. In OS X v10.2 and earlier, the next time the application tries to use a protected keychain item, a confirmation dialog appears. When the user clicks Always Allow, the system adds it to the access object as a new trusted application. Starting with OS X v10.3, on the other hand, the system maintains a database that keeps track of applications that were reprebound so that in most cases no confirmation dialog appears.

In OS X v10.3 and later, in addition, the system keeps track of applications that were updated by Software Update. When the updated application attempts to access a protected keychain item, the system either recognizes that it is the same application or, if necessary, displays a confirmation dialog saying that the application has been changed and asking the user whether to treat it like the older version (Figure 1-3). If the user clicks the Change All button, the system makes the change only to the current user’s keychains, not to the keychains of other users on the system.

Figure 1-3  Changed software confirmation dialog
Changed software confirmation dialog

ACL Entries

The SecAccessCreate function creates an access object with three ACL entries. The first, referred to as owner access, determines who can modify the access object itself. By default, there are no trusted applications for owner access; the user is always prompted for permission if someone tries to change access controls. The second ACL entry is for operations considered safe, such as encrypting data. This ACL entry applies to all applications. The third ACL entry is for operations that should be restricted, such as decrypting, signing, deriving keys, and exporting keys. This ACL entry applies to the trusted applications listed as input to the function.

In addition to providing a list of trusted applications to SecAccessCreate, you specify a CFString that describes the keychain item. This is the name of the item that appears in dialogs (see Figure 1-2 or Figure 1-3, for example). This is not necessarily the same name as appears for the item in the Keychain Access utility.

You use other functions in Keychain Services to modify any of these default ACL entries or to add additional ACL entries to the access object (see Keychain Services Reference). These functions let you retrieve all the ACL entries for an access object, modify ACL entries, and create new ones. For each ACL entry, you can specify trusted applications, the item descriptor string, a list of authorization tags, and a prompt selector bit. If you set the prompt selector bit, the user is prompted for the keychain password each time a nontrusted application attempts to access the item, even if the keychain is already unlocked. Figure 1-4 shows the dialog; compare this figure with Figure 1-2, which is the dialog that appears if the prompt selector bit is not set. If the user clicks Always Allow in response to this dialog, the application is added to the access object as a trusted application and the dialog does not appear again. This bit is clear by default—you must set it explicitly for any ACL entry for which you want this extra protection. There is one exception to this rule: the Keychain Access application always requires a password to display the secret of a keychain item unless the Keychain Access application itself is included in the trusted application list.

Figure 1-4  Unlock keychain dialog to confirm access
Unlock keychain dialog to confirm access

As noted earlier, because an ACL entry is always associated with an access object, when you modify an ACL entry, you are modifying the access object as well. Therefore, there is no need for a separate function to write a modified ACL entry back into the access object. However, if you modify an access object, you must write the new version of the access object to the keychain item before the keychain item can use it.

Keeping Your OS X Keychain Data Secure

In OS X, to provide security for the passwords and other valuable secrets stored in your keychain, you should adopt at least the following measures:

iPhone Keychain Backups

In iOS, an application always has access to its own keychain items and does not have access to any other application’s items. The system generates its own password for the keychain, and stores the key on the device in such a way that it is not accessible to any application. When a user backs up iPhone data, the keychain data is backed up but the secrets in the keychain remain encrypted in the backup. The keychain password is not included in the backup. Therefore, passwords and other secrets stored in the keychain on the iPhone cannot be used by someone who gains access to an iPhone backup. For this reason, it is important to use the keychain on iPhone to store passwords and other data (such as cookies) that can be used to log into secure web sites.

Keychain Services Ease of Use

Although the structure of the keychain provides a great deal of power and flexibility, it also introduces a level of complexity that most application writers would rather not have to deal with. Fortunately, you don’t. The Keychain Services API provides a handful of high-level functions that handle all of the keychain operations most applications will ever need to perform.

To create a keychain item and add it to a keychain in OS X, for example, you call one of two functions, depending on whether you want to add an Internet password or some other type of password: SecKeychainAddInternetPassword or SecKeychainAddGenericPassword. In your function call, you pass only those attributes for which there is no obvious default value. For example, you must specify the name of the service and the user’s account name, but you do not have to specify the creation date and creator, because the function can figure those out by itself. You also pass the data (usually a password) that you want to store in the keychain. You do not even have to specify a keychain; if you pass NULL for the keychain reference, the function uses the default keychain. If the keychain is locked, the function automatically displays a dialog prompting the user to unlock the keychain. The function also creates the access object for you, listing the calling application as the only trusted application.

The iOS Keychain Services API uses a different paradigm (see the following section, “iOS Keychain Services Search Dictionaries”). This API has a single function (SecItemAdd) for adding an item to a keychain.

Similarly, when your Mac app needs access to a user’s password, you call either SecKeychainFindInternetPassword or SecKeychainFindGenericPassword, passing some attributes (such as the name of the service and the user’s account name) so that the function can find the password that you need. If you pass NULL for the keychain to search, the function searches the keychains in the default keychain search list, which is the same as the keychain list in the Keychain Access utility. The function prompts the user to unlock the keychain if necessary. In iOS, you call the SecItemCopyMatching function to find a keychain item owned by your application. In this case there’s only one keychain and the user is never prompted to unlock it.

“OS X Keychain Services Tasks” contains detailed information on how to add basic Keychain Services features to your application.

iOS Keychain Services Search Dictionaries

In iOS, Keychain Services uses a key-value dictionary to specify the attributes of the keychain item that you want search for or create. For general discussions of key-value pairs and dictionaries, see Collections Programming Topics and Collections Programming Topics for Core Foundation.

A typical search dictionary consists of:

Which attributes can be specified depends on the class of the item for which you wish to search. For example, if you specify a value of kSecClassGenericPassword for the kSecClass key, then you can specify values for creation date and modification date, but not for subject or issuer (which are used with certificates).

For example, if you wanted to perform a case-insensitive search for the password for an Apple Store account with the account name of “ImaUser”, you could use the following dictionary with the SecItemCopyMatching function:

Type of key

Key

Value

Item class

kSecClass

kSecClassGenericPassword

Attribute

kSecAttrAccount

"ImaUser"

Attribute

kSecAttrService

"Apple Store"

Search attribute

kSecMatchCaseInsensitive

kCFBooleanTrue

Return type

kSecReturnData

kCFBooleanTrue

The kSecReturnData key causes the function to return the keychain item’s data—in this case, the password. If instead you want a dictionary of attribute keys and values (so you can determine, for example, the creation date of the item), you use the kSecReturnAttributes return-type key with a value of kCFBooleanTrue.

OS X Keychain Services Advanced Features

OS X Keychain Services allows you to create keychains, manipulate elements within a keychain, and manage collections of keychains. In most cases, a keychain-aware application does not have to do any keychain management and only has to call a few functions to store or retrieve passwords. By default, Keychain Services automatically interacts with the user to create or unlock a keychain when necessary. For example, if you are trying to add a password to a keychain but no keychain exists, Keychain Services prompts the user as shown in Figure 1-5. When the user clicks Reset To Defaults, Keychain Services creates a keychain with the name login.keychain and the same password as the user’s login account.

Figure 1-5  Prompting the user to create a keychain
Prompting the user to create a keychain

If the keychain is locked when you try to save or retrieve a password, Keychain Services prompts the user to unlock the keychain, as shown in Figure 1-6. Once the user enters the correct password, your application can access the keychain. Keychain Services also displays dialogs to confirm that the user wants the application to access the keychain (see Figure 3-2) and for other reasons.

Figure 1-6  The Unlock Keychain dialog box
The Unlock Keychain dialog box

In addition to storing and retrieving passwords, there are a few operations that some applications might need to perform, including:

OS X Keychain Services includes many other functions that can be used to manipulate keychains, keychain items, attributes, access objects, and ACLs. You can even register a callback function so that your application is called when a keychain event (such as unlocking the keychain) occurs. However, these functions are generally needed only by programs designed specifically to administer keychains. OS X includes a keychain administration program, called Keychain Access (Figure 1-7). With this utility, a user can lock or unlock keychains, create new keychains, change the default keychain, add and delete keychain items, change the values of the attributes of keychain items, and see or change the data stored in a keychain item.

Figure 1-7  The Keychain Access application
The Keychain Access applicationThe Keychain Access application

To duplicate the capabilities of this program in OS X, you would need to be familiar with the open source Common Data Security Architecture (CDSA) and its API, the Common Security Services Manager (CSSM), in addition to all of the functions provided by Keychain Services. For more information about the CSSM API, see Common Security: CDSA and CSSM, version 2 (with corrigenda) from The Open Group (http://www.opengroup.org/security/cdsa.htm).