1// 2// si-12-item-stress.c 3// sec 4// 5// Created by Michael Brouwer on 8/1/13. 6// Copyright (c) 2013 Apple Inc. All Rights Reserved. 7// 8// 9 10#include <CoreFoundation/CoreFoundation.h> 11#include <Security/SecCertificate.h> 12#include <Security/SecItem.h> 13#include <Security/SecItemPriv.h> 14#include <Security/SecBase.h> 15#include <utilities/array_size.h> 16#include <utilities/SecCFWrappers.h> 17#include <stdlib.h> 18#include <unistd.h> 19 20#include "Security_regressions.h" 21 22#if 0 23static void persistentRefIs(CFDataRef pref, CFDataRef data) { 24 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 25 CFTypeRef result = NULL; 26 CFDictionaryAddValue(dict, kSecValuePersistentRef, pref); 27 CFDictionaryAddValue(dict, kSecReturnData, kCFBooleanTrue); 28 ok_status(SecItemCopyMatching(dict, &result), "lookup item data by persistent ref"); 29 ok(CFEqual(data, result), "result %@ equals expected data %@", result, data); 30 CFReleaseNull(result); 31 CFReleaseNull(dict); 32} 33#endif 34 35enum ItemAttrType { 36 kBoolItemAttr, 37 kNumberItemAttr, 38 kStringItemAttr, 39 kDataItemAttr, 40 kBlobItemAttr, 41 kDateItemAttr, 42 kAccessabilityItemAttr, 43 kAccessGroupItemAttr, 44}; 45 46static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) { 47 va_list ap; 48 va_start(ap, each); 49 CFStringRef attr; 50 while((attr = va_arg(ap, CFStringRef)) != NULL) { 51 enum ItemAttrType atype = va_arg(ap, enum ItemAttrType); 52 each(attr, atype); 53 } 54 va_end(ap); 55} 56 57#if 0 58static void ItemForEachAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { 59 CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); 60 if (!iclass) { 61 return; 62 } else if (CFEqual(iclass, kSecClassGenericPassword)) { 63 WithEachString(each, 64 kSecAttrAccessible, kAccessabilityItemAttr, 65 kSecAttrAccessGroup, kAccessGroupItemAttr, 66 kSecAttrCreationDate, kDateItemAttr, 67 kSecAttrModificationDate, kDateItemAttr, 68 kSecAttrDescription, kStringItemAttr, 69 kSecAttrComment, kStringItemAttr, 70 kSecAttrCreator, kNumberItemAttr, 71 kSecAttrType, kNumberItemAttr, 72 kSecAttrLabel, kStringItemAttr, 73 kSecAttrIsInvisible, kBoolItemAttr, 74 kSecAttrIsNegative, kBoolItemAttr, 75 kSecAttrAccount, kStringItemAttr, 76 kSecAttrService, kStringItemAttr, 77 kSecAttrGeneric, kDataItemAttr, 78 kSecAttrSynchronizable, kBoolItemAttr, 79 NULL); 80 } else if (CFEqual(iclass, kSecClassInternetPassword)) { 81 WithEachString(each, 82 kSecAttrAccessible, kAccessabilityItemAttr, 83 kSecAttrAccessGroup, kAccessGroupItemAttr, 84 kSecAttrCreationDate, kDateItemAttr, 85 kSecAttrModificationDate, kDateItemAttr, 86 kSecAttrDescription, kStringItemAttr, 87 kSecAttrComment, kStringItemAttr, 88 kSecAttrCreator, kNumberItemAttr, 89 kSecAttrType, kNumberItemAttr, 90 kSecAttrLabel, kStringItemAttr, 91 kSecAttrIsInvisible, kBoolItemAttr, 92 kSecAttrIsNegative, kBoolItemAttr, 93 kSecAttrAccount, kStringItemAttr, 94 kSecAttrSecurityDomain, kStringItemAttr, 95 kSecAttrServer, kStringItemAttr, 96 kSecAttrProtocol, kNumberItemAttr, 97 kSecAttrAuthenticationType, kNumberItemAttr, 98 kSecAttrPort, kNumberItemAttr, 99 kSecAttrPath, kStringItemAttr, 100 kSecAttrSynchronizable, kBoolItemAttr, 101 NULL); 102 } else if (CFEqual(iclass, kSecClassCertificate)) { 103 WithEachString(each, 104 kSecAttrAccessible, kAccessabilityItemAttr, 105 kSecAttrAccessGroup, kAccessGroupItemAttr, 106 kSecAttrCertificateType, kNumberItemAttr, 107 kSecAttrCertificateEncoding, kNumberItemAttr, 108 kSecAttrLabel, kStringItemAttr, 109 kSecAttrSubject, kDataItemAttr, 110 kSecAttrIssuer, kDataItemAttr, 111 kSecAttrSerialNumber, kDataItemAttr, 112 kSecAttrSubjectKeyID, kDataItemAttr, 113 kSecAttrPublicKeyHash, kDataItemAttr, 114 kSecAttrSynchronizable, kBoolItemAttr, 115 NULL); 116 } else if (CFEqual(iclass, kSecClassKey)) { 117 WithEachString(each, 118 kSecAttrAccessible, kAccessabilityItemAttr, 119 kSecAttrAccessGroup, kAccessGroupItemAttr, 120 kSecAttrKeyClass, kStringItemAttr, // Might be Number on replies 121 kSecAttrLabel, kStringItemAttr, 122 kSecAttrApplicationLabel, kDataItemAttr, 123 kSecAttrIsPermanent, kBoolItemAttr, 124 kSecAttrApplicationTag, kDataItemAttr, 125 kSecAttrKeyType, kNumberItemAttr, 126 kSecAttrKeySizeInBits, kNumberItemAttr, 127 kSecAttrEffectiveKeySize, kNumberItemAttr, 128 kSecAttrCanEncrypt, kBoolItemAttr, 129 kSecAttrCanDecrypt, kBoolItemAttr, 130 kSecAttrCanDerive, kBoolItemAttr, 131 kSecAttrCanSign, kBoolItemAttr, 132 kSecAttrCanVerify, kBoolItemAttr, 133 kSecAttrCanWrap, kBoolItemAttr, 134 kSecAttrCanUnwrap, kBoolItemAttr, 135 kSecAttrStartDate, kDateItemAttr, 136 kSecAttrEndDate, kDateItemAttr, 137 kSecAttrSynchronizable, kBoolItemAttr, 138 NULL); 139 } else if (CFEqual(iclass, kSecClassIdentity)) { 140 WithEachString(each, 141 kSecAttrAccessible, kAccessabilityItemAttr, 142 kSecAttrAccessGroup, kAccessGroupItemAttr, 143 kSecAttrCertificateType, kNumberItemAttr, 144 kSecAttrCertificateEncoding, kNumberItemAttr, 145 kSecAttrLabel, kStringItemAttr, 146 kSecAttrSubject, kDataItemAttr, 147 kSecAttrIssuer, kDataItemAttr, 148 kSecAttrSerialNumber, kDataItemAttr, 149 kSecAttrSubjectKeyID, kDataItemAttr, 150 kSecAttrPublicKeyHash, kDataItemAttr, 151 kSecAttrKeyClass, kStringItemAttr, // Might be Number on replies 152 kSecAttrApplicationLabel, kDataItemAttr, 153 kSecAttrIsPermanent, kBoolItemAttr, 154 kSecAttrApplicationTag, kDataItemAttr, 155 kSecAttrKeyType, kNumberItemAttr, 156 kSecAttrKeySizeInBits, kNumberItemAttr, 157 kSecAttrEffectiveKeySize, kNumberItemAttr, 158 kSecAttrCanEncrypt, kBoolItemAttr, 159 kSecAttrCanDecrypt, kBoolItemAttr, 160 kSecAttrCanDerive, kBoolItemAttr, 161 kSecAttrCanSign, kBoolItemAttr, 162 kSecAttrCanVerify, kBoolItemAttr, 163 kSecAttrCanWrap, kBoolItemAttr, 164 kSecAttrCanUnwrap, kBoolItemAttr, 165 kSecAttrStartDate, kDateItemAttr, 166 kSecAttrEndDate, kDateItemAttr, 167 kSecAttrSynchronizable, kBoolItemAttr, 168 NULL); 169 } 170} 171#endif 172 173static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { 174 CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); 175 if (!iclass) { 176 return; 177 } else if (CFEqual(iclass, kSecClassGenericPassword)) { 178 WithEachString(each, 179 kSecAttrAccessGroup, kAccessGroupItemAttr, 180 kSecAttrAccount, kStringItemAttr, 181 kSecAttrService, kStringItemAttr, 182 kSecAttrSynchronizable, kBoolItemAttr, 183 NULL); 184 } else if (CFEqual(iclass, kSecClassInternetPassword)) { 185 WithEachString(each, 186 kSecAttrAccessGroup, kAccessGroupItemAttr, 187 kSecAttrAccount, kStringItemAttr, 188 kSecAttrSecurityDomain, kStringItemAttr, 189 kSecAttrServer, kStringItemAttr, 190 kSecAttrProtocol, kNumberItemAttr, 191 kSecAttrAuthenticationType, kNumberItemAttr, 192 kSecAttrPort, kNumberItemAttr, 193 kSecAttrPath, kStringItemAttr, 194 kSecAttrSynchronizable, kBoolItemAttr, 195 NULL); 196 } else if (CFEqual(iclass, kSecClassCertificate)) { 197 WithEachString(each, 198 kSecAttrAccessGroup, kAccessGroupItemAttr, 199 kSecAttrCertificateType, kNumberItemAttr, 200 kSecAttrIssuer, kDataItemAttr, 201 kSecAttrSerialNumber, kDataItemAttr, 202 kSecAttrSynchronizable, kBoolItemAttr, 203 NULL); 204 } else if (CFEqual(iclass, kSecClassKey)) { 205 WithEachString(each, 206 kSecAttrAccessGroup, kAccessGroupItemAttr, 207 kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies 208 kSecAttrApplicationLabel, kDataItemAttr, 209 kSecAttrApplicationTag, kDataItemAttr, 210 kSecAttrKeyType, kNumberItemAttr, 211 kSecAttrKeySizeInBits, kNumberItemAttr, 212 kSecAttrEffectiveKeySize, kNumberItemAttr, 213 kSecAttrStartDate, kDateItemAttr, 214 kSecAttrEndDate, kDateItemAttr, 215 kSecAttrSynchronizable, kBoolItemAttr, 216 NULL); 217 } else if (CFEqual(iclass, kSecClassIdentity)) { 218 WithEachString(each, 219 kSecAttrAccessGroup, kAccessGroupItemAttr, 220 kSecAttrCertificateType, kNumberItemAttr, 221 kSecAttrIssuer, kDataItemAttr, 222 kSecAttrSerialNumber, kDataItemAttr, 223 kSecAttrSynchronizable, kBoolItemAttr, 224 kSecAttrKeyClass, kStringItemAttr, // kNumberItemAttr on replies 225 kSecAttrApplicationLabel, kDataItemAttr, 226 kSecAttrApplicationTag, kDataItemAttr, 227 kSecAttrKeyType, kNumberItemAttr, 228 kSecAttrKeySizeInBits, kNumberItemAttr, 229 kSecAttrEffectiveKeySize, kNumberItemAttr, 230 kSecAttrStartDate, kDateItemAttr, 231 kSecAttrEndDate, kDateItemAttr, 232 kSecAttrSynchronizable, kBoolItemAttr, 233 NULL); 234 } 235} 236 237static CFMutableDictionaryRef ItemCreate(int num) { 238 CFStringRef iclass = NULL; 239 switch (num % 4) { 240 case 0: 241 iclass = kSecClassInternetPassword; 242 break; 243 case 1: 244 iclass = kSecClassGenericPassword; 245 break; 246 case 2: 247 iclass = kSecClassKey; 248 break; 249 case 3: 250 iclass = kSecClassCertificate; 251 break; 252 } 253 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, iclass, NULL); 254} 255 256/* Test add api in all it's variants. */ 257static void tests(void) 258{ 259 for (int num = 0 ; num < 8; ++num) { 260 CFMutableDictionaryRef item = ItemCreate(num); 261 ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) { 262 CFTypeRef value = NULL; 263 switch (atype) { 264 case kBoolItemAttr: 265 value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse); 266 CFRetain(value); 267 break; 268 case kNumberItemAttr: 269 value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num); 270 break; 271 case kStringItemAttr: 272 case kBlobItemAttr: 273 value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("string-%d"), num); 274 break; 275 case kDataItemAttr: 276 { 277 char buf[10]; 278 int len = snprintf(buf, sizeof(buf), "data-%d", num); 279 value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len); 280 break; 281 } 282 case kDateItemAttr: 283 value = NULL; // Don't mess with dates on create. 284 break; 285 case kAccessabilityItemAttr: 286 { 287 CFStringRef accessabilites[] = { 288 kSecAttrAccessibleWhenUnlocked, 289 kSecAttrAccessibleAfterFirstUnlock, 290 kSecAttrAccessibleAlways, 291 kSecAttrAccessibleWhenUnlockedThisDeviceOnly, 292 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, 293 kSecAttrAccessibleAlwaysThisDeviceOnly, 294 }; 295 value = accessabilites[num % array_size(accessabilites)]; 296 break; 297 } 298 case kAccessGroupItemAttr: 299 { 300 CFStringRef accessGroups[] = { 301 NULL, 302#if 0 303#if NO_SERVER 304 CFSTR("test"), 305 CFSTR("apple"), 306 CFSTR("lockdown-identities"), 307#else 308 CFSTR("sync"), 309#endif 310 CFSTR("com.apple.security.sos"), // Secd internally uses this 311 312 CFSTR("com.apple.security.regressions"), // SecurityTestApp is in this group. 313#endif 314 }; 315 value = accessGroups[num % array_size(accessGroups)]; 316 break; 317 } 318 } 319 if (value) 320 CFDictionarySetValue(item, attr, value); 321 CFReleaseSafe(value); 322 }); 323 324 CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanTrue); 325 ok_status(SecItemAdd(item, NULL), "add sync"); 326 327 CFDictionarySetValue(item, kSecUseTombstones, kCFBooleanTrue); 328 ok_status(SecItemDelete(item), "delete sync"); 329 330 CFDictionarySetValue(item, kSecAttrTombstone, kCFBooleanTrue); 331 ok_status(SecItemCopyMatching(item, NULL), "find tombstone after delete sync"); 332 ok_status(SecItemDelete(item), "delete sync tombstone"); 333 CFDictionaryRemoveValue(item, kSecAttrTombstone); 334 335 ok_status(SecItemAdd(item, NULL), "add sync again"); 336 337 CFDictionarySetValue(item, kSecUseTombstones, kCFBooleanFalse); 338 ok_status(SecItemDelete(item), "delete sync without leaving a tombstone behind"); 339 CFDictionaryRemoveValue(item, kSecUseTombstones); 340 341 CFDictionarySetValue(item, kSecAttrTombstone, kCFBooleanTrue); 342 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find tombstone after delete sync with kSecUseTombstones=false"); 343 344 CFDictionaryRemoveValue(item, kSecAttrSynchronizable); 345 ok_status(SecItemAdd(item, NULL), "add local"); 346 ok_status(SecItemDelete(item), "delete local"); 347 348 CFDictionarySetValue(item, kSecAttrTombstone, kCFBooleanTrue); 349 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find tombstone after delete local"); 350 is_status(SecItemDelete(item), errSecItemNotFound, "do not delete tombstone after delete local"); 351 CFDictionaryRemoveValue(item, kSecAttrTombstone); 352 353 ok_status(SecItemAdd(item, NULL), "add local again"); 354 355 CFDictionarySetValue(item, kSecUseTombstones, kCFBooleanTrue); 356 ok_status(SecItemDelete(item), "delete local and leave a tombstone behind"); 357 CFDictionaryRemoveValue(item, kSecUseTombstones); 358 359 CFDictionarySetValue(item, kSecAttrTombstone, kCFBooleanTrue); 360 ok_status(SecItemCopyMatching(item, NULL), "find tombstone after delete sync with kSecUseTombstones=true"); 361 362 CFDictionarySetValue(item, kSecUseTombstones, kCFBooleanTrue); 363 ok_status(SecItemDelete(item), "delete local tombstone kSecUseTombstones=true"); 364 CFDictionaryRemoveValue(item, kSecUseTombstones); 365 366 ok_status(SecItemCopyMatching(item, NULL), "find tombstone after delete local tombstone with kSecUseTombstones=true"); 367 ok_status(SecItemDelete(item), "delete local tombstone"); 368 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find tombstone after delete local"); 369 370 CFRelease(item); 371 } 372} 373 374int si_12_item_stress(int argc, char *const *argv) 375{ 376 plan_tests(144); 377 378 tests(); 379 380 return 0; 381} 382