]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/SecItem.cpp
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecItem.cpp
index ac9a9e6f234c7d84f338b66090c94e9e12040afd..ad88d453afc834ecf5df225ce809a9e14d666af6 100644 (file)
@@ -54,6 +54,7 @@
 #include <login/SessionAgentCom.h>
 #include <login/SessionAgentStatusCom.h>
 #include <os/activity.h>
+#include <CoreFoundation/CFPriv.h>
 
 
 const uint8_t kUUIDStringLength = 36;
@@ -80,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, ...)
 {
@@ -546,13 +548,10 @@ _ConvertNewFormatToOldFormat(
 
        // make storage to extract the dictionary items
        CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef);
-       CFTypeRef keys[itemsInDictionary];
-       CFTypeRef values[itemsInDictionary];
+       std::vector<CFTypeRef> keys(itemsInDictionary);
+       std::vector<CFTypeRef> 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;
@@ -560,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<SecKeychainAttrType> tags(itemsInDictionary);
+       std::vector<ItemRepresentation> types(itemsInDictionary);
 
        for (i = 0; i < itemsInDictionary; ++i)
        {
-               CFTypeRef key = keysPtr[i];
+               CFTypeRef key = keys[i];
 
                int j;
                for (j = 0; j < infoNumItems; ++j)
@@ -582,7 +581,7 @@ _ConvertNewFormatToOldFormat(
                if (j >= infoNumItems)
                {
                        // if we got here, we aren't interested in this item.
-                       valuesPtr[i] = NULL;
+                       values[i] = NULL;
                }
        }
 
@@ -600,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;
                }
        }
@@ -2362,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;
@@ -3074,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) {
@@ -4030,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()) {
@@ -4102,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;
 }
 
@@ -4317,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<Mutex> _(gParentCertCacheLock);
+    StLock<Mutex> _(gParentCertCacheLock());
     CFReleaseNull(gParentCertCache);
     CFReleaseNull(gParentCertCacheList);
 }
@@ -4334,7 +4339,7 @@ static CFArrayRef CF_RETURNS_RETAINED parentCacheRead(SecCertificateRef certific
     CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
     if (!digest) return NULL;
 
-    StLock<Mutex> _(gParentCertCacheLock);
+    StLock<Mutex> _(gParentCertCacheLock());
     if (gParentCertCache && gParentCertCacheList) {
         if (0 <= (ix = CFArrayGetFirstIndexOfValue(gParentCertCacheList,
                                                    CFRangeMake(0, CFArrayGetCount(gParentCertCacheList)),
@@ -4353,7 +4358,7 @@ static void parentCacheWrite(SecCertificateRef certificate, CFArrayRef parents)
     CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
     if (!digest) return;
 
-    StLock<Mutex> _(gParentCertCacheLock);
+    StLock<Mutex> _(gParentCertCacheLock());
     if (!gParentCertCache || !gParentCertCacheList) {
         CFReleaseNull(gParentCertCache);
         gParentCertCache = makeCFMutableDictionary();
@@ -4369,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);
@@ -4483,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
@@ -4659,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. */
@@ -4681,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,