Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
      6 #define CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
      7 #pragma once
      8 
      9 #include <set>
     10 #include <string>
     11 #include <vector>
     12 
     13 #include "chrome/browser/keychain_mac.h"
     14 
     15 // Mock Keychain wrapper for testing code that interacts with the OS Keychain.
     16 // The basic idea of this mock is that it has a static array of data, and
     17 // SecKeychainItemRef values are just indexes into that array (offset by 1 to
     18 // prevent problems with clients that null-check refs), cast to pointers.
     19 //
     20 // Note that "const" is pretty much meaningless for this class; the const-ness
     21 // of MacKeychain doesn't apply to the actual keychain data, so all of the Mock
     22 // data is mutable; don't assume that it won't change over the life of tests.
     23 class MockKeychain : public MacKeychain {
     24  public:
     25   // Create a Mock Keychain capable of holding item_capacity keychain items.
     26   explicit MockKeychain(unsigned int item_capacity);
     27   virtual ~MockKeychain();
     28   virtual OSStatus ItemCopyAttributesAndData(
     29       SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
     30       SecItemClass *itemClass, SecKeychainAttributeList **attrList,
     31       UInt32 *length, void **outData) const;
     32   // Pass "fail_me" as the data to get errSecAuthFailed.
     33   virtual OSStatus ItemModifyAttributesAndData(
     34       SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList,
     35       UInt32 length, const void *data) const;
     36   virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList *attrList,
     37                                              void *data) const;
     38   virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const;
     39   virtual OSStatus SearchCreateFromAttributes(
     40       CFTypeRef keychainOrArray, SecItemClass itemClass,
     41       const SecKeychainAttributeList *attrList,
     42       SecKeychainSearchRef *searchRef) const;
     43   virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
     44                                   SecKeychainItemRef *itemRef) const;
     45   // If there are unused slots in the Mock Keychain's capacity, the new item
     46   // will use the first free one, otherwise it will stomp the last item.
     47   // Pass "some.domain.com" as the serverName to get errSecDuplicateItem.
     48   virtual OSStatus AddInternetPassword(SecKeychainRef keychain,
     49                                        UInt32 serverNameLength,
     50                                        const char *serverName,
     51                                        UInt32 securityDomainLength,
     52                                        const char *securityDomain,
     53                                        UInt32 accountNameLength,
     54                                        const char *accountName,
     55                                        UInt32 pathLength, const char *path,
     56                                        UInt16 port, SecProtocolType protocol,
     57                                        SecAuthenticationType authenticationType,
     58                                        UInt32 passwordLength,
     59                                        const void *passwordData,
     60                                        SecKeychainItemRef *itemRef) const;
     61   virtual OSStatus FindGenericPassword(CFTypeRef keychainOrArray,
     62                                        UInt32 serviceNameLength,
     63                                        const char *serviceName,
     64                                        UInt32 accountNameLength,
     65                                        const char *accountName,
     66                                        UInt32 *passwordLength,
     67                                        void **passwordData,
     68                                        SecKeychainItemRef *itemRef) const;
     69   virtual OSStatus ItemFreeContent(SecKeychainAttributeList *attrList,
     70                                    void *data) const;
     71   virtual OSStatus AddGenericPassword(SecKeychainRef keychain,
     72                                       UInt32 serviceNameLength,
     73                                       const char *serviceName,
     74                                       UInt32 accountNameLength,
     75                                       const char *accountName,
     76                                       UInt32 passwordLength,
     77                                       const void *passwordData,
     78                                       SecKeychainItemRef *itemRef) const;
     79   virtual void Free(CFTypeRef ref) const;
     80 
     81   // Return the counts of objects returned by Create/Copy functions but never
     82   // Free'd as they should have been.
     83   int UnfreedSearchCount() const;
     84   int UnfreedKeychainItemCount() const;
     85   int UnfreedAttributeDataCount() const;
     86 
     87   // Returns true if all items added with AddInternetPassword have a creator
     88   // code set.
     89   bool CreatorCodesSetForAddedItems() const;
     90 
     91   struct KeychainTestData {
     92     const SecAuthenticationType auth_type;
     93     const char* server;
     94     const SecProtocolType protocol;
     95     const char* path;
     96     const UInt32 port;
     97     const char* security_domain;
     98     const char* creation_date;
     99     const char* username;
    100     const char* password;
    101     const bool negative_item;
    102   };
    103   // Adds a keychain item with the given info to the test set.
    104   void AddTestItem(const KeychainTestData& item_data);
    105 
    106   // |FindGenericPassword()| can return different results depending on user
    107   // interaction with the system Keychain.  For mocking purposes we allow the
    108   // user of this class to specify the result code of the
    109   // |FindGenericPassword()| call so we can simulate the result of different
    110   // user interactions.
    111   void set_find_generic_result(OSStatus result) {
    112     find_generic_result_ = result;
    113   }
    114 
    115   // Returns the true if |AddGenericPassword()| was called.
    116   bool called_add_generic() const { return called_add_generic_; }
    117 
    118   // Returns the value of the password set when |AddGenericPassword()| was
    119   // called.
    120   std::string add_generic_password() const { return add_generic_password_; }
    121 
    122   // Returns the number of allocations - deallocations for password data.
    123   int password_data_count() const { return password_data_count_; }
    124 
    125  private:
    126   // Sets the data and length of |tag| in the item-th test item.
    127   void SetTestDataBytes(int item, UInt32 tag, const void* data, size_t length);
    128   // Sets the data and length of |tag| in the item-th test item based on
    129   // |value|. The null-terminator will not be included; the Keychain Services
    130   // docs don't indicate whether it is or not, so clients should not assume
    131   // that it will be.
    132   void SetTestDataString(int item, UInt32 tag, const char* value);
    133   // Sets the data of the corresponding attribute of the item-th test item to
    134   // |value|. Assumes that the space has alread been allocated, and the length
    135   // set.
    136   void SetTestDataPort(int item, UInt32 value);
    137   void SetTestDataProtocol(int item, SecProtocolType value);
    138   void SetTestDataAuthType(int item, SecAuthenticationType value);
    139   void SetTestDataNegativeItem(int item, Boolean value);
    140   void SetTestDataCreator(int item, OSType value);
    141   // Sets the password data and length for the item-th test item.
    142   void SetTestDataPasswordBytes(int item, const void* data, size_t length);
    143   // Sets the password for the item-th test item. As with SetTestDataString,
    144   // the data will not be null-terminated.
    145   void SetTestDataPasswordString(int item, const char* value);
    146 
    147   // Returns the address of the attribute in attribute_list with tag |tag|.
    148   static SecKeychainAttribute* AttributeWithTag(
    149       const SecKeychainAttributeList& attribute_list, UInt32 tag);
    150 
    151   static const int kDummySearchRef = 1000;
    152 
    153   typedef struct  {
    154     void* data;
    155     UInt32 length;
    156   } KeychainPasswordData;
    157 
    158   SecKeychainAttributeList* keychain_attr_list_;
    159   KeychainPasswordData* keychain_data_;
    160   unsigned int item_capacity_;
    161   mutable unsigned int item_count_;
    162 
    163   // Tracks the items that should be returned in subsequent calls to
    164   // SearchCopyNext, based on the last call to SearchCreateFromAttributes.
    165   // We can't handle multiple active searches, since we don't track the search
    166   // ref we return, but we don't need to for our mocking.
    167   mutable std::vector<unsigned int> remaining_search_results_;
    168 
    169   // Track copies and releases to make sure they balance. Really these should
    170   // be maps to track per item, but this should be good enough to catch
    171   // real mistakes.
    172   mutable int search_copy_count_;
    173   mutable int keychain_item_copy_count_;
    174   mutable int attribute_data_copy_count_;
    175 
    176   // Tracks which items (by index) were added with AddInternetPassword.
    177   mutable std::set<unsigned int> added_via_api_;
    178 
    179   // Result code for the |FindGenericPassword()| method.
    180   OSStatus find_generic_result_;
    181 
    182   // Records whether |AddGenericPassword()| gets called.
    183   mutable bool called_add_generic_;
    184 
    185   // Tracks the allocations and frees of password data in |FindGenericPassword|
    186   // and |ItemFreeContent|.
    187   mutable unsigned int password_data_count_;
    188 
    189   // Records the password being set when |AddGenericPassword()| gets called.
    190   mutable std::string add_generic_password_;
    191 };
    192 
    193 #endif  // CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
    194