X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/866f8763175ff60e4fa455b92b5eb660a12fe6c7..07691282a056c4efea71e1e505527601e8cc166b:/OSX/libsecurity_keychain/lib/SecItem.cpp diff --git a/OSX/libsecurity_keychain/lib/SecItem.cpp b/OSX/libsecurity_keychain/lib/SecItem.cpp index 49a0a4d8..ad88d453 100644 --- a/OSX/libsecurity_keychain/lib/SecItem.cpp +++ b/OSX/libsecurity_keychain/lib/SecItem.cpp @@ -36,7 +36,6 @@ #include "SecIdentitySearchPriv.h" #include "SecKeychainPriv.h" #include "SecCertificatePriv.h" -#include "SecCertificatePrivP.h" #include "TrustAdditions.h" #include "TrustSettingsSchema.h" #include @@ -55,6 +54,7 @@ #include #include #include +#include const uint8_t kUUIDStringLength = 36; @@ -81,6 +81,7 @@ bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_cl } static Boolean SecItemSynchronizable(CFDictionaryRef query); +static CFArrayRef _CopyMatchingIssuers(CFArrayRef issuers); static void secitemlog(int priority, const char *format, ...) { @@ -547,13 +548,10 @@ _ConvertNewFormatToOldFormat( // make storage to extract the dictionary items CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); - CFTypeRef keys[itemsInDictionary]; - CFTypeRef values[itemsInDictionary]; + std::vector keys(itemsInDictionary); + std::vector values(itemsInDictionary); - CFTypeRef *keysPtr = keys; - CFTypeRef *valuesPtr = values; - - CFDictionaryGetKeysAndValues(dictionaryRef, keys, values); + CFDictionaryGetKeysAndValues(dictionaryRef, keys.data(), values.data()); // count the number of items we are interested in CFIndex count = 0; @@ -561,12 +559,12 @@ _ConvertNewFormatToOldFormat( // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that // we don't pay the price for this twice - SecKeychainAttrType tags[itemsInDictionary]; - ItemRepresentation types[itemsInDictionary]; + std::vector tags(itemsInDictionary); + std::vector types(itemsInDictionary); for (i = 0; i < itemsInDictionary; ++i) { - CFTypeRef key = keysPtr[i]; + CFTypeRef key = keys[i]; int j; for (j = 0; j < infoNumItems; ++j) @@ -583,7 +581,7 @@ _ConvertNewFormatToOldFormat( if (j >= infoNumItems) { // if we got here, we aren't interested in this item. - valuesPtr[i] = NULL; + values[i] = NULL; } } @@ -601,7 +599,7 @@ _ConvertNewFormatToOldFormat( // we have to clone the data pointer. The caller will need to make sure to throw these away // with _FreeAttrList when it is done... - attrList->attr[resultPointer].data = CloneDataByType(types[i], valuesPtr[i], attrList->attr[resultPointer].length); + attrList->attr[resultPointer].data = CloneDataByType(types[i], values[i], attrList->attr[resultPointer].length); resultPointer += 1; } } @@ -2363,19 +2361,6 @@ _ReplaceKeychainItem( for (i=0, newCount=0; i < attrList->count; i++) { if (attrList->attr[i].length > 0) { newAttrList.attr[newCount++] = attrList->attr[i]; - #if 0 - // debugging code to log item attributes - SecKeychainAttrType tag = attrList->attr[i].tag; - SecKeychainAttrType htag=(SecKeychainAttrType)OSSwapConstInt32(tag); - char tmp[sizeof(SecKeychainAttrType) + 1]; - char tmpdata[attrList->attr[i].length + 1]; - memcpy(tmp, &htag, sizeof(SecKeychainAttrType)); - tmp[sizeof(SecKeychainAttrType)]=0; - memcpy(tmpdata, attrList->attr[i].data, attrList->attr[i].length); - tmpdata[attrList->attr[i].length]=0; - secitemlog(priority, "item attr '%s' = %d bytes: \"%s\"", - tmp, (int)attrList->attr[i].length, tmpdata); - #endif } } newAttrList.count = newCount; @@ -3075,11 +3060,12 @@ _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error) require_action(!(itemParams->itemClass == 0 && !itemParams->useItems), error_exit, status = errSecItemClassMissing); } - // kSecMatchIssuers is only permitted with identities. + // kSecMatchIssuers is only permitted with identities or certificates. // Convert the input issuers to normalized form. require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchIssuers, (const void **)&itemParams->matchIssuers, CFArrayGetTypeID(), NULL), error_exit); if (itemParams->matchIssuers) { - require_action(itemParams->returnIdentity, error_exit, status = errSecParam); + CFTypeRef allowCerts = CFDictionaryGetValue(itemParams->query, kSecUseCertificatesWithMatchIssuers); + require_action(itemParams->returnIdentity || (allowCerts && CFEqual(allowCerts, kCFBooleanTrue)), error_exit, status = errSecParam); CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); CFArrayRef issuers = (CFArrayRef)itemParams->matchIssuers; if (canonical_issuers) { @@ -4031,15 +4017,23 @@ static OSStatus SecItemCategorizeQuery(CFDictionaryRef query, bool &can_target_i can_target_osx = can_target_ios = true; // Check no-legacy flag. - CFTypeRef value = CFDictionaryGetValue(query, kSecAttrNoLegacy); - if (value != NULL) { - can_target_ios = readNumber(value) != 0; + // it's iOS or bust if we're on MZ! + CFTypeRef noLegacy = NULL; + if (_CFMZEnabled()) { + noLegacy = kCFBooleanTrue; + } + else { + noLegacy = CFDictionaryGetValue(query, kSecAttrNoLegacy); + } + + if (noLegacy != NULL) { + can_target_ios = readNumber(noLegacy) != 0; can_target_osx = !can_target_ios; return errSecSuccess; } // Check whether the query contains kSecValueRef and modify can_ flags according to the kind and type of the value. - value = CFDictionaryGetValue(query, kSecValueRef); + CFTypeRef value = CFDictionaryGetValue(query, kSecValueRef); if (value != NULL) { CFTypeID typeID = CFGetTypeID(value); if (typeID == SecKeyGetTypeID()) { @@ -4103,6 +4097,13 @@ static OSStatus SecItemCategorizeQuery(CFDictionaryRef query, bool &can_target_i can_target_ios = can_target_ios && !CFDictionaryContainsKey(query, *osx_only_items[i]); } + // Absence of all of kSecItemClass, kSecValuePersistentRef, and kSecValueRef means that the query can't target iOS + if(CFDictionaryGetValue(query, kSecClass) == NULL && + CFDictionaryGetValue(query, kSecValuePersistentRef) == NULL && + CFDictionaryGetValue(query, kSecValueRef) == NULL) { + can_target_ios = false; + } + return (can_target_ios || can_target_osx) ? errSecSuccess : errSecParam; } @@ -4318,13 +4319,16 @@ SecItemValidateAppleApplicationGroupAccess(CFStringRef group) return status; } -static Mutex gParentCertCacheLock; +static Mutex& gParentCertCacheLock() { + static Mutex fParentCertCacheLock; + return fParentCertCacheLock; +} static CFMutableDictionaryRef gParentCertCache; static CFMutableArrayRef gParentCertCacheList; #define PARENT_CACHE_SIZE 100 void SecItemParentCachePurge() { - StLock _(gParentCertCacheLock); + StLock _(gParentCertCacheLock()); CFReleaseNull(gParentCertCache); CFReleaseNull(gParentCertCacheList); } @@ -4335,7 +4339,7 @@ static CFArrayRef CF_RETURNS_RETAINED parentCacheRead(SecCertificateRef certific CFDataRef digest = SecCertificateGetSHA1Digest(certificate); if (!digest) return NULL; - StLock _(gParentCertCacheLock); + StLock _(gParentCertCacheLock()); if (gParentCertCache && gParentCertCacheList) { if (0 <= (ix = CFArrayGetFirstIndexOfValue(gParentCertCacheList, CFRangeMake(0, CFArrayGetCount(gParentCertCacheList)), @@ -4354,7 +4358,7 @@ static void parentCacheWrite(SecCertificateRef certificate, CFArrayRef parents) CFDataRef digest = SecCertificateGetSHA1Digest(certificate); if (!digest) return; - StLock _(gParentCertCacheLock); + StLock _(gParentCertCacheLock()); if (!gParentCertCache || !gParentCertCacheList) { CFReleaseNull(gParentCertCache); gParentCertCache = makeCFMutableDictionary(); @@ -4370,6 +4374,7 @@ static void parentCacheWrite(SecCertificateRef certificate, CFArrayRef parents) CFDictionaryAddValue(gParentCertCache, digest, parents); if (PARENT_CACHE_SIZE <= CFArrayGetCount(gParentCertCacheList)) { // Remove least recently used cache entry. + CFDictionaryRemoveValue(gParentCertCache, CFArrayGetValueAtIndex(gParentCertCacheList, 0)); CFArrayRemoveValueAtIndex(gParentCertCacheList, 0); } CFArrayAppendValue(gParentCertCacheList, digest); @@ -4484,11 +4489,10 @@ SecCertificateRef SecItemCopyStoredCertificate(SecCertificateRef certificate, vo #pragma unused (context) /* for now; in future this can reference a container object */ /* Certificates are unique by issuer and serial number. */ + CFDataRef serialNumber = SecCertificateCopySerialNumberData(certificate, NULL); #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - CFDataRef serialNumber = SecCertificateCopySerialNumber(certificate, NULL); CFDataRef normalizedIssuer = SecCertificateCopyNormalizedIssuerContent(certificate, NULL); #else - CFDataRef serialNumber = SecCertificateCopySerialNumber(certificate); CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); CFRetainSafe(normalizedIssuer); #endif @@ -4660,6 +4664,18 @@ SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass, * which won't work once the item is updated. */ CFDictionaryRemoveValue(result, kSecAttrModificationDate); + + /* Find all intermediate certificates in OSX keychain and append them in to the kSecMatchIssuers. + * This is required because secd cannot do query in to the OSX keychain + */ + CFTypeRef matchIssuers = CFDictionaryGetValue(result, kSecMatchIssuers); + if (matchIssuers && CFGetTypeID(matchIssuers) == CFArrayGetTypeID()) { + CFArrayRef newMatchIssuers = _CopyMatchingIssuers((CFArrayRef)matchIssuers); + if (newMatchIssuers) { + CFDictionarySetValue(result, kSecMatchIssuers, newMatchIssuers); + CFRelease(newMatchIssuers); + } + } } else { /* iOS doesn't add the class attribute, so we must do it here. */ @@ -4682,6 +4698,46 @@ SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass, } /* extern "C" */ +static CFArrayRef +_CopyMatchingIssuers(CFArrayRef matchIssuers) { + CFMutableArrayRef result = NULL; + CFMutableDictionaryRef query = NULL; + CFMutableDictionaryRef policyProperties = NULL; + SecPolicyRef policy = NULL; + CFTypeRef matchedCertificates = NULL; + + require_quiet(policyProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out); + CFDictionarySetValue(policyProperties, kSecPolicyKU_KeyCertSign, kCFBooleanTrue); + require_quiet(policy = SecPolicyCreateWithProperties(kSecPolicyAppleX509Basic, policyProperties), out); + + require_quiet(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out); + CFDictionarySetValue(query, kSecClass, kSecClassCertificate); + CFDictionarySetValue(query, kSecMatchIssuers, matchIssuers); + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); + CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue); + CFDictionarySetValue(query, kSecUseCertificatesWithMatchIssuers, kCFBooleanTrue); + CFDictionarySetValue(query, kSecMatchPolicy, policy); + + if (SecItemCopyMatching_osx(query, &matchedCertificates) == errSecSuccess && CFGetTypeID(matchedCertificates) == CFArrayGetTypeID()) { + require_quiet(result = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, (CFArrayRef)matchedCertificates), out); + for(CFIndex i = 0; i < CFArrayGetCount((CFArrayRef)matchedCertificates); ++i) { + CFDictionaryRef attributes = (CFDictionaryRef)CFArrayGetValueAtIndex((CFArrayRef)matchedCertificates, i); + CFTypeRef subject = CFDictionaryGetValue(attributes, kSecAttrSubject); + if (!CFArrayContainsValue(result, CFRangeMake(0, CFArrayGetCount(result)), subject)) { + CFArrayAppendValue(result, subject); + } + } + } + +out: + CFReleaseSafe(query); + CFReleaseSafe(policyProperties); + CFReleaseSafe(policy); + CFReleaseSafe(matchedCertificates); + + return result; +} + static OSStatus SecItemMergeResults(bool can_target_ios, OSStatus status_ios, CFTypeRef result_ios, bool can_target_osx, OSStatus status_osx, CFTypeRef result_osx, @@ -4750,45 +4806,6 @@ SecItemMergeResults(bool can_target_ios, OSStatus status_ios, CFTypeRef result_i } } -static bool -ShouldTryUnlockKeybag(CFDictionaryRef query, OSErr status) -{ - static __typeof(SASSessionStateForUser) *soft_SASSessionStateForUser = NULL; - static dispatch_once_t onceToken; - static void *framework; - - if (status != errSecInteractionNotAllowed) - return false; - - // If the query disabled authUI, respect it. - CFTypeRef authUI = NULL; - if (query) { - authUI = CFDictionaryGetValue(query, kSecUseAuthenticationUI); - if (authUI == NULL) { - authUI = CFDictionaryGetValue(query, kSecUseNoAuthenticationUI); - authUI = (authUI != NULL && CFEqual(authUI, kCFBooleanTrue)) ? kSecUseAuthenticationUIFail : NULL; - } - } - if (authUI && !CFEqual(authUI, kSecUseAuthenticationUIAllow)) - return false; - - dispatch_once(&onceToken, ^{ - framework = dlopen("/System/Library/PrivateFrameworks/login.framework/login", RTLD_LAZY); - if (framework == NULL) - return; - soft_SASSessionStateForUser = (__typeof(soft_SASSessionStateForUser)) dlsym(framework, "SASSessionStateForUser"); - }); - - if (soft_SASSessionStateForUser == NULL) - return false; - - SessionAgentState sessionState = soft_SASSessionStateForUser(getuid()); - if(sessionState != kSA_state_desktopshowing) - return false; - - return true; -} - OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) { @@ -4817,14 +4834,6 @@ SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) } else { status_ios = SecItemCopyMatching_ios(attrs_ios, &result_ios); - if(ShouldTryUnlockKeybag(query, status_ios)) { - // The keybag is locked. Attempt to unlock it... - secitemlog(LOG_WARNING, "SecItemCopyMatching triggering SecurityAgent"); - if(errSecSuccess == SecKeychainVerifyKeyStorePassphrase(1)) { - CFReleaseNull(result_ios); - status_ios = SecItemCopyMatching_ios(attrs_ios, &result_ios); - } - } CFRelease(attrs_ios); } secitemlog(LOG_NOTICE, "SecItemCopyMatching_ios result: %d", status_ios); @@ -4881,14 +4890,6 @@ SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) status = errSecParam; } else { status = SecItemAdd_ios(attrs_ios, &result_ios); - if(ShouldTryUnlockKeybag(attributes, status)) { - // The keybag is locked. Attempt to unlock it... - secitemlog(LOG_WARNING, "SecItemAdd triggering SecurityAgent"); - if(errSecSuccess == SecKeychainVerifyKeyStorePassphrase(3)) { - CFReleaseNull(result_ios); - status = SecItemAdd_ios(attrs_ios, &result_ios); - } - } CFRelease(attrs_ios); } secitemlog(LOG_NOTICE, "SecItemAdd_ios result: %d", status); @@ -4938,22 +4939,8 @@ SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) else { if (SecItemHasSynchronizableUpdate(true, attributesToUpdate)) { status_ios = SecItemChangeSynchronizability(attrs_ios, attributesToUpdate, false); - if(ShouldTryUnlockKeybag(query, status_ios)) { - // The keybag is locked. Attempt to unlock it... - secitemlog(LOG_WARNING, "SecItemUpdate triggering SecurityAgent"); - if(errSecSuccess == SecKeychainVerifyKeyStorePassphrase(1)) { - status_ios = SecItemChangeSynchronizability(attrs_ios, attributesToUpdate, false); - } - } } else { status_ios = SecItemUpdate_ios(attrs_ios, attributesToUpdate); - if(ShouldTryUnlockKeybag(query, status_ios)) { - // The keybag is locked. Attempt to unlock it... - secitemlog(LOG_WARNING, "SecItemUpdate triggering SecurityAgent"); - if(errSecSuccess == SecKeychainVerifyKeyStorePassphrase(1)) { - status_ios = SecItemUpdate_ios(attrs_ios, attributesToUpdate); - } - } } CFRelease(attrs_ios); } @@ -5036,13 +5023,6 @@ OSStatus SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes) { OSStatus status = SecItemUpdateTokenItems_ios(tokenID, tokenItemsAttributes); - if(ShouldTryUnlockKeybag(NULL, status)) { - // The keybag is locked. Attempt to unlock it... - if(errSecSuccess == SecKeychainVerifyKeyStorePassphrase(1)) { - secitemlog(LOG_WARNING, "SecItemUpdateTokenItems triggering SecurityAgent"); - status = SecItemUpdateTokenItems_ios(tokenID, tokenItemsAttributes); - } - } secitemlog(LOG_NOTICE, "SecItemUpdateTokenItems_ios result: %d", status); return status; }