1 2// 3// si-72-syncableitems.c 4// regressions 5// 6// Created by Ken McLeod on 5/18/13. 7// 8// 9#include <CoreFoundation/CoreFoundation.h> 10#include <Security/Security.h> 11#include <Security/SecItemPriv.h> 12#include <Security/SecInternal.h> 13#include <utilities/array_size.h> 14 15#include "Security_regressions.h" 16 17static void tests(void) 18{ 19 CFUUIDRef uuid = CFUUIDCreate(0); 20 const CFStringRef uuidstr = CFUUIDCreateString(0, uuid); 21 const CFStringRef account = CFStringCreateWithFormat(NULL, NULL, CFSTR("Test Account %@"), uuidstr); 22 const CFStringRef service = CFSTR("Test Service"); 23 const CFStringRef label = CFSTR("Test Synchronizable Item"); 24 const CFStringRef comment = CFSTR("Test Comment"); 25 const CFDataRef passwordData = CFDataCreate(NULL, (const UInt8*)"Test", (CFIndex)5); 26 27 CFReleaseSafe(uuid); 28 CFReleaseSafe(uuidstr); 29 30 CFDictionaryRef query = NULL; 31 CFDictionaryRef attrs = NULL; 32 CFDictionaryRef result = NULL; 33 34 /* Test adding a synchronizable item */ 35 { 36 const void *keys[] = { 37 kSecClass, kSecAttrLabel, kSecAttrComment, kSecAttrAccount, kSecAttrService, 38 kSecAttrSynchronizable, 39 kSecValueData, kSecReturnAttributes }; 40 const void *values[] = { 41 kSecClassGenericPassword, label, comment, account, service, 42 kCFBooleanTrue, 43 passwordData, kCFBooleanTrue }; 44 45 attrs = CFDictionaryCreate(NULL, keys, values, 46 array_size(keys), 47 &kCFTypeDictionaryKeyCallBacks, 48 &kCFTypeDictionaryValueCallBacks); 49 50 is_status(SecItemAdd(attrs, (CFTypeRef *)&result), 51 errSecSuccess, "SecItemAdd sync=true"); 52 53 CFReleaseSafe(attrs); 54 CFReleaseNull(result); 55 } 56 57 /* Test finding the synchronizable item we just added, using sync=true */ 58 { 59 const void *keys[] = { 60 kSecClass, // class attribute is required 61 kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness 62 kSecAttrSynchronizable, // we want to get synchronizable results 63 kSecReturnAttributes }; 64 const void *values[] = { 65 kSecClassGenericPassword, 66 account, service, 67 kCFBooleanTrue, // only return synchronizable results 68 kCFBooleanTrue }; 69 70 query = CFDictionaryCreate(NULL, keys, values, 71 array_size(keys), 72 &kCFTypeDictionaryKeyCallBacks, 73 &kCFTypeDictionaryValueCallBacks); 74 75 is_status(SecItemCopyMatching(query, (CFTypeRef *)&result), 76 errSecSuccess, "SecItemCopyMatching sync=true"); 77 78 CFReleaseSafe(query); 79 CFReleaseNull(result); 80 } 81 82 /* Test finding the synchronizable item we just added, using sync=any */ 83 { 84 const void *keys[] = { 85 kSecClass, // class attribute is required 86 kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness 87 kSecAttrSynchronizable, // we want to get synchronizable results 88 kSecReturnAttributes }; 89 const void *values[] = { 90 kSecClassGenericPassword, 91 account, service, 92 kSecAttrSynchronizableAny, // return any match, regardless of whether it is synchronizable 93 kCFBooleanTrue }; 94 95 query = CFDictionaryCreate(NULL, keys, values, 96 array_size(keys), 97 &kCFTypeDictionaryKeyCallBacks, 98 &kCFTypeDictionaryValueCallBacks); 99 100 is_status(SecItemCopyMatching(query, (CFTypeRef *)&result), 101 errSecSuccess, "SecItemCopyMatching sync=any"); 102 103 CFReleaseSafe(query); 104 CFReleaseNull(result); 105 } 106 107 /* Test updating the synchronizable item */ 108 { 109 const void *keys[] = { 110 kSecClass, // class attribute is required 111 kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness 112 kSecAttrSynchronizable }; // we want synchronizable results 113 const void *values[] = { 114 kSecClassGenericPassword, 115 account, service, 116 kCFBooleanTrue }; // we only want to find the synchronizable item here, not a non-synchronizable one 117 118 query = CFDictionaryCreate(NULL, keys, values, 119 array_size(keys), 120 &kCFTypeDictionaryKeyCallBacks, 121 &kCFTypeDictionaryValueCallBacks); 122 123 const void *update_keys[] = { kSecAttrComment }; 124 const void *update_values[] = { CFSTR("Updated Comment") }; 125 attrs = CFDictionaryCreate(NULL, update_keys, update_values, 126 array_size(update_keys), 127 &kCFTypeDictionaryKeyCallBacks, 128 &kCFTypeDictionaryValueCallBacks); 129 130 is_status(SecItemUpdate(query, attrs), 131 errSecSuccess, "SecItemUpdate sync=true"); 132 133 CFReleaseSafe(query); 134 CFReleaseSafe(attrs); 135 } 136 137 /* Test finding the updated item with its new attribute */ 138 { 139 const void *keys[] = { 140 kSecClass, // class attribute is required 141 kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness 142 kSecAttrComment, // also search on the attr we just changed, so we know we've found the updated item 143 kSecAttrSynchronizable }; // we want synchronizable results 144 const void *values[] = { 145 kSecClassGenericPassword, 146 account, service, 147 CFSTR("Updated Comment"), 148 kCFBooleanTrue }; // we only want to find the synchronizable item here, not a non-synchronizable one 149 150 query = CFDictionaryCreate(NULL, keys, values, 151 array_size(keys), 152 &kCFTypeDictionaryKeyCallBacks, 153 &kCFTypeDictionaryValueCallBacks); 154 155 is_status(SecItemCopyMatching(query, (CFTypeRef *)&result), 156 errSecSuccess, "SecItemCopyMatching post-update"); 157 158 CFReleaseSafe(result); 159 // re-use query in next test... 160 } 161 162 /* Test deleting the item */ 163 { 164 is_status(SecItemDelete(query), errSecSuccess, "SecItemDelete sync=true"); 165 166 CFReleaseSafe(query); 167 } 168} 169 170int si_72_syncableitems(int argc, char * const *argv) 171{ 172 plan_tests(6); 173 tests(); 174 175 return 0; 176} 177