Search
Follow
Recent Comments

Entries in keychain (7)

Saturday
Jun182011

UYLPasswordManager clearing the cache

I recently posted a series of articles on the iOS keychain migration and data protection classes. I introduced the UYLPasswordManager class to experiment with some of the options but there was in hindsight one feature I left out of the class.

Clearing the cache

As I explained in the first post in the series on the keychain data protection classes by default new data added to the keychain is prevented from being accessed when the device is locked. You can change this behaviour if you want to allow the data to always be accessible but Apple recommends you choose the most restrictive class unless you have a reason to do otherwise. Setting this restriction on the keychain item is however pointless if you retrieve the keychain item and store it in an object somewhere in your application code for access when the device is locked.

The correct approach, assuming you do not need the keychain data when the device is locked, is to detect when the device is locked and clean up any keychain data you may be hanging onto. The UIApplication delegate provides a notification indicating when the device is about to be locked. In the example application that I used to demonstrate the UYLPasswordManager class I had the application delegate listen for this notification and then tell the UYLPasswordManager instance to purge the cached keychain data. A similar approach is used to purge the data when the app moves to the background. However, in hindsight, it seems better to move this code into the UYLPasswordManager class itself.

Adding observers for the notifications

To have the UYLPasswordManager object detect when the application moves to the background or when the device is locked we need to listen for two notifications:

  • UIApplicationDidEnterBackgroundNotification
  • UIApplicationProtectedDataWillBecomeUnavailable

To ensure we always receive these notifications I add observers in the init method of the class as follows:

- (id)init {

  self = [super init];
  if (self) {
    _migrate = YES;
     _accessMode = UYLPMAccessibleWhenUnlocked;
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(deviceWillLockOrBackground:)
                                                 name:UIApplicationProtectedDataWillBecomeUnavailable
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(deviceWillLockOrBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];

 

  }
   return self;

}

In both cases the UYLPasswordManager object is the observer (self) and the method that will be called has the selector deviceWillLockOrBackground:. Note that since we have registered the object as an observer we need to ensure to remove it when the object is deallocated:

- (void)dealloc {

  [[NSNotificationCenter defaultCenter] removeObserver:self];
  ...
  [super dealloc];

}

The actual method that gets called when the notification is received is trivial in that it just uses the purge method of the UYLPasswordManager to clear the cached values:

- (void)deviceWillLockOrBackground:(NSNotification *)notification {

  [self purge];

}

The nice thing about moving this code into the class is that I now no longer need to remember to do this for every application I write that uses the UYLPasswordManager class.

Get it on Github

I have updated the code on my Github page here if you want to take a closer a look or download the updated version. I have also updated the example app to remove the now redundant code.

Thursday
Jun022011

iOS and Keychain Migration and Data Protection - Part 3

This is part 3 of a series of posts on the data protection classes used by the iOS Keychain services (iOS 4.0 and later). Part 1 covered the key concepts, part 2 introduced an example app that demonstrated setting the data protection classes. This final part digs into the detailed implementation of the UYLPasswordManager class that acts as a wrapper around the keychain services.

The UYLPasswordManager class

I have tried to keep the interface to the UYLPasswordManager class as simple as possible. Ideally I want the most common use cases to be baked into the class by default with a minimum of properties and methods to store and retrieve passwords to the keychain. The actual interface definition is show below and I will step through each of these methods to show the detailed implementation. For an example of how to use this class refer back to part 2 of this series of posts.

@interface UYLPasswordManager : NSObject;

 

@property (nonatomic,assign) BOOL migrate;

@property (nonatomic,assign) UYLPMAccessMode accessMode;

 

+ (UYLPasswordManager *)sharedInstance;

+ (void)dropShared;

 

- (void)purge;

 

- (void)registerKey:(NSString *)key forIdentifier:(NSString *)identifier inGroup:(NSString *)group;

- (void)deleteKeyForIdentifier:(NSString *)identifier inGroup:(NSString *)group;

- (BOOL)validKey:(NSString *)key forIdentifier:(NSString *)identifier inGroup:(NSString *)group;

 

- (void)registerKey:(NSString *)key forIdentifier:(NSString *)identifier;

- (void)deleteKeyForIdentifier:(NSString *)identifier;

- (BOOL)validKey:(NSString *)key forIdentifier:(NSString *)identifier;

 

@end

The only prerequisites to using the class are that you link with the security framework (“Security.framework”) and include the class header file. It requires a minimum of iOS 4.0.

Creating the shared instance

I use a shared instance of the UYLPasswordManager to allow the results of a keychain operation to be cached. The shared instance is created the first time it is accessed with subsequent accesses returning a reference to the instance. This is not quite the same as a singleton instance as I take no steps to prevent other instances of UYLPasswordManager objects from being created by direct calls to alloc and init. However I find for iOS apps the simpler approach of a shared instance is sufficient. The code to create and drop the shared instance are shown below:

static UYLPasswordManager *_sharedInstance = nil;

 

+ (UYLPasswordManager *)sharedInstance {

    if (_sharedInstance == nil) {

        _sharedInstance = [[self alloc] init];
    }

    return _sharedInstance;

}

 

+ (void)dropShared {

    if (_sharedInstance) {
        [_sharedInstance release];
        _sharedInstance = nil;
    }

}

Hopefully this is fairly self explanatory, the sharedInstance method checks to see if we already have an object allocated in which case it is returned otherwise we allocate and init a new object. The dropShared method provides a way to release the shared instance though in practise this should not be necessary since the idea of the shared instance is that once created it lives for the life of the application.

Properties

Before looking at the class initialiser we will do a quick tour of the public and private properties of the class along with their accessor methods. There are two public properties that the user of the class can use to control whether a keychain item is migratable and which data protection class it will use (always available, available after first unlock or only available when the device is unlocked). Refer back to the first post in this series for a full discussion of these options. There is nothing special about these two properties which are declared in the public interface we saw earlier. The getter/setter methods are synthesized in the class implementation. The only piece I did not show is the definition of the enumerated type UYPMAccessMode which is used for the accessMode property. This is defined in the interface file as follows:

typedef enum _UYLPMAccessMode {

UYLPMAccessibleWhenUnlocked = 0,

UYLPMAccessibleAfterFirstUnlock = 1,

UYLPMAccessibleAlways = 2

} UYLPMAccessMode;

The class has three other properties which are defined as part of the private interface inside the class implementation file as follows:

@property (nonatomic,retain) NSString *keychainValue;

@property (nonatomic,copy) NSString *keychainAccessGroup;

@property (nonatomic,copy) NSString *keychainIdentifier;

 

The keychain value property is used to store the value of the item that is retrieved from a search of the keychain. The other two properties are used to copy the keychain access group and identifier that are parsed as arguments by the caller in many of the class instance methods as we will see shortly.The getter/setter methods of all of these methods are synthesized by the compiler with the exception of the setter for the last two where we specify our own implementation. Here is the setter for the keychainIdentifier property (the keychainAccessGroup setter is very similar so I will omit it):

- (void)setKeychainIdentifier:(NSString *)newValue {

    if (!_keychainIdentifier && !newValue)  {
        return;
    }

    [_keychainIdentifier release];
    _keychainIdentifier = nil;
    self.keychainValue = nil;

 

    if (newValue) {
        _keychainIdentifier = [newValue copy];
    }

}

This is pretty much the same as a standard setter with the exception that when a new identifier is set we clear (and release) the previously cached keychainValue instance variable to force a new search of the keychain.

The Initialiser

The initialiser for a new instance of the class is not very exciting, after taking care of the standard stuff of calling the initialiser of its superclass it sets some defaults for the keychain attributes as follows:

- (id)init {

    self = [super init];
    if (self) {
        _migrate = YES;
         _accessMode = UYLPMAccessibleWhenUnlocked;
    }
     return self;

}

So by default all items added or updated to the keychain will be set to be migratable and will use the most protected data class which ensures they can only be accessed when the device is unlocked. Most of the time these defaults should be correct so it keeps things nice and simple for the user of the class.

The Public Methods

The public instance methods are fairly simple as the hard work of interacting with the keychain services is performed by a number of private helper methods. The methods to register, search for and delete a key are all available in two forms the only difference being that one set of methods omits the access group argument. I have previously discussed keychain group access to share keys between applications but since my guess is that most of the time it will not be used I opted to create a set of convenience methods without a group argument. Since these methods just call the fuller method with the group argument set to nil I will not show them here.

To get started we will take a look at the implementation of the method to register a new key with the keychain service. To store an item in the keychain you need to supply an identifier, most commonly a username or some other means of identifying the key, and the actual key which is the password or thing that you want to keep secret. The implementation is as follows:

- (void)registerKey:(NSString *)key forIdentifier:(NSString *)identifier inGroup:(NSString *)group {

 

    self.keychainAccessGroup = group;
    self.keychainIdentifier = identifier;
    [self searchKeychain];

 

    if (self.keychainValue == nil) {

        [self createKeychainValue:key];

    } else {

        [self updateKeychainValue:key];
    }

    [self searchKeychain];

}

This method starts by copying the access group and identifier into our instance variables for future reference. It then calls a helper method which we will see shortly to search the keychain to determine if we already have an entry for the specified identifier. Depending on the results of the search we then either call a method to create a new entry to store the key or update the existing entry. Finally we perform a keychain search to ensure our cached keychain value is valid.

The method to search the keychain accepts the usual arguments of an identifier and key and optionally an access group and returns a boolean to indicate if the search was a success or not.

- (BOOL)validKey:(NSString *)key forIdentifier:(NSString *)identifier inGroup:(NSString *)group {

 

    BOOL result = NO;

 

    if (identifier) {
         self.keychainAccessGroup = group;
        self.keychainIdentifier = identifier;
        [self searchKeychain];

 

        if (self.keychainValue != nil) {

 

            if (key != nil) {

 

                if ([self.keychainValue isEqual:key]) { 
                    result = YES;
                }

 

            } else {

 

                result = YES;
            }
        }
    }
    return result;

}

As before the access group and identifier arguments are copied into our instance variables and then the method to search the keychain is called which will result in the keychainValue being set if the identifier was found. If we do not get a keychainValue back we return NO to the caller.

In some cases I am using the keychain to register that the user has completed an action, for example that they have registered a product. In that situation I do not really have a password key to store but it is useful to register an identifier in the keychain with some arbitrary key (the application name for example). Since in those situations I really only want to check to see if the identifier exists in the keychain I allow the key argument to validKey:forIdentifier:inGroup to be nil and do not bother to check that the key value actually matches.

The method to delete a key is shown below and simply calls the deleteKeychainValue private method after storing the arguments as usual:

- (void)deleteKeyForIdentifier:(NSString *)identifier inGroup:(NSString *)group {

 

     self.keychainAccessGroup = group;
    self.keychainIdentifier = identifier;
    [self deleteKeychainValue];

}

The final public method is the purge method which is used to empty the cached keychainValue instance variable in situations where the device is about to be locked or the application is moving to the background. Refer to post 2 in this series for a more detailed discussion for how and why you may want to do this.

- (void)purge {

     self.keychainAccessGroup = nil;
     self.keychainIdentifier = nil;
     self.keychainValue = nil;

}

Private Methods

The heavy lifting of  interacting with the keychain services is performed by a number of private methods. These methods are similar to ones I have discussed in earlier posts on the keychain so I will keep some of the explanations brief. If you are wondering about the various keychain classes and attributes refer back to that post for the full details. All of the interactions with the keychain API take a dictionary of attributes that indicates the class of item you want to store. We will be storing a generic password in the keychain so we need to initialise a dictionary as follows:

- (NSMutableDictionary *)newSearchDictionary {

NSMutableDictionary *searchDictionary = nil;

if (self.keychainIdentifier) {

   NSData *encodedIdentifier = [self.keychainIdentifier dataUsingEncoding:NSUTF8StringEncoding];

   searchDictionary = [[NSMutableDictionary alloc] init];
   [searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
   [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrGeneric];
   [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount];
   [searchDictionary setObject:kKeychainService forKey:(id)kSecAttrService];

   if (self.keychainAccessGroup) {
     [searchDictionary setObject:self.keychainAccessGroup forKey:(id)kSecAttrAccessGroup];
   }

}

return searchDictionary;

}

The keychainIdentifier instance variable is encoded and used as the keychain account name. Note the use of a keychain service (kSecAttrService) and account name (kSecAttrAccount) attribute are required to uniquely identify a generic password item in the keychain (see this post on duplicate items for the details).

The methods to create, update and delete a keychain entry are then just variations of the same basic theme. First here is the method to search the keychain for the identifier stored in the private instance variable keychainIdentifier:

- (void)searchKeychain {

 

  if (self.keychainValue == nil) {
    NSMutableDictionary *searchDictionary = [self newSearchDictionary];

 

    [searchDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    [searchDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];

 

    NSData *result = nil;
    OSStatus status = SecItemCopyMatching((CFDictionaryRef)searchDictionary, (CFTypeRef *)&result);
    [searchDictionary release];

 

    if (result) {
       self.keychainValue = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
      [result release];
    }
  }

}

The search method uses the Keychain function SecItemCopyMatching to perform the search with the attributes kSecMatchLimit and kSecReturnData to indicate we only want the first entry returned. If we find a value it is decoded and stored in the keychainValue instance variable.

The method to create keychain item uses the SecItemAdd function. The update method is very similar so I will omit it here for brevity but it makes use of the SecItemUpdate fucntion.

- (BOOL)createKeychainValue:(NSString *)password {

  NSMutableDictionary *dictionary = [self newSearchDictionary];

 

  NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
  [dictionary setObject:passwordData forKey:(id)kSecValueData];
  [dictionary setObject:(id)[self attributeAccess] forKey:(id)kSecAttrAccessible];

  OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);
  [dictionary release];

  if (status == errSecSuccess) {
    return YES;
  }

  return NO;

}

The interesting thing to note here is the kSecAttrAccessible attribute which is used to set the data protection class of the keychain item. The Keychain Service data protection class is determined from a combination of the two public properties (migrate and accessMode) of the UYLPasswordManager class. The data protection class is calculated by the method attributeAccess as follows:

- (CFTypeRef)attributeAccess {

 

  switch (self.accessMode) {
  case UYLPMAccessibleWhenUnlocked:
     return self.migrate ? kSecAttrAccessibleWhenUnlocked : 
kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
    break;
  case UYLPMAccessibleAfterFirstUnlock:
     return self.migrate ? kSecAttrAccessibleAfterFirstUnlock : 
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
    break;
  case UYLPMAccessibleAlways:
     return self.migrate ? kSecAttrAccessibleAlways : 
kSecAttrAccessibleAlwaysThisDeviceOnly;
    break;
  default:
     return self.migrate ? kSecAttrAccessibleWhenUnlocked : 
kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
    break;
  }

}

So using the default settings of an item that is migratable and which can be accessed only when the device is unlocked we end up with a data protection class of kSecAttrAccessibleWhenUnlocked.

Finally the method to delete a keychain item which uses SecItemDelete:

- (void)deleteKeychainValue {

  NSMutableDictionary *searchDictionary = [self newSearchDictionary];

  if (searchDictionary) {
    OSStatus status = SecItemDelete((CFDictionaryRef)searchDictionary);
    [searchDictionary release];
  }
  self.keychainValue = nil;

}

Wrapping Up

This has been a long series of posts, so congratulations if you made it this far! I find the keychain service to be one of the hardest parts of iOS to understand which is a shame given that it serves such an important role. My intention was to take all of the tricky keychain code and wrap it with an easy to understand and hopefully easy to use class. If you want to see the code and try it yourself you can download it from here.

Wednesday
Jun012011

iOS and Keychain Migration and Data Protection - Part 2

This is part 2 of a post covering how you can control the data protection properties of iOS keychain items. Refer back to part 1 for a more general discussion of the features.

Keychain Item Accessibility

In this post I want to be able to experiment with the various keychain migration and data protection options. To make this easier I am using a simple wrapper class (UYLPasswordManager) to hide some of the complexity of the keychain services. I will dig into the implementation of that class in a later post - it is largely a reworking of some previous code that I used in a much earlier post on simple keychain access. So to get started I should introduce the basic methods for storing and searching for items in the keychain:

Accessing the shared instance

A shared instance of the UYLPasswordManager class is used to allow some caching of the previous keychain access. This makes repeat searches fast. To access the shared instance use the class method sharedInstance:

UYLPasswordManager *manager = [UYLPasswordManager sharedInstance];

Registering a Username and Password in the Keychain

To store a username (identifier) and password (key) in the keychain use the instance method: registerKey:forIdentifier:

[registerKey:@"password" forIdentifier:@"username"];

Searching the Keychain

To search the keychain for an existing username and password use the instance method validKey:forIdentifier:

BOOL result = [manager validKey:@"password" forIdentifier:@"username"];

 

 

The result is YES if a matching username and password is found, otherwise NO is returned.

The Example App

With just those three simple methods we can create a simple example app to store and retrieve an item from the keychain. Once we have that working we can examine the effects of changing some of the data protection options. The simplest example app that I could come up with prompts the user for a username and password and then reports whether it is found in the keychain. The user interface is shown below:

The view controller interface is very simple consisting of some text fields and labels. The view controller also implements the UITextFieldDelegate protocol. I will not show it here but the delegate of the password text field is set in Interface Builder so that we get informed when the user hits return in the password field. The interface definition is as follows:

@interface PasswordManagerViewController : UIViewController <UITextFieldDelegate> {
}
@property (nonatomic, retain) IBOutlet UILabel *pmLabel;
@property (nonatomic, retain) IBOutlet UITextField *username;
@end

 

In the view controller implementation we use the viewDidLoad method to store a hard-coded username and password in the keychain using the registerkey:forIdentifier: method:

- (void)viewDidLoad {
    [[UYLPasswordManager sharedInstance] registerKey:@"secret" forIdentifier:@"manager"];
}

The text field delegate method (textFieldShouldReturn:) is called when the user hits return so we perform a search of the keychain at that point and display the result:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    self.pmLabel.hidden = NO;
    [textField resignFirstResponder];
 
    NSString *identifier = self.username.text;
    NSString *key = textField.text;
    if (identifier) {
        UYLPasswordManager *manager = [UYLPasswordManager sharedInstance];
        if ([manager validKey:key forIdentifier:identifier]) {
            self.pmLabel.text = @"Success";
        } else {
            self.pmLabel.text = @"Failed!";
        }
    }
    return YES;
}

Migration and Data Protection Options

So with the basics up and running we can start to experiment with the data protection options. Again to keep things easy the UYLPasswordManager has two properties to make it easy to specify migration and data accessibility of any items added to the keychain:

@property (nonatomic,assign) BOOL migrate;

@property (nonatomic,assign) UYLPMAccessMode accessMode;

 

The migrate property is a boolean which controls whether items added or updated to the keychain are migratable. As I explained in the previous post the keychain provides the option to specify whether an item can be migrated to a new device. If a user restores an encrypted backup to a new device the keychain items which are set to migratable will be restored to that device. This allows a user to migrate to a new device without having to manually enter password data. By default items are migratable.

The accessMode property is a little more complicated as it is an enumerated type taking thee possible values as follows:

  • UYLPMAccessibleWhenUnlocked - data can only be access when the device is unlocked.
  • UYLPMAccessibleAfterFirstUnlock - data can be accessed when the device is locked provided it has been unlocked at least once since the device was started.
  • UYLPMAccessibleAlways - data is accessible always even when the device is locked.

The default is the most secure option, UYLPMAccessibleWhenUnlocked, which means that a keychain item cannot be retrieved when the device is locked. Note that these attributes apply to each item that is added to the keychain. When we dig into the implementation we will see that these two properties actually combine into a single attribute that is set on a keychain item (which can therefore have 6 possible values).

It is difficult to demonstrate the impact of setting the migrate option to NO since it requires a device restore. Also most of the time you probably want to leave keychain items set to be migratable. The only time you might want to change this is if you have keychain data that is only relevant to a specific device.

It is easier to play with the data protection option since the keychain services provide an application delegate method, applicationProtectedDataWillBecomeAvailable: and a notification, UIApplicationProtectedDataWillBecomeUnavailable, to allow us to detect when the device is about to be locked. Apple recommends that you use these to cleanup any user sensitive data when the device is being locked.

Since the UYLPasswordManager shared instance caches the previous keychain search it needs to have its data purged when the device is locked. A purge method makes that easy:

[[UYLPasswordManager sharedInstance] purge];


The application delegate method is useful if you can perform all of the data cleanup in the application delegate which is true in this simple application. In real life you may find it more useful to have individual view controllers listen for the notification so that they can perform their own cleanup.

Detecting when the device will lock

To illustrate the technique we can add an observer for the notification as follows:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(deviceWillLock)
                                             name:UIApplicationProtectedDataWillBecomeUnavailable 
                                            object:nil];

 

The deviceWillLock is called when the user has decided to the lock the device at which point you have about 10 seconds before the keychain protected data becomes unavailable. To test this out I created a method as follows to purge the UYLPasswordManager cache and then check the keychain after 10 seconds:

- (void)deviceWillLock {
    NSLog(@"device is about to be locked");
    [[UYLPasswordManager sharedInstance] purge];
    [self performSelector:@selector(checkKey) withObject:nil afterDelay:10];
}

The checkKey method attempts to search the keychain and outputs the result:

- (void)checkKey {
    NSLog(@"checkKey");
    UYLPasswordManager *manager = [UYLPasswordManager sharedInstance]; 
    if ([manager validKey:@"secret" forIdentifier:@"manager"]) {
        NSLog(@"Password valid");
    }
}

If we try this with the app running on a real device (this will not work with the simulator) we get the following:

2011-06-01 21:59:01.515 PasswordManager[20599:707] device is about to be locked

2011-06-01 21:59:11.527 PasswordManager[20599:707] checkKey

2011-06-01 21:59:11.542 PasswordManager[20599:707] searchKeychain for identifier: manager - Interaction with the Security Server is not allowed


The final message is logged by the UYLPasswordManager class and is the error returned by the keychain services when we tried to access our item with the device locked. To make the item accessible when locked we can set the accessMode before register the key as follows:

UYLPasswordManager *manager = [UYLPasswordManager sharedInstance];
manager.
accessMode = UYLPMAccessibleAlways;
[manager
registerKey:@”secret” forIdentifier:@”manager”];

Now when we run the same test we are able to access the data with the device locked:

2011-06-01 22:04:43.897 PasswordManager[20631:707] device is about to be locked

2011-06-01 22:04:53.923 PasswordManager[20631:707] checkKey

2011-06-01 22:04:53.980 PasswordManager[20631:707] Password valid

Handling the background

There is a small issue with relying on the application delegate or notification to allow us to perform some cleanup when the device is locked. If our app is suspended in the background when the user locks the device we do not get a chance to react. So unless you need to access keychain data when you are running in the background it is a good idea to clean up as the app moves to the background. That is easy enough to do if we implement the correct application delegate:

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [[UYLPasswordManager sharedInstance] purge];
}

Wrapping Up

To sum up if you are storing sensitive user data in the keychain you should think about setting the appropriate data protection class for that data. I have found that wrapping the keychain code into a separate class keeps my application code simple. I will cover the details of the UYLPasswordManager class in a future post but if you want a sneak peak you can find the full code for the example app here.

Friday
May272011

iOS Keychain Migration and Data Protection - Part 1

I have posted in the past on how to access the keychain to securely store and retrieve data from within an iOS app. However the recent press attention on iOS location data being stored in iTunes backups has got me to take a closer look at how data is secured when it is moved off the device.

Encrypted Backups

When you connect an iOS device (iPhone, iPod touch, iPad) to a computer to sync with an iTunes library a backup of the data on the device is also made. The backup includes application settings and data but excludes things like the tmp and Caches folder (see this Apple support article for the full list of what is included). The backup also includes the keychain so that account passwords, WiFi passwords or any other data you choose to save in the keychain is stored. iTunes allows you to specify that the backup should be encrypted in which case a password is required to restore the backup to a device.

Keychain Migration

You may decide that it is not worth the effort of encrypting the backup data especially since it is questionable how secure the backup really is. However even if you are not worried about the security of the backup there is a really good reason why you might want to encrypt the backup.

An unencrypted backup can only be restored the original device that it was taken from. This means that if you buy a new device you will have to enter keychain data such as account settings and passwords manually. An encrypted backup can be restored to a different device avoiding a whole load of pain. The only requirement is that you remember the password as you will be asked for it when you attempt the restore.

This ability to migrate keychain data between devices was introduced in iOS 4 but I think has been overlooked somewhat both by users and application developers. In fact the keychain services allow the application developer a fine degree of control on how data is handled when it is backed up.

Data Protection

As well as providing a means to migrate keychain data iOS 4 also introduced a more sophisticated level of data protection for data stored on the device itself. The iPhone 3GS introduced hardware based encryption of data on the device but it seems that is what not too difficult to circumvent. Things have hopefully been improved with iOS 4:

  • The user entered passcode is now used to protect the hardware encryption keys providing an additional layer of protection.
  • The application developer can specify when encrypted data should be available (e.g. only when the device is unlocked).
  • Keychain data can be set as migratable or non-migratable preventing it from being restored to a new device if required.
  • Separate encryption keys are used to encrypt the keychain data and the device filesystem

To enable data protection you need to set a passcode for the device (Settings > General > Passcode) once you do that you should see a confirmation that data protection is enabled at the bottom of the Passcode Lock settings screen:

As it would happen there have been some reports this week that the iOS 4 hardware encryption has been cracked though this looks like it involves a brute force attack on the user passcode. By default the passcode is a simple 4 digit pin code giving only 10,000 combinations which it is claimed can be broken in under 40 minutes on an iPhone 4. To defeat this attack you can set a stronger passcode by turing off the Simple Passcode option in the settings screen. You can then enter a longer and stronger alphanumeric passcode. You can also set the device to erase all data after 10 failed passcode attempts to be extra sure.

Data Protection Classes

The keychain services provide API access to add, update, search and delete items from the keychain. Refer back to my post on simple keychain access for the full details and example code. What I want to cover here are the additional data protection classes that can be used to control the availability of the data stored in the keychain. Basically you can choose between three classes of availability for keychain data:

  • Unlocked: data can only be accessed when the device is unlocked (which of course may require the user to enter the passcode).
  • After first unlock: data can be accessed when the device is locked provided it has been unlocked at least once since the device was started.
  • Always: the data is accessible always even when the device is locked

For backward compatibility the default is “always” though Apple recommends that you use the most protective class possible. This is generally “unlocked” unless you have an application that needs to access keychain data when running in the background (the user might lock the device whilst your app is running cutting off its access to the keychain). In the situation where you might need to access the keychain of a locked device you should use the “after first unlock” class.

If you are hanging onto data that you have retrieved from the keychain then you also need to ensure you purge this data when the user locks the device. Apple provides application delegate methods and notifications to make it easy for you to do this. Your application has about 10 seconds to clean up before the keychain service is locked. Attempting to access it after that point will generate an error until the device is unlocked again.

As well as being able to set the availability of the keychain data you can also control how it is handled when the keychain is migrated to a new device. Remember if the user has an encrypted backup they can restore the keychain contents to a different device. By default all data added to the keychain is set as migratable. If you want the data to only be available on the current device you must set it to be non-migratable.

Apple actually defines six data protection classes consisting of migratable and non-migratable versions of the three data availability classes. If you do nothing the keychain defaults to the most open option so data will be available always and migratable.

Where is the Code?

This is becoming a long post so I will follow up with some example code in a separate post. In the meantime if you want to dig into some more detail on how data encryption works on iOS I recommend taking a look at Session 209 - Securing Application Data from WWDC 2010.

Wednesday
Apr282010

Keychain duplicate item when adding password

I thought I was done with Keychain access on the iPhone but I hit a problem which made me realise there was still a gap in my knowledge (and in the keychain documentation). The problem I was seeing came when trying to add a second password entry of class kSecClassGenericPassword. A search for the entry was not finding anything but when I tried to add the new entry using SecItemAdd I was getting the error errSecDuplicateItem (-25299) indicating that the item already exists.

When adding an entry to the keychain I was only including the kSecAttrGeneric attribute as an identifier and relying on the value of this identifier when retrieving the entry from the keychain. The problems is that for a keychain entry of class kSecClassGenericPassword the attributes that are used to determine a unique entry are kSecAttrAccount and kSecAttrService. Since I was not including these entries my second password was not considered to be unique. The fact that it had a different value for kSecAttrGeneric did not matter as that is not used to determine uniqueness. Of course you can search on all attributes which explains why the search was coming up empty.

In database terms you could think of their being a unique index on the two attributes kSecAttrAccount, kSecAttrService requiring the combination of those two attributes to be unique for each entry in the keychain.

Unfortunately the problem with the keychain services is that these finer points are very poorly documented. There is a passing reference to the required attributes in the Keychain Services Programming Guide, in the section Keychain Services Ease of Use (my emphasis):

To create a keychain item and add it to a keychain in Mac 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 have to be paying pretty close attention to spot that. The best reference I could find was on an Apple CDSA mailing list which put me on the right track but as far as I know the key attributes for each keychain class are not included in any Apple documentation that I have been able to find. I will go back and fix the example code in the previous post but the important piece is when building the dictionary used when searching or adding to the keychain:

 

static NSString *serviceName = @"com.mycompany.myAppServiceName";

- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];  
	
    [searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
	
    NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
    [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrGeneric];
    [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount];
    [searchDictionary setObject:serviceName forKey:(id)kSecAttrService];
	
    return searchDictionary; 
}

 

In this example I have just used a fixed service name and set the account name to the identifier which I expect to be unique for each password stored.