]> git.saurik.com Git - apple/security.git/commitdiff
Security-57031.20.26.tar.gz os-x-10103 v57031.20.26
authorApple <opensource@apple.com>
Wed, 10 Jun 2015 06:04:57 +0000 (06:04 +0000)
committerApple <opensource@apple.com>
Wed, 10 Jun 2015 06:04:57 +0000 (06:04 +0000)
98 files changed:
Security.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/Release.xcscheme
Security/Security.xcodeproj/project.pbxproj
Security/libsecurity_codesigning/lib/CodeSigner.cpp
Security/libsecurity_codesigning/lib/CodeSigner.h
Security/libsecurity_codesigning/lib/SecStaticCode.cpp
Security/libsecurity_codesigning/lib/SecStaticCode.h
Security/libsecurity_codesigning/lib/StaticCode.cpp
Security/libsecurity_codesigning/lib/StaticCode.h
Security/libsecurity_codesigning/lib/bundlediskrep.cpp
Security/libsecurity_codesigning/lib/bundlediskrep.h
Security/libsecurity_codesigning/lib/csutilities.cpp
Security/libsecurity_codesigning/lib/csutilities.h
Security/libsecurity_codesigning/lib/dirscanner.cpp
Security/libsecurity_codesigning/lib/gkoverride.m [deleted file]
Security/libsecurity_codesigning/lib/opaquewhitelist.cpp
Security/libsecurity_codesigning/lib/policyengine.cpp
Security/libsecurity_codesigning/lib/resources.cpp
Security/libsecurity_codesigning/lib/resources.h
Security/libsecurity_codesigning/lib/signer.cpp
Security/libsecurity_codesigning/lib/signer.h
Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj
Security/libsecurity_keychain/lib/SecItem.cpp
Security/libsecurity_keychain/lib/SecTrust.cpp
Security/libsecurity_keychain/lib/SecTrustPriv.h
Security/libsecurity_keychain/lib/Trust.cpp
Security/libsecurity_keychain/lib/Trust.h
Security/libsecurity_keychain/lib/TrustRevocation.cpp
Security/libsecurity_smime/lib/tsaSupport.c
Security/libsecurity_smime/regressions/smime-cms-test.c
Security/libsecurity_ssl/lib/sslContext.c
Security/libsecurity_ssl/lib/sslCrypto.c
Security/libsecurity_ssl/regressions/ssl-42-ciphers.c
Security/libsecurity_ssl/regressions/ssl-44-crashes.c
Security/libsecurity_utilities/lib/dispatch.cpp [new file with mode: 0644]
Security/libsecurity_utilities/lib/dispatch.h [new file with mode: 0644]
Security/libsecurity_utilities/lib/errors.cpp
Security/libsecurity_utilities/lib/errors.h
Security/libsecurity_utilities/lib/macho++.cpp
Security/libsecurity_utilities/lib/unix++.cpp
Security/libsecurity_utilities/lib/unix++.h
Security/libsecurity_utilities/libsecurity_utilities.xcodeproj/project.pbxproj
Security/sec/SOSCircle/Regressions/SOSTestDevice.c
Security/sec/SOSCircle/Regressions/SOSTestDevice.h
Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c
Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c
Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c
Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c
Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
Security/sec/SOSCircle/SecureObjectSync/SOSManifest.c
Security/sec/SOSCircle/SecureObjectSync/SOSMessage.c
Security/sec/SOSCircle/SecureObjectSync/SOSPeer.c
Security/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c
Security/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c
Security/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c
Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c
Security/sec/Security/Regressions/Security_regressions.h
Security/sec/Security/Regressions/otr/otr-30-negotiation.c
Security/sec/Security/Regressions/otr/otr-40-edgecases.c [new file with mode: 0644]
Security/sec/Security/Regressions/otr/otr-50-roll.c [new file with mode: 0644]
Security/sec/Security/Regressions/otr/otr-60-slowroll.c [new file with mode: 0644]
Security/sec/Security/Regressions/otr/otr-otrdh.c
Security/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c
Security/sec/Security/SecAccessControl.c
Security/sec/Security/SecBasePriv.h
Security/sec/Security/SecCertificatePath.c
Security/sec/Security/SecCertificateRequest.c
Security/sec/Security/SecExports.exp-in
Security/sec/Security/SecIdentity.c
Security/sec/Security/SecOTRDHKey.c
Security/sec/Security/SecOTRDHKey.h
Security/sec/Security/SecOTRFullIdentity.c
Security/sec/Security/SecOTRPacketData.h
Security/sec/Security/SecOTRPackets.h
Security/sec/Security/SecOTRPublicIdentity.c
Security/sec/Security/SecOTRSession.c
Security/sec/Security/SecOTRSession.h
Security/sec/Security/SecOTRSessionAKE.c
Security/sec/Security/SecOTRSessionPriv.h
Security/sec/Security/SecPolicy.c
Security/sec/Security/SecTrust.c
Security/sec/Security/SecTrustSettings.c
Security/sec/ipc/server.c
Security/sec/sec.xcodeproj/project.pbxproj
Security/sec/securityd/OTATrustUtilities.c
Security/sec/securityd/Regressions/secd-70-engine.c
Security/sec/securityd/SecCAIssuerRequest.c
Security/sec/securityd/SecDbItem.c
Security/sec/securityd/SecDbKeychainItem.c
Security/sec/securityd/SecOCSPResponse.c
Security/sec/securityd/SecTrustServer.c
Security/utilities/Regressions/su-16-cfdate-der.c
Security/utilities/src/SecCFWrappers.c
Security/utilities/src/SecCFWrappers.h
Security/utilities/src/SecDb.c
Security/utilities/src/der_date.c
libsecurity_smime/lib/cmssiginfo.c
libsecurity_smime/lib/crypto-embedded.c

index 24a82cc5b1d8c816aeb419f1fb771dd6d157546b..42cabb3d0ca8254c33e1d4d988965e71e98bb66a 100644 (file)
@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
    LastUpgradeVersion = "0600"
-   version = "1.3">
+   version = "1.8">
    <BuildAction
       parallelizeBuildables = "NO"
-      buildImplicitDependencies = "YES">
+      buildImplicitDependencies = "YES"
+      enableAddressSanitizer = "NO">
       <BuildActionEntries>
          <BuildActionEntry
             buildForTesting = "YES"
@@ -71,6 +72,7 @@
       buildConfiguration = "Debug"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
       allowLocationSimulation = "YES">
       <PreActions>
          <ExecutionAction
@@ -90,7 +92,8 @@
             </ActionContent>
          </ExecutionAction>
       </PostActions>
-      <BuildableProductRunnable>
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
          <BuildableReference
             BuildableIdentifier = "primary"
             BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
             argument = "ssl_43_ciphers"
             isEnabled = "NO">
          </CommandLineArgument>
+         <CommandLineArgument
+            argument = "ssl_44_crashes"
+            isEnabled = "NO">
+         </CommandLineArgument>
          <CommandLineArgument
             argument = "ssl_45_tls12"
             isEnabled = "NO">
             argument = "otr_30_negotiation"
             isEnabled = "NO">
          </CommandLineArgument>
+         <CommandLineArgument
+            argument = "otr_40_edgecases"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "otr_40_edgecases"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "otr_50_roll"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "otr_60_slowroll"
+            isEnabled = "NO">
+         </CommandLineArgument>
          <CommandLineArgument
             argument = "otr_otrdh"
             isEnabled = "NO">
       useCustomWorkingDirectory = "NO"
       buildConfiguration = "Debug"
       debugDocumentVersioning = "YES">
-      <BuildableProductRunnable>
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
          <BuildableReference
             BuildableIdentifier = "primary"
             BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
index 1d521a915302330ebef894fcff31820747fa9060..e824fedcf04d1838a9e662bd1d7d31368406a208 100644 (file)
@@ -72,7 +72,8 @@
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
       allowLocationSimulation = "YES">
-      <BuildableProductRunnable>
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
          <BuildableReference
             BuildableIdentifier = "primary"
             BlueprintIdentifier = "E710C7411331946400F85568"
       useCustomWorkingDirectory = "NO"
       buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
-      <BuildableProductRunnable>
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
          <BuildableReference
             BuildableIdentifier = "primary"
             BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
index ee84cb23a729e66a2b28a1698319e5bba561177a..2ba044e02c984abf6a8634e5c44be2b5cb2fb371 100644 (file)
                72756C31175D48C100F52070 /* cloud_keychain_diagnose.c in Sources */ = {isa = PBXBuildFile; fileRef = 72756C30175D48C100F52070 /* cloud_keychain_diagnose.c */; };
                72CC327B175D6E0A00217455 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72756C9E175D566800F52070 /* CoreFoundation.framework */; };
                72CC327C175D6E1800217455 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 722CF215175D5E5000BCE0A5 /* Security.framework */; };
+               7A21DAE619B7F27C0007D37F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 18270EFD14CF429600B05E7F /* IOKit.framework */; };
                AAF3DCCB1666D03300376593 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18F235F715CA0D9D00060520 /* libsecurity_utilities.a */; };
                AC5688BC18B4396D00F0526C /* SecCMS.h in Headers */ = {isa = PBXBuildFile; fileRef = AC5688BA18B4396D00F0526C /* SecCMS.h */; settings = {ATTRIBUTES = (Private, ); }; };
                ACB6171918B5231800EBEDD7 /* libsecurity_smime_regressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ACB6171818B5231800EBEDD7 /* libsecurity_smime_regressions.a */; };
                                182BB5AE146FEF43000BF1F3 /* libsqlite3.dylib in Frameworks */,
                                182BB5AC146FEF15000BF1F3 /* libpam.dylib in Frameworks */,
                                182BB5AA146FEE50000BF1F3 /* CoreFoundation.framework in Frameworks */,
+                               7A21DAE619B7F27C0007D37F /* IOKit.framework in Frameworks */,
                                182BB4E1146F2591000BF1F3 /* libsecurity_manifest.a in Frameworks */,
                                182BB4E2146F2591000BF1F3 /* libsecurity_mds.a in Frameworks */,
                                182BB4E3146F2591000BF1F3 /* libsecurity_sd_cspdl.a in Frameworks */,
index 004b25b72e695e48633171ac450b7e27c769e241..7f8335250590eccefca9af4376fc00af0e2f5f0e 100644 (file)
@@ -65,7 +65,7 @@ public:
 // Construct a SecCodeSigner
 //
 SecCodeSigner::SecCodeSigner(SecCSFlags flags)
-       : mOpFlags(flags), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm)
+       : mOpFlags(flags), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm), mLimitedAsync(NULL)
 {
 }
 
@@ -75,6 +75,7 @@ SecCodeSigner::SecCodeSigner(SecCSFlags flags)
 //
 SecCodeSigner::~SecCodeSigner() throw()
 try {
+       delete mLimitedAsync;
 } catch (...) {
        return;
 }
index be888dbd9e696a55d3f9299e7da2c33a4a5ef22f..197df36411c98acf8c96620a46ed45aa0f100409 100644 (file)
@@ -94,6 +94,7 @@ private:
        CFRef<CFURLRef> mTimestampService;              // URL for Timestamp server
     bool mWantTimeStamp;          // use a Timestamp server
     bool mNoTimeStampCerts;       // don't request certificates with timestamping request
+       LimitedAsync *mLimitedAsync;    // limited async workers for verification
 };
 
 
index 6d71272ce2fb2d526e49b1fcfb885e52a577e16a..cc4e8c17da0b5a8bd0d5a3da19f66db4d0f3892f 100644 (file)
@@ -115,7 +115,9 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
         | kSecCSEnforceRevocationChecks
                | kSecCSNoNetworkAccess
                | kSecCSCheckNestedCode
-               | kSecCSStrictValidate);
+               | kSecCSStrictValidate
+               | kSecCSCheckGatekeeperArchitectures
+       );
        
        if (errors)
                flags |= kSecCSFullReport;      // internal-use flag
index 397de4ff70b1786d06b59d3c330289c51e4acb8f..7eae837a248a364954a36f0ddcfb6daf14d18216 100644 (file)
@@ -148,6 +148,7 @@ enum {
        kSecCSCheckNestedCode = 1 << 3,
        kSecCSStrictValidate = 1 << 4,
        kSecCSFullReport = 1 << 5,
+       kSecCSCheckGatekeeperArchitectures = (1 << 6) | kSecCSCheckAllArchitectures,
 };
 
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags,
index f7503184cdc9ee735a7d22e50e14668dfa47e929..f221e5bec4cda9fea916729866456ef5aaabaae2 100644 (file)
@@ -34,7 +34,6 @@
 #include "resources.h"
 #include "detachedrep.h"
 #include "csdatabase.h"
-#include "csutilities.h"
 #include "dirscanner.h"
 #include <CoreFoundation/CFURLAccess.h>
 #include <Security/SecPolicyPriv.h>
@@ -51,6 +50,7 @@
 #include <security_utilities/logging.h>
 #include <dirent.h>
 #include <sstream>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
 
 
 namespace Security {
@@ -88,7 +88,8 @@ static inline OSStatus errorForSlot(CodeDirectory::SpecialSlot slot)
 SecStaticCode::SecStaticCode(DiskRep *rep)
        : mRep(rep),
          mValidated(false), mExecutableValidated(false), mResourcesValidated(false), mResourcesValidContext(NULL),
-         mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mEvalDetails(NULL)
+         mProgressQueue("com.apple.security.validation-progress", false, DISPATCH_QUEUE_PRIORITY_DEFAULT),
+         mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mLimitedAsync(NULL), mEvalDetails(NULL)
 {
        CODESIGN_STATIC_CREATE(this, rep);
        CFRef<CFDataRef> codeDirectory = rep->codeDirectory();
@@ -104,12 +105,20 @@ SecStaticCode::SecStaticCode(DiskRep *rep)
 SecStaticCode::~SecStaticCode() throw()
 try {
        ::free(const_cast<Requirement *>(mDesignatedReq));
-       if (mResourcesValidContext)
-               delete mResourcesValidContext;
+       delete mResourcesValidContext;
+       delete mLimitedAsync;
 } catch (...) {
        return;
 }
 
+//
+// Initialize a nested SecStaticCode object from its parent
+//
+void SecStaticCode::initializeFromParent(const SecStaticCode& parent) {
+       setMonitor(parent.monitor());
+       if (parent.mLimitedAsync)
+               mLimitedAsync = new LimitedAsync(*parent.mLimitedAsync);
+}
 
 //
 // CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
@@ -148,10 +157,9 @@ CFTypeRef SecStaticCode::reportEvent(CFStringRef stage, CFDictionaryRef info)
 
 void SecStaticCode::prepareProgress(unsigned int workload)
 {
-       {
-               StLock<Mutex> _(mCancelLock);
+       dispatch_sync(mProgressQueue, ^{
                mCancelPending = false;                 // not cancelled
-       }
+       });
        if (mValidationFlags & kSecCSReportProgress) {
                mCurrentWork = 0;                               // nothing done yet
                mTotalWork = workload;                  // totally fake - we don't know how many files we'll get to chew
@@ -161,15 +169,17 @@ void SecStaticCode::prepareProgress(unsigned int workload)
 void SecStaticCode::reportProgress(unsigned amount /* = 1 */)
 {
        if (mMonitor && (mValidationFlags & kSecCSReportProgress)) {
-               {
-                       // if cancellation is pending, abort now
-                       StLock<Mutex> _(mCancelLock);
-                       if (mCancelPending)
-                               MacOSError::throwMe(errSecCSCancelled);
-               }
                // update progress and report
-               mCurrentWork += amount;
-               mMonitor(this->handle(false), CFSTR("progress"), CFTemp<CFDictionaryRef>("{current=%d,total=%d}", mCurrentWork, mTotalWork));
+               __block bool cancel = false;
+               dispatch_sync(mProgressQueue, ^{
+                       if (mCancelPending)
+                               cancel = true;
+                       mCurrentWork += amount;
+                       mMonitor(this->handle(false), CFSTR("progress"), CFTemp<CFDictionaryRef>("{current=%d,total=%d}", mCurrentWork, mTotalWork));
+               });
+               // if cancellation is pending, abort now
+               if (cancel)
+                       MacOSError::throwMe(errSecCSCancelled);
        }
 }
 
@@ -204,10 +214,11 @@ void SecStaticCode::setValidationModifiers(CFDictionaryRef conditions)
 //
 void SecStaticCode::cancelValidation()
 {
-       StLock<Mutex> _(mCancelLock);
        if (!(mValidationFlags & kSecCSReportProgress))         // not using progress reporting; cancel won't make it through
                MacOSError::throwMe(errSecCSInvalidFlags);
-       mCancelPending = true;
+       dispatch_sync(mProgressQueue, ^{
+               mCancelPending = true;
+       });
 }
 
 
@@ -784,7 +795,12 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                if (!(flags & kSecCSCheckNestedCode) || mResourcesDeep) // was deep or need no deep scan
                        doit = false;
        }
+
        if (doit) {
+               if (mLimitedAsync == NULL) {
+                       mLimitedAsync = new LimitedAsync(diskRep()->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
+               }
+
                try {
                        // sanity first
                        CFDictionaryRef sealedResources = resourceDictionary();
@@ -809,6 +825,7 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                        else
                                mResourcesValidContext = new ValidationContext(*this);          // simple bug-out on first error
 
+                       // use V2 resource seal if available, otherwise fall back to V1
                        CFDictionaryRef rules;
                        CFDictionaryRef files;
                        uint32_t version;
@@ -823,6 +840,7 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                        }
                        if (!rules || !files)
                                MacOSError::throwMe(errSecCSResourcesInvalid);
+
                        // check for weak resource rules
                        bool strict = flags & kSecCSStrictValidate;
                        if (strict) {
@@ -833,16 +851,29 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                                        if (mTolerateErrors.find(errSecCSWeakResourceEnvelope) == mTolerateErrors.end())
                                                MacOSError::throwMe(errSecCSWeakResourceEnvelope);
                        }
+
+                       Dispatch::Group group;
+                       Dispatch::Group &groupRef = group;  // (into block)
+
+                       // scan through the resources on disk, checking each against the resourceDirectory
                        __block CFRef<CFMutableDictionaryRef> resourceMap = makeCFMutableDictionary(files);
                        string base = cfString(this->resourceBase());
                        ResourceBuilder resources(base, base, rules, codeDirectory()->hashType, strict, mTolerateErrors);
                        diskRep()->adjustResources(resources);
-                       resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, ResourceBuilder::Rule *rule) {
-                               validateResource(files, relpath, ent->fts_info == FTS_SL, *mResourcesValidContext, flags, version);
-                               reportProgress();
+
+                       resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const string relpath, ResourceBuilder::Rule *rule) {
                                CFDictionaryRemoveValue(resourceMap, CFTempString(relpath));
+                               bool isSymlink = (ent->fts_info == FTS_SL);
+
+                               void (^validate)() = ^{
+                                       validateResource(files, relpath, isSymlink, *mResourcesValidContext, flags, version);
+                                       reportProgress();
+                               };
+
+                               mLimitedAsync->perform(groupRef, validate);
                        });
-                       
+                       group.wait();   // wait until all async resources have been validated as well
+
                        unsigned leftovers = unsigned(CFDictionaryGetCount(resourceMap));
                        if (leftovers > 0) {
                                secdebug("staticCode", "%d sealed resource(s) not found in code", int(leftovers));
@@ -917,6 +948,7 @@ bool SecStaticCode::hasWeakResourceRules(CFDictionaryRef rulesDict, uint32_t ver
        string catchAllRule = (version == 1) ? "^Resources/" : "^.*";
        __block bool coversAll = false;
        __block bool forbiddenOmission = false;
+       CFArrayRef allowedRef = allowed.get();  // (into block)
        CFDictionary rules(rulesDict, errSecCSResourceRulesInvalid);
        rules.apply(^(CFStringRef key, CFTypeRef value) {
                string pattern = cfString(key, errSecCSResourceRulesInvalid);
@@ -925,7 +957,7 @@ bool SecStaticCode::hasWeakResourceRules(CFDictionaryRef rulesDict, uint32_t ver
                        return;
                }
                if (isOmitRule(value))
-                       forbiddenOmission |= !CFArrayContainsValue(allowed, range, key);
+                       forbiddenOmission |= !CFArrayContainsValue(allowedRef, range, key);
        });
 
        return !coversAll || forbiddenOmission;
@@ -1124,7 +1156,7 @@ void SecStaticCode::validateNestedCode(CFURLRef path, const ResourceSeal &seal,
                if (!(flags & kSecCSCheckNestedCode))
                        flags |= kSecCSBasicValidateOnly;
                SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(cfString(path)));
-               code->setMonitor(this->monitor());
+               code->initializeFromParent(*this);
                code->staticValidate(flags, SecRequirement::required(req));
 
                if (isFramework && (flags & kSecCSStrictValidate))
@@ -1192,7 +1224,7 @@ void SecStaticCode::validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRe
                                continue;
 
                        SecPointer<SecStaticCode> frameworkVersion = new SecStaticCode(DiskRep::bestGuess(real_full_path));
-                       frameworkVersion->setMonitor(this->monitor());
+                       frameworkVersion->initializeFromParent(*this);
                        frameworkVersion->staticValidate(flags, SecRequirement::required(req));
                }
        }
@@ -1488,6 +1520,7 @@ void SecStaticCode::ValidationContext::reportProblem(OSStatus rc, CFStringRef ty
 
 void SecStaticCode::CollectingContext::reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value)
 {
+       StLock<Mutex> _(mLock);
        if (mStatus == errSecSuccess)
                mStatus = rc;                   // record first failure for eventual error return
        if (type) {
@@ -1535,6 +1568,13 @@ void SecStaticCode::staticValidate(SecCSFlags flags, const SecRequirement *req)
        this->staticValidateCore(flags, req);
        if (flags & kSecCSCheckAllArchitectures)
                handleOtherArchitectures(^(SecStaticCode* subcode) {
+                       if (flags & kSecCSCheckGatekeeperArchitectures) {
+                               Universal *fat = subcode->diskRep()->mainExecutableImage();
+                               assert(fat && fat->narrowed()); // handleOtherArchitectures gave us a focused architecture slice
+                               Architecture arch = fat->bestNativeArch();      // actually, the ONLY one
+                               if ((arch.cpuType() & ~CPU_ARCH_MASK) == CPU_TYPE_POWERPC)
+                                       return; // irrelevant to Gatekeeper
+                       }
                        subcode->detachedSignature(this->mDetachedSig); // carry over explicit (but not implicit) architecture
                        subcode->staticValidateCore(flags, req);
                });
index b9eac887de426f3b2e3256c5de7d06d9cb1fe229..90e0718c1f976a817fcfd7776b3e3ee4c46d4a49 100644 (file)
 #define _H_STATICCODE
 
 #include "cs.h"
+#include "csutilities.h"
 #include "Requirements.h"
 #include "requirement.h"
 #include "diskrep.h"
 #include "codedirectory.h"
 #include <Security/SecTrust.h>
 #include <CoreFoundation/CFData.h>
+#include <security_utilities/dispatch.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -93,8 +95,9 @@ protected:
        private:
                CFRef<CFMutableDictionaryRef> mCollection;
                OSStatus mStatus;
+               Mutex mLock;
        };
-       
+
 public:
        SECCFFUNCTIONS(SecStaticCode, SecStaticCodeRef,
                errSecCSInvalidObjectRef, gCFObjects().StaticCode)
@@ -105,7 +108,9 @@ public:
 
        SecStaticCode(DiskRep *rep);
     virtual ~SecStaticCode() throw();
-       
+
+    void initializeFromParent(const SecStaticCode& parent);
+
     bool equal(SecCFObject &other);
     CFHashCode hash();
        
@@ -231,7 +236,7 @@ private:
        unsigned mTotalWork;                            // total expected work (arbitrary units)
        unsigned mCurrentWork;                          // currently completed work
        bool mCancelPending;                            // cancellation was requested
-       Mutex mCancelLock;                                      // protects mCancelPending
+       Dispatch::Queue mProgressQueue;         // progress reporting queue
 
        // cached contents
        CFRef<CFDataRef> mDir;                          // code directory data
@@ -251,7 +256,9 @@ private:
        CFRef<CFURLRef> mResourceBase;          // URL form of resource base directory
 
        SecCodeCallback mMonitor;                       // registered monitor callback
-       
+
+       LimitedAsync *mLimitedAsync;            // limited async workers for verification
+
        // signature verification outcome (mTrust == NULL => not done yet)
        CFRef<SecTrustRef> mTrust;                      // outcome of crypto validation (valid or not)
        CFRef<CFArrayRef> mCertChain;
index aaf8bc0688178a34292e62e83919bacb13d26df9..b70059f1cc10dcd8eeaa4dc001722a00d1c964ed 100644 (file)
@@ -23,6 +23,7 @@
 #include "bundlediskrep.h"
 #include "filediskrep.h"
 #include "dirscanner.h"
+#include <CoreFoundation/CFBundlePriv.h>
 #include <CoreFoundation/CFURLAccess.h>
 #include <CoreFoundation/CFBundlePriv.h>
 #include <security_utilities/cfmunge.h>
@@ -64,6 +65,20 @@ BundleDiskRep::BundleDiskRep(CFBundleRef ref, const Context *ctx)
 BundleDiskRep::~BundleDiskRep()
 {
 }
+       
+void BundleDiskRep::checkMoved(CFURLRef oldPath, CFURLRef newPath)
+{
+       char cOld[PATH_MAX];
+       char cNew[PATH_MAX];
+       // The realpath call is important because alot of Framework bundles have a symlink
+       // to their "Current" version binary in the main bundle
+       if (realpath(cfString(oldPath).c_str(), cOld) == NULL ||
+               realpath(cfString(newPath).c_str(), cNew) == NULL)
+               MacOSError::throwMe(errSecCSInternalError);
+       
+       if (strcmp(cOld, cNew) != 0)
+               recordStrictError(errSecCSAmbiguousBundleFormat);
+}
 
 // common construction code
 void BundleDiskRep::setup(const Context *ctx)
@@ -72,10 +87,12 @@ void BundleDiskRep::setup(const Context *ctx)
 
        // capture the path of the main executable before descending into a specific version
        CFRef<CFURLRef> mainExecBefore = CFBundleCopyExecutableURL(mBundle);
+       CFRef<CFURLRef> infoPlistBefore = _CFBundleCopyInfoPlistURL(mBundle);
 
        // validate the bundle root; fish around for the desired framework version
        string root = cfStringRelease(copyCanonicalPath());
        string contents = root + "/Contents";
+       string supportFiles = root + "/Support Files";
        string version = root + "/Versions/"
                + ((ctx && ctx->version) ? ctx->version : "Current")
                + "/.";
@@ -88,6 +105,8 @@ void BundleDiskRep::setup(const Context *ctx)
                } catch (const MacOSError &err) {
                        recordStrictError(err.error);
                }
+       } else if (::access(supportFiles.c_str(), F_OK) == 0) { // ancient legacy boondoggle bundle
+               // treat like a shallow bundle; do not allow Versions arbitration
        } else if (::access(version.c_str(), F_OK) == 0) {      // versioned bundle
                if (CFBundleRef versionBundle = CFBundleCreate(NULL, CFTempURL(version)))
                        mBundle.take(versionBundle);    // replace top bundle ref
@@ -112,17 +131,12 @@ void BundleDiskRep::setup(const Context *ctx)
                        // That's because you know what you are doing if you are looking at a specific version.
                        // This check is designed to stop someone who did a verification on an app root, from mistakenly
                        // verifying a framework
-                       if (mainExecBefore && (!ctx || !ctx->version)) {
-                               char main_exec_before[PATH_MAX];
-                               char main_exec[PATH_MAX];
-                               // The realpath call is important because alot of Framework bundles have a symlink
-                               // to their "Current" version binary in the main bundle
-                               if (realpath(cfString(mainExecBefore).c_str(), main_exec_before) == NULL ||
-                                       realpath(cfString(mainExec).c_str(), main_exec) == NULL)
-                                       MacOSError::throwMe(errSecCSInternalError);
-
-                               if (strcmp(main_exec_before, main_exec) != 0)
-                                       recordStrictError(errSecCSAmbiguousBundleFormat);
+                       if (!ctx || !ctx->version) {
+                               if (mainExecBefore)
+                                       checkMoved(mainExecBefore, mainExec);
+                               if (infoPlistBefore)
+                                       if (CFRef<CFURLRef> infoDictPath = _CFBundleCopyInfoPlistURL(mBundle))
+                                               checkMoved(infoPlistBefore, infoDictPath);
                        }
 
                        mMainExecutableURL = mainExec;
index 6654239485c772f0e6d3903863fd0142d81f366b..3b810dd92f63964a64dd68c3b7721fb4eeea926f 100644 (file)
@@ -94,6 +94,7 @@ private:
        CFDataRef loadRegularFile(CFURLRef url);
        void recordStrictError(OSStatus error);
        void validateFrameworkRoot(std::string root);
+       void checkMoved(CFURLRef oldPath, CFURLRef newPath);
 
 private:
        CFRef<CFBundleRef> mBundle;
index 092ec1eddb60a8adb1a869c48de34686759c6cf3..dfa6e3a503002b2091085f7f3c61b93d0159a569 100644 (file)
@@ -219,5 +219,50 @@ void MessageTrace::send(const char *format, ...)
 }
 
 
+
+// Resource limited async workers for doing work on nested bundles
+LimitedAsync::LimitedAsync(bool async)
+{
+       // validate multiple resources concurrently if bundle resides on solid-state media
+
+       // How many async workers to spin off. If zero, validating only happens synchronously.
+       long async_workers = 0;
+
+       long ncpu = sysconf(_SC_NPROCESSORS_ONLN);
+
+       if (async && ncpu > 0)
+               async_workers = ncpu - 1; // one less because this thread also validates
+
+       mResourceSemaphore = new Dispatch::Semaphore(async_workers);
+}
+
+LimitedAsync::LimitedAsync(LimitedAsync &limitedAsync)
+{
+       mResourceSemaphore = new Dispatch::Semaphore(*limitedAsync.mResourceSemaphore);
+}
+
+LimitedAsync::~LimitedAsync()
+{
+       delete mResourceSemaphore;
+}
+
+bool LimitedAsync::perform(Dispatch::Group &groupRef, void (^block)()) {
+       __block Dispatch::SemaphoreWait wait(*mResourceSemaphore, DISPATCH_TIME_NOW);
+
+       if (wait.acquired()) {
+               dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+               groupRef.enqueue(defaultQueue, ^{
+                       // Hold the semaphore count until the worker is done validating.
+                       Dispatch::SemaphoreWait innerWait(wait);
+                       block();
+               });
+               return true;
+       } else {
+               block();
+               return false;
+       }
+}
+
 } // end namespace CodeSigning
 } // end namespace Security
index f9556a5aecf1d33f728be4981c4041badffcb990..6f039d4b5aed21542002496bddc6c83fd4e8ca7c 100644 (file)
@@ -31,6 +31,7 @@
 #define _H_CSUTILITIES
 
 #include <Security/Security.h>
+#include <security_utilities/dispatch.h>
 #include <security_utilities/hashing.h>
 #include <security_utilities/unix++.h>
 #include <security_cdsa_utilities/cssmdata.h>
@@ -170,6 +171,32 @@ private:
 };
 
 
+// This class provides resource limited parallelization,
+// used for work on nested bundles (e.g. signing or validating them).
+
+// We only spins off async workers if they are available right now,
+// otherwise we continue synchronously in the current thread.
+// This is important because we must progress at all times, otherwise
+// deeply nested bundles will deadlock on waiting for resource validation,
+// with no available workers to actually do so.
+// Their nested resources, however, may again spin off async workers if
+// available.
+
+class LimitedAsync {
+       NOCOPY(LimitedAsync)
+public:
+       LimitedAsync(bool async);
+       LimitedAsync(LimitedAsync& limitedAsync);
+       virtual ~LimitedAsync();
+
+       bool perform(Dispatch::Group &groupRef, void (^block)());
+
+private:
+       Dispatch::Semaphore *mResourceSemaphore;
+};
+
+
+
 } // end namespace CodeSigning
 } // end namespace Security
 
index 12756ab30e95adbcda9b8f1e4386d6bcd508b31c..0d16d74f265abc3465e8d87b8c8efde61c15972f 100644 (file)
@@ -183,7 +183,9 @@ bool DirValidator::Rule::matchTarget(const char *path, const char *target) const
        regex_t re;
        if (::regcomp(&re, pattern.c_str(), REG_EXTENDED | REG_NOSUB))
                MacOSError::throwMe(errSecCSInternalError);
-       switch (::regexec(&re, target, 0, NULL, 0)) {
+       int rv = ::regexec(&re, target, 0, NULL, 0);
+       ::regfree(&re);
+       switch (rv) {
        case 0:
                return true;
        case REG_NOMATCH:
diff --git a/Security/libsecurity_codesigning/lib/gkoverride.m b/Security/libsecurity_codesigning/lib/gkoverride.m
deleted file mode 100644 (file)
index 47a7066..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2014 Apple Inc. All Rights Reserved.
- * 
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-#import <Foundation/Foundation.h>
-#import <CrashReporterSupport/CrashReporterSupportPrivate.h>
-#import <sys/utsname.h>
-
-static bool useInternalServer() {
-       struct utsname name;
-       return ((uname(&name) == 0 && strstr(name.version, "DEVELOPMENT") != NULL)
-               && access("/var/db/gkoverride_use_internal", F_OK) == 0);
-}
-
-@interface OverrideClient : NSObject<NSURLConnectionDelegate> {
-       BOOL allow;
-       NSMutableData *buffer;
-       NSURLConnection *connection;
-       int state;
-}
-@property NSString *currentHash;
-@property NSString *opaqueHash;
-@property NSString *bundleID;
-@property NSString *bundleVersion;
-- (NSString *)serverHost;
-- (void)sendQuery;
-- (void)sendReport;
-- (void)abort;
-@end
-
-@implementation OverrideClient
-
-- (NSString *)serverHost {
-       if (useInternalServer())
-               return @"gkq-stg.siri.apple.com";
-       else
-               return @"gkq.apple.com";
-}
-
-- (id)init {
-       self = [super init];
-       allow = NO;
-       buffer = [NSMutableData new];
-       return self;
-}
-
-- (void)sendQuery {
-       state = 1;
-       NSMutableURLRequest *request = [NSMutableURLRequest new];
-       NSString *url = [NSString stringWithFormat:@"https://%@/q/%@/%@", [self serverHost], self.currentHash, self.opaqueHash];
-       [request setURL:[NSURL URLWithString:url]];
-       [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
-       [request setTimeoutInterval:5];
-       connection = [NSURLConnection connectionWithRequest:request delegate:self];
-}
-
-- (void)sendReport {
-       state = 2;
-       NSMutableURLRequest *request = [NSMutableURLRequest new];
-       NSString *body = [NSString stringWithFormat:@"current=%@&bundleid=%@&version=%@",
-               [self.currentHash stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
-               [self.bundleID stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
-               [self.bundleVersion stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
-       NSString *url = [NSString stringWithFormat:@"https://%@/report", [self serverHost]];
-       [request setURL:[NSURL URLWithString:url]];
-       [request setTimeoutInterval:5];
-       [request setHTTPMethod:@"POST"];
-       [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
-       connection = [NSURLConnection connectionWithRequest:request delegate:self];
-}
-
-- (BOOL)connection:(NSURLConnection *)conn canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
-       SecTrustRef trust = [protectionSpace serverTrust];
-       // abort if untrusted
-       SecTrustResultType trustResult;
-       SecTrustEvaluate(trust, &trustResult);
-       if (trustResult != kSecTrustResultProceed && trustResult != kSecTrustResultUnspecified) {
-               [conn cancel];
-               [self abort];
-               return NO;
-       }
-       // allow if server presented an EV cert
-       NSDictionary *result = CFBridgingRelease(SecTrustCopyResult(trust));
-       if (result) {
-               NSNumber *ev = [result objectForKey:(__bridge id)kSecTrustExtendedValidation];
-               if (ev != NULL && [ev boolValue] == YES) {
-                       return NO;
-               }
-       }
-       // allow if using internal server (EV not required)
-       if (useInternalServer())
-               return NO;
-       // otherwise abort
-       [conn cancel];
-       [self abort];
-       return NO;
-}
-
-- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
-       [buffer appendData:data];
-       if ([buffer length] > 100)
-               [self abort];
-}
-
-- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
-       if (state == 1) {
-               NSString *verdict = [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
-               if ([verdict isEqualToString:@"allow"]) {
-                       allow = YES;
-                       [self abort];
-               } else if (CRIsAutoSubmitEnabled()) {   // "Send diagnostic & usage data to Apple" checked
-                       [self sendReport];
-               }
-       } else {
-               [self abort];   // report sent
-       }
-}
-
-- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
-       [self abort];
-}
-
-- (void)abort {
-       if (allow) {
-               printf("allow\n");
-               exit(42);
-       } else {
-               printf("deny\n");
-               exit(1);
-       }
-}
-
-@end
-
-int main(int argc, const char * argv[]) {
-       if (argc != 5) {
-               fprintf(stderr, "usage: %s <current> <opaque> <bundleid> <version>\n", argv[0]);
-               return 1;
-       }
-       @autoreleasepool {
-               OverrideClient *client = [OverrideClient new];
-               client.currentHash = [NSString stringWithUTF8String:argv[1]];
-               client.opaqueHash = [NSString stringWithUTF8String:argv[2]];
-               client.bundleID = [NSString stringWithUTF8String:argv[3]];
-               client.bundleVersion = [NSString stringWithUTF8String:argv[4]];
-               [client sendQuery];
-               [[NSRunLoop currentRunLoop] run];
-       }
-       return 0;
-}
index e8f50afafeb9b623ad3f97a48a0ed3d70553e0f4..cf453ea31b8484e2f2f6a29e7ede8aa481da6673 100644 (file)
@@ -118,46 +118,8 @@ bool OpaqueWhitelist::contains(SecStaticCodeRef codeRef, SecAssessmentFeedback f
                }
        }
 
-       // prepare strings for use inside block
        std::string currentHash = hashString(current);
        std::string opaqueHash = hashString(opaque);
-       std::string identifier = code->identifier();
-       std::string longVersion = cfString(cfShortVersion) + " (" + cfString(cfVersion) + ")";
-
-       // check override killswitch
-       bool enableOverride = true;
-       SQLite::Statement killswitch(*this,
-               "SELECT 1 FROM whitelist"
-               " WHERE current='disable override'"
-               " OR (current=:current AND opaque='disable override')"
-               " LIMIT 1");
-       killswitch.bind(":current") = current.get();
-       if (killswitch.nextRow())
-               enableOverride = false;
-
-       // allow external program to override decision
-       __block bool override = false;
-       if (!match && enableOverride) {
-               dispatch_group_t group = dispatch_group_create();
-               dispatch_group_async(group, mOverrideQueue, ^{
-                       const char *argv[] = {
-                               "/usr/libexec/gkoverride",
-                               currentHash.c_str(),
-                               opaqueHash.c_str(),
-                               identifier.c_str(),
-                               longVersion.c_str(),
-                               NULL    // sentinel
-                       };
-                       int pid, status = 0;
-                       if (posix_spawn(&pid, argv[0], NULL, NULL, (char **)argv, NULL) == 0)
-                               if (waitpid(pid, &status, 0) == pid && WIFEXITED(status) && WEXITSTATUS(status) == 42)
-                                       override = true;
-               });
-               dispatch_group_wait(group, dispatch_walltime(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
-               dispatch_release(group);
-               if (override)
-                       match = true;
-       }
 
        // send a trace indicating the result
        MessageTrace trace("com.apple.security.assessment.whitelist2", code->identifier().c_str());
@@ -165,7 +127,6 @@ bool OpaqueWhitelist::contains(SecStaticCodeRef codeRef, SecAssessmentFeedback f
        trace.add("signature3", "%s", opaqueHash.c_str());
        trace.add("result", match ? "pass" : "fail");
        trace.add("reason", "%d", reason);
-       trace.add("override", "%d", override);
        if (!team.empty())
                trace.add("teamid", "%s", team.c_str());
        if (cfVersion)
index 286199b2533f33200cb9703fc64ba67ce438b13f..6e03d8f23789dcf13be0b2bc632acd5c8929484e 100644 (file)
@@ -144,7 +144,7 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author
                
                CFRef<SecRequirementRef> requirement;
                MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
-               switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly, requirement)) {
+               switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly | kSecCSCheckGatekeeperArchitectures, requirement)) {
                case errSecSuccess:
                        break;                                          // rule match; process below
                case errSecCSReqFailed:
index 8d26b6e1f4ec8b3f7e997d67f86d815cb428ebfc..8fffbb7f24afb2700dc6a57237d0748720c63141 100644 (file)
@@ -164,7 +164,7 @@ void ResourceBuilder::scan(Scanner next)
 
                        if (Rule *rule = findRule(relpath))
                                if (!(rule->flags & (omitted | exclusion)))
-                                       next(ent, rule->flags, relpath, rule);
+                                       next(ent, rule->flags, string(relpath), rule);
                        break;
                case FTS_SL:
                        // symlinks cannot ever be nested code, so quietly convert to resource file
@@ -176,7 +176,7 @@ void ResourceBuilder::scan(Scanner next)
                 
                        if (Rule *rule = findRule(relpath))
                                if (!(rule->flags & (omitted | exclusion)))
-                                       next(ent, rule->flags & ~nested, relpath, rule);
+                                       next(ent, rule->flags & ~nested, string(relpath), rule);
                        break;
                case FTS_D:
                        secdebug("rdirenum", "entering %s", ent->fts_path);
@@ -186,7 +186,7 @@ void ResourceBuilder::scan(Scanner next)
                                if (Rule *rule = findRule(relpath)) {
                                        if (rule->flags & nested) {
                                                if (strchr(ent->fts_name, '.')) {       // nested, has extension -> treat as nested bundle
-                                                       next(ent, rule->flags, relpath, rule);
+                                                       next(ent, rule->flags, string(relpath), rule);
                                                        fts_set(mFTS, ent, FTS_SKIP);
                                                }
                                        } else if (rule->flags & exclusion) {   // exclude the whole directory
index 05344a5060e1e5bf1c866720aef39778364a1f8b..e3a5475be643651d4b0b88dc1810f4612f8e0380 100644 (file)
@@ -80,7 +80,7 @@ public:
 
        static std::string escapeRE(const std::string &s);
        
-       typedef void (^Scanner)(FTSENT *ent, uint32_t flags, const char *relpath, Rule *rule);
+       typedef void (^Scanner)(FTSENT *ent, uint32_t flags, const std::string relpath, Rule *rule);
        void scan(Scanner next);
        bool includes(string path) const;
        Rule *findRule(string path) const;
index 59d0e05b67a6fbe002ed27645a21bb804b293971..68b02b39f9054decba7eeece4eaced798a78f6f3 100644 (file)
@@ -41,6 +41,8 @@
 #include <security_utilities/unix++.h>
 #include <security_utilities/unixchild.h>
 #include <security_utilities/cfmunge.h>
+#include <security_utilities/dispatch.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -284,6 +286,11 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase
        CFDictionaryRef rules = cfget<CFDictionaryRef>(rulesDict, "rules");
        assert(rules);
 
+       if (this->state.mLimitedAsync == NULL) {
+               this->state.mLimitedAsync =
+            new LimitedAsync(rep->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
+       }
+
        CFDictionaryRef files2 = NULL;
        if (!(state.signingFlags() & kSecCSSignV1)) {
                CFCopyRef<CFDictionaryRef> rules2 = cfget<CFDictionaryRef>(rulesDict, "rules2");
@@ -294,35 +301,48 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase
                                "'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories
                        "}", rules);
                }
+
+               Dispatch::Group group;
+               Dispatch::Group &groupRef = group;  // (into block)
+
                // build the modern (V2) resource seal
                __block CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
+               CFMutableDictionaryRef filesRef = files.get();  // (into block)
                ResourceBuilder resourceBuilder(root, relBase, rules2, digestAlgorithm(), strict, MacOSErrorSet());
                ResourceBuilder &resources = resourceBuilder;   // (into block)
                rep->adjustResources(resources);
-               resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, Rule *rule) {
-                       CFRef<CFMutableDictionaryRef> seal;
-                       if (ruleFlags & ResourceBuilder::nested) {
-                               seal.take(signNested(ent, relpath));
-                       } else if (ent->fts_info == FTS_SL) {
-                               char target[PATH_MAX];
-                               ssize_t len = ::readlink(ent->fts_accpath, target, sizeof(target)-1);
-                               if (len < 0)
-                                       UnixError::check(-1);
-                               target[len] = '\0';
-                               seal.take(cfmake<CFMutableDictionaryRef>("{symlink=%s}", target));
-                       } else {
-                               seal.take(cfmake<CFMutableDictionaryRef>("{hash=%O}",
-                                       CFRef<CFDataRef>(resources.hashFile(ent->fts_accpath)).get()));
-                       }
-                       if (ruleFlags & ResourceBuilder::optional)
-                               CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue);
-                       CFTypeRef hash;
-                       if ((hash = CFDictionaryGetValue(seal, CFSTR("hash"))) && CFDictionaryGetCount(seal) == 1) // simple form
-                               CFDictionaryAddValue(files, CFTempString(relpath).get(), hash);
-                       else
-                               CFDictionaryAddValue(files, CFTempString(relpath).get(), seal.get());
-                       code->reportProgress();
+
+               resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const std::string relpath, Rule *rule) {
+                       bool isSymlink = (ent->fts_info == FTS_SL);
+                       const std::string path(ent->fts_path);
+                       const std::string accpath(ent->fts_accpath);
+                       this->state.mLimitedAsync->perform(groupRef, ^{
+                               CFRef<CFMutableDictionaryRef> seal;
+                               if (ruleFlags & ResourceBuilder::nested) {
+                                       seal.take(signNested(path, relpath));
+                               } else if (isSymlink) {
+                                       char target[PATH_MAX];
+                                       ssize_t len = ::readlink(accpath.c_str(), target, sizeof(target)-1);
+                                       if (len < 0)
+                                               UnixError::check(-1);
+                                       target[len] = '\0';
+                                       seal.take(cfmake<CFMutableDictionaryRef>("{symlink=%s}", target));
+                               } else {
+                                       seal.take(cfmake<CFMutableDictionaryRef>("{hash=%O}",
+                                               CFRef<CFDataRef>(resources.hashFile(accpath.c_str())).get()));
+                               }
+                               if (ruleFlags & ResourceBuilder::optional)
+                                       CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue);
+                               CFTypeRef hash;
+                               StLock<Mutex> _(resourceLock);
+                               if ((hash = CFDictionaryGetValue(seal, CFSTR("hash"))) && CFDictionaryGetCount(seal) == 1) // simple form
+                                       CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), hash);
+                               else
+                                       CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), seal.get());
+                               code->reportProgress();
+                       });
                });
+               group.wait();
                CFDictionaryAddValue(result, CFSTR("rules2"), resourceBuilder.rules());
                files2 = files;
                CFDictionaryAddValue(result, CFSTR("files2"), files2);
@@ -335,7 +355,7 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase
                ResourceBuilder resourceBuilder(root, relBase, rules, digestAlgorithm(), strict, MacOSErrorSet());
                ResourceBuilder &resources = resourceBuilder;
                rep->adjustResources(resources);        // DiskRep-specific adjustments
-               resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, Rule *rule) {
+               resources.scan(^(FTSENT *ent, uint32_t ruleFlags, std::string relpath, Rule *rule) {
                        if (ent->fts_info == FTS_F) {
                                CFRef<CFDataRef> hash;
                                if (files2)     // try to get the hash from a previously-made version
@@ -348,12 +368,12 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase
                                if (!hash)
                                        hash.take(resources.hashFile(ent->fts_accpath));
                                if (ruleFlags == 0) {   // default case - plain hash
-                                       cfadd(files, "{%s=%O}", relpath, hash.get());
-                                       secdebug("csresource", "%s added simple (rule %p)", relpath, rule);
+                                       cfadd(files, "{%s=%O}", relpath.c_str(), hash.get());
+                                       secdebug("csresource", "%s added simple (rule %p)", relpath.c_str(), rule);
                                } else {        // more complicated - use a sub-dictionary
                                        cfadd(files, "{%s={hash=%O,optional=%B}}",
-                                               relpath, hash.get(), ruleFlags & ResourceBuilder::optional);
-                                       secdebug("csresource", "%s added complex (rule %p)", relpath, rule);
+                                               relpath.c_str(), hash.get(), ruleFlags & ResourceBuilder::optional);
+                                       secdebug("csresource", "%s added complex (rule %p)", relpath.c_str(), rule);
                                }
                        }
                });
@@ -368,11 +388,11 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase
 //
 // Deal with one piece of nested code
 //
-CFMutableDictionaryRef SecCodeSigner::Signer::signNested(FTSENT *ent, const char *relpath)
+CFMutableDictionaryRef SecCodeSigner::Signer::signNested(const std::string &path, const std::string &relpath)
 {
        // sign nested code and collect nesting information
        try {
-               SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(ent->fts_path));
+               SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(path));
                if (state.signingFlags() & kSecCSSignNestedCode)
                        this->state.sign(code, state.signingFlags());
                std::string dr = Dumper::dump(code->designatedRequirement());
index c7ac989cc5e06d9572cdef9d9c003ecf29e762b1..f3a8b9efde2f979bce611598db12bf40bab0cdca 100644 (file)
@@ -76,7 +76,7 @@ protected:
 
 protected:
        void buildResources(std::string root, std::string relBase, CFDictionaryRef rules);
-       CFMutableDictionaryRef signNested(FTSENT *ent, const char *relpath);
+       CFMutableDictionaryRef signNested(const std::string &path, const std::string &relpath);
        CFDataRef hashFile(const char *path);
 
 private:
@@ -91,6 +91,7 @@ private:
        size_t pagesize;                                // size of main executable pages
        CFAbsoluteTime signingTime;             // signing time for CMS signature (0 => none)
        bool strict;                                    // strict validation
+       Mutex resourceLock;
 };
 
 
index bd92c79deaec56c57aca594b3366389467141c74..8dca872dc97879da49630f3201249b9a9e1631b4 100644 (file)
                18B965951472FE30005A4D2E /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
                37DDE33C1947A4F3005CE18B /* dirscanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 37DDE33B1947A4F3005CE18B /* dirscanner.h */; };
                37DDE3421947A501005CE18B /* dirscanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE3411947A501005CE18B /* dirscanner.cpp */; };
-               48674DE319EC9E610049EB7D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48674DE219EC9E610049EB7D /* Security.framework */; };
-               7A4FAF1B19C215DF00D297CB /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A4FAF1A19C215DF00D297CB /* CrashReporterSupport.framework */; };
                7A9DA65C1948D1BA004635E6 /* opaquewhitelist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */; };
                7A9DA65D1948D1BA004635E6 /* opaquewhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */; };
-               7AADF58919C0CED800292339 /* gkoverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AADF58819C0CED800292339 /* gkoverride.m */; };
                7ACF261219958B6F00849B25 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */; };
                BEC3A75C16F78D21003E5634 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */; };
                C200424D15D425D9004AE0A1 /* libsecurity_codesigning.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */; };
                C2F4439A14C626D4000A01E6 /* quarantine++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F4439814C626D4000A01E6 /* quarantine++.cpp */; };
                C2F4439B14C626D4000A01E6 /* quarantine++.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F4439914C626D4000A01E6 /* quarantine++.h */; };
                C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F6566C0BCBFB250078779E /* cserror.cpp */; };
+               CD97D27C1A2D2BFE00AE62B7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD97D27B1A2D2BFE00AE62B7 /* Security.framework */; };
                EB68B111150DAEEA00B4013D /* RequirementLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB68B10B150DAEBB00B4013D /* RequirementLexer.cpp */; };
                EB68B112150DAEEA00B4013D /* RequirementParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB68B10D150DAEBB00B4013D /* RequirementParser.cpp */; };
                EB68B133150DB04400B4013D /* RequirementKeywords.h in Headers */ = {isa = PBXBuildFile; fileRef = EB68B10A150DAEBB00B4013D /* RequirementKeywords.h */; };
                184461A2146E9AD100B12992 /* release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = "<group>"; };
                37DDE33B1947A4F3005CE18B /* dirscanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirscanner.h; sourceTree = "<group>"; };
                37DDE3411947A501005CE18B /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = "<group>"; };
-               48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = "../../../Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos/Security.framework"; sourceTree = "<group>"; };
+               48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.Internal.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
                4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurity_codesigning.a; sourceTree = BUILT_PRODUCTS_DIR; };
                7A4FAF1A19C215DF00D297CB /* CrashReporterSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporterSupport.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.Internal.sdk/System/Library/PrivateFrameworks/CrashReporterSupport.framework; sourceTree = DEVELOPER_DIR; };
                7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaquewhitelist.cpp; sourceTree = "<group>"; };
                7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opaquewhitelist.h; sourceTree = "<group>"; };
-               7AADF57D19C0CE8C00292339 /* gkoverride */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gkoverride; sourceTree = BUILT_PRODUCTS_DIR; };
-               7AADF58819C0CED800292339 /* gkoverride.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = gkoverride.m; sourceTree = "<group>"; };
                BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTaskPriv.h; sourceTree = "<group>"; };
                C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_codesigning.a; path = ../../../usr/local/lib/libsecurity_codesigning.a; sourceTree = "<group>"; };
                C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; path = ../../../usr/local/lib/libsecurity_utilities.a; sourceTree = "<group>"; };
                C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqdumper.h; sourceTree = "<group>"; };
                C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeSigner.cpp; sourceTree = "<group>"; };
                C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeSigner.h; sourceTree = "<group>"; };
-               C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = "<group>"; };
-               C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = "<group>"; };
+               C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = "<group>"; usesTabs = 1; };
+               C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = "<group>"; usesTabs = 1; };
                C235340E145F1B050073F964 /* xar++.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xar++.h"; sourceTree = "<group>"; };
                C2353410145F1B110073F964 /* xar++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "xar++.cpp"; sourceTree = "<group>"; };
-               C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = "<group>"; };
-               C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = "<group>"; };
+               C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = "<group>"; usesTabs = 1; };
+               C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = "<group>"; usesTabs = 1; };
                C236E3D90AD595C2000F5140 /* signerutils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signerutils.cpp; sourceTree = "<group>"; };
                C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = "<group>"; };
                C24EABAA1421432800C16AA9 /* policydb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policydb.h; sourceTree = "<group>"; };
                C293E2C21554653700F3E396 /* sp-watch.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "sp-watch.d"; path = "dtrace/sp-watch.d"; sourceTree = SOURCE_ROOT; };
                C2A436130F2133B2007A41A6 /* slcrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slcrep.cpp; sourceTree = "<group>"; };
                C2A436140F2133B2007A41A6 /* slcrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slcrep.h; sourceTree = "<group>"; };
-               C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = "<group>"; };
-               C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = "<group>"; };
+               C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = "<group>"; usesTabs = 1; };
+               C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = "<group>"; usesTabs = 1; };
                C2BC1F260B580D3A003EC9DC /* libintegrity.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libintegrity.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcodehost.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeHostLib.h; sourceTree = "<group>"; };
                C2D3832E0A237F47005C63A2 /* Code.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Code.h; sourceTree = "<group>"; };
                C2D3832F0A237F47005C63A2 /* kerneldiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = kerneldiskrep.cpp; sourceTree = "<group>"; };
                C2D383300A237F47005C63A2 /* kerneldiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kerneldiskrep.h; sourceTree = "<group>"; };
-               C2D383310A237F47005C63A2 /* StaticCode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StaticCode.cpp; sourceTree = "<group>"; };
-               C2D383320A237F47005C63A2 /* StaticCode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StaticCode.h; sourceTree = "<group>"; };
+               C2D383310A237F47005C63A2 /* StaticCode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StaticCode.cpp; sourceTree = "<group>"; usesTabs = 1; };
+               C2D383320A237F47005C63A2 /* StaticCode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StaticCode.h; sourceTree = "<group>"; usesTabs = 1; };
                C2D383330A237F47005C63A2 /* reqparser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqparser.cpp; sourceTree = "<group>"; };
                C2D383340A237F47005C63A2 /* reqparser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqparser.h; sourceTree = "<group>"; };
                C2D383350A237F47005C63A2 /* requirement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = requirement.cpp; sourceTree = "<group>"; };
                C2F6071B107D575700A83618 /* codesign-watch.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "codesign-watch.d"; path = "dtrace/codesign-watch.d"; sourceTree = SOURCE_ROOT; };
                C2F6566C0BCBFB250078779E /* cserror.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cserror.cpp; sourceTree = "<group>"; };
                C2F6566D0BCBFB250078779E /* cserror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cserror.h; sourceTree = "<group>"; };
+               CD97D27B1A2D2BFE00AE62B7 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Security.framework; sourceTree = "<group>"; };
                EB68B10A150DAEBB00B4013D /* RequirementKeywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequirementKeywords.h; sourceTree = "<group>"; };
                EB68B10B150DAEBB00B4013D /* RequirementLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RequirementLexer.cpp; sourceTree = "<group>"; };
                EB68B10C150DAEBB00B4013D /* RequirementLexer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RequirementLexer.hpp; sourceTree = "<group>"; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               7AADF57A19C0CE8C00292339 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               48674DE319EC9E610049EB7D /* Security.framework in Frameworks */,
-                               7A4FAF1B19C215DF00D297CB /* CrashReporterSupport.framework in Frameworks */,
+                               CD97D27C1A2D2BFE00AE62B7 /* Security.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */,
                                C209696015BF52040093035F /* gkunpack */,
                                EBB9FF6F1682E51300FF9774 /* com.apple.CodeSigningHelper.xpc */,
-                               7AADF57D19C0CE8C00292339 /* gkoverride */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                C27360D71436868600A9A5FF /* xpcengine.h */,
                                C27360D41436866C00A9A5FF /* xpcengine.cpp */,
                                C27249D2143237CD0058B552 /* syspolicy.sql */,
-                               7AADF58819C0CED800292339 /* gkoverride.m */,
                        );
                        name = "System Policy";
                        sourceTree = "<group>";
                        productReference = 4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */;
                        productType = "com.apple.product-type.library.static";
                };
-               7AADF57C19C0CE8C00292339 /* gkoverride */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 7AADF58719C0CE8C00292339 /* Build configuration list for PBXNativeTarget "gkoverride" */;
-                       buildPhases = (
-                               7AADF57919C0CE8C00292339 /* Sources */,
-                               7AADF57A19C0CE8C00292339 /* Frameworks */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = gkoverride;
-                       productName = gkoverride;
-                       productReference = 7AADF57D19C0CE8C00292339 /* gkoverride */;
-                       productType = "com.apple.product-type.tool";
-               };
                C209695F15BF52040093035F /* gkunpack */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = C209696B15BF52040093035F /* Build configuration list for PBXNativeTarget "gkunpack" */;
                        isa = PBXProject;
                        attributes = {
                                LastUpgradeCheck = 0500;
-                               TargetAttributes = {
-                                       7AADF57C19C0CE8C00292339 = {
-                                               CreatedOnToolsVersion = 6.0;
-                                       };
-                               };
                        };
                        buildConfigurationList = C263E67909A2971B000043F1 /* Build configuration list for PBXProject "libsecurity_codesigning" */;
                        compatibilityVersion = "Xcode 3.2";
                                C26AC7090DAEB3A7005BFB40 /* DTrace */,
                                C26AC0EB143BCF01001C98CE /* SystemPolicy */,
                                C209695F15BF52040093035F /* gkunpack */,
-                               7AADF57C19C0CE8C00292339 /* gkoverride */,
                                EBB9FF6E1682E51300FF9774 /* CodeSigningHelper */,
                        );
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               7AADF57919C0CE8C00292339 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               7AADF58919C0CED800292339 /* gkoverride.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                C209695C15BF52040093035F /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
-               7AADF58119C0CE8C00292339 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = NO;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               COPY_PHASE_STRIP = NO;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
-                                       "/Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos",
-                               );
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = /usr/libexec;
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               ONLY_ACTIVE_ARCH = YES;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               SDKROOT = macosx.internal;
-                               SKIP_INSTALL = NO;
-                       };
-                       name = Debug;
-               };
-               7AADF58219C0CE8C00292339 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_MODULES = NO;
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_BOOL_CONVERSION = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               COPY_PHASE_STRIP = YES;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               ENABLE_NS_ASSERTIONS = NO;
-                               ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
-                                       "/Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos",
-                               );
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_UNDECLARED_SELECTOR = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = /usr/libexec;
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               SDKROOT = macosx.internal;
-                               SKIP_INSTALL = NO;
-                       };
-                       name = Release;
-               };
                C209696C15BF52040093035F /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-               7AADF58719C0CE8C00292339 /* Build configuration list for PBXNativeTarget "gkoverride" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               7AADF58119C0CE8C00292339 /* Debug */,
-                               7AADF58219C0CE8C00292339 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                C209696B15BF52040093035F /* Build configuration list for PBXNativeTarget "gkunpack" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
index 87fe7af3cd056a19a11db30a6b718a02707ce82f..537b92b754f65c69ee0d62f7e81da422ca03980f 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2015 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -2157,7 +2157,7 @@ _SafeSecKeychainItemDelete(
        CFArrayRef appList = NULL;
        CFStringRef description = NULL;
        CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
-       CFIndex count = 0;
+       CFIndex idx, count = 0;
        SecTrustedApplicationRef currentAppRef = NULL;
        CFStringRef itemAppName = NULL, currentAppName = NULL;
 
@@ -2205,37 +2205,41 @@ _SafeSecKeychainItemDelete(
        require_noerr(status, finish);
        require_quiet(appList != NULL, finish);
 
-       // does only a single application/tool have decrypt access to this item?
+       // does the calling application/tool have decrypt access to this item?
        count = CFArrayGetCount(appList);
-       if ( count == 1 ) {
-               // get SecTrustedApplicationRef for item's application/tool
-               SecTrustedApplicationRef itemAppRef = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(appList, 0);
+       for ( idx = 0; idx < count; idx++ ) {
+               // get SecTrustedApplicationRef for this entry
+               SecTrustedApplicationRef itemAppRef = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(appList, idx);
                require_quiet(itemAppRef != NULL, finish);
 
                // copy the name out
+               CFReleaseSafe(itemAppName);
                itemAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), itemAppRef);
                if (itemAppName == NULL) {
                        /*
                         * If there is no app name, it's probably because it's not an appname
                         * in the ACE but an entitlement/info.plist based rule instead;
                         * just let the caller have it. */
-                       count--;
+                       count = 0;
                        goto finish;
                }
 
                // create SecTrustedApplicationRef for current application/tool
+               CFReleaseSafe(currentAppRef);
                status = SecTrustedApplicationCreateFromPath(NULL, &currentAppRef);
                require_noerr(status, finish);
                require_quiet(currentAppRef != NULL, finish);
 
                // copy the name out
+               CFReleaseSafe(currentAppName);
                currentAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), currentAppRef);
                require_quiet(currentAppName != NULL, finish);
 
                // compare the names to see if we own the decrypt access
+               // TBD: validation of membership in an application group
                if ( CFStringCompare(currentAppName, itemAppName, 0) == kCFCompareEqualTo ) {
-                       // decrement the count to zero, which will remove the item below
-                       --count;
+                       count = 0;
+                       goto finish;
                }
        }
 
@@ -2260,6 +2264,142 @@ finish:
        return status;
 }
 
+static OSStatus
+_ReplaceKeychainItem(
+       SecKeychainItemRef itemToUpdate,
+       SecKeychainAttributeList *changeAttrList,
+       CFDataRef itemData)
+{
+       OSStatus status;
+       UInt32 itemID;
+       SecItemClass itemClass;
+       SecKeychainAttributeInfo *info = NULL;
+       SecKeychainAttributeList *attrList = NULL;
+       SecKeychainAttributeList newAttrList = { 0, NULL};
+       SecKeychainRef keychain = NULL;
+       SecKeychainItemRef newItem = NULL;
+
+       int priority = LOG_DEBUG;
+       const char *format = "ReplaceKeychainItem (%d) error %d";
+
+       // get existing item's keychain
+       status = SecKeychainItemCopyKeychain(itemToUpdate, &keychain);
+       if (status) { secitemlog(priority, format, 1, (int)status); }
+       require_noerr(status, replace_failed);
+
+       // get attribute info (i.e. database schema) for the item class
+       status = SecKeychainItemCopyAttributesAndData(itemToUpdate, NULL, &itemClass, NULL, NULL, NULL);
+       if (status) { secitemlog(priority, format, 2, (int)status); }
+       require_noerr(status, replace_failed);
+
+       switch (itemClass)
+       {
+               case kSecInternetPasswordItemClass:
+                       itemID = CSSM_DL_DB_RECORD_INTERNET_PASSWORD;
+                       break;
+               case kSecGenericPasswordItemClass:
+                       itemID = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
+                       break;
+               default:
+                       itemID = itemClass;
+                       break;
+       }
+       status = SecKeychainAttributeInfoForItemID(keychain, itemID, &info);
+       if (status) { secitemlog(priority, format, 3, (int)status); }
+
+       // get item's existing attributes (but not data!)
+       status = SecKeychainItemCopyAttributesAndData(itemToUpdate, info, &itemClass, &attrList, NULL, NULL);
+       if (status) { secitemlog(priority, format, 4, (int)status); }
+       require(attrList != NULL, replace_failed);
+
+       // move aside the item by changing a primary attribute
+    // (currently only for passwords)
+       if (itemClass == kSecInternetPasswordItemClass || itemClass == kSecGenericPasswordItemClass) {
+               CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
+               CFStringRef uuidStr = (uuid) ? CFUUIDCreateString(kCFAllocatorDefault, uuid) : CFSTR("MOVED");
+               CFReleaseSafe(uuid);
+               if (uuidStr) {
+                       CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr), kCFStringEncodingUTF8) + 1;
+                       char* buffer = (char*) malloc(maxLength);
+                       if (buffer) {
+                               if (CFStringGetCString(uuidStr, buffer, maxLength, kCFStringEncodingUTF8)) {
+                                       UInt32 length = (UInt32)strlen(buffer);
+                                       SecKeychainAttribute attrs[] = { { kSecAccountItemAttr, length, (char*)buffer }, };
+                                       SecKeychainAttributeList updateAttrList = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+                                       status = SecKeychainItemModifyAttributesAndData(itemToUpdate, &updateAttrList, 0, NULL);
+                                       if (status) { secitemlog(priority, format, 5, (int)status); }
+                                       if (status == errSecVerifyFailed) {
+                                               // still unable to change attrs? delete unconditionally here
+                                               status = SecKeychainItemDelete(itemToUpdate);
+                                               if (status) { secitemlog(priority, format, 6, (int)status); }
+                                       }
+                               }
+                               free(buffer);
+                       }
+                       CFReleaseSafe(uuidStr);
+               }
+       }
+       require_noerr(status, replace_failed);
+
+       // make attribute list for new item (the data is still owned by attrList)
+       newAttrList.count = attrList->count;
+       newAttrList.attr = (SecKeychainAttribute *) malloc(sizeof(SecKeychainAttribute) * attrList->count);
+       int i, newCount;
+       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;
+
+       // create new item in the same keychain
+       status = SecKeychainItemCreateFromContent(itemClass, &newAttrList,
+               (UInt32)((itemData) ? CFDataGetLength(itemData) : 0),
+               (const void *)((itemData) ? CFDataGetBytePtr(itemData) : NULL),
+               keychain, NULL, &newItem);
+       if (status) { secitemlog(priority, format, 7, (int)status); }
+       require_noerr(status, replace_failed);
+
+       // delete the old item unconditionally once new item exists
+       status = SecKeychainItemDelete(itemToUpdate);
+
+       // update the new item with changed attributes, if any
+       status = (changeAttrList) ? SecKeychainItemModifyContent(newItem, changeAttrList, 0, NULL) : errSecSuccess;
+       if (status) { secitemlog(priority, format, 8, (int)status); }
+       if (status == errSecSuccess) {
+               // say the item already exists, because it does now. <rdar://19063674>
+               status = errSecDuplicateItem;
+       }
+
+replace_failed:
+       if (newAttrList.attr) {
+               free(newAttrList.attr);
+       }
+    if (attrList) {
+        SecKeychainItemFreeAttributesAndData(attrList, NULL);
+    }
+    if (info) {
+        SecKeychainFreeAttributeInfo(info);
+    }
+       CFReleaseSafe(newItem);
+       CFReleaseSafe(keychain);
+
+       return status;
+}
+
 static OSStatus
 _UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes)
 {
@@ -2357,6 +2497,7 @@ _UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes)
                                (changeAttrList->count == 0) ? NULL : changeAttrList,
                                (theData != NULL) ? (UInt32)CFDataGetLength(theData) : 0,
                                (theData != NULL) ? CFDataGetBytePtrVoid(theData) : NULL);
+       require_noerr(status, update_failed);
 
        // one more thing... update access?
        if (CFDictionaryGetValueIfPresent(changedAttributes, kSecAttrAccess, (const void **)&access)) {
@@ -2364,6 +2505,13 @@ _UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes)
        }
 
 update_failed:
+       if (status == errSecVerifyFailed &&
+               (itemClass == kSecInternetPasswordItemClass || itemClass == kSecGenericPasswordItemClass)) {
+               // if we got a cryptographic failure updating a password item, it needs to be replaced
+               status = _ReplaceKeychainItem(itemToUpdate,
+                                       (changeAttrList->count == 0) ? NULL : changeAttrList,
+                                       theData);
+       }
        if (itemToUpdate)
                CFRelease(itemToUpdate);
        _FreeAttrList(changeAttrList);
index 0c56946dbea102697233b5214fa0fe6eed4b190b..94a580926913a5211a9dd4ffd890a362bd3e00a3 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2002-2014 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
index a4ee4e7be1fb7cef763b9b28c574e7437854ebb3..ac0b795212ace5138d3156c79ce5f206a4421d97 100644 (file)
@@ -147,7 +147,7 @@ extern CFTypeRef kSecTrustResultDetails
 /* OCSP and CRL style keys, followed by values used for both of them */
 #define kSecRevocationOcspStyle                                CFSTR("OCSPStyle")
 #define kSecRevocationCrlStyle                         CFSTR("CRLStyle")
-  #define kSecRevocationOff                                    CFSTR("None")   /* default for each one */
+  #define kSecRevocationOff                                    CFSTR("None")
   #define kSecRevocationBestAttempt                    CFSTR("BestAttempt")
   #define kSecRevocationRequireIfPresent       CFSTR("RequireIfPresent")
   #define kSecRevocationRequireForAll          CFSTR("RequireForAll")
index 1a6f96c269a0d85ec52320dee5c5948d975512ee..04a27c24fbc781baa63c351eb679b9b8e3f53b58 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2002-2014 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -148,7 +148,7 @@ Trust::~Trust()
        if (mSearchLibs) {
                delete mSearchLibs;
        }
-    
+
     mPolicies = NULL;
 }
 
@@ -307,13 +307,16 @@ void Trust::evaluate(bool disableEV)
                context.actionData() = localActionCData;
        }
 
+       bool hasSSLPolicy = policySpecified(mPolicies, CSSMOID_APPLE_TP_SSL);
+       bool hasEAPPolicy = policySpecified(mPolicies, CSSMOID_APPLE_TP_EAP);
+
        if (!mAnchors) {
                // always check trust settings if caller did not provide explicit trust anchors
                actionDataP->ActionFlags |= CSSM_TP_ACTION_TRUST_SETTINGS;
        }
 
        if (mNetworkPolicy == useNetworkDefault) {
-               if (policySpecified(mPolicies, CSSMOID_APPLE_TP_SSL)) {
+               if (hasSSLPolicy) {
                        // enable network cert fetch for SSL only: <rdar://7422356>
                        actionDataP->ActionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
                }
@@ -330,7 +333,6 @@ void Trust::evaluate(bool disableEV)
        CFMutableArrayRef allPolicies = NULL;
        uint32 numRevocationAdded = 0;
        bool requirePerCert = (actionDataP->ActionFlags & CSSM_TP_ACTION_REQUIRE_REV_PER_CERT);
-       bool avoidRevChecks = (policySpecified(mPolicies, CSSMOID_APPLE_TP_EAP));
 
        // If a new unified revocation policy was explicitly specified,
        // convert into old-style individual OCSP and CRL policies.
@@ -354,16 +356,16 @@ void Trust::evaluate(bool disableEV)
                allPolicies = NULL; // use only mPolicies
                isEVCandidate = false;
        }
-       else if ((isEVCandidate && !avoidRevChecks) || requirePerCert) {
+       else if (isEVCandidate || requirePerCert) {
                // force revocation checking for this evaluation
                secdebug("evTrust", "Trust::evaluate() forcing OCSP/CRL revocation check");
-               allPolicies = forceRevocationPolicies(numRevocationAdded,
-                       context.allocator, requirePerCert);
+               allPolicies = forceRevocationPolicies(true, requirePerCert,
+                       numRevocationAdded, context.allocator, requirePerCert);
        }
-       else if(!(revocationPolicySpecified(mPolicies)) && !avoidRevChecks) {
+       else if(!(revocationPolicySpecified(mPolicies))) {
                // none specified in mPolicies; try preferences
-               allPolicies = addPreferenceRevocationPolicies(numRevocationAdded,
-                       context.allocator);
+               allPolicies = addPreferenceRevocationPolicies(!(hasSSLPolicy || hasEAPPolicy),
+                       !(hasSSLPolicy || hasEAPPolicy), numRevocationAdded, context.allocator);
        }
        if (allPolicies == NULL) {
                // use mPolicies; no revocation checking will be performed
index ad7662b836e374f557dddb8276badfed8f9ea701..1df98146ef98ca22ab1274b44ead7a7d7aed2ef4 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2002-2014 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -122,7 +122,10 @@ private:
        Keychain keychainByDLDb(const CSSM_DL_DB_HANDLE &handle);
 
        /* revocation policy support */
-       CFMutableArrayRef       addPreferenceRevocationPolicies(uint32 &numAdded,
+       CFMutableArrayRef       addPreferenceRevocationPolicies(
+                                                       bool ocspEnabledOnBestAttempt,
+                                                       bool crlEnabledOnBestAttempt,
+                                                       uint32 &numAdded,
                                                        Allocator &alloc);
        void                            freeAddedRevocationPolicyData(CFArrayRef policies,
                                                        uint32 numAdded,
@@ -134,7 +137,10 @@ public:
        bool                            revocationPolicySpecified(CFArrayRef policies);
        void                            orderRevocationPolicies(CFMutableArrayRef policies);
        CFMutableArrayRef       convertRevocationPolicy(uint32 &numAdded, Allocator &alloc);
-       CFMutableArrayRef       forceRevocationPolicies(uint32 &numAdded,
+       CFMutableArrayRef       forceRevocationPolicies(
+                                                       bool ocspEnabled,
+                                                       bool crlEnabled,
+                                                       uint32 &numAdded,
                                                        Allocator &alloc,
                                                        bool requirePerCert=false);
 
index 591ff209766e592ded8b36344a1ae71919e9e736..3202d2fb0cefaaa04186d2eec7156fecd50aca37 100644 (file)
@@ -243,6 +243,8 @@ CFDictionaryRef Trust::defaultRevocationSettings()
 }
 
 CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
+       bool ocspEnabledOnBestAttempt,
+       bool crlEnabledOnBestAttempt,
        uint32 &numAdded,
        Allocator &alloc)
 {
@@ -294,6 +296,9 @@ CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
                if(ocspStyle != kSecDisabled) {
                        doOcsp = true;
                }
+               if(ocspStyle == kSecBestAttempt) {
+                       doOcsp = ocspEnabledOnBestAttempt;
+               }
        }
        val = prefsDict->getStringValue(kSecRevocationCrlStyle);
        if(val != NULL) {
@@ -301,7 +306,11 @@ CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
                if(crlStyle != kSecDisabled) {
                        doCrl = true;
                }
+               if(crlStyle == kSecBestAttempt) {
+                       doCrl = crlEnabledOnBestAttempt;
+               }
        }
+
        if(!doCrl && !doOcsp) {
                return NULL;
        }
@@ -423,8 +432,7 @@ CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
                }
 
        }
-       else {
-               assert(doCrl);
+       else if(doCrl) {
                CFArrayAppendValue(policies, crlPolicy->handle(false));
        }
        return policies;
@@ -581,6 +589,8 @@ void Trust::orderRevocationPolicies(
  * Caller is responsible for releasing the returned policies array.
  */
 CFMutableArrayRef Trust::forceRevocationPolicies(
+       bool ocspEnabled,
+       bool crlEnabled,
        uint32 &numAdded,
        Allocator &alloc,
        bool requirePerCert)
@@ -644,7 +654,7 @@ CFMutableArrayRef Trust::forceRevocationPolicies(
                throw std::bad_alloc();
        }
 
-       if(!hasOcspPolicy) {
+       if(!hasOcspPolicy && ocspEnabled) {
                /* Cook up a new Policy object */
                ocspPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP));
                CSSM_APPLE_TP_OCSP_OPTIONS opts;
@@ -698,7 +708,7 @@ CFMutableArrayRef Trust::forceRevocationPolicies(
                        delete prefsDict;
        }
 
-       if(!hasCrlPolicy) {
+       if(!hasCrlPolicy && crlEnabled) {
                /* Cook up a new Policy object */
                crlPolicy = new Policy(mTP, CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL));
                CSSM_APPLE_TP_CRL_OPTIONS opts;
index a92e956bede76197afe7499b3b6cef5839bcdff3..1d2db8337b975bcfd3a3648ab6639f61cc93cb93 100644 (file)
@@ -195,6 +195,8 @@ static void printDataAsHex(const char *title, const CSSM_DATA *d, unsigned maxTo
 
 //    fprintf(stderr, "%s", buffer);
     dtprintf("%s", buffer);
+
+    free(buffer);
 #endif
 }
 
@@ -336,6 +338,7 @@ static void debugShowSignerInfo(SecCmsSignedDataRef signedData)
                 dtprintf("%s%s\n", signerhdr, cn);
                 if (cn)
                     free(cn);
+                CFReleaseNull(commonName);
             }
             else
                 dtprintf("%s<NULL>\n", signerhdr);
@@ -889,6 +892,8 @@ static OSStatus SecTSAValidateTimestamp(const SecAsn1TSATSTInfo *tstInfo, CSSM_D
     if (timestampTime)
         *timestampTime = genTime;
 xit:
+    if (signingCertificate)
+        CFReleaseNull(signingCertificate);
     return result;
 }
 
@@ -1014,6 +1019,7 @@ static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigner
     // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
     // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
 
+    SecTrustRef trustRef = NULL;
     CFTypeRef policy = CFRetainSafe(timeStampPolicy);
     int result=errSecInternalError;
     int rx;
@@ -1026,7 +1032,6 @@ static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigner
     for (jx = 0; jx < numberOfSigners; ++jx)
     {
         SecTrustResultType trustResultType;
-        SecTrustRef trustRef = NULL;
         CFDictionaryRef extendedResult = NULL;
         CFArrayRef certChain = NULL;
         uint16_t certCount = 0;
@@ -1082,6 +1087,7 @@ static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigner
         dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__,rx, trustResultType);
         certCount = certChain?CFArrayGetCount(certChain):0;
         debugShowCertEvidenceInfo(certCount, statusChain);
+        CFReleaseNull(certChain);
 
         rx = SecTrustCopyExtendedResult(trustRef, &extendedResult);
         dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__, rx);
@@ -1092,12 +1098,14 @@ static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigner
         }
 
         if (trustRef)
-            CFRelease (trustRef);
+            CFReleaseNull(trustRef);
      }
 
 xit:
+    if (trustRef)
+        CFReleaseNull(trustRef);
     if (policy)
-        CFRelease (policy);
+        CFRelease(policy);
     return result;
 }
 
index 7d743c592ea91231ab83a3b69c992a91271a4098..7c9296a85eea0939260e4f7bbe5d5a0700d587b0 100644 (file)
@@ -470,6 +470,7 @@ static void tests(void)
 {
     CFArrayRef certs = NULL;
     CFDataRef message;
+    CFIndex count;
 
     // Premade message containing one certificate blob
     message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
@@ -504,7 +505,11 @@ static void tests(void)
     ok(message = SecCMSCreateCertificatesOnlyMessageIAP(another_cert), "create iAP specific cert only message (2certs)");
     ok(certs = SecCMSCertificatesOnlyMessageCopyCertificates(message),
        "SecCMSCertificatesOnlyMessageCopyCertificates");
-    is(CFArrayGetCount(certs), 2, "certificate count is 2");
+    // %%% SecCMSCreateCertificatesOnlyMessageIAP should be changed to take a CFArrayRef argument.
+    // Note that a SecCertificateRef can only contain the data of a single certificate.
+    // If the fix for rdar://17159227 is present, the message will only contain one certificate.
+    count = (certs) ? CFArrayGetCount(certs) : 0;
+    ok(count > 0 && count < 3, "certificate count is 1 or 2");
 
     // Clean up
     CFReleaseNull(another_cert);
index 826fdaf2471270baa9bab9370740e1ef751dca94..b4161e70afd923ec9af7ae490a1563ca2f367b74 100644 (file)
@@ -292,7 +292,7 @@ SSLDisposeContext                           (SSLContextRef context)
        return errSecSuccess;
 }
 
-CFStringRef SSLContextCopyDescription(CFTypeRef arg)
+CFStringRef SSLContextCopyFormatDescription(CFTypeRef arg, CFDictionaryRef formatOptions)
 {
     SSLContext* ctx = (SSLContext*) arg;
 
index 07457375e2a529cacf9111c6e4aab18c8f948e75..600916ccac931767571eb040a1a4884a10f8f191 100644 (file)
@@ -187,13 +187,17 @@ static OSStatus sslVerifyCertChain(
        OSStatus status;
        SecTrustRef trust = NULL;
 
-    assert(certChain);
-
     if (arePeerCerts) {
                /* renegotiate - start with a new SecTrustRef */
         CFReleaseNull(ctx->peerSecTrust);
     }
 
+    if(certChain==NULL) {
+        sslErrorLog("***Error: NULL cert chain\n");
+        status = errSSLXCertChainInvalid;
+        goto errOut;
+    }
+
        status = sslCreateSecTrust(ctx, certChain, arePeerCerts, &trust);
 
        if (!ctx->enableCertVerify) {
@@ -446,8 +450,14 @@ tls_verify_peer_cert(SSLContext *ctx)
     if(err)
         goto out;
 
-    /* Set the public key */
-    tls_set_peer_pubkey(ctx->hdsk, certs);
+    /* Set the public key, only if we have certs.
+       We don't return an handshake error if there is no cert,
+       The fact that there is no cert should be reflected in the
+       trust results above, or will be handle when the application
+       does its own trust evaluation. */
+    if(certs) {
+        require_noerr(err=tls_set_peer_pubkey(ctx->hdsk, certs), out);
+    }
 
     /* Now that cert verification is done, update context state */
     /* (this code was formerly in SSLProcessHandshakeMessage, */
index e2f442ddb125ba5e3a66588d7aaa762f4d617ae3..9eadbcbca05e6c81b1e320f77daa64d78ab68374 100644 (file)
@@ -191,7 +191,7 @@ typedef struct {
     SSLContextRef st;
     bool is_server;
     bool is_dtls;
-    bool client_side_auth;
+    int client_side_auth;
     bool dh_anonymous;
     int comm;
     CFArrayRef certs;
@@ -322,7 +322,7 @@ static unsigned char dn[] = {
 };
 static unsigned int dn_len = 96;
 
-static SSLContextRef make_ssl_ref(bool server, bool client_side_auth, bool dh_anonymous,
+static SSLContextRef make_ssl_ref(bool server, int client_side_auth, bool dh_anonymous,
     bool dtls, int sock, CFArrayRef certs, SSLProtocol proto)
 {
     SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, server?kSSLServerSide:kSSLClientSide, dtls?kSSLDatagramType:kSSLStreamType);
@@ -468,7 +468,9 @@ static void *securetransport_ssl_thread(void *arg)
             CFRelease(DNs);
 
             require_string(ssl->client_side_auth, out, "errSSLClientCertRequested in run not testing that");
-            require_noerr(SSLSetCertificate(ctx, ssl->certs), out);
+            if(ssl->client_side_auth==1) { // Don't set a client cert in mode 2.
+                require_noerr(SSLSetCertificate(ctx, ssl->certs), out);
+            }
         } else if (ortn == errSSLWouldBlock) {
             require_action(ssl_state==kSSLHandshake, out, ortn = -1);
         }
@@ -563,7 +565,7 @@ out:
 
 
 static ssl_test_handle *
-ssl_test_handle_create(uint32_t session_id, bool resume, bool server, bool client_side_auth, bool dh_anonymous, bool dtls,
+ssl_test_handle_create(uint32_t session_id, bool resume, bool server, int client_side_auth, bool dh_anonymous, bool dtls,
     int comm, CFArrayRef certs, SSLProtocol proto)
 {
     ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle));
@@ -597,7 +599,7 @@ tests(void)
 
     for (p=0; p<nprotos; p++)
     for (d=0;d<2; d++)  /* dtls or not dtls */
-    for (k=0; k<2; k++)
+        for (k=0; k<3; k++) /* client side auth mode: 0: server doesn't request , 1: server request, client provide, 2: server request, client does not provide */
     {
         for (i=0; ciphers[i].cipher != (SSLCipherSuite)(-1); i++)
         for (l = 0; l<2; l++) {
@@ -612,7 +614,7 @@ tests(void)
 
                 ssl_test_handle *server, *client;
 
-                bool client_side_auth = (k);
+                int client_side_auth = (k);
 
                 uint32_t session_id = (k+1) << 16 | (i+1);
                 //fprintf(stderr, "session_id: %d\n", session_id);
@@ -662,7 +664,7 @@ out:
 int ssl_42_ciphers(int argc, char *const *argv)
 {
 
-    plan_tests(2 * 2 * 2 * nprotos * (ciphers_len-1)/* client auth on/off * #configs * #ciphers */
+    plan_tests(3 * 2 * 2 * nprotos * (ciphers_len-1)/* client auth 0/1/2 * #configs * protos * #ciphers */
                 + 1 /*cert*/);
 
 
index c656aa17ab5cc6865a698d306c96850dd554536b..07b2d4a0133b19e8b8173b56856c2292ee98aabc 100644 (file)
@@ -21,8 +21,6 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-
-
 #include <stdbool.h>
 #include <pthread.h>
 #include <fcntl.h>
@@ -145,6 +143,11 @@ static OSStatus SocketRead(SSLConnectionRef h, void *data, size_t *length)
         ptr[31]=ptr[31]^0x08^0xff; // expected padding was 8, changing it to 0xff to trigger integer underflow.
     }
 
+    /* We are reading the server cert */
+    if((*length==765) && (ptr[0]==0x0b) && (handle->test==3)) {
+        ptr[0xc] = 0x4; // version = 4 certificate should cause error, but not crash .
+    }
+
     /* We are reading a data application header */
     if(*length==5 && ptr[0]==0x17) {
         switch(handle->test) {
@@ -187,8 +190,7 @@ static void *securetransport_ssl_thread(void *arg)
     } while (ortn == errSSLWouldBlock
              || ortn == errSSLServerAuthCompleted);
 
-    require_noerr_action_quiet(ortn, out,
-                               fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn));
+    require_noerr_quiet(ortn, out);
 
     unsigned char ibuf[8], obuf[8];
     size_t len;
@@ -255,7 +257,7 @@ tests(void)
 
     int i;
 
-    for(i=0; i<3; i++)
+    for(i=0; i<4; i++)
     {
         int sp[2];
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
@@ -283,10 +285,14 @@ tests(void)
         pthread_join(client_thread, (void*)&client_err);
         pthread_join(server_thread, (void*)&server_err);
 
-
-        ok(!server_err, "Server error = %d", server_err);
-        /* tests 0/1 should cause errSSLClosedAbort, 2 should cause errSSLBadRecordMac */
-        ok(client_err==((i==2)?errSSLBadRecordMac:errSSLClosedAbort), "Client error = %d", client_err);
+        ok(server_err==((i==3)?errSSLClosedGraceful:0), "Server error = %d", server_err);
+        /* tests 0/1 should cause errSSLClosedAbort, 2 should cause errSSLBadRecordMac, 3 can be either errSSLXCertChainInvalid or errSSLCrypto */
+#if TARGET_OS_IPHONE
+        int test_3_expected_error = errSSLXCertChainInvalid;
+#else
+        int test_3_expected_error = errSSLBadCert;
+#endif
+        ok(client_err==((i==3)?test_3_expected_error:(i==2)?errSSLBadRecordMac:errSSLClosedAbort), "Client error = %d", client_err);
 
 out:
         free(client);
@@ -299,7 +305,7 @@ out:
 int ssl_44_crashes(int argc, char *const *argv)
 {
 
-    plan_tests(3*2 + 1 /*cert*/);
+    plan_tests(4*2 + 1 /*cert*/);
 
 
     tests();
diff --git a/Security/libsecurity_utilities/lib/dispatch.cpp b/Security/libsecurity_utilities/lib/dispatch.cpp
new file mode 100644 (file)
index 0000000..97224e9
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// dispatch - libdispatch wrapper
+//
+#include "dispatch.h"
+#include <security_utilities/errors.h>
+
+namespace Security {
+namespace Dispatch {
+
+ExceptionAwareEnqueuing::ExceptionAwareEnqueuing()
+: mExceptionPending(false)
+{ }
+
+void ExceptionAwareEnqueuing::enqueueWithDispatcher(void (^dispatcher)(dispatch_block_t), dispatch_block_t block)
+{
+       if (mExceptionPending)
+               return;
+
+       dispatcher(^{
+               if (mExceptionPending)
+                       return;
+               try {
+                       block();
+               } catch (...) {
+                       StLock<Mutex> _(mLock);
+                       mExceptionPending = true;
+                       mException = std::current_exception();
+               }
+       });
+}
+
+void ExceptionAwareEnqueuing::throwPendingException()
+{
+       if (mExceptionPending) {
+               mExceptionPending = false;
+               std::rethrow_exception(mException);
+       }
+}
+
+
+
+Queue::Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class)
+{
+       dispatch_queue_attr_t attr = concurrent ? DISPATCH_QUEUE_CONCURRENT : DISPATCH_QUEUE_SERIAL;
+       attr = dispatch_queue_attr_make_with_qos_class(attr, qos_class, 0);
+       mQueue = dispatch_queue_create(label, attr);
+}
+
+Queue::~Queue()
+{
+       dispatch_barrier_sync(mQueue, ^{});
+       dispatch_release(mQueue);
+}
+
+void Queue::enqueue(dispatch_block_t block)
+{
+       enqueuing.enqueueWithDispatcher(^(dispatch_block_t block){ dispatch_async(mQueue, block); }, block);
+}
+
+void Queue::wait()
+{
+       dispatch_barrier_sync(mQueue, ^{});
+       enqueuing.throwPendingException();
+}
+
+
+
+Group::Group()
+{
+       mGroup = dispatch_group_create();
+}
+
+Group::~Group()
+{
+       dispatch_group_wait(mGroup, DISPATCH_TIME_FOREVER);
+       dispatch_release(mGroup);
+}
+
+void Group::enqueue(dispatch_queue_t queue, dispatch_block_t block)
+{
+       enqueuing.enqueueWithDispatcher(^(dispatch_block_t block){ dispatch_group_async(mGroup, queue, block); }, block);
+}
+
+void Group::wait()
+{
+       dispatch_group_wait(mGroup, DISPATCH_TIME_FOREVER);
+       enqueuing.throwPendingException();
+}
+
+
+
+Semaphore::Semaphore(long count) {
+       mSemaphore = dispatch_semaphore_create(count);
+}
+
+Semaphore::Semaphore(Semaphore& semaphore)
+: mSemaphore(semaphore.mSemaphore)
+{
+       dispatch_retain(mSemaphore);
+}
+
+Semaphore::~Semaphore() {
+       dispatch_release(mSemaphore);
+}
+
+bool Semaphore::signal() {
+       return dispatch_semaphore_signal(mSemaphore) == 0;
+}
+
+bool Semaphore::wait(dispatch_time_t timeout) {
+       return dispatch_semaphore_wait(mSemaphore, timeout) == 0;
+}
+
+
+// Transfer ownership of held resource.
+SemaphoreWait::SemaphoreWait(SemaphoreWait &originalWait)
+: mSemaphore(originalWait.mSemaphore), mAcquired(originalWait.mAcquired)
+{
+       originalWait.mAcquired = false;
+}
+
+SemaphoreWait::SemaphoreWait(Semaphore &semaphore, dispatch_time_t timeout)
+: mSemaphore(semaphore)
+{
+       mAcquired = mSemaphore.wait(timeout);
+}
+
+SemaphoreWait::~SemaphoreWait()
+{
+       if (mAcquired)
+               mSemaphore.signal();
+}
+
+
+} // end namespace Dispatch
+} // end namespace Security
diff --git a/Security/libsecurity_utilities/lib/dispatch.h b/Security/libsecurity_utilities/lib/dispatch.h
new file mode 100644 (file)
index 0000000..558e5f0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// dispatch - libdispatch wrapper
+//
+#ifndef _H_DISPATCH
+#define _H_DISPATCH
+
+#include <dispatch/dispatch.h>
+#include <security_utilities/utilities.h>
+#include <security_utilities/threading.h>
+
+#include <exception>
+
+namespace Security {
+namespace Dispatch {
+
+
+// Wraps dispatch objects which can be used to queue blocks, i.e. dispatch groups and queues.
+// If a block throws an exception, no further blocks are enqueued and the exception is rethrown
+// after waiting for completion of all blocks.
+class ExceptionAwareEnqueuing {
+       NOCOPY(ExceptionAwareEnqueuing)
+public:
+       ExceptionAwareEnqueuing();
+
+       void enqueueWithDispatcher(void (^dispatcher)(dispatch_block_t), dispatch_block_t block);
+       void throwPendingException();
+private:
+       Mutex mLock;
+       bool mExceptionPending;
+       std::exception_ptr mException;
+};
+
+
+class Queue {
+       NOCOPY(Queue)
+public:
+       Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class = QOS_CLASS_DEFAULT);
+       virtual ~Queue();
+
+       operator dispatch_queue_t () const { return mQueue; }
+
+       void enqueue(dispatch_block_t block);
+       void wait();
+
+private:
+       ExceptionAwareEnqueuing enqueuing;
+       dispatch_queue_t mQueue;
+};
+
+
+class Group {
+       NOCOPY(Group)
+public:
+       Group();
+       virtual ~Group();
+
+       operator dispatch_group_t () const { return mGroup; }
+
+       void enqueue(dispatch_queue_t queue, dispatch_block_t block);
+       void wait();
+
+private:
+       ExceptionAwareEnqueuing enqueuing;
+       dispatch_group_t mGroup;
+};
+
+
+class Semaphore {
+       NOCOPY(Semaphore)
+public:
+       Semaphore(long count);
+       Semaphore(Semaphore& semaphore);
+       virtual ~Semaphore();
+
+       operator dispatch_semaphore_t () const { return mSemaphore; };
+
+       bool signal();
+       bool wait(dispatch_time_t timeout = DISPATCH_TIME_FOREVER);
+
+private:
+       dispatch_semaphore_t mSemaphore;
+};
+
+
+class SemaphoreWait {
+       NOCOPY(SemaphoreWait)
+public:
+       SemaphoreWait(SemaphoreWait& originalWait);
+       SemaphoreWait(Semaphore& semaphore, dispatch_time_t timeout = DISPATCH_TIME_FOREVER);
+       virtual ~SemaphoreWait();
+
+       bool acquired() const { return mAcquired; };
+
+private:
+       Semaphore &mSemaphore;
+       bool mAcquired;
+};
+
+
+} // end namespace Dispatch
+} // end namespace Security
+
+#endif // !_H_DISPATCH
index 57695adbfa943695f8d6b8d017056982c5ed35a1..eab27f83273374d7e07882bb68b8eb5327d06a1f 100644 (file)
@@ -128,6 +128,9 @@ int MacOSError::unixError() const
 void MacOSError::throwMe(int error)
 { throw MacOSError(error); }
 
+MacOSError MacOSError::make(int error)
+{ return MacOSError(error); }
+
 
 //
 // CFError exceptions
index 6ff8ac4520c9e2e7e8d923b0e1ec44c704803e13..cbc2bd624195bff2e98d26c4e97b6d45055d9f39 100644 (file)
@@ -94,6 +94,8 @@ public:
     
     static void check(OSStatus status) { if (status != errSecSuccess) throwMe(status); }
     static void throwMe(int err) __attribute__((noreturn));
+
+    static MacOSError make(int err);
 };
        
 typedef std::set<OSStatus> MacOSErrorSet;
index cfd448abb2eae8a341191285479279e7b48d14b9..2959da4a615b0176f538e2537c3179102098c520 100644 (file)
@@ -286,6 +286,9 @@ uint32_t MachOBase::flags() const
 const load_command *MachOBase::nextCommand(const load_command *command) const
 {
        using LowLevelMemoryUtilities::increment;
+       /* Do not try and increment by 0, or it will loop forever */
+       if (flip(command->cmdsize) == 0)
+               UnixError::throwMe(ENOEXEC);
        command = increment<const load_command>(command, flip(command->cmdsize));
        if (command >= mEndCommands)    // end of load commands
                return NULL;
index d00dee77e72329554f881a21baab2dfbd2d5ea05..6fb3a445d31bcaf438d1c2090a168c2383d8b32c 100644 (file)
 // unix++ - C++ layer for basic UNIX facilities
 //
 #include "unix++.h"
+#include <security_utilities/cfutilities.h>
 #include <security_utilities/memutils.h>
 #include <security_utilities/debugging.h>
+#include <sys/dirent.h>
 #include <sys/xattr.h>
 #include <cstdarg>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
 
 
 namespace Security {
@@ -409,6 +414,49 @@ FILE *FileDesc::fdopen(const char *form)
 }
 
 
+//
+// Device characteristics
+//
+static CFDictionaryRef deviceCharacteristics(FileDesc &fd)
+{
+       // get device name
+       AutoFileDesc::UnixStat st;
+       fd.fstat(st);
+       char buffer[MAXNAMLEN];
+       checkError(::devname_r(st.st_dev, S_IFBLK, buffer, MAXNAMLEN));
+
+       // search in IO Registry for named device
+       CFDictionaryRef matching = IOBSDNameMatching(kIOMasterPortDefault, 0, buffer);
+       if (matching) {
+               // fetch the object with the matching BSD name (consumes reference on matching)
+               io_registry_entry_t entry = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
+               if (entry != IO_OBJECT_NULL) {
+                       // get device characteristics
+                       CFDictionaryRef characteristics = (CFDictionaryRef)IORegistryEntrySearchCFProperty(entry,
+                               kIOServicePlane,
+                               CFSTR(kIOPropertyDeviceCharacteristicsKey),
+                               NULL,
+                               kIORegistryIterateRecursively | kIORegistryIterateParents);
+                       IOObjectRelease(entry);
+                       return characteristics;
+               }
+       }
+
+       return NULL;    // unable to get device characteristics
+}
+
+std::string FileDesc::mediumType()
+{
+       CFRef<CFDictionaryRef> characteristics = deviceCharacteristics(*this);
+       if (characteristics) {
+               CFStringRef mediumType = (CFStringRef)CFDictionaryGetValue(characteristics, CFSTR(kIOPropertyMediumTypeKey));
+               if (mediumType)
+                       return cfString(mediumType);
+       }
+       return string();
+}
+
+
 //
 // Signals and signal masks
 //
index c7e098b96afc464f3a53277e35a110a4366bd302..26360eb7d30d1d12c3b23392c4d4f23ca8731a81 100644 (file)
@@ -234,6 +234,9 @@ public:
        // Is this a regular file? (not a symlink, fifo, etc.)
        bool isPlainFile(const std::string &path);
 
+       // device characteristics
+       std::string mediumType();
+
 private:
     int mFd;                           // UNIX file descriptor
 
index 03c008f1681e3a161305f8c3c9b4eafa74f48ab1..e6e6338204386902a3f5271407c9cc0370f88526 100644 (file)
                4CA684FB0525011E00233BF2 /* url.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA684BB0525011E00233BF2 /* url.cpp */; };
                4CA684FD0525011E00233BF2 /* utilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA684BD0525011E00233BF2 /* utilities.cpp */; };
                4E4813D707739B0C0090D7C2 /* ccaudit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4E4813D507739B0C0090D7C2 /* ccaudit.cpp */; };
+               7A93A12419BE6FA600F07E9A /* dispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A93A12219BE6FA600F07E9A /* dispatch.cpp */; };
+               7A93A12519BE6FA600F07E9A /* dispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A93A12319BE6FA600F07E9A /* dispatch.h */; };
                AAA4B91E16653547005DEFDC /* debugging_internal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAA4B91D16653547005DEFDC /* debugging_internal.cpp */; };
                AAA4B920166535B4005DEFDC /* debugging_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AAA4B91F16653597005DEFDC /* debugging_internal.h */; settings = {ATTRIBUTES = (Public, ); }; };
                AAAA499A0CC587B50099E9D4 /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = AAAA49980CC587B50099E9D4 /* crc.c */; };
                4CA684BF0525011E00233BF2 /* utility_config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = utility_config.h; sourceTree = "<group>"; };
                4E4813D507739B0C0090D7C2 /* ccaudit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ccaudit.cpp; sourceTree = "<group>"; };
                4E4813D607739B0C0090D7C2 /* ccaudit.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ccaudit.h; sourceTree = "<group>"; };
+               7A93A12219BE6FA600F07E9A /* dispatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dispatch.cpp; sourceTree = "<group>"; usesTabs = 1; };
+               7A93A12319BE6FA600F07E9A /* dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dispatch.h; sourceTree = "<group>"; usesTabs = 1; };
                AA3BC08D166549EA00EF1D2E /* exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = exports; sourceTree = "<group>"; };
                AA5B97E70E140C3E0032C12F /* dtrace.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dtrace.mk; path = lib/dtrace.mk; sourceTree = "<group>"; usesTabs = 1; };
                AAA4B91D16653547005DEFDC /* debugging_internal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugging_internal.cpp; sourceTree = "<group>"; };
                                AAA4B91F16653597005DEFDC /* debugging_internal.h */,
                                4CA6848C0525011D00233BF2 /* devrandom.h */,
                                4CA6848B0525011D00233BF2 /* devrandom.cpp */,
+                               7A93A12219BE6FA600F07E9A /* dispatch.cpp */,
+                               7A93A12319BE6FA600F07E9A /* dispatch.h */,
                                4CA6848E0525011D00233BF2 /* endian.h */,
                                4CA6848D0525011D00233BF2 /* endian.cpp */,
                                C22EC38F052B7F5D00D55C69 /* errors.h */,
                                181EA3BB146D1D7F00A6D320 /* dyldcache.h in Headers */,
                                181EA3BC146D1D7F00A6D320 /* dyld_cache_format.h in Headers */,
                                181EA3BD146D1D7F00A6D320 /* machserver.h in Headers */,
+                               7A93A12519BE6FA600F07E9A /* dispatch.h in Headers */,
                                181EA3BE146D1D7F00A6D320 /* machrunloopserver.h in Headers */,
                                181EA3BF146D1D8600A6D320 /* coderepository.h in Headers */,
                                181EA3C0146D1D8600A6D320 /* cfclass.h in Headers */,
                                4CA684C20525011E00233BF2 /* buffers.cpp in Sources */,
                                C2B9F3630D5A28CA00CAB713 /* cfmunge.cpp in Sources */,
                                4CA684C40525011E00233BF2 /* cfutilities.cpp in Sources */,
+                               7A93A12419BE6FA600F07E9A /* dispatch.cpp in Sources */,
                                4CA684C60525011E00233BF2 /* daemon.cpp in Sources */,
                                4CA684C80525011E00233BF2 /* debugging.cpp in Sources */,
                                4CA684CB0525011E00233BF2 /* devrandom.cpp in Sources */,
index e8aa5e2be54aa8246a00a7923f7dccc9e13e27cb..a92c2015cec599f273d5824c0a55fe41e846d295 100644 (file)
@@ -85,7 +85,7 @@ void SOSTestDeviceForEachPeerID(SOSTestDeviceRef td, void(^peerBlock)(CFStringRe
     }
 }
 
-static CFStringRef SOSTestDeviceCopyDescription(CFTypeRef cf) {
+static CFStringRef SOSTestDeviceCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SOSTestDeviceRef td = (SOSTestDeviceRef)cf;
     CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorDefault, 0);
     CFStringAppendFormat(result, NULL, CFSTR("<SOSTestDevice %@"), td->ds->engine);
@@ -103,6 +103,7 @@ CFGiblisFor(SOSTestDevice)
 static SOSTestDeviceRef SOSTestDeviceCreateInternal(CFAllocatorRef allocator, CFStringRef engineID) {
     SOSTestDeviceRef td = CFTypeAllocate(SOSTestDevice, struct __OpaqueSOSTestDevice, allocator);
     td->peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
+    td->mute = false;
     return td;
 }
 
@@ -173,6 +174,15 @@ SOSTestDeviceRef SOSTestDeviceSetPeerIDs(SOSTestDeviceRef td, CFArrayRef peerIDs
     return td;
 }
 
+SOSTestDeviceRef SOSTestDeviceSetMute(SOSTestDeviceRef td, bool mute) {
+    td->mute = mute;
+    return td;
+}
+
+bool SOSTestDeviceIsMute(SOSTestDeviceRef td) {
+    return td->mute;
+}
+
 CFDataRef SOSTestDeviceCreateMessage(SOSTestDeviceRef td, CFStringRef peerID) {
     setup("create message");
     CFErrorRef error = NULL;
@@ -307,15 +317,17 @@ void SOSTestDeviceListSync(const char *name, const char *test_directive, const c
                 bool handled = false;
                 msgSentSinceLastChangeCount++;
                 if (msg && CFDataGetLength(msg) > 0) {
-                    handled = SOSTestDeviceHandleMessage(dest, sourceID, msg);
-                    if (handled) {
-                        noMsgSentCount = 0;
+                    if (!source->mute) {
+                        handled = SOSTestDeviceHandleMessage(dest, sourceID, msg);
+                        if (handled) {
+                            noMsgSentCount = 0;
+                        }
+
+                        CFErrorRef error = NULL;
+                        message = SOSMessageCreateWithData(kCFAllocatorDefault, msg, &error);
+                        ok(handled, "%s %@->%@ %@", name, sourceID, destID, message);
+                        CFReleaseNull(error);
                     }
-
-                    CFErrorRef error = NULL;
-                    message = SOSMessageCreateWithData(kCFAllocatorDefault, msg, &error);
-                    ok(handled, "%s %@->%@ %@", name, sourceID, destID, message);
-                    CFReleaseNull(error);
                 } else {
                     SOSManifestRef sourceManifest = SOSEngineCopyManifest(SOSDataSourceGetSharedEngine(source->ds, NULL), NULL);
                     pass("%s %@->%@ done L:%@", name, sourceID, destID, sourceManifest);
index 8af4e1722d0ca166d6686752383586ac37de5380..bb653ffdb843fb1ec14d5696069a87d84dd5c587 100644 (file)
@@ -33,6 +33,7 @@ struct __OpaqueSOSTestDevice {
     SOSDataSourceFactoryRef dsf;
     SOSDataSourceRef ds;
     CFMutableArrayRef peers;
+    bool mute;
 };
 
 CFStringRef SOSMessageCopyDigestHex(SOSMessageRef message);
@@ -44,6 +45,9 @@ SOSTestDeviceRef SOSTestDeviceCreateWithDbNamed(CFAllocatorRef allocator, CFStri
 SOSTestDeviceRef SOSTestDeviceCreateWithTestDataSource(CFAllocatorRef allocator, CFStringRef engineID);
 SOSTestDeviceRef SOSTestDeviceSetPeerIDs(SOSTestDeviceRef td, CFArrayRef peerIDs, CFIndex version);
 
+SOSTestDeviceRef SOSTestDeviceSetMute(SOSTestDeviceRef td, bool mute);
+bool SOSTestDeviceIsMute(SOSTestDeviceRef td);
+
 CFDataRef SOSTestDeviceCreateMessage(SOSTestDeviceRef td, CFStringRef peerID);
 
 bool SOSTestDeviceHandleMessage(SOSTestDeviceRef td, CFStringRef peerID, CFDataRef msgData);
index 52d4a632dcf4f7ca233052817b309c5a897284ba..9b1bfdfe5e260ac08caf63602bd956972a85d8fa 100644 (file)
@@ -165,7 +165,7 @@ void SOSAccountSetToNew(SOSAccountRef a) {
 }
 
 
-static CFStringRef SOSAccountCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSAccountCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
     SOSAccountRef a = (SOSAccountRef) aObj;
     
     return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSAccount@%p: Gestalt: %@\n Circles: %@ CircleIDs: %@>"), a, a->gestalt, a->circles, a->circle_identities);
@@ -210,6 +210,10 @@ CFArrayRef SOSAccountCopyAccountIdentityPeerInfos(SOSAccountRef account, CFAlloc
 
 static bool SOSAccountThisDeviceCanSyncWithCircle(SOSAccountRef account, SOSCircleRef circle) {
     CFErrorRef error = NULL;
+
+    if (!SOSAccountHasPublicKey(account, &error))
+        return false;
+
     SOSFullPeerInfoRef myfpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), &error);
     SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(myfpi);
     CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi);
index 5b23afa595cb409a30ecf810571c6cd9c540e032..21c8df95ccde278512a996eb4f6943844b490f36 100644 (file)
@@ -352,7 +352,7 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
     SOSCircleRef circleToPush = NULL;
 
     if (circle_action == leave) {
-        circle_action = ignore;
+        circle_action = ignore; (void) circle_action; // Acknowledge this is a dead store.
         
         if (me && SOSCircleHasPeer(oldCircle, me, NULL)) {
             if (sosAccountLeaveCircle(account, newCircle, error)) {
index 3f167d231de4f5e898722c837b12224b0edd0cba..0c099933347842b078536cef3d4dfdb1d8fd50a9 100644 (file)
@@ -714,7 +714,7 @@ static void SOSCircleDestroy(CFTypeRef aObj) {
     CFReleaseNull(c->signatures);
 }
 
-static CFStringRef SOSCircleCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
     SOSCircleRef c = (SOSCircleRef) aObj;
     
     SOSCircleAssertStable(c);
index a033cad8594e0e91991f7d3543a2e644eec11ec3..4c8b7cebb3ee25c3b72f29b405451e2daf1ac23b 100644 (file)
@@ -614,7 +614,9 @@ static bool SOSEngineHandleMessage_locked(SOSEngineRef engine, CFStringRef peerI
     confirmed = CFRetainSafe(SOSEngineGetManifestForDigest(engine, SOSMessageGetSenderDigest(message)));
     if (!confirmed) {
         if (SOSManifestGetCount(SOSMessageGetRemovals(message)) || SOSManifestGetCount(allAdditions)) {
-            confirmed = SOSManifestCreateWithPatch(base, SOSMessageGetRemovals(message), allAdditions, error);
+            if (base || !baseDigest) {
+                confirmed = SOSManifestCreateWithPatch(base, SOSMessageGetRemovals(message), allAdditions, error);
+            }
             if (!confirmed) {
                 confirmedRemovals = CFRetainSafe(SOSMessageGetRemovals(message));
                 confirmedAdditions = CFRetainSafe(allAdditions);
index a59314c8483f4d98447f9334b5c07b7e0726a3f1..c34e3533483c1b355010eaabd337b59c7516bb24 100644 (file)
@@ -199,7 +199,7 @@ static CFHashCode   SOSFullPeerInfoHash(CFTypeRef cf) {
     return CFHash(peer->peer_info);
 }
 
-static CFStringRef SOSFullPeerInfoCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
     SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
 
     return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
index 0e0aee286e4f11ce4adfa938419577cfd287d4c4..ea333f33985dbbc61e11d108785a808ca2383f9a 100644 (file)
@@ -209,7 +209,7 @@ CFDataRef SOSManifestGetDigest(SOSManifestRef m, CFErrorRef *error) {
     return m->digest;
 }
 
-static CFStringRef SOSManifestCopyDescription(CFTypeRef cf) {
+static CFStringRef SOSManifestCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SOSManifestRef m = (SOSManifestRef)cf;
     CFMutableStringRef desc = CFStringCreateMutable(0, 0);
     CFStringAppendFormat(desc, NULL, CFSTR("<[%zu]"), SOSManifestGetCount(m));
index d5e69d1c45adcdd79b30b8b358c7cd5978612d51..d5023fb0237b71aaa5fb1a73d273ac1cf7a06cff 100644 (file)
@@ -304,7 +304,7 @@ static void SOSMessageDestroy(CFTypeRef cf) {
 
 static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error);
 
-static CFStringRef SOSMessageCopyDescription(CFTypeRef cf) {
+static CFStringRef SOSMessageCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SOSMessageRef message = (SOSMessageRef)cf;
     static const uint8_t zero[4] = {};
     const uint8_t *S = message->senderDigest ? CFDataGetBytePtr(message->senderDigest) : zero;
index 07f10cb798a48b3cc0ea400c1b3c0e25c11cdb96..fe6b0b835e812518e934681feeeeec70cb8a781b 100644 (file)
@@ -119,7 +119,7 @@ static CFStringRef SOSPeerCreateManifestArrayDescriptionWithKey(SOSPeerRef peer,
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(" %@[%" PRIdCFIndex "]%@"), label, count, SOSEngineGetManifestForDigest(peer->engine, digest));
 }
 
-static CFStringRef SOSPeerCopyDescription(CFTypeRef cf) {
+static CFStringRef SOSPeerCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SOSPeerRef peer = (SOSPeerRef)cf;
     if(peer){
         CFStringRef po = SOSManifestCreateOptionalDescriptionWithLabel(SOSPeerGetPendingObjects(peer), CFSTR("O"));
index d4db2ae9161a16e31451547d0346848f6078023b..a51a2478bd032235c2385d476b244755772481fb 100644 (file)
@@ -461,7 +461,7 @@ static CFHashCode SOSPeerInfoHash(CFTypeRef cf) {
     return CFHash(peer->description) ^ CFHash(peer->signature);
 }
 
-static CFStringRef SOSPeerInfoCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
     SOSPeerInfoRef pi = (SOSPeerInfoRef) aObj;
     CFIndex version = SOSPeerInfoGetPeerProtocolVersion(pi);
     
index 13abb72b9fcc68cb129589396de65bb56d1e8736..60d3ef0bfa730277896f224819f2a04936b0122c 100644 (file)
@@ -21,7 +21,7 @@ SOSTransportCircleRef SOSTransportCircleCreateForSubclass(size_t size, SOSAccoun
     return tpt;
 }
 
-static CFStringRef SOSTransportCircleCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSTransportCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
     SOSTransportCircleRef t = (SOSTransportCircleRef) aObj;
     
     return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportCircle@%p\n>"), t);
index ece0dcd067e7c2145c7a8992c6a2495bdab24496..f57b366fc8cb5d29c6bd06a23c1798465430af67 100644 (file)
@@ -21,7 +21,7 @@ bool SOSTransportKeyParameterHandleNewAccount(SOSTransportKeyParameterRef transp
     return transport->setToNewAccount(transport);
 }
 
-static CFStringRef SOSTransportKeyParameterCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSTransportKeyParameterCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
     SOSTransportKeyParameterRef t = (SOSTransportKeyParameterRef) aObj;
     
     return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportKeyParameter@%p\n>"), t);
index 0fcb2f0539448a186e88f622ecc81c9ba8794367..14be9ef7b35e8fcbe74cf04f679e86bbef281051 100644 (file)
@@ -24,7 +24,7 @@ SOSTransportMessageRef SOSTransportMessageCreateForSubclass(size_t size,
 }
 
 
-static CFStringRef SOSTransportMessageCopyDescription(CFTypeRef aObj){
+static CFStringRef SOSTransportMessageCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions){
     SOSTransportMessageRef t = (SOSTransportMessageRef) aObj;
     
     return t->copyDescription ? t->copyDescription(t)
index 87884aaf290511d9f87a91d66a4ed845c07d4b5f..0cb73edcbfeae016bf4251f1a70ed151588d8d7d 100644 (file)
@@ -91,6 +91,9 @@ ONE_TEST(otr_00_identity)
 ONE_TEST(otr_30_negotiation)
 ONE_TEST(otr_otrdh)
 ONE_TEST(otr_packetdata)
+ONE_TEST(otr_40_edgecases)
+ONE_TEST(otr_50_roll)
+ONE_TEST(otr_60_slowroll)
 
 #if TARGET_OS_IPHONE
 ONE_TEST(so_01_serverencryption)
index 5b09d0e510c17c464cf9dcfddd8d7440c7ddc845..bac5680e79ec2127d896b7af0e779120c9af022d 100644 (file)
@@ -63,7 +63,7 @@ static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
 
 
 
-#define sendMessagesCount(n) ((n) * 8)
+#define sendMessagesCount(n) ((n) * 14)
 static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
 {
     for(int count = howMany; count > 0; --count) {
@@ -75,6 +75,7 @@ static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessio
         ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
         ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
 
+
         if (serialize) {
             serializeAndDeserialize(bobSession);
             serializeAndDeserialize(aliceSession);
@@ -92,8 +93,8 @@ static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessio
         CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
         CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
 
-        ok_status(SecOTRSSignAndProtectMessage(*bobSession, rawBobToAlice, protectedBobToAlice), "encode reply");
-        ok_status(SecOTRSVerifyAndExposeMessage(*aliceSession, protectedBobToAlice, aliceDecode), "decode reply");
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
 
         if (serialize) {
             serializeAndDeserialize(bobSession);
@@ -109,6 +110,49 @@ static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessio
         CFReleaseNull(protectedAliceToBob);
         CFReleaseNull(aliceDecode);
 
+        rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+         protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+         bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(bobDecode);
+
+         bobToAlice = "i liked your silly message from me to you";
+         rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+         protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+         aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(rawBobToAlice);
+        CFReleaseNull(protectedBobToAlice);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(aliceDecode);
+
+
+
         CFStringRef stateString = CFCopyDescription(*bobSession);
         ok(stateString, "getting state from bob");
         CFReleaseNull(stateString);
@@ -123,7 +167,7 @@ static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessio
                                + 2 + sendMessagesCount(1) \
                                + 1 + sendMessagesCount(1) \
                                + sendMessagesCount(3))
-static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serialize, bool textMode, bool compact)
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
 {
     const int kEmptyMessageSize = textMode ? 6 : 0;
 
@@ -132,14 +176,14 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     
     ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(bobSession);
     
     CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
     
     ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(aliceSession);
     
     // Step 2: Exchange the start packets, forcing the DH commit messages to collide
@@ -148,8 +192,8 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
               "Bob DH packet failed");
     
-    if (serialize)
-        serializeAndDeserialize(aliceSession);
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);    
     
     CFReleaseNull(bobStartPacket);
     
@@ -158,7 +202,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
               "Alice DH packet failed");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(bobSession);
     
     CFReleaseNull(aliceStartPacket);
@@ -170,7 +214,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
               "Alice DH Key packet failed");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(bobSession);
     
     CFReleaseNull(aliceDHKeyResponse);
@@ -180,7 +224,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
               "Bob DH Key packet failed");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(aliceSession);
     
     CFReleaseNull(bobDHKeyResponse);
@@ -192,7 +236,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
               "Bob Reveal sig failed");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(aliceSession);
     
     CFReleaseNull(bobRevealSigResponse);
@@ -202,7 +246,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
               "Alice Reveal sig failed");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(bobSession);
     
     CFReleaseNull(aliceRevealSigResponse);
@@ -213,7 +257,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
               "Alice Final Sig failed");
     
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(bobSession);
     
     CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
@@ -225,7 +269,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     CFReleaseNull(aliceFinalResponse);
     CFReleaseNull(bobSigResponse);
 
-    if (serialize)
+    if (serializeNegotiating)
         serializeAndDeserialize(aliceSession);
     
     is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
@@ -235,7 +279,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     CFReleaseNull(aliceSigResponse);
     CFReleaseNull(bobFinalResponse);
 
-    sendMessages(5, bobSession, aliceSession, serialize);
+    sendMessages(5, bobSession, aliceSession, serializeMessaging);
 
     const char* aliceToBob = "deferredMessage";
     CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
@@ -245,17 +289,15 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
     ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
 
 
-    const OSStatus expectedError = compact ? errSecAuthFailed : errSecOTRTooOld;
-
-    sendMessages(1, bobSession, aliceSession, serialize);
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
 
-    is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), expectedError, "Decode old message");
+    is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), errSecOTRTooOld, "Decode old message");
 
-    sendMessages(1, bobSession, aliceSession, serialize);
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
 
-    is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), expectedError, "Decode excessively old message");
+    is(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), errSecOTRTooOld, "Decode excessively old message");
 
-    sendMessages(3, bobSession, aliceSession, serialize);
+    sendMessages(3, bobSession, aliceSession, serializeMessaging);
 
     CFReleaseNull(rawAliceToBob);
     CFReleaseNull(protectedAliceToBob);
@@ -263,7 +305,7 @@ static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSessi
 }
 
 
-#define kTestTestCount (9 + kNegotiateTestCount * 2)
+#define kTestTestCount (11 + kNegotiateTestCount * 6)
 
 static void tests()
 {
@@ -301,6 +343,12 @@ static void tests()
 
     ok(aliceCompactSession, "create alice compact session");
     ok(bobCompactSession, "create bob compact session");
+    
+    SecOTRSessionRef aliceCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
+    SecOTRSessionRef bobCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
+    
+    ok(aliceCompactHashesSession, "create alice compact session with hashes");
+    ok(bobCompactHashesSession, "create bob compact session with hashes");
 
     // Release the IDs, sessions shouldn't need us to retain them for them.
     CFReleaseNull(aliceID);
@@ -309,9 +357,17 @@ static void tests()
     CFReleaseNull(alicePublicID);
     CFReleaseNull(bobPublicID);
 
-    negotiate(&aliceSession, &bobSession, true, true, false);
+    negotiate(&aliceSession, &bobSession, true, true, true, false);
 
-    negotiate(&aliceCompactSession, &bobCompactSession, true, false, true);
+    negotiate(&aliceSession, &bobSession, true, false, true, false);
+    
+    negotiate(&aliceCompactSession, &bobCompactSession, true, true, false, true);
+
+    negotiate(&aliceCompactSession, &bobCompactSession, true, false, false, true);
+    
+    negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, true, false, true);
+    
+    negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, false, false, true);
 
     /* cleanup keychain */
     ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
@@ -320,6 +376,12 @@ static void tests()
 
     CFReleaseNull(aliceSession);
     CFReleaseNull(bobSession);
+    
+    CFReleaseNull(aliceCompactSession);
+    CFReleaseNull(bobCompactSession);
+    
+    CFReleaseNull(aliceCompactHashesSession);
+    CFReleaseNull(bobCompactHashesSession);
 }
 
 int otr_30_negotiation(int argc, char *const *argv)
diff --git a/Security/sec/Security/Regressions/otr/otr-40-edgecases.c b/Security/sec/Security/Regressions/otr/otr-40-edgecases.c
new file mode 100644 (file)
index 0000000..6729cb1
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Security_regressions.h"
+
+#include <CoreFoundation/CFData.h>
+#include <Security/SecOTRSession.h>
+#include <Security/SecInternal.h>
+#include <Security/SecBasePriv.h>
+
+static void SecMPLogError(CFErrorRef error) {
+    if (error == NULL) {
+        return;
+    }
+    CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error);
+    CFIndex errorCode = CFErrorGetCode(error);
+    CFStringRef errorDomain = CFErrorGetDomain(error);
+    CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey);
+    CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey);
+    if (previousError != NULL) {
+        SecMPLogError(previousError);
+    }
+    char errorDomainStr[1024];
+    char errorStringStr[1024];
+    
+    CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8);
+    CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8);
+    printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr);
+    CFReleaseSafe(tempDictionary);
+}
+
+static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
+{
+    CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    SecOTRSAppendSerialization(*thisOne, serialized);
+    CFReleaseNull(*thisOne);
+    *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
+    
+    CFReleaseSafe(serialized);
+}
+
+#define renegotiateTests 9
+
+static void renegotiate(SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serializeNegotiating, CFDataRef messageDuringNegotiation){
+    
+    CFMutableDataRef aliceRestartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    CFMutableDataRef bobDHKeyPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    CFDataRef empty = CFDataCreate(kCFAllocatorDefault, NULL, 0);
+
+    CFMutableDataRef hopefullyNothing = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    //send a restart packet after session has successfully sent messages
+    ok_status(SecOTRSAppendRestartPacket(*aliceSession, aliceRestartPacket), "Alice restart packet");
+    
+    if(serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    SKIP: {
+        skip("No messageDuringNegotiation", 1, messageDuringNegotiation);
+        is(SecOTRSVerifyAndExposeMessage(*aliceSession, messageDuringNegotiation, hopefullyNothing), errSecOTRNotReady, "Message during negotiation");
+    }
+
+    if(serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceRestartPacket, bobDHKeyPacket),
+              "Bob DH packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+    
+    CFMutableDataRef aliceRevealSigPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyPacket, aliceRevealSigPacket),
+              "Alice DH Key packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigPacket, bobRevealSigResponse),
+              "Bob DH Key packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    // Step 4: Having gotten the reveal signature, now work for the signature
+    
+    CFMutableDataRef aliceSigPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigPacket),
+              "Bob Reveal sig failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    
+    ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+    ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+    
+    CFReleaseNull(aliceRestartPacket);
+    CFReleaseNull(aliceRevealSigPacket);
+    CFReleaseNull(aliceSigPacket);
+    
+    CFReleaseNull(bobDHKeyPacket);
+    CFReleaseNull(bobRevealSigResponse);
+    
+    CFReleaseNull(hopefullyNothing);
+    CFReleaseNull(empty);
+
+}
+
+
+#define sendMessagesCount(n) ((n) * 14)
+static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
+{
+    for(int count = howMany; count > 0; --count) {
+        const char* aliceToBob = "aliceToBob";
+        CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+        CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+        
+        
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+        
+        ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+        
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(bobDecode);
+        
+        const char* bobToAlice = "i liked your silly message from me to you";
+        CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+        CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+        
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+        
+        ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+        
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(rawBobToAlice);
+        CFReleaseNull(protectedBobToAlice);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(aliceDecode);
+        
+        rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+        protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+        
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+        
+        ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+        
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(bobDecode);
+        
+        bobToAlice = "i liked your silly message from me to you";
+        rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+        protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+        
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+        
+        ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+        
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(rawBobToAlice);
+        CFReleaseNull(protectedBobToAlice);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(aliceDecode);
+        
+        
+        
+        CFStringRef stateString = CFCopyDescription(*bobSession);
+        ok(stateString, "getting state from bob");
+        CFReleaseNull(stateString);
+        
+        stateString = CFCopyDescription(*aliceSession);
+        ok(stateString, "getting state from alice");
+        CFReleaseNull(stateString);
+    }
+}
+
+#define kNegotiateTestCount (14 + sendMessagesCount(1) * 4 \
++ renegotiateTests)
+
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, SecOTRSessionRef *brandNewBobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
+{
+    const int kEmptyMessageSize = textMode ? 6 : 0;
+    
+    // Step 1: Create a start packet for each side of the transaction
+    CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    // Step 2: Exchange the start packets, forcing the DH commit messages to collide
+    CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
+              "Bob DH packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    CFReleaseNull(bobStartPacket);
+    
+    CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
+              "Alice DH packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    CFReleaseNull(aliceStartPacket);
+    
+    // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+    
+    CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
+              "Alice DH Key packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    CFReleaseNull(aliceDHKeyResponse);
+    
+    CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
+              "Bob DH Key packet failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    CFReleaseNull(bobDHKeyResponse);
+    
+    // Step 4: Having gotten the reveal signature, now work for the signature
+    
+    CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
+              "Bob Reveal sig failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    CFReleaseNull(bobRevealSigResponse);
+    
+    CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
+              "Alice Reveal sig failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    CFReleaseNull(aliceRevealSigResponse);
+    
+    // Step 5: All the messages have been sent, now deal with any replays from the collision handling
+    CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
+              "Alice Final Sig failed");
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+    
+    CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
+              "Bob Final Sig failed");
+    
+    is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
+    CFReleaseNull(aliceFinalResponse);
+    CFReleaseNull(bobSigResponse);
+    
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+    
+    is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
+    ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+    ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+    
+    CFReleaseNull(aliceSigResponse);
+    CFReleaseNull(bobFinalResponse);
+    
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+    
+    const char *bobToAlice = "i liked your silly message from me to you";
+    CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+    CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSSignAndProtectMessage(*bobSession, rawBobToAlice, protectedBobToAlice), "protected bob to alice message");
+
+    CFReleaseNull(rawBobToAlice);
+
+    renegotiate(brandNewBobSession, aliceSession, serializeNegotiating, protectedBobToAlice);
+
+    CFReleaseNull(protectedBobToAlice);
+
+}
+
+#define kEdgeCaseTestCount (10 + kNegotiateTestCount * 2)
+
+static void tryEdgeCases(uint32_t flags)
+{
+    CFErrorRef testError = NULL;
+    SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    testError = NULL;
+    SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    testError = NULL;
+    
+    ok(aliceID, "create alice ID");
+    ok(bobID, "create bob ID");
+    
+    SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    
+    ok(alicePublicID, "extract alice public");
+    ok(bobPublicID, "extract bob public");
+    
+    SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, flags);
+    SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+    SecOTRSessionRef brandNewBobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+    SecOTRSessionRef brandNewBobSession2 = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+    SecOTRSessionRef brandNewBobSession3 = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+    
+    ok(aliceSession, "create alice session");
+    ok(bobSession, "create bob session");
+    ok(brandNewBobSession, "create new bob session");
+    
+    
+    // Release the IDs, sessions shouldn't need us to retain them for them.
+    CFReleaseNull(aliceID);
+    CFReleaseNull(bobID);
+    
+    CFReleaseNull(alicePublicID);
+    CFReleaseNull(bobPublicID);
+    
+    negotiate(&aliceSession, &bobSession, &brandNewBobSession, true, true, false, flags & kSecOTRUseAppleCustomMessageFormat);
+    
+    negotiate(&aliceSession, &bobSession, &brandNewBobSession2, true, false, false, flags & kSecOTRUseAppleCustomMessageFormat);
+    
+    
+    const char * testMessageString = "i liked your silly message from me to you";
+    CFDataRef testMessage = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)testMessageString, (CFIndex) strlen(testMessageString));
+    CFMutableDataRef protectedTestMessage = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    ok_status(SecOTRSSignAndProtectMessage(aliceSession, testMessage, protectedTestMessage), "Make message");
+    
+    CFMutableDataRef hopefullyNothing = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    
+    is(SecOTRSVerifyAndExposeMessage(brandNewBobSession3, protectedTestMessage, hopefullyNothing), errSecOTRNotReady, "Message Before Negotiating");
+    
+    /* cleanup keychain */
+    ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    
+    CFReleaseNull(aliceSession);
+    CFReleaseNull(bobSession);
+    
+    CFReleaseNull(brandNewBobSession);
+    CFReleaseNull(brandNewBobSession2);
+    CFReleaseNull(brandNewBobSession3);
+    CFReleaseNull(testMessage);
+    CFReleaseNull(protectedTestMessage);
+    CFReleaseNull(hopefullyNothing);
+}
+
+
+#define kTestTestCount (2 * kEdgeCaseTestCount)
+
+static void tests()
+{
+    tryEdgeCases(0);
+    tryEdgeCases(kSecOTRUseAppleCustomMessageFormat);
+}
+
+int otr_40_edgecases(int argc, char *const *argv)
+{
+    plan_tests(kTestTestCount);
+    
+    tests();
+    
+    return 0;
+}
diff --git a/Security/sec/Security/Regressions/otr/otr-50-roll.c b/Security/sec/Security/Regressions/otr/otr-50-roll.c
new file mode 100644 (file)
index 0000000..b07c4ee
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Security_regressions.h"
+
+#include <CoreFoundation/CFData.h>
+#include <Security/SecOTRSession.h>
+#include <Security/SecOTRSessionPriv.h>
+#include <Security/SecInternal.h>
+#include <Security/SecBasePriv.h>
+
+static void SecMPLogError(CFErrorRef error) {
+    if (error == NULL) {
+        return;
+    }
+    CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error);
+    CFIndex errorCode = CFErrorGetCode(error);
+    CFStringRef errorDomain = CFErrorGetDomain(error);
+    CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey);
+    CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey);
+    if (previousError != NULL) {
+        SecMPLogError(previousError);
+    }
+    char errorDomainStr[1024];
+    char errorStringStr[1024];
+
+    CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8);
+    CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8);
+    printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr);
+    CFReleaseSafe(tempDictionary);
+}
+
+static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
+{
+    CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    SecOTRSAppendSerialization(*thisOne, serialized);
+    CFReleaseNull(*thisOne);
+    *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
+
+    CFReleaseSafe(serialized);
+}
+
+
+
+#define sendMessagesCount(n) ((n) * 14)
+static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
+{
+    for(int count = howMany; count > 0; --count) {
+        const char* aliceToBob = "aliceToBob";
+        CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+        CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(bobDecode);
+
+        const char* bobToAlice = "i liked your silly message from me to you";
+        CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+        CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(rawBobToAlice);
+        CFReleaseNull(protectedBobToAlice);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(aliceDecode);
+
+        rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+        protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(bobDecode);
+
+        bobToAlice = "i liked your silly message from me to you";
+        rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+        protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(rawBobToAlice);
+        CFReleaseNull(protectedBobToAlice);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(aliceDecode);
+
+
+
+        CFStringRef stateString = CFCopyDescription(*bobSession);
+        ok(stateString, "getting state from bob");
+        CFReleaseNull(stateString);
+
+        stateString = CFCopyDescription(*aliceSession);
+        ok(stateString, "getting state from alice");
+        CFReleaseNull(stateString);
+    }
+}
+
+#define kNegotiateTestCount (19 + sendMessagesCount(5) \
++ 2 * sendMessagesCount(5))
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
+{
+    const int kEmptyMessageSize = textMode ? 6 : 0;
+
+    // Step 1: Create a start packet for each side of the transaction
+    CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    // Step 2: Exchange the start packets, forcing the DH commit messages to collide
+    CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
+              "Bob DH packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    CFReleaseNull(bobStartPacket);
+
+    CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
+              "Alice DH packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFReleaseNull(aliceStartPacket);
+
+    // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+
+    CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
+              "Alice DH Key packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFReleaseNull(aliceDHKeyResponse);
+
+    CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
+              "Bob DH Key packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    CFReleaseNull(bobDHKeyResponse);
+
+    // Step 4: Having gotten the reveal signature, now work for the signature
+
+    CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
+              "Bob Reveal sig failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    CFReleaseNull(bobRevealSigResponse);
+
+    CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
+              "Alice Reveal sig failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFReleaseNull(aliceRevealSigResponse);
+
+    // Step 5: All the messages have been sent, now deal with any replays from the collision handling
+    CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
+              "Alice Final Sig failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
+              "Bob Final Sig failed");
+
+    is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
+    CFReleaseNull(aliceFinalResponse);
+    CFReleaseNull(bobSigResponse);
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
+    ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+    ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+
+    CFReleaseNull(aliceSigResponse);
+    CFReleaseNull(bobFinalResponse);
+
+    sendMessages(5, bobSession, aliceSession, serializeMessaging);
+
+    for(int i = 0; i < 5; i++){
+        sendMessages(1, aliceSession, bobSession, serializeMessaging);
+        sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+        ok(SecOTRSGetKeyID(*aliceSession) == SecOTRSGetKeyID(*bobSession));
+    }
+}
+
+
+#define kTestTestCount (11 + kNegotiateTestCount * 6)
+
+static void tests()
+{
+    CFErrorRef testError = NULL;
+    SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    testError = NULL;
+    SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    testError = NULL;
+
+    ok(aliceID, "create alice ID");
+    ok(bobID, "create bob ID");
+
+    SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+
+    ok(alicePublicID, "extract alice public");
+    ok(bobPublicID, "extract bob public");
+
+    SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRSendTextMessages);
+    SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRSendTextMessages);
+
+    ok(aliceSession, "create alice session");
+    ok(bobSession, "create bob session");
+
+    SecOTRSessionRef aliceCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat);
+    SecOTRSessionRef bobCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat);
+
+    ok(aliceCompactSession, "create alice compact session");
+    ok(bobCompactSession, "create bob compact session");
+
+    SecOTRSessionRef aliceCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
+    SecOTRSessionRef bobCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
+
+    ok(aliceCompactHashesSession, "create alice compact session with hashes");
+    ok(bobCompactHashesSession, "create bob compact session with hashes");
+
+    // Release the IDs, sessions shouldn't need us to retain them for them.
+    CFReleaseNull(aliceID);
+    CFReleaseNull(bobID);
+
+    CFReleaseNull(alicePublicID);
+    CFReleaseNull(bobPublicID);
+
+    negotiate(&aliceSession, &bobSession, true, true, true, false);
+
+    negotiate(&aliceSession, &bobSession, true, false, true, false);
+
+    negotiate(&aliceCompactSession, &bobCompactSession, true, true, false, true);
+
+    negotiate(&aliceCompactSession, &bobCompactSession, true, false, false, true);
+
+    negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, true, false, true);
+
+    negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, false, false, true);
+
+    /* cleanup keychain */
+    ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+
+    CFReleaseNull(aliceSession);
+    CFReleaseNull(bobSession);
+
+    CFReleaseNull(aliceCompactSession);
+    CFReleaseNull(bobCompactSession);
+
+    CFReleaseNull(aliceCompactHashesSession);
+    CFReleaseNull(bobCompactHashesSession);
+}
+
+int otr_50_roll(int argc, char *const *argv)
+{
+    plan_tests(kTestTestCount);
+
+    tests();
+
+    return 0;
+}
diff --git a/Security/sec/Security/Regressions/otr/otr-60-slowroll.c b/Security/sec/Security/Regressions/otr/otr-60-slowroll.c
new file mode 100644 (file)
index 0000000..53a9c1b
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Security_regressions.h"
+
+#include <CoreFoundation/CFData.h>
+#include <Security/SecOTRSession.h>
+#include <Security/SecOTRSessionPriv.h>
+#include <Security/SecInternal.h>
+#include <Security/SecBasePriv.h>
+
+static void SecMPLogError(CFErrorRef error) {
+    if (error == NULL) {
+        return;
+    }
+    CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error);
+    CFIndex errorCode = CFErrorGetCode(error);
+    CFStringRef errorDomain = CFErrorGetDomain(error);
+    CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey);
+    CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey);
+    if (previousError != NULL) {
+        SecMPLogError(previousError);
+    }
+    char errorDomainStr[1024];
+    char errorStringStr[1024];
+
+    CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8);
+    CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8);
+    printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr);
+    CFReleaseSafe(tempDictionary);
+}
+
+static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
+{
+    CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    SecOTRSAppendSerialization(*thisOne, serialized);
+    CFReleaseNull(*thisOne);
+    *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
+
+    CFReleaseSafe(serialized);
+}
+
+
+
+#define sendMessagesCount(n) ((n) * 5)
+static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
+{
+    for(int count = howMany; count > 0; --count) {
+        const char* aliceToBob = "aliceToBob";
+        CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+        CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+        CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+        ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+        ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+
+        if (serialize) {
+            serializeAndDeserialize(bobSession);
+            serializeAndDeserialize(aliceSession);
+        }
+
+        ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+           && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+        CFReleaseNull(rawAliceToBob);
+        CFReleaseNull(protectedAliceToBob);
+        CFReleaseNull(bobDecode);
+
+        CFStringRef stateString = CFCopyDescription(*bobSession);
+        ok(stateString, "getting state from bob");
+        CFReleaseNull(stateString);
+
+        stateString = CFCopyDescription(*aliceSession);
+        ok(stateString, "getting state from alice");
+        CFReleaseNull(stateString);
+    }
+}
+
+#define kNegotiateTestCount (14 + sendMessagesCount(5) \
++ 60 + (69 * sendMessagesCount(1)))
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
+{
+    const int kEmptyMessageSize = textMode ? 6 : 0;
+
+    // Step 1: Create a start packet for each side of the transaction
+    CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    // Step 2: Exchange the start packets, forcing the DH commit messages to collide
+    CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
+              "Bob DH packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    CFReleaseNull(bobStartPacket);
+
+    CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
+              "Alice DH packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFReleaseNull(aliceStartPacket);
+
+    // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+
+    CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
+              "Alice DH Key packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFReleaseNull(aliceDHKeyResponse);
+
+    CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
+              "Bob DH Key packet failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    CFReleaseNull(bobDHKeyResponse);
+
+    // Step 4: Having gotten the reveal signature, now work for the signature
+
+    CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
+              "Bob Reveal sig failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    CFReleaseNull(bobRevealSigResponse);
+
+    CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
+              "Alice Reveal sig failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFReleaseNull(aliceRevealSigResponse);
+
+    // Step 5: All the messages have been sent, now deal with any replays from the collision handling
+    CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
+              "Alice Final Sig failed");
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(bobSession);
+
+    CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+    ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
+              "Bob Final Sig failed");
+
+    is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
+    CFReleaseNull(aliceFinalResponse);
+    CFReleaseNull(bobSigResponse);
+
+    if (serializeNegotiating)
+        serializeAndDeserialize(aliceSession);
+
+    is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
+    ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+    ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+
+    CFReleaseNull(aliceSigResponse);
+    CFReleaseNull(bobFinalResponse);
+
+    sendMessages(5, bobSession, aliceSession, serializeMessaging);
+
+    //////
+    //both sessions are kicked to roll
+    //////
+    SecOTRSKickTimeToRoll(*aliceSession);
+    SecOTRSKickTimeToRoll(*bobSession);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+    SecOTRSKickTimeToRoll(*bobSession);
+    SecOTRSKickTimeToRoll(*aliceSession);
+
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+    //now we make sure keys do not roll for 10 iterations
+    int aliceKeyID = SecOTRSGetKeyID(*aliceSession);
+    int bobKeyID = SecOTRSGetKeyID(*bobSession);
+
+    for(int i = 0; i< 10; i++){
+        sendMessages(1, aliceSession, bobSession, serializeMessaging);
+        sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+        ok(SecOTRSGetKeyID(*aliceSession) == aliceKeyID);
+        ok(SecOTRSGetKeyID(*bobSession) == bobKeyID);
+    }
+    //////
+    //kicking sending side
+    ///////
+
+    SecOTRSKickTimeToRoll(*aliceSession);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+    SecOTRSKickTimeToRoll(*bobSession);
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+    //now we make sure keys do not roll for 10 iterations
+    aliceKeyID = SecOTRSGetKeyID(*aliceSession);
+    bobKeyID = SecOTRSGetKeyID(*bobSession);
+
+    for(int i = 0; i< 10; i++){
+        sendMessages(1, aliceSession, bobSession, serializeMessaging);
+        sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+        ok(SecOTRSGetKeyID(*aliceSession) == aliceKeyID);
+        ok(SecOTRSGetKeyID(*bobSession) == bobKeyID);
+    }
+    //////
+    //kicking receiving side
+    //////
+    SecOTRSKickTimeToRoll(*bobSession);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+    SecOTRSKickTimeToRoll(*aliceSession);
+    sendMessages(1, bobSession, aliceSession, serializeMessaging);
+    sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+    aliceKeyID = SecOTRSGetKeyID(*aliceSession);
+    bobKeyID = SecOTRSGetKeyID(*bobSession);
+
+    for(int i = 0; i< 10; i++){
+        sendMessages(1, aliceSession, bobSession, serializeMessaging);
+        sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+        ok(SecOTRSGetKeyID(*aliceSession) == aliceKeyID);
+        ok(SecOTRSGetKeyID(*bobSession) == bobKeyID);
+    }
+
+}
+
+
+#define kTestTestCount (11 + kNegotiateTestCount * 6)
+
+static void tests()
+{
+    CFErrorRef testError = NULL;
+    SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    testError = NULL;
+    SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    testError = NULL;
+
+    ok(aliceID, "create alice ID");
+    ok(bobID, "create bob ID");
+
+    SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+    SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+
+    ok(alicePublicID, "extract alice public");
+    ok(bobPublicID, "extract bob public");
+
+    SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRSendTextMessages | kSecOTRSlowRoll);
+    SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRSendTextMessages | kSecOTRSlowRoll);
+
+    ok(aliceSession, "create alice session");
+    ok(bobSession, "create bob session");
+
+    SecOTRSessionRef aliceCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat | kSecOTRSlowRoll);
+    SecOTRSessionRef bobCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat | kSecOTRSlowRoll);
+
+    ok(aliceCompactSession, "create alice compact session");
+    ok(bobCompactSession, "create bob compact session");
+
+    SecOTRSessionRef aliceCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages | kSecOTRSlowRoll);
+    SecOTRSessionRef bobCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages | kSecOTRSlowRoll);
+
+    ok(aliceCompactHashesSession, "create alice compact session with hashes");
+    ok(bobCompactHashesSession, "create bob compact session with hashes");
+
+    // Release the IDs, sessions shouldn't need us to retain them for them.
+    CFReleaseNull(aliceID);
+    CFReleaseNull(bobID);
+
+    CFReleaseNull(alicePublicID);
+    CFReleaseNull(bobPublicID);
+
+    negotiate(&aliceSession, &bobSession, true, true, true, false);
+
+    negotiate(&aliceSession, &bobSession, true, false, true, false);
+
+    negotiate(&aliceCompactSession, &bobCompactSession, true, true, false, true);
+
+    negotiate(&aliceCompactSession, &bobCompactSession, true, false, false, true);
+
+    negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, true, false, true);
+
+    negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, false, false, true);
+
+    /* cleanup keychain */
+    ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
+    SecMPLogError(testError);
+    CFReleaseNull(testError);
+
+    CFReleaseNull(aliceSession);
+    CFReleaseNull(bobSession);
+
+    CFReleaseNull(aliceCompactSession);
+    CFReleaseNull(bobCompactSession);
+
+    CFReleaseNull(aliceCompactHashesSession);
+    CFReleaseNull(bobCompactHashesSession);
+}
+
+int otr_60_slowroll(int argc, char *const *argv)
+{
+    plan_tests(kTestTestCount);
+
+    tests();
+
+    return 0;
+}
index b2bde0c9b7f802294860d336f5f1a9708c770b99..e852ff060bb65c521b8865d98061705a6de9d7af 100644 (file)
 
 #include <Security/SecOTRMath.h>
 #include <Security/SecOTRDHKey.h>
+#include <utilities/SecCFWrappers.h>
 
 int otr_otrdh(int argc, char *const * argv)
 {
-    plan_tests(4);
+    plan_tests(7);
     
     SecOTRFullDHKeyRef aliceFull = SecOTRFullDHKCreate(kCFAllocatorDefault);
     SecOTRPublicDHKeyRef alicePublic = SecOTRPublicDHKCreateFromFullKey(kCFAllocatorDefault, aliceFull);
     
     SecOTRFullDHKeyRef bobFull = SecOTRFullDHKCreate(kCFAllocatorDefault);
     SecOTRPublicDHKeyRef bobPublic = SecOTRPublicDHKCreateFromFullKey(kCFAllocatorDefault, bobFull);
-    
+
+    SecOTRPublicDHKeyRef aliceCompactDeserialized = NULL;
+    SecOTRPublicDHKeyRef aliceDeserialized = NULL;
+
+    CFMutableDataRef aliceCompactSerialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    SecFDHKAppendCompactPublicSerialization(aliceFull, aliceCompactSerialized);
+    size_t aliceCompactLength = CFDataGetLength(aliceCompactSerialized);
+    const uint8_t *aliceCompactSerializationStart = CFDataGetMutableBytePtr(aliceCompactSerialized);
+
+    aliceCompactDeserialized = SecOTRPublicDHKCreateFromCompactSerialization(kCFAllocatorDefault, &aliceCompactSerializationStart, &aliceCompactLength);
+    ok(CFEqualSafe(aliceCompactDeserialized, alicePublic), "Compact serialized compare to created");
+
+
+    CFMutableDataRef aliceSerialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+    SecFDHKAppendPublicSerialization(aliceFull, aliceSerialized);
+    size_t aliceLength = CFDataGetLength(aliceSerialized);
+    const uint8_t *aliceSerializationStart = CFDataGetMutableBytePtr(aliceSerialized);
+
+    aliceDeserialized = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &aliceSerializationStart, &aliceLength);
+    ok(CFEqualSafe(aliceDeserialized, alicePublic), "Serialized compare to created");
+
+    ok(CFEqualSafe(aliceCompactDeserialized, aliceDeserialized), "Serialized compared to compact serailized");
+
     uint8_t aliceMessageKeys[2][kOTRMessageKeyBytes];
     uint8_t aliceMacKeys[2][kOTRMessageMacKeyBytes];
     
@@ -56,6 +79,11 @@ int otr_otrdh(int argc, char *const * argv)
     ok(0 == memcmp(aliceMessageKeys[1], bobMessageKeys[0], sizeof(aliceMessageKeys[1])), "Mac Keys don't match!!");
     ok(0 == memcmp(aliceMacKeys[0], bobMacKeys[1], sizeof(aliceMacKeys[0])), "Mac Keys don't match!!");
     ok(0 == memcmp(aliceMacKeys[1], bobMacKeys[0], sizeof(aliceMacKeys[1])), "Mac Keys don't match!!");
-    
+    CFReleaseNull(aliceCompactSerialized);
+    CFReleaseNull(aliceSerialized);
+    CFReleaseNull(aliceFull);
+    CFReleaseNull(alicePublic);
+    CFReleaseNull(bobFull);
+    CFReleaseNull(bobPublic);
     return 0;
 }
index d29dff66939e761c635afbcfee10492ca6b4e3c5..c8a8b1d0acbf341a6cad9333a79318989dca6411 100644 (file)
@@ -563,6 +563,176 @@ static unsigned char comodo_aia_certificate[1178]={
 0x25,0x5B,0x85,0xFA,0x46,0x9D,0xFE,0xDB,0x64,0xF0,
 };
 
+static unsigned char revoked_ist_certificate[1515]={
+0x30,0x82,0x05,0xE7,0x30,0x82,0x04,0xCF,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x7F,
+0x00,0xCE,0x8A,0xD6,0x3F,0x5B,0x34,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x62,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,
+0x03,0x13,0x13,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,0x20,0x43,0x41,0x20,
+0x32,0x20,0x2D,0x20,0x47,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,
+0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
+0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
+0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x34,
+0x31,0x31,0x32,0x38,0x31,0x35,0x30,0x36,0x31,0x34,0x5A,0x17,0x0D,0x31,0x36,0x31,
+0x32,0x32,0x37,0x31,0x35,0x30,0x36,0x31,0x34,0x5A,0x30,0x81,0xAB,0x31,0x4B,0x30,
+0x49,0x06,0x03,0x55,0x04,0x03,0x0C,0x42,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x2E,
+0x67,0x65,0x6F,0x74,0x72,0x75,0x73,0x74,0x2D,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x2D,
+0x63,0x61,0x2E,0x74,0x65,0x73,0x74,0x2D,0x70,0x61,0x67,0x65,0x73,0x2E,0x63,0x65,
+0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,0x6E,0x61,0x67,0x65,0x72,
+0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x25,0x30,0x23,0x06,0x03,
+0x55,0x04,0x0B,0x0C,0x1C,0x6D,0x61,0x6E,0x61,0x67,0x65,0x6D,0x65,0x6E,0x74,0x3A,
+0x69,0x64,0x6D,0x73,0x2E,0x67,0x72,0x6F,0x75,0x70,0x2E,0x31,0x37,0x36,0x33,0x39,
+0x39,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
+0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
+0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,
+0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,
+0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA9,0xD7,0xE0,0x65,0x48,0x36,0x8A,
+0x4B,0x6C,0xBB,0x16,0xAF,0xFD,0x09,0xA5,0x9C,0x30,0xDA,0xC5,0x9B,0x3D,0xD6,0xB4,
+0x8E,0x6B,0xC2,0xF4,0xBF,0x30,0xA7,0xCC,0xF7,0xA1,0x23,0x58,0xA0,0x16,0xE8,0x31,
+0x5F,0xE7,0xD2,0x21,0x3D,0x24,0x3D,0xF4,0x1E,0x82,0x46,0x45,0xA0,0xB8,0x2E,0xD7,
+0xB6,0x86,0xD3,0x2A,0xBC,0x93,0x74,0x44,0xAB,0x1C,0x9F,0x86,0xBF,0x19,0xCE,0xA4,
+0xD0,0xC9,0xB9,0x65,0x84,0x89,0x87,0xDE,0x77,0xDC,0xAE,0x85,0xA9,0xDE,0x5A,0xCF,
+0xAF,0x46,0x80,0x45,0x72,0x68,0x87,0x55,0x5B,0x4D,0x49,0xE2,0x7B,0x25,0x31,0x22,
+0x00,0x87,0xAB,0x72,0xEB,0x9A,0x2D,0x81,0x35,0x0E,0x76,0x82,0x5C,0x99,0x10,0xFB,
+0xD6,0x3F,0x29,0xE8,0xFD,0x2E,0xAD,0xF6,0xF8,0xCF,0xC1,0x99,0x5F,0xDA,0xC1,0xB3,
+0x90,0x70,0xA5,0x4B,0x23,0x4D,0xD6,0x1D,0xC9,0x73,0x27,0xD1,0xAE,0x38,0xA3,0xD0,
+0x71,0x92,0xFF,0x89,0xA8,0xE5,0x51,0x3E,0x2F,0xB6,0xB4,0x02,0x20,0x54,0x62,0xA0,
+0x69,0x6D,0xB6,0x10,0x8D,0xB7,0x13,0x2A,0x94,0x4E,0xED,0x73,0x8C,0x78,0x39,0xF6,
+0x04,0xC0,0xF8,0x7A,0x75,0x2D,0x1E,0x82,0x7E,0x55,0x7B,0xE7,0xA7,0xFA,0x6E,0xB1,
+0x53,0x81,0x75,0xB6,0x19,0xD8,0xD2,0xD3,0x8E,0x30,0x95,0x0D,0xD8,0xC9,0xBA,0x3F,
+0x70,0x23,0xC3,0x7B,0xE2,0x6E,0xA9,0xA8,0x91,0x69,0x89,0x8D,0xEA,0x64,0x5D,0x8E,
+0x49,0x43,0x30,0x99,0xBC,0x54,0x97,0xAC,0xEB,0x98,0x09,0x8C,0xE9,0xA7,0xE8,0xDC,
+0xFC,0xE4,0xBE,0x20,0xDA,0xA1,0x88,0xB6,0x99,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,
+0x02,0x55,0x30,0x82,0x02,0x51,0x30,0x48,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+0x01,0x01,0x04,0x3C,0x30,0x3A,0x30,0x38,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+0x30,0x01,0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,
+0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x34,
+0x2D,0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,0x63,0x61,0x32,0x67,0x31,0x30,0x31,
+0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x75,0x81,0x7F,0xDF,0xDE,
+0x90,0xE2,0xFB,0x67,0xA8,0x04,0xC9,0x82,0xE1,0x2A,0x13,0x08,0x3D,0xCE,0x8E,0x30,
+0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x1F,0x06,
+0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xD8,0x7A,0x94,0x44,0x7C,0x90,
+0x70,0x90,0x16,0x9E,0xDD,0x17,0x9C,0x01,0x44,0x03,0x86,0xD6,0x2A,0x29,0x30,0x81,
+0xFF,0x06,0x03,0x55,0x1D,0x20,0x04,0x81,0xF7,0x30,0x81,0xF4,0x30,0x81,0xF1,0x06,
+0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x05,0x0B,0x04,0x30,0x81,0xE2,0x30,0x81,
+0xA4,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,0x30,0x81,0x97,0x0C,0x81,
+0x94,0x52,0x65,0x6C,0x69,0x61,0x6E,0x63,0x65,0x20,0x6F,0x6E,0x20,0x74,0x68,0x69,
+0x73,0x20,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x62,0x79,
+0x20,0x61,0x6E,0x79,0x20,0x70,0x61,0x72,0x74,0x79,0x20,0x61,0x73,0x73,0x75,0x6D,
+0x65,0x73,0x20,0x61,0x63,0x63,0x65,0x70,0x74,0x61,0x6E,0x63,0x65,0x20,0x6F,0x66,
+0x20,0x61,0x6E,0x79,0x20,0x61,0x70,0x70,0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,
+0x74,0x65,0x72,0x6D,0x73,0x20,0x61,0x6E,0x64,0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,
+0x69,0x6F,0x6E,0x73,0x20,0x6F,0x66,0x20,0x75,0x73,0x65,0x20,0x61,0x6E,0x64,0x2F,
+0x6F,0x72,0x20,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,
+0x20,0x70,0x72,0x61,0x63,0x74,0x69,0x63,0x65,0x20,0x73,0x74,0x61,0x74,0x65,0x6D,
+0x65,0x6E,0x74,0x73,0x2E,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,
+0x01,0x16,0x2D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x61,0x70,
+0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,
+0x61,0x74,0x65,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2F,0x72,0x70,0x61,
+0x30,0x37,0x06,0x03,0x55,0x1D,0x1F,0x04,0x30,0x30,0x2E,0x30,0x2C,0xA0,0x2A,0xA0,
+0x28,0x86,0x26,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,
+0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,
+0x63,0x61,0x32,0x67,0x31,0x2E,0x63,0x72,0x6C,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
+0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,
+0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x4D,0x06,0x03,0x55,0x1D,0x11,0x04,
+0x46,0x30,0x44,0x82,0x42,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x2E,0x67,0x65,0x6F,
+0x74,0x72,0x75,0x73,0x74,0x2D,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x2D,0x63,0x61,0x2E,
+0x74,0x65,0x73,0x74,0x2D,0x70,0x61,0x67,0x65,0x73,0x2E,0x63,0x65,0x72,0x74,0x69,
+0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,0x6E,0x61,0x67,0x65,0x72,0x2E,0x61,0x70,
+0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC0,0x5B,0xA6,0xAF,0x2C,
+0x27,0xBA,0x49,0x8D,0x41,0xF6,0xC4,0x02,0xEE,0x9D,0xB1,0x48,0xC3,0x34,0x7B,0xF2,
+0xD2,0x82,0x49,0xA5,0x13,0x5A,0x66,0xAD,0xC9,0x73,0xBF,0x6B,0xC9,0x30,0x86,0xBA,
+0x7A,0xD2,0x9D,0x61,0xFE,0x04,0x07,0x15,0x66,0xC2,0x25,0xF7,0x6C,0x88,0xB1,0x0E,
+0x22,0x11,0xF9,0x26,0xA7,0x4E,0x88,0x96,0x20,0x99,0xA6,0x51,0xEE,0x02,0x96,0xC7,
+0xA4,0xCA,0xD4,0xAB,0xFC,0x5F,0x96,0x16,0x0D,0x8D,0xA0,0xA1,0x17,0x6E,0x77,0x92,
+0xC9,0x64,0xD9,0xA2,0x5A,0x00,0x08,0xA6,0x55,0x73,0x2C,0xDD,0xD3,0x0C,0xA5,0xCA,
+0x68,0x48,0xAE,0xCE,0x5F,0xF2,0x56,0x4A,0x66,0x57,0xB2,0x2D,0xB5,0xC6,0xFF,0x50,
+0xD8,0x36,0x9C,0x31,0x31,0xE8,0xB2,0x07,0xE2,0x7B,0xC0,0xCE,0x72,0xA4,0x60,0x91,
+0xBB,0x84,0xA7,0xA8,0xC0,0x1D,0x42,0xE8,0x1D,0xF5,0xD9,0x6B,0x85,0x67,0x23,0x20,
+0xA6,0xF8,0x0F,0xBA,0x83,0x63,0x49,0xE2,0x79,0x23,0x90,0xFF,0x6B,0xEF,0xFA,0xB4,
+0x04,0xA8,0x99,0x1E,0x5D,0x5A,0xCD,0x8C,0xBC,0x8E,0x30,0x41,0x7E,0xE7,0x4E,0xDB,
+0x6F,0x4E,0xB7,0xBA,0xE0,0x5B,0x31,0xC4,0xD2,0x2D,0xD3,0x5D,0x82,0x95,0x44,0x7D,
+0x11,0x60,0x75,0xCE,0x6D,0x12,0xDA,0x89,0x71,0x23,0x80,0x75,0xC0,0x13,0x67,0x27,
+0xE8,0xE8,0xCA,0xE0,0xE3,0xFC,0x72,0x23,0x98,0xFA,0xF0,0x96,0x05,0x23,0xC9,0x03,
+0xC8,0x29,0xA4,0xB1,0xE5,0x07,0xE6,0xE8,0x09,0x26,0xD1,0x8C,0xAF,0xE0,0x53,0xBB,
+0xB4,0x1E,0x4D,0x5E,0xEA,0x9A,0x1E,0xE9,0x42,0x87,0x9F,
+};
+
+static unsigned char ist_intermediate_certificate[1092]={
+0x30,0x82,0x04,0x40,0x30,0x82,0x03,0x28,0xA0,0x03,0x02,0x01,0x02,0x02,0x03,0x02,
+0x3A,0x74,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
+0x00,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
+0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,
+0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,
+0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,
+0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x34,0x30,0x36,0x31,0x36,0x31,
+0x35,0x34,0x32,0x30,0x32,0x5A,0x17,0x0D,0x32,0x32,0x30,0x35,0x32,0x30,0x31,0x35,
+0x34,0x32,0x30,0x32,0x5A,0x30,0x62,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x03,
+0x13,0x13,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,0x20,0x43,0x41,0x20,0x32,
+0x20,0x2D,0x20,0x47,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,0x17,
+0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,
+0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,
+0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,
+0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,
+0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,
+0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD0,0x93,0xA1,0x1D,0x47,0x43,
+0x20,0x16,0xB2,0x0B,0x6B,0xEB,0xC3,0xD5,0xB4,0xE8,0xC7,0x98,0xCD,0xF3,0xDE,0xBF,
+0xE8,0x4D,0xE9,0xE3,0x36,0x80,0x07,0xFC,0x45,0x1B,0x6A,0x7C,0x45,0x86,0xAE,0x56,
+0xD3,0xA4,0x09,0x7F,0x61,0x0D,0x6B,0x5D,0x7E,0x52,0x6B,0x7D,0xB4,0xC8,0x39,0xC4,
+0xF4,0x67,0x3A,0xF7,0x83,0xCE,0x19,0x6F,0x86,0x2F,0x7E,0x45,0x7E,0x47,0x1C,0x67,
+0x52,0xCA,0x95,0x05,0x5D,0xE2,0x36,0x51,0x85,0xC0,0xD4,0x67,0x80,0x35,0x6F,0x15,
+0xDD,0x3E,0xFD,0x1D,0xD2,0xFD,0x8F,0x34,0x50,0xD8,0xEC,0x76,0x2A,0xBE,0xE3,0xD3,
+0xDA,0xE4,0xFD,0xC8,0xEB,0x28,0x02,0x96,0x11,0x97,0x17,0x61,0x1C,0xE9,0xC4,0x59,
+0x3B,0x42,0xDC,0x32,0xD1,0x09,0x1D,0xDA,0xA6,0xD1,0x43,0x86,0xFF,0x5E,0xB2,0xBC,
+0x8C,0xCF,0x66,0xDB,0x01,0x8B,0x02,0xAE,0x94,0x48,0xF3,0x38,0x8F,0xFD,0xEA,0x32,
+0xA8,0x08,0xEC,0x86,0x97,0x51,0x94,0x24,0x3E,0x49,0x49,0x96,0x53,0xE8,0x79,0xA1,
+0x40,0x81,0xE9,0x05,0xBB,0x93,0x95,0x51,0xFC,0xE3,0xFD,0x7C,0x11,0x4B,0xF7,0x9E,
+0x08,0xB3,0x15,0x49,0x15,0x07,0xF9,0xD1,0x37,0xA0,0x9B,0x4B,0x32,0xF6,0xB5,0xC4,
+0xDC,0x6A,0xD1,0xFC,0x0A,0xED,0xF6,0xE0,0xC5,0x29,0xA0,0xA8,0x8B,0x71,0xFE,0x0D,
+0x92,0xBC,0xFE,0x54,0x70,0x18,0x0A,0x6D,0xC7,0xED,0x0C,0xFB,0xC9,0x2D,0x06,0xC3,
+0x8C,0x85,0xFC,0xCB,0x86,0x5C,0xD6,0x36,0x8E,0x12,0x8B,0x09,0x7F,0xFB,0x19,0x1A,
+0x38,0xD5,0xF0,0x94,0x30,0x7A,0x0F,0xA6,0x8C,0xF3,0x02,0x03,0x01,0x00,0x01,0xA3,
+0x82,0x01,0x1D,0x30,0x82,0x01,0x19,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,
+0x30,0x16,0x80,0x14,0xC0,0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,
+0x7D,0xAA,0x7D,0x65,0xB8,0xCA,0xCC,0x4E,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,
+0x16,0x04,0x14,0xD8,0x7A,0x94,0x44,0x7C,0x90,0x70,0x90,0x16,0x9E,0xDD,0x17,0x9C,
+0x01,0x44,0x03,0x86,0xD6,0x2A,0x29,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,
+0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x0E,0x06,0x03,0x55,
+0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x35,0x06,0x03,0x55,
+0x1D,0x1F,0x04,0x2E,0x30,0x2C,0x30,0x2A,0xA0,0x28,0xA0,0x26,0x86,0x24,0x68,0x74,
+0x74,0x70,0x3A,0x2F,0x2F,0x67,0x2E,0x73,0x79,0x6D,0x63,0x62,0x2E,0x63,0x6F,0x6D,
+0x2F,0x63,0x72,0x6C,0x73,0x2F,0x67,0x74,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x2E,0x63,
+0x72,0x6C,0x30,0x2E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x22,
+0x30,0x20,0x30,0x1E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x12,
+0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x67,0x2E,0x73,0x79,0x6D,0x63,0x64,0x2E,0x63,
+0x6F,0x6D,0x30,0x4C,0x06,0x03,0x55,0x1D,0x20,0x04,0x45,0x30,0x43,0x30,0x41,0x06,
+0x0A,0x60,0x86,0x48,0x01,0x86,0xF8,0x45,0x01,0x07,0x36,0x30,0x33,0x30,0x31,0x06,
+0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x25,0x68,0x74,0x74,0x70,0x3A,
+0x2F,0x2F,0x77,0x77,0x77,0x2E,0x67,0x65,0x6F,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,
+0x6F,0x6D,0x2F,0x72,0x65,0x73,0x6F,0x75,0x72,0x63,0x65,0x73,0x2F,0x63,0x70,0x73,
+0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
+0x82,0x01,0x01,0x00,0x16,0x47,0x73,0x6F,0x85,0xA2,0x62,0xE1,0xE7,0x2A,0x76,0xBB,
+0x89,0x95,0x42,0x26,0x97,0xBC,0x4A,0xAC,0xAC,0x70,0x53,0x3A,0x3F,0x31,0x83,0x3D,
+0x3C,0x1C,0xAB,0x9A,0xE2,0xB1,0x5D,0x1C,0x76,0x1A,0xA0,0x3C,0x0C,0x72,0x57,0xBE,
+0xD3,0x9E,0x50,0xE0,0xC8,0x99,0xD6,0x58,0xD7,0x02,0xEA,0xCE,0x0D,0x29,0x54,0x7C,
+0xCD,0xF5,0xC2,0xC6,0x90,0x29,0x55,0xA3,0x6F,0x14,0xA8,0x0B,0x42,0x0D,0x3A,0x98,
+0x6D,0x06,0x78,0x9E,0xF0,0x6A,0xA3,0x1D,0x02,0x0A,0xA2,0x28,0xA4,0x8D,0xC2,0x81,
+0x46,0x3E,0x6D,0x67,0xDA,0xDE,0x3F,0xFE,0x85,0x0E,0x42,0x2A,0x12,0xDE,0xB5,0xB7,
+0xFB,0xB8,0x1B,0xA7,0x96,0xEC,0x77,0x9F,0xEC,0xD4,0x53,0x95,0x7A,0xFF,0x07,0xF4,
+0xF2,0x0A,0x14,0xC0,0x51,0x52,0xB1,0xD6,0x8E,0x50,0x0B,0x1A,0x99,0x5C,0xBC,0x0B,
+0xC9,0xBD,0xED,0xED,0xF8,0x5E,0xC1,0x56,0xDB,0x4D,0x7E,0x23,0xA4,0x11,0xA1,0x2C,
+0xD4,0x1B,0x05,0x9A,0xE4,0x1B,0x52,0xF6,0x7C,0x38,0x99,0x05,0x4B,0xBA,0x72,0x8D,
+0x42,0x89,0x60,0x04,0x66,0x2A,0xF4,0xFD,0x68,0xD7,0x6B,0xF7,0x99,0x41,0x28,0xD6,
+0x6C,0x24,0xAB,0xE6,0x25,0x53,0x2E,0xC8,0x82,0x99,0xE2,0xA2,0x8F,0x23,0xBE,0x30,
+0x83,0xB1,0x27,0x8B,0xFA,0x68,0x7F,0x01,0x49,0xE8,0xC6,0x98,0x6B,0x10,0x2E,0x98,
+0x5E,0x8A,0xD7,0xCA,0x4B,0xB1,0xC7,0xC9,0x58,0x9A,0xD0,0x36,0xDB,0x96,0x95,0xEC,
+0xB6,0x81,0xE4,0xF2,0xCD,0x6F,0x1B,0x79,0x87,0x4C,0x10,0x3C,0x89,0xE4,0x4D,0xFA,
+0x54,0xDC,0xAA,0xA6,
+};
+
 #define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) CFRelease(_cf); }
 #define CFReleaseNull(CF) { CFTypeRef _cf = (CF); \
        if (_cf) { (CF) = NULL; CFRelease(_cf); } }
@@ -600,7 +770,7 @@ static void tests(void)
     is_status(trustResult, kSecTrustResultUnspecified,
                "trust is kSecTrustResultUnspecified");
 
-    
+
     CFDictionaryRef info = SecTrustCopyInfo(trust);
     CFBooleanRef ev = (CFBooleanRef)CFDictionaryGetValue(info,
         kSecTrustInfoExtendedValidationKey);
@@ -649,6 +819,92 @@ static void tests(void)
     CFReleaseSafe(date);
 }
 
+static void test_revocation() {
+    SecTrustRef trust;
+    SecCertificateRef rcert0, rcert1;
+    isnt(rcert0 = SecCertificateCreateWithBytes(NULL,
+         revoked_ist_certificate, sizeof(revoked_ist_certificate)),
+         NULL, "create rcert0");
+    isnt(rcert1 = SecCertificateCreateWithBytes(NULL,
+         ist_intermediate_certificate, sizeof(ist_intermediate_certificate)),
+         NULL, "create rcert1");
+    CFMutableArrayRef rcerts = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+                                                   &kCFTypeArrayCallBacks);
+    CFArrayAppendValue(rcerts, rcert0);
+    CFArrayAppendValue(rcerts, rcert1);
+
+    SecPolicyRef sslPolicy = SecPolicyCreateSSL(false, CFSTR("revoked.geotrust-global-ca.test-pages.certificatemanager.apple.com"));
+    SecPolicyRef ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
+    const void *v_policies[] = { sslPolicy, ocspPolicy };
+    CFArrayRef policies = CFArrayCreate(NULL, v_policies,
+                                        array_size(v_policies), &kCFTypeArrayCallBacks);
+    CFRelease(sslPolicy);
+    CFRelease(ocspPolicy);
+    ok_status(SecTrustCreateWithCertificates(rcerts, policies, &trust),
+              "create trust");
+    /* Feb 5th 2015. */
+    CFDateRef date = CFDateCreate(NULL, 444900000);
+    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
+    CFReleaseSafe(date);
+
+    is(SecTrustGetVerifyTime(trust), 444900000, "get date");
+
+    SecTrustResultType trustResult;
+    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
+    is((trustResult > kSecTrustResultUnspecified), true,
+       "trust is %d, expected value greater than 4", (int)trustResult);
+    CFDictionaryRef results = SecTrustCopyResult(trust);
+    CFTypeRef revoked = NULL;
+    if (results) {
+        CFArrayRef perCertResults = CFDictionaryGetValue(results, CFSTR("TrustResultDetails"));
+        if (perCertResults) {
+            CFDictionaryRef leafResults = CFArrayGetValueAtIndex(perCertResults, 0);
+            if (leafResults) {
+                revoked = CFDictionaryGetValue(leafResults, CFSTR("Revocation"));
+            }
+        }
+    }
+    is(revoked != NULL, true, "revoked result is %@", revoked);
+    CFReleaseSafe(results);
+
+
+    /* Now verify the cert at a date in the past relative to the previous
+       date, but still within the cert's validity period. Although the
+       cached response from our prior attempt will appear to have been
+       produced in the future, it should still be honored since it's
+       validly signed.
+     */
+    /* Dec 11th 2014. */
+    date = CFDateCreate(NULL, 440000000);
+    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
+    CFReleaseSafe(date);
+
+    is(SecTrustGetVerifyTime(trust), 440000000, "get date");
+
+    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
+    is((trustResult > kSecTrustResultUnspecified), true,
+              "trust is %d, expected value greater than 4", (int)trustResult);
+    results = SecTrustCopyResult(trust);
+    revoked = NULL;
+    if (results) {
+        CFArrayRef perCertResults = CFDictionaryGetValue(results, CFSTR("TrustResultDetails"));
+        if (perCertResults) {
+            CFDictionaryRef leafResults = CFArrayGetValueAtIndex(perCertResults, 0);
+            if (leafResults) {
+                revoked = CFDictionaryGetValue(leafResults, CFSTR("Revocation"));
+            }
+        }
+    }
+    is(revoked != NULL, true, "revoked result is %@", revoked);
+    CFReleaseSafe(results);
+
+    CFReleaseSafe(trust);
+    CFReleaseSafe(policies);
+    CFReleaseSafe(rcerts);
+    CFReleaseSafe(rcert0);
+    CFReleaseSafe(rcert1);
+}
+
 #if 0
 static void hexdump(const uint8_t *bytes, size_t len) {
        size_t ix;
@@ -773,27 +1029,34 @@ static void test_aia(void) {
 }
 
 static int ping_host(char *host_name){
-    
+
     struct sockaddr_in pin;
     struct hostent *nlp_host;
     int sd;
     int port;
-    
+    int retries = 5;
+
     port=80;
-    
-    while ((nlp_host=gethostbyname(host_name))==0){
-        printf("Resolve Error!\n");
+
+    //tries 5 times then give up
+    while ((nlp_host=gethostbyname(host_name))==0 && retries--){
+        printf("Resolve Error! (%s) %d\n", host_name, h_errno);
+        sleep(1);
     }
-    
+
+    if(nlp_host==0)
+        return 0;
+
     bzero(&pin,sizeof(pin));
     pin.sin_family=AF_INET;
     pin.sin_addr.s_addr=htonl(INADDR_ANY);
     pin.sin_addr.s_addr=((struct in_addr *)(nlp_host->h_addr))->s_addr;
     pin.sin_port=htons(port);
-    
+
     sd=socket(AF_INET,SOCK_STREAM,0);
-    
+
     if (connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1){
+        printf("connect error! (%s) %d\n", host_name, errno);
         close(sd);
         return 0;
     }
@@ -811,19 +1074,24 @@ int si_23_sectrust_ocsp(int argc, char *const *argv)
         "EVIntl-ocsp.verisign.com",
         "EVIntl-aia.verisign.com",
         "ocsp.comodoca.com",
-        "crt.comodoca.com"
+        "crt.comodoca.com",
+        "ocsp.entrust.net"
     };
-    
-    int host_cnt = 0;
-    for (host_cnt = 0; host_cnt < 5; host_cnt ++)
-        if(!ping_host(hosts[host_cnt])){
-            printf("Accessing specific server failed, checked the network!\n");
+
+    unsigned host_cnt = 0;
+
+    plan_tests(52);
+
+    for (host_cnt = 0; host_cnt < sizeof(hosts)/sizeof(hosts[0]); host_cnt ++) {
+        if(!ping_host(hosts[host_cnt])) {
+            printf("Accessing specific server (%s) failed, check the network!\n", hosts[host_cnt]);
             return 0;
         }
-       plan_tests(39);
+    }
 
     tests();
     test_aia();
+    test_revocation();
 
        return 0;
 }
index 357c0b29f21c16a3712e16216cdaf97f24f57120..0f2ea2c8f6df2fcbd4188d690467db2808cac434 100644 (file)
@@ -53,7 +53,7 @@ struct __SecAccessControl {
     CFMutableDictionaryRef dict;
 };
 
-static CFStringRef SecAccessControlCopyDescription(CFTypeRef cf) {
+static CFStringRef SecAccessControlCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecAccessControlRef access_control = (SecAccessControlRef)cf;
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecAccessControlRef: %p>"), access_control);
 }
index ae6e2f7f2cf4e83968cf7107a1c9ff3d6aea3972..77ad6cdad4747eb92292242fc7460d5ef694f927 100644 (file)
@@ -116,6 +116,7 @@ enum
     errSecMPSignatureInvalid     = -25327,  /* Signature invalid on MP message */
     errSecOTRTooOld              = -25328,  /* Message is too old to use */
     errSecOTRIDTooNew            = -25329,  /* Key ID is too new to use! Message from the future? */
+    errSecOTRNotReady            = -25331,  /* Can't process packets because the session hasn't finished negotiating */
 
 };
 
index f634500cba11e4f70aba8cf0b696a96b9cc3f57d..ba700d3c7983e974f462860595fed97baaa43b73 100644 (file)
@@ -119,7 +119,7 @@ static CFHashCode SecCertificatePathHash(CFTypeRef cf) {
        return hashCode;
 }
 
-static CFStringRef SecCertificatePathCopyDescription(CFTypeRef cf) {
+static CFStringRef SecCertificatePathCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
        SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
     CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
     CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
index 7cf9f9162746f0a63d4e72310515d66bf8930af6..f9b82190a1a21bec2466b5f1b1c49993027b223e 100644 (file)
@@ -930,17 +930,14 @@ DER_CFDateToUTCTime(PRArenaPool *poolp, CFAbsoluteTime date, SecAsn1Item * utcTi
     if (!utcTime->Data)
         return SECFailure;
     
-    int year;
-    int month;
-    int day;
-    int hour;
-    int minute;
-    int second;
-    
-    if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), date, "yMdHms", &year, &month, &day, &hour, &minute, &second))
+    __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+    __block bool result;
+    SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+        result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second);
+    });
+    if (!result)
         return SECFailure;
     
-    
     /* UTC time does not handle the years before 1950 */
     if (year < 1950)
         return SECFailure;
index 35fd8cfbaa484b6c40dd1c5dff63565fe160a3ee..8e929c86965dc34a9a809f0e3f12c2caa0f450c5 100644 (file)
@@ -328,6 +328,14 @@ _SecGenerateSelfSignedCertificate
 //
 // OTR
 //
+_SecOTRSKickTimeToRoll
+_SecOTRSGetTheirKeyID
+_SecOTRSGetKeyID
+_SecFDHKAppendCompactPublicSerialization
+_SecFDHKAppendPublicSerialization
+_SecOTRCopyIncomingBytes
+_SecOTRPublicDHKCreateFromSerialization
+_SecOTRPublicDHKCreateFromCompactSerialization
 _SecOTRDHKGenerateOTRKeys
 _SecOTRFullDHKCreate
 _SecOTRPublicDHKCreateFromFullKey
index 7668a5e9e84790967f703beaf35293be469bc04a..ed2f9d6838493efa06f8289978ce03575483bbfc 100644 (file)
@@ -47,7 +47,7 @@ struct __SecIdentity {
 CFGiblisWithHashFor(SecIdentity)
 
 /* Static functions. */
-static CFStringRef SecIdentityCopyDescription(CFTypeRef cf) {
+static CFStringRef SecIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecIdentityRef identity = (SecIdentityRef)cf;
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
         CFSTR("<SecIdentityRef: %p>"), identity);
index fb5d2e25b9c6be0c47c4a9481e9a7267a3e8c14e..5bb75172f859199f8950a4e6e4a3f89e1d01f56e 100644 (file)
 
 #define kECKeySize 256
 
+static void GenerateHashForKey(ccec_pub_ctx_t public_key, void *output)
+{
+    size_t size = ccec_export_pub_size(public_key);
+
+    uint8_t pub_key_bytes_buffer[size];
+
+    ccec_export_pub(public_key, pub_key_bytes_buffer);
+
+    ccdigest(ccsha1_di(), size, pub_key_bytes_buffer, output);
+}
+
+
 struct _SecOTRFullDHKey {
     CFRuntimeBase _base;
 
@@ -65,11 +77,40 @@ static size_t AppendECCompactPublicKey(CFMutableDataRef data, ccec_pub_ctx_t pub
     return size;
 }
 
+static CFStringRef CCNCopyAsHex(size_t n, cc_unit *value){
+    size_t bytes = ccn_write_uint_size(n, value);
+    uint8_t byte_array [bytes];
+    ccn_write_uint(n, value, bytes, byte_array);
+
+    __block CFStringRef description = NULL;
 
-static CFStringRef SecOTRFullDHKeyCopyDescription(CFTypeRef cf)
+    BufferPerformWithHexString(byte_array, sizeof(byte_array), ^(CFStringRef dataString) {
+        description = CFRetainSafe(dataString);
+    });
+    return description;
+}
+static void withXandY(ccec_pub_ctx_t pubKey, void (^action)(CFStringRef x, CFStringRef y)){
+    CFStringRef xString = NULL;
+    CFStringRef yString = NULL;
+    xString = CCNCopyAsHex(ccec_ctx_n(pubKey), ccec_ctx_x(pubKey));
+    yString = CCNCopyAsHex(ccec_ctx_n(pubKey), ccec_ctx_y(pubKey));
+
+    action(xString, yString);
+    CFReleaseNull(xString);
+    CFReleaseNull(yString);
+}
+static CFStringRef SecOTRFullDHKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
 {
-    SecOTRFullDHKeyRef session = (SecOTRFullDHKeyRef)cf;
-    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRFullDHKeyRef: %p>"), session);
+    SecOTRFullDHKeyRef fullDHKey = (SecOTRFullDHKeyRef)cf;
+    __block CFStringRef description = NULL;
+
+    withXandY(fullDHKey->_key, ^(CFStringRef x, CFStringRef y) {
+        BufferPerformWithHexString(fullDHKey->keyHash, sizeof(fullDHKey->keyHash), ^(CFStringRef dataString) {
+            description = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRFullDHKeyRef@%p: x: %@ y: %@ [%@]>"), fullDHKey, x, y, dataString);
+        });
+    });
+
+    return description;
 }
 
 static Boolean SecOTRFullDHKeyCompare(CFTypeRef leftCF, CFTypeRef rightCF)
@@ -87,6 +128,11 @@ static void SecOTRFullDHKeyDestroy(CFTypeRef cf)
     bzero(fullKey->_key, sizeof(fullKey->_key));
 }
 
+static inline void SecOTRFDHKUpdateHash(SecOTRFullDHKeyRef fullKey)
+{
+    GenerateHashForKey(fullKey->_key, fullKey->keyHash);
+}
+
 SecOTRFullDHKeyRef SecOTRFullDHKCreate(CFAllocatorRef allocator)
 {
     SecOTRFullDHKeyRef newFDHK = CFTypeAllocate(SecOTRFullDHKey, struct _SecOTRFullDHKey, allocator);
@@ -107,13 +153,14 @@ SecOTRFullDHKeyRef SecOTRFullDHKCreateFromBytes(CFAllocatorRef allocator, const
 
     require(publicKeySize <= *size, fail);
     require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize, *bytes, newFDHK->_key), fail);
-    ccdigest(ccsha1_di(), publicKeySize, *bytes, newFDHK->keyHash);
     
     *size -= publicKeySize;
     *bytes += publicKeySize;
 
     require_noerr(ReadMPI(bytes, size, ccec_ctx_n(newFDHK->_key), ccec_ctx_k(newFDHK->_key)), fail);
 
+    SecOTRFDHKUpdateHash(newFDHK);
+
     return newFDHK;
 
 fail:
@@ -131,11 +178,8 @@ void SecFDHKNewKey(SecOTRFullDHKeyRef fullKey)
 
     ccec_compact_generate_key(ccec_cp_256(), rng, fullKey->_key);
 
-    size_t size = ccec_export_pub_size(fullKey->_key);
-    uint8_t publicKey[size];
+    SecOTRFDHKUpdateHash(fullKey);
 
-    ccec_export_pub(fullKey->_key, publicKey);
-    ccdigest(ccsha1_di(), size, publicKey, fullKey->keyHash);
 }
 
 void SecFDHKAppendSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo)
@@ -173,14 +217,21 @@ struct _SecOTRPublicDHKey {
 
     ccec_pub_ctx_decl(ccn_sizeof(kECKeySize), _key);
     uint8_t keyHash[CCSHA1_OUTPUT_SIZE];
-
 };
 
 CFGiblisWithCompareFor(SecOTRPublicDHKey);
 
-static CFStringRef SecOTRPublicDHKeyCopyDescription(CFTypeRef cf) {
-    SecOTRPublicDHKeyRef session = (SecOTRPublicDHKeyRef)cf;
-    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicDHKeyRef: %p>"), session);
+static CFStringRef SecOTRPublicDHKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
+    SecOTRPublicDHKeyRef publicDHKey = (SecOTRPublicDHKeyRef)cf;
+
+    __block CFStringRef description = NULL;
+    withXandY(publicDHKey->_key, ^(CFStringRef x, CFStringRef y) {
+        BufferPerformWithHexString(publicDHKey->keyHash, sizeof(publicDHKey->keyHash), ^(CFStringRef dataString) {
+            description = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicDHKeyRef@%p: x: %@ y: %@ [%@]>"), publicDHKey, x, y, dataString);
+        });
+
+    });
+        return description;
 }
 
 static Boolean SecOTRPublicDHKeyCompare(CFTypeRef leftCF, CFTypeRef rightCF)
@@ -196,6 +247,11 @@ static void SecOTRPublicDHKeyDestroy(CFTypeRef cf) {
     (void) pubKey;
 }
 
+static inline void SecOTRPDHKUpdateHash(SecOTRPublicDHKeyRef pubKey)
+{
+    GenerateHashForKey(pubKey->_key, pubKey->keyHash);
+}
+
 static void ccec_copy_public(ccec_pub_ctx_t source, ccec_pub_ctx_t dest)
 {
     ccec_ctx_cp(dest) = ccec_ctx_cp(source);
@@ -244,7 +300,7 @@ SecOTRPublicDHKeyRef SecOTRPublicDHKCreateFromCompactSerialization(CFAllocatorRe
     *size -= publicKeySize;
     *bytes += publicKeySize;
 
-    ccdigest(ccsha1_di(), *size, *bytes, newPDHK->keyHash);
+    SecOTRPDHKUpdateHash(newPDHK);
 
     return newPDHK;
 fail:
@@ -258,11 +314,12 @@ SecOTRPublicDHKeyRef SecOTRPublicDHKCreateFromBytes(CFAllocatorRef allocator, co
     SecOTRPublicDHKeyRef newPDHK = CFTypeAllocate(SecOTRPublicDHKey, struct _SecOTRPublicDHKey, allocator);
 
     require_noerr(ccec_import_pub(ccec_cp_256(), *size, *bytes, newPDHK->_key), fail);
-    ccdigest(ccsha1_di(), *size, *bytes, newPDHK->keyHash);
 
     *bytes += *size;
     *size = 0;
 
+    SecOTRPDHKUpdateHash(newPDHK);
+
     return newPDHK;
 fail:
     CFReleaseNull(newPDHK);
index 14d1ae87e4a5b8056ef3ca2f81c81af86fb01ca5..39773ebda023ad5841226bb0043a4ea15be2bede 100644 (file)
@@ -27,6 +27,7 @@
 #include <CoreFoundation/CFBase.h>
 #include <CoreFoundation/CFData.h>
 #include <corecrypto/ccn.h>
+#include <corecrypto/ccsha1.h>
 
 __BEGIN_DECLS
 
@@ -41,6 +42,8 @@ void SecFDHKAppendSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef app
 void SecFDHKAppendPublicSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo);
 void SecFDHKAppendCompactPublicSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo);
 
+static const size_t kSecDHKHashSize = CCSHA1_OUTPUT_SIZE;
+
 uint8_t* SecFDHKGetHash(SecOTRFullDHKeyRef pubKey);
 
 
index 538862edbd5096498153cb7bd446a9512647f115..21e458b1c2268334e7aa88ffed37c92ec8d71cae 100644 (file)
@@ -70,7 +70,7 @@ static CFStringRef sSigningKeyName = CFSTR("OTR Signing Key");
 
 CFGiblisFor(SecOTRFullIdentity);
 
-static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyDescription(CFTypeRef cf) {
+static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
     return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
                                     requestor,
index c7b3d67f004bbc580b3a51f657379eae5d5c5f15..5cf2ebd0bf18931db731ce149f111efeb5103fdb 100644 (file)
 
 __BEGIN_DECLS
 
-static OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint8_t expected);
-static OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uint16_t expected);
-static OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*size, OTRMessageType expected);
-
-static OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size,
-                                const uint8_t **dataBytes, size_t *dataSize);
-static OSStatus SizeAndSkipMPI(const uint8_t **bytes, size_t *size,
-                               const uint8_t **mpiBytes, size_t *mpiSize);
-
-    
-static OSStatus ReadLongLongCompact(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value);
-static OSStatus ReadLongLong(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value);
-static OSStatus ReadLong(const uint8_t**bytesPtr, size_t*sizePtr, uint32_t* value);
-static OSStatus ReadShort(const uint8_t**bytesPtr, size_t*sizePtr, uint16_t* value);
-static OSStatus ReadByte(const uint8_t**bytesPtr, size_t*sizePtr, uint8_t* value);
-static OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr, OTRMessageType* type);
-static OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x);
-static OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data);
-static OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr, SecOTRPublicIdentityRef* publicId);
-static CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator, const uint8_t**bytesPtr, size_t*sizePtr);
-    
-static void AppendLongLongCompact(CFMutableDataRef appendTo, uint64_t value);
-static void AppendLongLong(CFMutableDataRef appendTo, uint64_t value);
-static void AppendLong(CFMutableDataRef appendTo, uint32_t value);
-static void AppendShort(CFMutableDataRef appendTo, uint16_t value);
-static void AppendByte(CFMutableDataRef appendTo, uint8_t type);
-static void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type);
-static void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x);
-static void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data);
-static void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId);
+static CC_NONNULL((1,2))
+OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint8_t expected);
+
+static CC_NONNULL((1,2))
+OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uint16_t expected);
+
+static CC_NONNULL((1,2))
+OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*size, OTRMessageType expected);
+
+static CC_NONNULL((1,2,3,4))
+OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size,
+                         const uint8_t **dataBytes, size_t *dataSize);
+static CC_NONNULL((1,2,3,4))
+OSStatus SizeAndSkipMPI(const uint8_t **bytes, size_t *size,
+                        const uint8_t **mpiBytes, size_t *mpiSize);
+
+
+static CC_NONNULL((1,2,3))
+OSStatus ReadLongLongCompact(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value);
+
+static CC_NONNULL((1,2,3))
+OSStatus ReadLongLong(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value);
+
+static CC_NONNULL((1,2,3))
+OSStatus ReadLong(const uint8_t**bytesPtr, size_t*sizePtr, uint32_t* value);
+
+static CC_NONNULL((1,2,3))
+OSStatus ReadShort(const uint8_t**bytesPtr, size_t*sizePtr, uint16_t* value);
+
+static CC_NONNULL((1,2,3))
+OSStatus ReadByte(const uint8_t**bytesPtr, size_t*sizePtr, uint8_t* value);
+
+static CC_NONNULL((1,2,3))
+OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr, OTRMessageType* type);
+
+static CC_NONNULL((1,2,4))
+OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x);
+
+static CC_NONNULL((1,2,3,4))
+OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data);
+
+static CC_NONNULL((1,2,3))
+OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr, SecOTRPublicIdentityRef* publicId);
+
+static CC_NONNULL((1,2,3))
+CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator, const uint8_t**bytesPtr, size_t*sizePtr);
+
+static CC_NONNULL((1))
+void AppendLongLongCompact(CFMutableDataRef appendTo, uint64_t value);
+
+static CC_NONNULL((1))
+void AppendLongLong(CFMutableDataRef appendTo, uint64_t value);
+
+static CC_NONNULL((1))
+void AppendLong(CFMutableDataRef appendTo, uint32_t value);
+
+static CC_NONNULL((1))
+void AppendShort(CFMutableDataRef appendTo, uint16_t value);
+
+static CC_NONNULL((1))
+void AppendByte(CFMutableDataRef appendTo, uint8_t type);
+
+static CC_NONNULL((1))
+void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type);
+
+static CC_NONNULL((1,3))
+void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x);
+
+static CC_NONNULL((1,3))
+void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data);
+
+static CC_NONNULL((1,2))
+void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId);
 
     
 //
@@ -203,7 +246,7 @@ static inline OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr,
     uint8_t value;
 
     require(type != NULL, fail);
-    require_noerr(result = ReadByte(bytesPtr, sizePtr, &value), fail);
+    require_noerr_quiet(result = ReadByte(bytesPtr, sizePtr, &value), fail);
     
     *type = value;
 fail:
@@ -215,13 +258,13 @@ static inline OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
     require(x != NULL, fail);
-    require(*sizePtr >= 5, fail);
+    require_quiet(*sizePtr >= 5, fail);
     
     uint32_t mpiLength;
     
     ReadLong(bytesPtr, sizePtr, &mpiLength);
     
-    require(mpiLength <= *sizePtr, fail);
+    require_quiet(mpiLength <= *sizePtr, fail);
     
     ccn_read_uint(n, x, mpiLength, *bytesPtr);
     
@@ -239,13 +282,13 @@ static inline OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t*
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
     require(data != NULL, fail);
-    require(*sizePtr >= 5, fail);
+    require_quiet(*sizePtr >= 5, fail);
     
     uint32_t dataLength;
     
     ReadLong(bytesPtr, sizePtr, &dataLength);
     
-    require(dataLength <= *sizePtr, fail);
+    require_quiet(dataLength <= *sizePtr, fail);
     memmove(data, bytesPtr, dataLength);
     
     *bytesPtr += dataLength;
@@ -269,14 +312,14 @@ static inline OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr,
     uint16_t type = 0;
     ReadShort(bytesPtr, sizePtr, &type);
 
-    require(type == 0xF000, fail);
-    require(*sizePtr >= 5, fail);
+    require_quiet(type == 0xF000, fail);
+    require_quiet(*sizePtr >= 5, fail);
     
     uint32_t serializedIDLength = 0;
     ReadLong(bytesPtr, sizePtr, &serializedIDLength);
     
-    require(*sizePtr >= serializedIDLength, fail);
-    require(((CFIndex)serializedIDLength) >= 0, fail);
+    require_quiet(*sizePtr >= serializedIDLength, fail);
+    require_quiet(((CFIndex)serializedIDLength) >= 0, fail);
     
     CFDataRef serializedBytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, *bytesPtr, (CFIndex)serializedIDLength, kCFAllocatorNull);
     
@@ -297,9 +340,9 @@ static inline CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef all
 {
     CFMutableDataRef result = NULL;
     uint32_t sizeInStream;
-    require_noerr(ReadLong(bytesPtr, sizePtr, &sizeInStream), exit);
-    require(sizeInStream <= *sizePtr, exit);
-    require(((CFIndex)sizeInStream) >= 0, exit);
+    require_noerr_quiet(ReadLong(bytesPtr, sizePtr, &sizeInStream), exit);
+    require_quiet(sizeInStream <= *sizePtr, exit);
+    require_quiet(((CFIndex)sizeInStream) >= 0, exit);
     
     result = CFDataCreateMutable(allocator, 0);
     
@@ -320,8 +363,8 @@ static inline OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint
 {
     uint8_t found;
     OSStatus result = ReadByte(bytes, size, &found);
-    require_noerr(result, exit);
-    require_action(found == expected, exit, result = errSecDecode);
+    require_noerr_quiet(result, exit);
+    require_action_quiet(found == expected, exit, result = errSecDecode);
 exit:
     return result;
 }
@@ -330,8 +373,8 @@ static inline OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uin
 {
     uint16_t found;
     OSStatus result = ReadShort(bytes, size, &found);
-    require_noerr(result, exit);
-    require_action(found == expected, exit, result = errSecDecode);
+    require_noerr_quiet(result, exit);
+    require_action_quiet(found == expected, exit, result = errSecDecode);
 exit:
     return result;
 }
@@ -340,8 +383,8 @@ static inline OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*siz
 {
     OTRMessageType found;
     OSStatus result = ReadMessageType(bytes, size, &found);
-    require_noerr(result, exit);
-    require_action(found == expected, exit, result = errSecDecode);
+    require_noerr_quiet(result, exit);
+    require_action_quiet(found == expected, exit, result = errSecDecode);
 exit:
     return result;
 }
@@ -354,10 +397,10 @@ static inline OSStatus ReadAndVerifyVersion(const uint8_t**bytes, size_t*size)
 static inline OSStatus ReadAndVerifyHeader(const uint8_t**bytes, size_t*size, OTRMessageType expected)
 {
     OSStatus result = ReadAndVerifyVersion(bytes, size);
-    require_noerr(result, exit);
+    require_noerr_quiet(result, exit);
     
     result = ReadAndVerifyMessageType(bytes, size, expected);
-    require_noerr(result, exit);
+    require_noerr_quiet(result, exit);
     
 exit:
     return result;
@@ -366,10 +409,10 @@ exit:
 static inline OSStatus ReadHeader(const uint8_t**bytes, size_t*size, OTRMessageType *messageType)
 {
     OSStatus result = ReadAndVerifyVersion(bytes, size);
-    require_noerr(result, exit);
+    require_noerr_quiet(result, exit);
     
     result = ReadMessageType(bytes, size, messageType);
-    require_noerr(result, exit);
+    require_noerr_quiet(result, exit);
     
 exit:
     return result;
@@ -382,8 +425,8 @@ static inline OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size,
     uint32_t sizeRead;
     result = ReadLong(bytes, size, &sizeRead);
     
-    require_noerr(result, exit);
-    require_action(sizeRead <= *size, exit, result = errSecDecode);
+    require_noerr_quiet(result, exit);
+    require_action_quiet(sizeRead <= *size, exit, result = errSecDecode);
     
     *dataSize = sizeRead;
     *dataBytes = *bytes;
index 334ba51e7320724bf5e1f5a85e8033e031fc59f0..45bf8d251af9e6ba1bc4875fc9745c1602f15065 100644 (file)
@@ -43,6 +43,9 @@ typedef enum {
 
     kEvenCompactDataMessage = 0x20,
     kOddCompactDataMessage = 0x21,
+    
+    kEvenCompactDataMessageWithHashes = 0x30,
+    kOddCompactDataMessageWithHashes = 0x31,
 
     kInvalidMessage = 0xFF
 } OTRMessageType;
index 89cfb17c4c364fcad0a6599449b28fa9baf6c76b..aeefde2cedc27cf44065900190fe486210fb1f20 100644 (file)
@@ -65,7 +65,7 @@ CFGiblisFor(SecOTRPublicIdentity);
 
 static bool sAdvertiseHashes = false;
 
-static CF_RETURNS_RETAINED CFStringRef SecOTRPublicIdentityCopyDescription(CFTypeRef cf) {
+static CF_RETURNS_RETAINED CFStringRef SecOTRPublicIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecOTRPublicIdentityRef requestor = (SecOTRPublicIdentityRef)cf;
    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
                                     requestor,
index 1f7d80a34d672b2fb770a8f7a827f48d9bc2f8ce..b15cac39daf69e35b3d90b952a9834c48be8a137 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include "utilities/comparison.h"
+#include <CoreFoundation/CFDate.h>
 
 #include "SecOTRSession.h"
 
 
 CFGiblisFor(SecOTRSession);
 
+static uint64_t setup_defaults_settings(){
+    
+    Boolean keyExistsAndHasValue = false;
+    uint64_t seconds;
+    seconds = CFPreferencesGetAppIntegerValue(CFSTR("OTR"), CFSTR("com.apple.security"), &keyExistsAndHasValue);
+    secdebug("OTR", "Retrieving OTR default settings was success? %d value retrieved: %llu", keyExistsAndHasValue, seconds);
+    return keyExistsAndHasValue ? seconds : (kSecondsPerMinute * 15); //15 minutes by default
+}
+
+static uint64_t SecOTRGetDefaultsWriteSeconds(void) {
+    static dispatch_once_t sdOnceToken;
+    static uint64_t seconds;
+    
+    dispatch_once(&sdOnceToken, ^{
+        seconds = setup_defaults_settings();
+    });
+    
+    return seconds;
+}
+
+static void SecOTRSEnableTimeToRoll(SecOTRSessionRef session){
+    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+    CFAbsoluteTime nextTimeToRoll = now + session->_stallSeconds;
+    
+    if(session->_timeToRoll == 0 || session->_timeToRoll > nextTimeToRoll){
+        session->_timeToRoll = nextTimeToRoll;
+    }
+}
+
+static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
+{
+    for(int i = 0; i < kOTRKeyCacheSize; ++i)
+    {
+        if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
+            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
+            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
+        }
+    }
+}
+
+static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
+{
+    for(int i = 0; i < kOTRKeyCacheSize; ++i)
+    {
+        if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
+            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
+            
+            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
+        }
+    }
+}
+
+static void SecOTRGenerateNewProposedKey(SecOTRSessionRef session)
+{
+    SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
+    
+    // Swap the keys so we know the current key.
+    {
+        SecOTRFullDHKeyRef oldKey = session->_myKey;
+        session->_myKey = session->_myNextKey;
+        session->_myNextKey = oldKey;
+    }
+    
+    // Derive a new next key by regenerating over the old key.
+    SecFDHKNewKey(session->_myNextKey);
+    
+    session->_keyID += 1;
+}
+
+
+static void SecOTRSHandleProposalAcknowledge(SecOTRSessionRef session){
+    if(session->_missedAck){
+        SecOTRGenerateNewProposedKey(session);
+        session->_missedAck = false;
+    }
+    else{
+        session->_receivedAck = true;
+        SecOTRSEnableTimeToRoll(session);
+    }
+}
+
+static void SecOTRSRollIfTime(SecOTRSessionRef session){
+    
+    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+    CFAbsoluteTime longestTimeToRoll = now + session->_stallSeconds;
+    
+    //in case time to roll becomes too large we're going to roll now!
+    if(session->_timeToRoll < now || session->_timeToRoll > longestTimeToRoll){
+        SOSOTRSRoll(session);
+        session->_timeToRoll = 0;
+    }
+}
+
+
 static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
 {
     OTRMessageType type = kInvalidMessage;
@@ -83,6 +178,8 @@ static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
         switch (firstByte) {
             case kOddCompactDataMessage:
             case kEvenCompactDataMessage:
+            case kOddCompactDataMessageWithHashes:
+            case kEvenCompactDataMessageWithHashes:
                 type = firstByte;
                 break;
                 
@@ -96,19 +193,34 @@ static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
     return type;
 }
 
+#if DEBUG
+
+static CFStringRef SecOTRCacheElementCopyDescription(SecOTRCacheElement *keyCache){
+    __block CFStringRef description = NULL;
+    BufferPerformWithHexString(keyCache->_fullKeyHash, sizeof(keyCache->_fullKeyHash), ^(CFStringRef fullKeyHashString) {
+        BufferPerformWithHexString(keyCache->_publicKeyHash,sizeof(keyCache->_publicKeyHash), ^(CFStringRef publicKeyHashString) {
+            description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("fkh: [%@], pkh: [%@], c: %llu tc: %llu"), fullKeyHashString, publicKeyHashString, keyCache->_counter, keyCache->_theirCounter);
+        });
+    });
+    return description;
+}
+
+#endif
 const char *SecOTRPacketTypeString(CFDataRef message)
 {
     if (!message) return "NoMessage";
     switch (SecOTRSGetMessageType(message)) {
-        case kDHMessage:                return "DHMessage (0x02)";
-        case kDataMessage:              return "DataMessage (0x03)";
-        case kDHKeyMessage:             return "DHKeyMessage (0x0A)";
-        case kRevealSignatureMessage:   return "RevealSignatureMessage (0x11)";
-        case kSignatureMessage:         return "SignatureMessage (0x12)";
-        case kEvenCompactDataMessage:   return "kEvenCompactDatamessage (0x20)";
-        case kOddCompactDataMessage:    return "kOddCompactDataMessage (0x21)";
-        case kInvalidMessage:           return "InvalidMessage (0xFF)";
-        default:                        return "UnknownMessage";
+        case kDHMessage:                        return "DHMessage (0x02)";
+        case kDataMessage:                      return "DataMessage (0x03)";
+        case kDHKeyMessage:                     return "DHKeyMessage (0x0A)";
+        case kRevealSignatureMessage:           return "RevealSignatureMessage (0x11)";
+        case kSignatureMessage:                 return "SignatureMessage (0x12)";
+        case kEvenCompactDataMessage:           return "kEvenCompactDatamessage (0x20)";
+        case kOddCompactDataMessage:            return "kOddCompactDataMessage (0x21)";
+        case kEvenCompactDataMessageWithHashes: return "kEvenCompactDatamessage (0x30)";
+        case kOddCompactDataMessageWithHashes:  return "kOddCompactDataMessage (0x31)";
+        case kInvalidMessage:                   return "InvalidMessage (0xFF)";
+        default:                                return "UnknownMessage";
     }
 }
 
@@ -124,9 +236,12 @@ static const char *SecOTRAuthStateString(SecOTRAuthState authState)
     }
 }
 
-static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyDescription(CFTypeRef cf) {
+static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecOTRSessionRef session = (SecOTRSessionRef)cf;
-    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s %s%s%s%s %d:%d %s%s>"),
+
+    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+
+    return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<%s %s %s%s%s%s %d:%d %s%s %llu %s%s%s%s>"),
                                     SecOTRAuthStateString(session->_state),
                                     session->_compactAppleMessages ? "C" :"c",
                                     session->_me ? "F" : "f",
@@ -136,7 +251,12 @@ static CF_RETURNS_RETAINED CFStringRef SecOTRSessionCopyDescription(CFTypeRef cf
                                     session->_keyID,
                                     session->_theirKeyID,
                                     session->_theirPreviousKey ? "P" : "p",
-                                    session->_theirKey ? "T" : "t");
+                                    session->_theirKey ? "T" : "t",
+                                    session->_stallSeconds,
+                                    session->_missedAck ? "M" : "m",
+                                    session->_receivedAck ? "R" : "r",
+                                    session->_stallingTheirRoll ? "S" : "s",
+                                    (session->_timeToRoll > now && session->_timeToRoll != 0) ? "E" : "e");
 }
 
 static void SecOTRSessionDestroy(CFTypeRef cf) {
@@ -178,6 +298,14 @@ static void SecOTRSessionResetInternal(SecOTRSessionRef session)
     bzero(session->_keyCache, sizeof(session->_keyCache));
 }
 
+int SecOTRSGetKeyID(SecOTRSessionRef session){
+    return session->_keyID;
+}
+
+int SecOTRSGetTheirKeyID(SecOTRSessionRef session){
+    return session->_theirKeyID;
+}
+
 void SecOTRSessionReset(SecOTRSessionRef session)
 {
     dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSessionResetInternal);
@@ -190,6 +318,7 @@ SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
 {
     SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
 
+    (void)SecOTRGetDefaultsWriteSeconds();
     newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
 
     newID->_me = myID;
@@ -203,6 +332,13 @@ SecOTRSessionRef SecOTRSessionCreateFromID(CFAllocatorRef allocator,
     newID->_macKeysToExpose = NULL;
     newID->_textOutput = false;
     newID->_compactAppleMessages = false;
+    newID->_includeHashes = false;
+    
+    newID->_timeToRoll =  0;
+    newID->_stallingTheirRoll = false;
+    newID->_stallSeconds = 0;
+    newID->_missedAck = true;
+    newID->_receivedAck = false;
 
     SecOTRSessionResetInternal(newID);
 
@@ -217,6 +353,9 @@ SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
                                            SecOTRPublicIdentityRef theirID,
                                            uint32_t flags)
 {
+    
+    uint64_t seconds = SecOTRGetDefaultsWriteSeconds();
+    
     SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
     if (flags & kSecOTRSendTextMessages) {
         newID->_textOutput = true;
@@ -224,6 +363,15 @@ SecOTRSessionRef SecOTRSessionCreateFromIDAndFlags(CFAllocatorRef allocator,
     if (flags & kSecOTRUseAppleCustomMessageFormat) {
         newID->_compactAppleMessages = true;
     }
+    if(flags & kSecOTRIncludeHashesInMessages)
+    {
+        newID->_includeHashes = true;
+    }
+    if(flags & kSecOTRSlowRoll)
+    {
+        newID->_stallSeconds = seconds;
+    }
+
     return newID;
 }
 
@@ -238,12 +386,33 @@ static bool hashIsZero(uint8_t hash[CCSHA1_OUTPUT_SIZE])
     return isZero;
 }
 
-
 static bool SOSOTRSCacheEntryIsEmpty(SecOTRCacheElement *element)
 {
     return hashIsZero(element->_fullKeyHash) && hashIsZero(element->_publicKeyHash);
 }
 
+#if DEBUG
+
+static void WithCacheDescription(SecOTRSessionRef session, void (^operation)(CFStringRef cacheDescription)) {
+    CFStringRef description = NULL;
+    
+    CFStringRef keyCache0Description = SecOTRCacheElementCopyDescription(&session->_keyCache[0]);
+    CFStringRef keyCache1Description = SecOTRCacheElementCopyDescription(&session->_keyCache[1]);
+    CFStringRef keyCache2Description = SecOTRCacheElementCopyDescription(&session->_keyCache[2]);
+    CFStringRef keyCache3Description = SecOTRCacheElementCopyDescription(&session->_keyCache[3]);
+    
+    description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{%@, %@, %@, %@}"), keyCache0Description, keyCache1Description, keyCache2Description, keyCache3Description);
+    
+    operation(description);
+    
+    CFReleaseNull(keyCache0Description);
+    CFReleaseNull(keyCache1Description);
+    CFReleaseNull(keyCache2Description);
+    CFReleaseNull(keyCache3Description);
+}
+
+#endif
+
 static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
                                       SecOTRFullDHKeyRef myKey,
                                       SecOTRPublicDHKeyRef theirKey,
@@ -252,7 +421,10 @@ static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
 {
     SecOTRCacheElement* emptyKeys = NULL;
     SecOTRCacheElement* cachedKeys = NULL;
-    
+#if DEBUG
+    int emptyPosition = kOTRKeyCacheSize;
+#endif
+
     if ((NULL == myKey) || (NULL == theirKey)) {
         if (messageKey)
             *messageKey = NULL;
@@ -269,18 +441,32 @@ static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
         if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)
          && (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE))) {
             cachedKeys = &session->_keyCache[i];
+#if DEBUG
+            secerror("session@[%p] found key match: mk: %@, tk: %@", session, myKey, theirKey);
+#endif
             break;
         }
 
         if (emptyKeys == NULL && SOSOTRSCacheEntryIsEmpty(&(session->_keyCache[i]))) {
+#if DEBUG
+            emptyPosition = i;
+#endif
+
             emptyKeys = &session->_keyCache[i];
         }
     }
 
     if (cachedKeys == NULL) {
         if (emptyKeys == NULL) {
-            secerror("SecOTRSession key cache was full. Should never happen, spooky.\n");
+#if DEBUG
+            WithCacheDescription(session, ^(CFStringRef cacheDescription) {
+                secerror("session@[%p] Cache miss, spooky for mk: %@, tk: %@ cache: %@", session, myKey, theirKey, cacheDescription);
+            });
+            emptyPosition = 0;
+#endif
+
             emptyKeys = &session->_keyCache[0];
+
         }
 
         // Fill in the entry.
@@ -295,6 +481,12 @@ static void SecOTRSFindKeysForMessage(SecOTRSessionRef session,
                               emptyKeys->_receiveEncryptionKey, emptyKeys->_receiveMacKey);
 
         cachedKeys = emptyKeys;
+#if DEBUG
+        WithCacheDescription(session, ^(CFStringRef cacheDescription) {
+            secerror("mk %@, th: %@ session@[%p] new key cache state added key@[%d]: %@", myKey, theirKey, session, emptyPosition, cacheDescription);
+        });
+#endif
+
     }
     
     if (messageKey)
@@ -313,9 +505,14 @@ SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef
     SecOTRSessionRef result = NULL;
     SecOTRSessionRef session = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
 
+    uint8_t numberOfKeys;
+    uint64_t timeToRoll;
+    
     const uint8_t *bytes = CFDataGetBytePtr(data);
     size_t size = (size_t)CFDataGetLength(data);
-
+    
+    (void)SecOTRGetDefaultsWriteSeconds();
+    
     session->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
 
     session->_me = NULL;
@@ -328,12 +525,17 @@ SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef
     session->_receivedDHKeyMessage = NULL;
     session->_textOutput = false;
     session->_compactAppleMessages = false;
+    session->_timeToRoll =  0;
+    session->_stallingTheirRoll = false;
+    session->_stallSeconds = 0;
+    session->_missedAck = true;
+    session->_receivedAck = false;
 
     bzero(session->_keyCache, sizeof(session->_keyCache));
 
     uint8_t version;
     require_noerr(ReadByte(&bytes, &size, &version), fail);
-    require(version <= 4, fail);
+    require(version <= 6, fail);
 
     require_noerr(ReadLong(&bytes, &size, &session->_state), fail);
     session->_me = SecOTRFullIdentityCreateFromBytes(kCFAllocatorDefault, &bytes, &size, NULL);
@@ -361,14 +563,15 @@ SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef
             session->_receivedDHKeyMessage = CFDataCreateMutableFromOTRDATA(kCFAllocatorDefault, &bytes, &size);
         }
     }
-
+    
     if (version < 3) {
         uint8_t ready;
         require_noerr(ReadByte(&bytes, &size, &ready), fail);
         if (ready && session->_state == kIdle)
             session->_state = kDone;
     }
-
+    
+    
     require_noerr(ReadLong(&bytes, &size, &session->_keyID), fail);
     if (session->_keyID > 0) {
         session->_myKey = SecOTRFullDHKCreateFromBytes(kCFAllocatorDefault, &bytes, &size);
@@ -377,16 +580,32 @@ SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef
         require(session->_myNextKey != NULL, fail);
     }
     
+    
+    require_noerr(ReadByte(&bytes, &size, &numberOfKeys), fail);
+    
     require_noerr(ReadLong(&bytes, &size, &session->_theirKeyID), fail);
-    if (session->_theirKeyID > 0) {
-        if (session->_theirKeyID > 1) {
-            session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
-            require(session->_theirPreviousKey != NULL, fail);
+    if (version < 5) {
+        if (session->_theirKeyID > 0) {
+            if (session->_theirKeyID > 1) {
+                session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
+                require(session->_theirPreviousKey != NULL, fail);
+            }
+            session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
+            require(session->_theirKey != NULL, fail);
         }
-        session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
-        require(session->_theirKey != NULL, fail);
     }
-
+    else {
+        if(numberOfKeys >= 1){
+            if (numberOfKeys >= 2) {
+                session->_theirPreviousKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
+                require(session->_theirPreviousKey != NULL, fail);
+            }
+            session->_theirKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &bytes, &size);
+            require(session->_theirKey != NULL, fail);
+        }
+    }
+    
+    
     uint64_t *counter;
     SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
     require_noerr(ReadLongLong(&bytes, &size, counter), fail);
@@ -413,7 +632,17 @@ SecOTRSessionRef SecOTRSessionCreateFromData(CFAllocatorRef allocator, CFDataRef
     if (version >= 4) {
         require_noerr(ReadByteAsBool(&bytes, &size, &session->_compactAppleMessages), fail);
     }
-
+    if (version >= 5) {
+        require_noerr(ReadByteAsBool(&bytes, &size, &session->_includeHashes), fail);
+    }
+    if (version >= 6) {
+        require_noerr(ReadLongLong(&bytes, &size, &session->_stallSeconds), fail);
+        require_noerr(ReadByteAsBool(&bytes, &size, &session->_stallingTheirRoll), fail);
+        require_noerr(ReadLongLong(&bytes, &size, &timeToRoll), fail);
+        require_noerr(ReadByteAsBool(&bytes, &size, &session->_missedAck), fail);
+        require_noerr(ReadByteAsBool(&bytes, &size, &session->_receivedAck), fail);
+        session->_timeToRoll = timeToRoll;
+    }
     result = session;
     session = NULL;
 
@@ -431,10 +660,10 @@ OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef s
     require(serializeInto, abort);
 
     CFIndex start = CFDataGetLength(serializeInto);
-
+    
     dispatch_sync(session->_queue, ^{
-        const uint8_t version = 4;
-
+        const uint8_t version = 6;
+        uint8_t numberOfKeys = 0;
         CFDataAppendBytes(serializeInto, &version, sizeof(version));
 
         AppendLong(serializeInto, session->_state);
@@ -454,27 +683,35 @@ OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef s
                 AppendByte(serializeInto, 1);
                 AppendCFDataAsDATA(serializeInto, session->_receivedDHMessage);
             }
-
+            
             if (session->_receivedDHKeyMessage == NULL) {
                 AppendByte(serializeInto, 0);
             } else {
                 AppendByte(serializeInto, 1);
                 AppendCFDataAsDATA(serializeInto, session->_receivedDHKeyMessage);
             }
-
+            
             AppendLong(serializeInto, session->_keyID);
             if (session->_keyID > 0) {
                 SecFDHKAppendSerialization(session->_myKey, serializeInto);
                 SecFDHKAppendSerialization(session->_myNextKey, serializeInto);
             }
-
+            
+            if(session->_theirPreviousKey != NULL)
+                numberOfKeys++;
+            if(session->_theirKey != NULL)
+                numberOfKeys++;
+            
+            AppendByte(serializeInto, numberOfKeys);
+            
             AppendLong(serializeInto, session->_theirKeyID);
-            if (session->_theirKeyID > 0) {
-                if (session->_theirKeyID > 1) {
-                    SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
-                }
+            
+            if (session->_theirPreviousKey != NULL)
+                SecPDHKAppendSerialization(session->_theirPreviousKey, serializeInto);
+            
+            if (session->_theirKey != NULL )
                 SecPDHKAppendSerialization(session->_theirKey, serializeInto);
-            }
+            
             
             uint64_t *counter;
             SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey, false, NULL, NULL, &counter);
@@ -498,6 +735,15 @@ OSStatus SecOTRSAppendSerialization(SecOTRSessionRef session, CFMutableDataRef s
             
             AppendByte(serializeInto, session->_textOutput ? 1 : 0);
             AppendByte(serializeInto, session->_compactAppleMessages ? 1 : 0);
+            AppendByte(serializeInto, session->_includeHashes ? 1 : 0);
+
+            AppendLongLong(serializeInto, session->_stallSeconds ? session->_stallSeconds : constant_zero);
+
+            AppendByte(serializeInto, session->_stallingTheirRoll ? 1 : 0);
+            AppendLongLong(serializeInto, (uint64_t)session->_timeToRoll);
+            AppendByte(serializeInto, session->_missedAck ? 1 : 0);
+            AppendByte(serializeInto, session->_receivedAck ? 1 : 0);
+
         }
     });
 
@@ -527,30 +773,6 @@ bool SecOTRSGetIsIdle(SecOTRSessionRef session)
     return result;
 }
 
-static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
-{
-    for(int i = 0; i < kOTRKeyCacheSize; ++i)
-    {
-        if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
-            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
-
-            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
-        }
-    }
-}
-
-static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
-{
-    for(int i = 0; i < kOTRKeyCacheSize; ++i)
-    {
-        if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
-            CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
-
-            bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
-        }
-    }
-}
-
 static void SecOTRSPrecalculateForPair(SecOTRSessionRef session,
                                        SecOTRFullDHKeyRef myKey,
                                        SecOTRPublicDHKeyRef theirKey)
@@ -570,6 +792,11 @@ static void SecOTRSPrecalculateKeysInternal(SecOTRSessionRef session)
     SecOTRSPrecalculateForPair(session, session->_myNextKey, session->_theirPreviousKey);
 }
 
+static void SecOTRSPrecalculateNextKeysInternal(SecOTRSessionRef session)
+{
+    SecOTRSPrecalculateForPair(session, session->_myKey, session->_theirKey);
+}
+
 void SecOTRSPrecalculateKeys(SecOTRSessionRef session)
 {
     dispatch_sync_f(session->_queue, session, (dispatch_function_t) SecOTRSPrecalculateKeysInternal);
@@ -585,6 +812,8 @@ enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRe
         case kDataMessage:
         case kEvenCompactDataMessage:
         case kOddCompactDataMessage:
+        case kEvenCompactDataMessageWithHashes:
+        case kOddCompactDataMessageWithHashes:
             kind = kOTRDataPacket;
             break;
         case kDHMessage:
@@ -604,7 +833,7 @@ enum SecOTRSMessageKind SecOTRSGetMessageKind(SecOTRSessionRef session, CFDataRe
 
 static OSStatus SecOTRSSignAndProtectRaw_locked(SecOTRSessionRef session,
                                                 CFDataRef sourceMessage, CFMutableDataRef destinationMessage,
-                                                uint8_t* messageKey, uint8_t* macKey, uint64_t* counter)
+                                                uint8_t* messageKey, uint8_t* macKey, uint64_t* counter, uint32_t theirKeyID,  SecOTRPublicDHKeyRef theirKey)
 {
     CFIndex start = CFDataGetLength(destinationMessage);
 
@@ -612,7 +841,7 @@ static OSStatus SecOTRSSignAndProtectRaw_locked(SecOTRSessionRef session,
     AppendByte(destinationMessage, 0); // Flags, all zero
 
     AppendLong(destinationMessage, session->_keyID);
-    AppendLong(destinationMessage, session->_theirKeyID);
+    AppendLong(destinationMessage, theirKeyID);
     SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
     AppendLongLong(destinationMessage, ++*counter);
 
@@ -643,11 +872,15 @@ const size_t kCompactMessageMACSize = 16;
 
 static OSStatus SecOTRSSignAndProtectCompact_locked(SecOTRSessionRef session,
                                                     CFDataRef sourceMessage, CFMutableDataRef destinationMessage,
-                                                    uint8_t* messageKey, uint8_t* macKey, uint64_t* counter)
+                                                    uint8_t* messageKey, uint8_t* macKey, uint64_t* counter, uint32_t theirKeyID, SecOTRPublicDHKeyRef theirKey)
 {
     CFIndex start = CFDataGetLength(destinationMessage);
+    bool sendHashes = session->_includeHashes;
+    
+    const uint8_t messageType = sendHashes ? ((theirKeyID & 0x1) ? kOddCompactDataMessageWithHashes : kEvenCompactDataMessageWithHashes)
+                                           : ((theirKeyID & 0x1) ? kOddCompactDataMessage           : kEvenCompactDataMessage);
 
-    AppendByte(destinationMessage, (session->_theirKeyID & 0x1) ? kOddCompactDataMessage : kEvenCompactDataMessage);
+    AppendByte(destinationMessage, messageType);
 
     SecFDHKAppendCompactPublicSerialization(session->_myNextKey, destinationMessage);
     AppendLongLongCompact(destinationMessage, ++*counter);
@@ -660,6 +893,17 @@ static OSStatus SecOTRSSignAndProtectCompact_locked(SecOTRSessionRef session,
                                (size_t)sourceSize, CFDataGetBytePtr(sourceMessage),
                                encryptedDataPointer);
 
+    if (sendHashes) {
+        uint8_t *senderHashPtr = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, kSecDHKHashSize);
+        
+        memcpy(senderHashPtr, SecFDHKGetHash(session->_myKey), kSecDHKHashSize);
+        
+        uint8_t *receiverHashPtr = CFDataIncreaseLengthAndGetMutableBytes(destinationMessage, kSecDHKHashSize);
+        
+        memcpy(receiverHashPtr, SecPDHKGetHash(theirKey), kSecDHKHashSize);
+    }
+    
+    
     CFIndex macedContentsSize = CFDataGetLength(destinationMessage) - start;
     CFIndex macSize = CCSHA1_OUTPUT_SIZE;
     uint8_t mac[macSize];
@@ -692,16 +936,25 @@ OSStatus SecOTRSSignAndProtectMessage(SecOTRSessionRef session,
         uint8_t *messageKey;
         uint8_t *macKey;
         uint64_t *counter;
+        uint32_t theirKeyID = session->_theirKeyID;
+
+        SecOTRPublicDHKeyRef theirKeyToUse = session->_theirKey;
+        
+        SecOTRSRollIfTime(session);
 
-        SecOTRSFindKeysForMessage(session, session->_myKey, session->_theirKey,
+        if(session->_stallingTheirRoll && session->_theirPreviousKey){
+            theirKeyToUse = session->_theirPreviousKey;
+            theirKeyID = session->_theirKeyID - 1;
+        }
+
+        SecOTRSFindKeysForMessage(session, session->_myKey, theirKeyToUse,
                                   true,
                                   &messageKey, &macKey, &counter);
 
-
         CFMutableDataRef destinationMessage = session->_textOutput ? CFDataCreateMutable(kCFAllocatorDefault, 0) : CFRetainSafe(protectedMessage);
 
-        result = session->_compactAppleMessages ? SecOTRSSignAndProtectCompact_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter)
-        : SecOTRSSignAndProtectRaw_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter);
+        result = session->_compactAppleMessages ? SecOTRSSignAndProtectCompact_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter, theirKeyID, theirKeyToUse)
+        : SecOTRSSignAndProtectRaw_locked(session, sourceMessage, destinationMessage, messageKey, macKey, counter, theirKeyID, theirKeyToUse);
         
         if (result == errSecSuccess) {
             if (session->_textOutput) {
@@ -720,6 +973,10 @@ abort:
     return result;
 }
 
+void SecOTRSKickTimeToRoll(SecOTRSessionRef session){
+       session->_timeToRoll = CFAbsoluteTimeGetCurrent();
+}
+
 static void SecOTRAcceptNewRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef newKey)
 {
     if (session->_theirPreviousKey) {
@@ -733,21 +990,29 @@ static void SecOTRAcceptNewRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKey
     session->_theirKeyID += 1;
 }
 
-static void SecOTRGenerateNewProposedKey(SecOTRSessionRef session)
-{
-    SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
+OSStatus SecOTRSetupInitialRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef initialKey) {
+   
+    bzero(session->_keyCache, sizeof(session->_keyCache));
+    
+    session->_theirKey = initialKey;
+    session->_theirKeyID = 1;
+    
+    return errSecSuccess;
+}
 
-    // Swap the keys so we know the current key.
-    {
-        SecOTRFullDHKeyRef oldKey = session->_myKey;
-        session->_myKey = session->_myNextKey;
-        session->_myNextKey = oldKey;
+void SOSOTRSRoll(SecOTRSessionRef session){
+    
+    session->_stallingTheirRoll = false;
+    
+    //receiving side roll
+    if(session->_receivedAck){
+        SecOTRGenerateNewProposedKey(session);
+        session->_missedAck = false;
+        session->_receivedAck = false;
+    }
+    else{
+        session->_missedAck = true;
     }
-
-    // Derive a new next key by regenerating over the old key.
-    SecFDHKNewKey(session->_myNextKey);
-
-    session->_keyID += 1;
 }
 
 static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session,
@@ -841,10 +1106,12 @@ static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session,
     }
 
     if (myID == (session->_keyID + 1)) {
-        SecOTRGenerateNewProposedKey(session);
+        SecOTRSHandleProposalAcknowledge(session);
     }
 
-    SecOTRSPrecalculateKeysInternal(session);
+    SecOTRSRollIfTime(session);
+
+    SecOTRSPrecalculateNextKeysInternal(session);
 
 fail:
     CFReleaseNull(newKey);
@@ -859,45 +1126,85 @@ static OSStatus SecOTRVerifyAndExposeRawCompact_locked(SecOTRSessionRef session,
     OSStatus result = errSecDecode;
     const uint8_t* bytes;
     size_t  size;
-
+    SecOTRPublicDHKeyRef theirKeyForMessage = NULL;
     bytes = CFDataGetBytePtr(decodedBytes);
     size = CFDataGetLength(decodedBytes);
-
+    SecOTRFullDHKeyRef myKeyForMessage = NULL;
     const uint8_t* macDataStart = bytes;
+    bool useEvenKey = false;
+    bool useCurrentKey = false;
+    bool sentHashes = false;
+    uint64_t counter = 0;
 
     uint8_t type_byte;
     require_noerr_quiet(result = ReadByte(&bytes, &size, &type_byte), fail);
-    require_action_quiet(type_byte == kOddCompactDataMessage || type_byte == kEvenCompactDataMessage, fail, result = errSecDecode);
+    require_action_quiet(type_byte == kOddCompactDataMessage || type_byte == kEvenCompactDataMessage
+                         || type_byte == kOddCompactDataMessageWithHashes || type_byte == kEvenCompactDataMessageWithHashes, fail, result = errSecDecode);
 
-    bool useEvenKey = (type_byte == kEvenCompactDataMessage);
+    useEvenKey = (type_byte == kEvenCompactDataMessage || type_byte == kEvenCompactDataMessageWithHashes);
+    sentHashes = (type_byte == kOddCompactDataMessageWithHashes || type_byte == kEvenCompactDataMessageWithHashes);
 
-    bool useCurrentKey = useEvenKey ^ (session->_keyID & 1);
-    SecOTRFullDHKeyRef myKeyForMessage =  useCurrentKey ? session->_myKey : session->_myNextKey;
+    useCurrentKey = useEvenKey ^ (session->_keyID & 1);
+    myKeyForMessage = useCurrentKey ? session->_myKey : session->_myNextKey;
+    
+    require_action_quiet(myKeyForMessage, fail, result = errSecDecode);
 
     theirProposal = SecOTRPublicDHKCreateFromCompactSerialization(kCFAllocatorDefault, &bytes, &size);
-
+    
     require_action_quiet(theirProposal, fail, result = errSecDecode);
-
+    
     bool proposalIsNew = !CFEqualSafe(theirProposal, session->_theirKey);
-    SecOTRPublicDHKeyRef theirKeyForMessage = proposalIsNew ? session->_theirKey : session->_theirPreviousKey;
-
+    theirKeyForMessage = proposalIsNew ? session->_theirKey : session->_theirPreviousKey;
+    
+    require_action_quiet(theirKeyForMessage, fail, result = errSecDecode);
+    
     uint8_t *messageKey;
     uint8_t *macKey;
     uint64_t *theirCounter;
 
+
     SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false, &messageKey, &macKey, &theirCounter);
 
-    uint64_t counter;
     require_noerr_quiet(result = ReadLongLongCompact(&bytes, &size, &counter), fail);
     require_action_quiet(counter > *theirCounter, fail, result = errSecOTRTooOld);
 
-    uint8_t mac[CCSHA1_OUTPUT_SIZE];
-    require_action_quiet(sizeof(mac) < size, fail, result = errSecDecode); // require space for the mac and some bytes
-
-    size_t messageSize = size - kCompactMessageMACSize; // It's all message except for the MAC
+    size_t messageSize = size - kCompactMessageMACSize - (sentHashes ? 2 * kSecDHKHashSize : 0); // It's all message except for the MAC and maybe hashes
     const uint8_t* messageStart = bytes;
 
     bytes += messageSize;
+    size -= messageSize;
+    
+    if (sentHashes) {
+        // Sender then receiver keys
+
+        if (memcmp(SecPDHKGetHash(theirKeyForMessage), bytes, kSecDHKHashSize) != 0) {
+            // Wrong sender key WTF.
+#if DEBUG
+            BufferPerformWithHexString(bytes, kSecDHKHashSize, ^(CFStringRef dataString) {
+                secerror("Sender key hash doesn't match: %@ != %@", theirKeyForMessage, dataString);
+            });
+#endif
+        }
+        
+        bytes += kSecDHKHashSize;
+        size -= kSecDHKHashSize;
+        
+        if (memcmp(SecFDHKGetHash(myKeyForMessage), bytes, kSecDHKHashSize) != 0) {
+            // Wrong sender key WTF.
+#if DEBUG
+            BufferPerformWithHexString(bytes, kSecDHKHashSize, ^(CFStringRef dataString) {
+                secerror("Receiver key hash doesn't match: %@ != %@", myKeyForMessage, dataString);
+            });
+#endif
+        }
+        
+        bytes += kSecDHKHashSize;
+        size -= kSecDHKHashSize;
+        
+    }
+    
+    uint8_t mac[CCSHA1_OUTPUT_SIZE];
+    require_action_quiet(kCompactMessageMACSize == size, fail, result = errSecDecode); // require space for the mac and some bytes
 
     size_t macDataSize = (size_t)(bytes - macDataStart);
 
@@ -923,10 +1230,11 @@ static OSStatus SecOTRVerifyAndExposeRawCompact_locked(SecOTRSessionRef session,
     }
     
     if (!useCurrentKey) {
-        SecOTRGenerateNewProposedKey(session);
+        SecOTRSHandleProposalAcknowledge(session);
     }
+    SecOTRSRollIfTime(session);
 
-    SecOTRSPrecalculateKeysInternal(session);
+    SecOTRSPrecalculateNextKeysInternal(session);
 
 fail:
     CFReleaseNull(theirProposal);
@@ -940,34 +1248,41 @@ OSStatus SecOTRSVerifyAndExposeMessage(SecOTRSessionRef session,
 {
     __block OSStatus result = errSecParam;
 
-
+    
     require(session, abort);
     require(incomingMessage, abort);
     require(exposedMessageContents, abort);
-
-    dispatch_sync(session->_queue, ^{
-        CFDataRef decodedBytes = SecOTRCopyIncomingBytes(incomingMessage);
-
-        OTRMessageType messageType = SecOTRSGetMessageType(decodedBytes);
-
-        switch (messageType) {
-            case kDataMessage:
-                result = SecOTRVerifyAndExposeRaw_locked(session, decodedBytes, exposedMessageContents);
-                break;
-
-            case kOddCompactDataMessage:
-            case kEvenCompactDataMessage:
-                result = SecOTRVerifyAndExposeRawCompact_locked(session, decodedBytes, exposedMessageContents);
-                break;
-
-            default:
-                result = errSecUnsupportedFormat;
-                break;
-        }
-
-        CFReleaseSafe(decodedBytes);
-    });
-
+    
+    if(session->_state == kDone){
+        dispatch_sync(session->_queue, ^{
+            CFDataRef decodedBytes = SecOTRCopyIncomingBytes(incomingMessage);
+            
+            OTRMessageType messageType = SecOTRSGetMessageType(decodedBytes);
+            
+            switch (messageType) {
+                case kDataMessage:
+                    result = SecOTRVerifyAndExposeRaw_locked(session, decodedBytes, exposedMessageContents);
+                    break;
+                    
+                case kOddCompactDataMessage:
+                case kEvenCompactDataMessage:
+                case kOddCompactDataMessageWithHashes:
+                case kEvenCompactDataMessageWithHashes:
+                    result = SecOTRVerifyAndExposeRawCompact_locked(session, decodedBytes, exposedMessageContents);
+                    break;
+                    
+                default:
+                    result = errSecUnsupportedFormat;
+                    break;
+            }
+            
+            CFReleaseSafe(decodedBytes);
+        });
+    }
+    else{
+        secnotice("OTR", "session[%p]Cannot process message:%@, session is not done negotiating, session state: %@", session, incomingMessage, session);
+        result = errSecOTRNotReady;
+    }
 abort:
     return result;
 }
@@ -1019,6 +1334,7 @@ static bool data_data_to_data_data_bool_error_request(enum SecXPCOperation op, C
 
 CFDataRef SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) {
 
+    (void)SecOTRGetDefaultsWriteSeconds();
     CFDataRef otrSession = SECURITYD_XPC(sec_otr_session_create_remote, data_to_data_error_request, publicPeerId, error);
     return otrSession;
 
index 5b60f81e76a99e7cdd4906c3b695e00685bb5dad..3d2aab6342a76410711fadb670ab4e5a16f5dc61 100644 (file)
@@ -43,8 +43,10 @@ enum SecOTRSMessageKind {
 // MARK: OTR Session
 
 enum SecOTRCreateFlags {
-    kSecOTRSendTextMessages = 1, // OTR messages will be encoded as Base-64 with header/footer per the standard, not just given back in binary
-    kSecOTRUseAppleCustomMessageFormat = 2, // OTR Messages will be encoded without revealing MAC keys and as compact as we can (P-256)
+    kSecOTRSendTextMessages = 1 << 0, // OTR messages will be encoded as Base-64 with header/footer per the standard, not just given back in binary
+    kSecOTRUseAppleCustomMessageFormat = 1 << 1, // OTR Messages will be encoded without revealing MAC keys and as compact as we can (P-256)
+    kSecOTRIncludeHashesInMessages = 1 << 2,
+    kSecOTRSlowRoll = 1 << 3,
 };
 
 /*!
index 0613d8152e1bc63089b7944c847303ec2d1acaef..5d666af2c95cb74b4e1ce4ec0f5db9f22ac0fce9 100644 (file)
@@ -211,10 +211,8 @@ static OSStatus SecOTRSetupTheirKeyFrom(SecOTRSessionRef session, const uint8_t*
 {
     SecOTRPublicDHKeyRef tempKey = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, data, size);
     require(tempKey != NULL, fail);
-    session->_theirKey = tempKey;
-    session->_theirKeyID = 1;
     
-    return errSecSuccess;
+    return SecOTRSetupInitialRemoteKey(session, tempKey);
 
 fail:
     return errSecDecode;
index 357890eb538df25b59ad498eb9b3ce30d81beeb2..bf0b28c1eb26d2fe4383ff5bb0feaf163d9910d0 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <CoreFoundation/CFBase.h>
 #include <CoreFoundation/CFRuntime.h>
+#include <CoreFoundation/CFDate.h>
 
 #include <Security/SecOTR.h>
 #include <corecrypto/ccn.h>
@@ -39,6 +40,7 @@
 
 #include <Security/SecOTRMath.h>
 #include <Security/SecOTRDHKey.h>
+#include <Security/SecOTRSession.h>
 
 __BEGIN_DECLS
 
@@ -67,6 +69,7 @@ struct _SecOTRCacheElement {
 typedef struct _SecOTRCacheElement SecOTRCacheElement;
 
 #define kOTRKeyCacheSize 4
+#define kSecondsPerMinute 60
 
 struct _SecOTRSession {
     CFRuntimeBase _base;
@@ -97,11 +100,25 @@ struct _SecOTRSession {
     
     bool _textOutput;
     bool _compactAppleMessages;
+    bool _includeHashes;
+    uint64_t _stallSeconds;
+
+    bool _stallingTheirRoll;
+    CFAbsoluteTime _timeToRoll;
+
+    bool _missedAck;
+    bool _receivedAck;
 };
 
 CFDataRef SecOTRCopyIncomingBytes(CFDataRef incomingMessage);
 void SecOTRPrepareOutgoingBytes(CFMutableDataRef destinationMessage, CFMutableDataRef protectedMessage);
 
+OSStatus SecOTRSetupInitialRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef initialKey);
+void SOSOTRSRoll(SecOTRSessionRef session);
+int SecOTRSGetKeyID(SecOTRSessionRef session);
+int SecOTRSGetTheirKeyID(SecOTRSessionRef session);
+void SecOTRSKickTimeToRoll(SecOTRSessionRef session);
+
 __END_DECLS
 
 #endif
index 31ba7388d8192f88eda5cb5ab9a12ad0a361dd99..7cf760f5f298af7796004881e2602bc352476841 100644 (file)
@@ -454,7 +454,7 @@ static CFHashCode SecPolicyHash(CFTypeRef cf) {
        return CFHash(policy->_oid) + CFHash(policy->_options);
 }
 
-static CFStringRef SecPolicyCopyDescription(CFTypeRef cf) {
+static CFStringRef SecPolicyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
        SecPolicyRef policy = (SecPolicyRef) cf;
     CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
     CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
index a7138f505d31de5d710d90ee03681c1a605ef25d..8c3d253fec76ca445969752f18e3eda02863eb03 100644 (file)
@@ -114,7 +114,7 @@ struct __SecTrust {
 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust);
 
 /* Static functions. */
-static CFStringRef SecTrustCopyDescription(CFTypeRef cf) {
+static CFStringRef SecTrustCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecTrustRef trust = (SecTrustRef)cf;
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
         CFSTR("<SecTrustRef: %p>"), trust);
index 92fb33545de7e8faa11bd809b5dcb8e0092471ac..fb8663f130cfc0fb374c87482d971305c894a513 100644 (file)
@@ -131,7 +131,7 @@ struct __SecTrustSettings {
        bool                                                    _dirty;         /* we've changed _trustDict since creation */
 };
 
-static CFStringRef SecTrustSettingsCopyDescription(CFTypeRef cf) {
+static CFStringRef SecTrustSettingsCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     SecTrustSettingsRef ts = (SecTrustSettingsRef)cf;
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
                                     CFSTR("<SecTrustSettings: %p>"), ts);
index 0ea6e15585aa054ba8254ca38dbbdcaef301ef5d..d62a180d2c580e8679df77f11d35d76195f8ba68 100644 (file)
@@ -65,7 +65,7 @@
 #include <xpc/private.h>
 #include <xpc/xpc.h>
 
-#if TARGET_OS_MAC
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
 #include <Security/SecTaskPriv.h>
 #endif
 
@@ -126,7 +126,7 @@ static CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) {
     CFStringRef appID = SecTaskCopyApplicationIdentifier(task);
     CFIndex kagLen = keychainAccessGroups ? CFArrayGetCount(keychainAccessGroups) : 0;
     CFIndex asagLen = appleSecurityApplicationGroups ? CFArrayGetCount(appleSecurityApplicationGroups) : 0;
-#if TARGET_OS_MAC
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
     if ((appID || asagLen) && !SecTaskEntitlementsValidated(task)) {
         CFReleaseNull(appID);
         asagLen = 0;
index 7a78c02acbc2586d3a2edfcc8b040074dc9f37df..8bad54627cc879998c81052e023fe822eb126ba3 100644 (file)
                CD0F8AF61899BF46003E0C52 /* SOSTransportCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = CD0F8AF51899BF46003E0C52 /* SOSTransportCircle.c */; };
                CD0F8AF81899BF57003E0C52 /* SOSTransportMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0F8AF71899BF57003E0C52 /* SOSTransportMessage.h */; };
                CD0F8AFA1899BF63003E0C52 /* SOSTransportCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0F8AF91899BF63003E0C52 /* SOSTransportCircle.h */; };
+               CD303E301A32629700737AD7 /* otr-50-roll.c in Sources */ = {isa = PBXBuildFile; fileRef = CD303E2F1A32629700737AD7 /* otr-50-roll.c */; };
+               CD303E321A32650C00737AD7 /* otr-60-slowroll.c in Sources */ = {isa = PBXBuildFile; fileRef = CD303E311A32650C00737AD7 /* otr-60-slowroll.c */; };
                CD32776B18F8AEFD006B5280 /* SOSPeerCoder.c in Sources */ = {isa = PBXBuildFile; fileRef = CD32776A18F8AEFD006B5280 /* SOSPeerCoder.c */; };
                CD32776D18F8B06E006B5280 /* SOSPeerCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = CD32776C18F8B06E006B5280 /* SOSPeerCoder.h */; };
                CD32776F18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c in Sources */ = {isa = PBXBuildFile; fileRef = CD32776E18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c */; };
                CD32777918F8B3B4006B5280 /* SOSTransportMessageKVS.h in Headers */ = {isa = PBXBuildFile; fileRef = CD32777818F8B3B4006B5280 /* SOSTransportMessageKVS.h */; };
                CD3FD10716C3064B00A83BB6 /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = E7B01B8816572579000485F1 /* SecuritydXPC.c */; };
                CD86DE4E18BD554D00C90CDF /* SOSTransport.c in Sources */ = {isa = PBXBuildFile; fileRef = CD86DE4D18BD554D00C90CDF /* SOSTransport.c */; };
+               CD8E09011A2E918900A2503A /* otr-40-edgecases.c in Sources */ = {isa = PBXBuildFile; fileRef = CD8E09001A2E918900A2503A /* otr-40-edgecases.c */; };
                CD95312B19228D8D005A76B2 /* SOSTransportTestTransports.c in Sources */ = {isa = PBXBuildFile; fileRef = CDAD4E9818EC8424007D4BC2 /* SOSTransportTestTransports.c */; };
                CD95312C19228D92005A76B2 /* SOSTransportTestTransports.h in Headers */ = {isa = PBXBuildFile; fileRef = CDAD4E9A18EC8447007D4BC2 /* SOSTransportTestTransports.h */; };
                CD95312D19228D96005A76B2 /* SOSAccountTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = E7A10FAA1771245D00C4602F /* SOSAccountTesting.h */; };
                4A5CCA4F15ACEFA500702357 /* libSecOtrOSX.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecOtrOSX.a; sourceTree = BUILT_PRODUCTS_DIR; };
                4A824B03158FF07000F932C0 /* libSecurityRegressions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecurityRegressions.a; sourceTree = BUILT_PRODUCTS_DIR; };
                4A971682158FDEB800D439B7 /* SecOTR.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTR.h; sourceTree = "<group>"; };
-               4A971683158FDEB800D439B7 /* SecOTRDHKey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOTRDHKey.c; path = ../../../SecOTRDHKey.c; sourceTree = "<group>"; };
+               4A971683158FDEB800D439B7 /* SecOTRDHKey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRDHKey.c; sourceTree = "<group>"; };
                4A971684158FDEB800D439B7 /* SecOTRDHKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTRDHKey.h; sourceTree = "<group>"; };
                4A971685158FDEB800D439B7 /* SecOTRErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTRErrors.h; sourceTree = "<group>"; };
                4A971686158FDEB800D439B7 /* SecOTRFullIdentity.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRFullIdentity.c; sourceTree = "<group>"; };
                CD0F8AF51899BF46003E0C52 /* SOSTransportCircle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportCircle.c; sourceTree = "<group>"; };
                CD0F8AF71899BF57003E0C52 /* SOSTransportMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessage.h; sourceTree = "<group>"; };
                CD0F8AF91899BF63003E0C52 /* SOSTransportCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircle.h; sourceTree = "<group>"; };
+               CD303E2F1A32629700737AD7 /* otr-50-roll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-50-roll.c"; sourceTree = "<group>"; };
+               CD303E311A32650C00737AD7 /* otr-60-slowroll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-60-slowroll.c"; sourceTree = "<group>"; };
                CD32776A18F8AEFD006B5280 /* SOSPeerCoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerCoder.c; sourceTree = "<group>"; };
                CD32776C18F8B06E006B5280 /* SOSPeerCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerCoder.h; sourceTree = "<group>"; };
                CD32776E18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportKeyParameterKVS.c; sourceTree = "<group>"; };
                CD32777618F8B39B006B5280 /* SOSTransportMessageKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportMessageKVS.c; sourceTree = "<group>"; };
                CD32777818F8B3B4006B5280 /* SOSTransportMessageKVS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessageKVS.h; sourceTree = "<group>"; };
                CD86DE4D18BD554D00C90CDF /* SOSTransport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransport.c; sourceTree = "<group>"; };
+               CD8E09001A2E918900A2503A /* otr-40-edgecases.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-40-edgecases.c"; sourceTree = "<group>"; };
                CDA7729616B899F10069434D /* si-69-keydesc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-69-keydesc.c"; sourceTree = "<group>"; };
                CDAD4E9818EC8424007D4BC2 /* SOSTransportTestTransports.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportTestTransports.c; sourceTree = "<group>"; };
                CDAD4E9A18EC8447007D4BC2 /* SOSTransportTestTransports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportTestTransports.h; sourceTree = "<group>"; };
                                4A824AFA158FF05900F932C0 /* Regressions */,
                                52D0F026169CA72800F07D79 /* SecOnOSX.h */,
                                4A971682158FDEB800D439B7 /* SecOTR.h */,
+                               4A971683158FDEB800D439B7 /* SecOTRDHKey.c */,
                                4A971684158FDEB800D439B7 /* SecOTRDHKey.h */,
                                4A971685158FDEB800D439B7 /* SecOTRErrors.h */,
                                4A971686158FDEB800D439B7 /* SecOTRFullIdentity.c */,
                                4CC92A1315A3ABD400C6D578 /* otr-30-negotiation.c */,
                                4CC92A1415A3ABD400C6D578 /* otr-otrdh.c */,
                                4CC92A1515A3ABD400C6D578 /* otr-packetdata.c */,
+                               CD8E09001A2E918900A2503A /* otr-40-edgecases.c */,
+                               CD303E2F1A32629700737AD7 /* otr-50-roll.c */,
+                               CD303E311A32650C00737AD7 /* otr-60-slowroll.c */,
                        );
                        name = otr;
                        path = Regressions/otr;
                4CC92A4F15A3ABD400C6D578 /* si-67-sectrust-blacklist */ = {
                        isa = PBXGroup;
                        children = (
-                               4A971683158FDEB800D439B7 /* SecOTRDHKey.c */,
                                4CC92A5015A3ABD400C6D578 /* Global Trustee.cer.h */,
                                4CC92A5115A3ABD400C6D578 /* UTN-USERFirst-Hardware.cer.h */,
                                4CC92A5215A3ABD400C6D578 /* addons.mozilla.org.cer.h */,
                                4CC92A6615A3ABD400C6D578 /* si-05-add.c in Sources */,
                                4CC92A6715A3ABD400C6D578 /* si-10-find-internet.c in Sources */,
                                3A70988218CDF648009FD2CC /* si_77_SecAccessControl.c in Sources */,
+                               CD8E09011A2E918900A2503A /* otr-40-edgecases.c in Sources */,
                                4CC92A6815A3ABD400C6D578 /* si-11-update-data.c in Sources */,
                                4CC92A6915A3ABD400C6D578 /* si-14-dateparse.c in Sources */,
                                4CC92A6A15A3ABD400C6D578 /* si-15-certificate.c in Sources */,
                                4CC92A7615A3ABD400C6D578 /* si-24-sectrust-nist.c in Sources */,
                                4CC92A7715A3ABD400C6D578 /* si-24-sectrust-otatasking.c in Sources */,
                                4CC92A7815A3ABD400C6D578 /* si-24-sectrust-shoebox.c in Sources */,
+                               CD303E321A32650C00737AD7 /* otr-60-slowroll.c in Sources */,
                                4CC92A7915A3ABD400C6D578 /* si-25-sectrust-ipsec-eap.c in Sources */,
                                4CC92A7A15A3ABD400C6D578 /* si-26-applicationsigning.c in Sources */,
                                4CC92A7B15A3ABD400C6D578 /* si-27-sectrust-exceptions.c in Sources */,
                                4CC92A8815A3ABD400C6D578 /* si-50-secrandom.c in Sources */,
                                4CC92A8915A3ABD400C6D578 /* si-60-cms.c in Sources */,
                                5DE4A7BD17441CCD0036339E /* si-71-mobile-store-policy.c in Sources */,
+                               CD303E301A32629700737AD7 /* otr-50-roll.c in Sources */,
                                CDD565A2173193AC00B6B074 /* si-73-secpasswordgenerate.c in Sources */,
                                4CC92A8A15A3ABD400C6D578 /* si-61-pkcs12.c in Sources */,
                                4CC92A8B15A3ABD400C6D578 /* si-62-csr.c in Sources */,
index e3eaa575a1f6ea8b22ad31f519d23dc7e80ce54d..6bddb1f20693754336da743375fe7290ad634328 100644 (file)
@@ -109,7 +109,7 @@ struct _OpaqueSecOTAPKI
 
 CFGiblisFor(SecOTAPKI)
 
-static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyDescription(CFTypeRef cf)
+static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
 {
     SecOTAPKIRef otapkiRef = (SecOTAPKIRef)cf;
     return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef->_assetVersion);
index 4922f54956da2625948d3f610e361f4b42a0554a..e49f9988ee19bd5ffdfe1501b755e038303c554b 100644 (file)
@@ -44,7 +44,9 @@
 #include <AssertMacros.h>
 #include <stdint.h>
 
-static int kTestTestCount = 1286;
+
+
+static int kTestTestCount = 1866;
 
 __unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) {
 
@@ -129,6 +131,27 @@ static void testsync2(const char *name,  const char *test_directive, const char
     }, CFSTR("alice"), CFSTR("bob"), CFSTR("claire"), CFSTR("dave"),CFSTR("edward"), CFSTR("frank"), CFSTR("gary"), NULL);
 }
 
+// Smash together identical items, but mute the devices every once in a while.
+// (Simulating packet loss.)
+static void testsmash(const char *name,  const char *test_directive, const char *test_reason) {
+    __block int iteration=0;
+    SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
+        if (iteration < 100 && iteration % 10 == 0) {
+            SOSTestDeviceSetMute(source, !SOSTestDeviceIsMute(source));
+        }
+        return false;
+    }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
+        if (iteration++ < 200) {
+            CFStringRef name = CFStringCreateWithFormat(NULL, NULL, CFSTR("smash-post-%d"), iteration);
+            SOSTestDeviceAddGenericItem(source, name, name);
+            SOSTestDeviceAddGenericItem(dest, name, name);
+            CFReleaseNull(name);
+            return true;
+        }
+        return false;
+    }, CFSTR("alice"), CFSTR("bob"), NULL);
+}
+
 static void testsync(const char *name,  const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), ...) {
     __block int msg_index = 0;
     __block int last_msg_index = 0;
@@ -293,6 +316,7 @@ SKIP:
 #else
         skip("Keychain not reset", kTestTestCount, false);
 #endif
+        testsmash("secd_70_engine-smash", test_directive, test_reason);
 
         testsync3("secd_70_engine3", test_directive, test_reason);
 
index e0cf2e54771dfd2df4b185b2ce439a96307415f9..dcb30f50330511dd47493678fb2b01ac22a0363a 100644 (file)
@@ -103,7 +103,8 @@ static CFArrayRef SecCAIssuerConvertToParents(SecCertificateRef certificate,
     CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate);
     CFArrayRef parents = NULL;
     if (parent) {
-        if (CFEqual(nic, SecCertificateGetNormalizedSubjectContent(parent))) {
+      CFDataRef parent_nic = SecCertificateGetNormalizedSubjectContent(parent);
+      if (parent_nic && CFEqual(nic, parent_nic)) {
             const void *ventry = parent;
             parents = CFArrayCreate(NULL, &ventry, 1, &kCFTypeArrayCallBacks);
         }
index 077f0d486b1667c62f23208d539aa6d1e259731a..d8713b3ccea3c88911fb7997f08e036824bedb7d 100644 (file)
@@ -496,7 +496,7 @@ static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool
     return true;
 }
 
-static CFStringRef SecDbItemCopyDescription(CFTypeRef cf) {
+static CFStringRef SecDbItemCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
 #if 0 //defined(DEBUG) && DEBUG != 0
     SecDbItemRef item = (SecDbItemRef)cf;
     CFMutableStringRef desc = CFStringCreateMutable(CFGetAllocator(cf), 0);
index 39c38ef6481653000a044cae459091bee4a8b7bd..9e69d2456372d36a4aabc0261050ff91441bc495 100644 (file)
@@ -871,14 +871,14 @@ bool SecDbItemDecrypt(SecDbItemRef item, CFDataRef edata, CFDataRef *neededAuth,
 
     if (!ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, &item->credHandle, edata, item->class, item->callerAccessGroups, &dict, &version, error)) {
         // Copy access control data, which might indicate why decryption failed.
-        if (neededAuth)
+        if (access_control && neededAuth)
             *neededAuth = SecAccessControlCopyData(access_control);
         ok = false;
         goto out;
     }
 
     if (!dict) {
-        if (neededAuth)
+        if (access_control && neededAuth)
             *neededAuth = SecAccessControlCopyData(access_control);
         else
             require_quiet(ok = SecError(errSecInteractionNotAllowed, error, CFSTR("auth needed, but caller does not provide it")), out);
index 2b663652e207c05927115025ffef9afeba8a4321..fb24c8a954e7022b01723b170f5e44115b77985b 100644 (file)
@@ -617,7 +617,7 @@ SecCertificatePathRef SecOCSPResponseCopySigner(SecOCSPResponseRef this,
             kCFAllocatorDefault, (*certs)->Data, (*certs)->Length);
         if (cert) {
             CFDataRef certIssuer = SecCertificateGetNormalizedIssuerContent(cert);
-            if (CFEqual(issuerSubject, certIssuer)) {
+            if (certIssuer && CFEqual(issuerSubject, certIssuer)) {
                 SecCertificatePathRef signer = SecCertificatePathCopyAddingLeaf(issuer, cert);
                 CFRelease(cert);
                 if (signer) {
index f5bb542db2ceb838281d97084fa8c81b9508b051..3b5a766354759d07c177f82068deeb45542a9bc4 100644 (file)
@@ -487,8 +487,8 @@ static bool SecMemoryCertificateSourceCopyParents(
                (SecMemoryCertificateSourceRef)source;
        CFDataRef normalizedIssuer =
         SecCertificateGetNormalizedIssuerContent(certificate);
-       CFArrayRef parents = CFDictionaryGetValue(msource->subjects,
-               normalizedIssuer);
+                   CFArrayRef parents = (normalizedIssuer) ? CFDictionaryGetValue(msource->subjects,
+                              normalizedIssuer) : NULL;
     /* FIXME filter parents by subjectID if certificate has an
        authorityKeyIdentifier. */
     secdebug("trust", "%@ parents -> %@", certificate, parents);
index 86080d0ed4fdd15840e59fb74cc29668e8a89f80..19d1227eee78bd0fd98945c1e47148f91d8b0f39 100644 (file)
 
 #include "utilities/SecCFRelease.h"
 #include "utilities/array_size.h"
+#include <utilities/SecCFWrappers.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <corecrypto/ccder.h>
+#include <dispatch/dispatch.h>
 
 #include "utilities_regressions.h"
 
@@ -112,6 +114,110 @@ static bool ok_date_equals(int testnumber, CFDateRef decoded, CFDateRef expected
     }
 }
 
+static CFCalendarRef sZuluCalendar = NULL;
+
+static CFCalendarRef SecCFCalendarGetZulu() {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
+        CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
+        CFCalendarSetTimeZone(sZuluCalendar, tz);
+        CFReleaseSafe(tz);
+    });
+    return sZuluCalendar;
+}
+
+static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *month, int *day, int *hour, int *minute, int *second, CFErrorRef *error) {
+    // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires filesystem access to timezone files when we are only doing zulu time anyway
+    if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), at, "yMdHms", year, month, day, hour, minute, second)) {
+        SecCFDERCreateError(-1000, CFSTR("Failed to encode date."), 0, error);
+        return false;
+    }
+    return true;
+}
+
+//                                                          &year, &month, &day, &hour, &minute, &second
+CFTimeInterval referenceTimeDate = 416957062.807688;   //  2014    3       19      21      24      22
+#define expectedYear 2014
+#define expectedMonth 3
+#define expectedDay 19
+#define expectedHour 21
+#define expectedMinute 24
+#define expectedSecond 22
+
+static bool parallelizeZulu(bool useSharedZuluCalendar, void(^action)(CFCalendarRef zuluCalendar, bool *STOP)) {
+    // If useSharedZuluCalendar is false, NULL will be passed to zuluCalendar parameter of action
+    int ix;
+    static int kThreadLimit = 75000;                                        // on a J86, this took 49963 threads to fail
+    static const int64_t kFailureTimeLimit = (NSEC_PER_SEC * 10);           // Assume failure after 10s
+    dispatch_time_t failTime = dispatch_time(DISPATCH_TIME_NOW, kFailureTimeLimit);
+
+    // This is a __block variable since it can get modified (due the the <rdar://problem/16372688>)
+    __block CFCalendarRef zuluCalendar = useSharedZuluCalendar ? SecCFCalendarGetZulu() : NULL;
+    __block bool stop = false;
+
+    dispatch_group_t dgroup = dispatch_group_create();
+    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+    for (ix=0;ix<kThreadLimit && !stop;ix++) {
+        dispatch_group_enter(dgroup);
+        dispatch_async(queue, ^{
+            action(zuluCalendar, &stop);
+            dispatch_group_leave(dgroup);
+        });
+    }
+    dispatch_group_wait(dgroup, failTime);
+    dispatch_release(dgroup);
+    return !stop;
+}
+
+// We expect this to fail until this is fixed:
+//  <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
+//
+static void testWithUnguardedZuluCalendar() {
+    const bool useSharedZuluCalendar = true;
+    __block bool success = true;
+    __block int successCount = 0;
+
+    success &= parallelizeZulu(useSharedZuluCalendar, ^(CFCalendarRef zuluCalendar, bool *STOP) {
+        int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+        bool matches = false;
+        if (!SecAbsoluteTimeGetGregorianDate(referenceTimeDate, &year, &month, &day, &hour, &minute, &second, NULL))
+            success = false;
+        matches = year==expectedYear && month==expectedMonth && day==expectedDay &&
+        hour==expectedHour && minute==expectedMinute && second==expectedSecond;
+//      assert(matches);    // enable to catch crash
+        if (matches)
+            successCount++;
+        else
+            *STOP = true;
+    });
+
+    todo("<rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe, not yet fixed");
+
+    TODO: {
+        ok(success,"unexpected result from SecAbsoluteTimeGetGregorianDate, failed, successes: %d", successCount);
+    }
+}
+
+static void testDoWithZulu() {
+    const bool useSharedZuluCalendar = false;
+    int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+    __block bool success = true;
+
+    success &= parallelizeZulu(useSharedZuluCalendar, ^(CFCalendarRef zuluCalendar, bool *STOP) {
+        SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+            bool matches = false;
+            success &= CFCalendarDecomposeAbsoluteTime(zuluCalendar, referenceTimeDate, "yMdHms", &year, &month, &day, &hour, &minute, &second);
+            matches = year==expectedYear && month==expectedMonth && day==expectedDay &&
+                hour==expectedHour && minute==expectedMinute && second==expectedSecond;
+            *STOP = !matches;
+        });
+    });
+
+    ok(success,"unexpected result from CFCalendarDecomposeAbsoluteTime");
+}
+
 #define kTestsPerTestCase 12
 static void one_test(const struct test_case * thisCase, int testnumber)
 {
@@ -171,11 +277,14 @@ static void tests(void)
 {
     for (int testnumber = 0; testnumber < array_size(test_cases); ++testnumber)
         one_test(test_cases + testnumber, testnumber);
+
+    testWithUnguardedZuluCalendar();
+    testDoWithZulu();
 }
 
 int su_16_cfdate_der(int argc, char *const *argv)
 {
-    plan_tests(kTestCount);
+    plan_tests(kTestCount+2);
     tests();
 
     return 0;
index 0c33c803aace81329479bd0c535550d3d2392e2a..de37f87a429932bb58977cacdbe0f687e7815752 100644 (file)
 #include <utilities/SecCFWrappers.h>
 
 //
-// Global sigleton Zulu time.
+// Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
+//  <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
 //
-CFGiblisGetSingleton(CFCalendarRef, SecCFCalendarGetZulu, zuluCalendar, ^{
-    *zuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
-    CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
-    CFCalendarSetTimeZone(*zuluCalendar, tz);
-    CFReleaseSafe(tz);
-})
+static dispatch_queue_t fqueue_cf;
+static CFCalendarRef sZuluCalendar = NULL;
 
+static dispatch_queue_t SecCFCalendarGetZuluQueue() {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        fqueue_cf = dispatch_queue_create("ZuluCalendar", DISPATCH_QUEUE_SERIAL);
+    });
+    return fqueue_cf;
+}
+
+static CFCalendarRef SecCFCalendarGetZulu() {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
+        CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
+        CFCalendarSetTimeZone(sZuluCalendar, tz);
+        if (tz)
+            CFRelease(tz);
+    });
+    return sZuluCalendar;
+}
 
+void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar)) {
+    dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
+        action(SecCFCalendarGetZulu());
+    });
+}
 
 void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8String, size_t utf8Length)) {
     const char *cstr = CFStringGetCStringPtr(inStr, kCFStringEncodingUTF8);
index e18413f2db781abfb8e7c5485bc25f2960886815..7d51175fa95183813ec42dfbc3ed7ef98d825102 100644 (file)
@@ -68,6 +68,9 @@
 // Call this to create a function that returns a singleton instance of type stype,
 // which is initialized once by calling doThisOnce, with result in its context.  Upon
 // completion body should assign to *result.
+
+CFDictionaryRef kDebugDescriptionFormatOptions;
+
 #define CFGiblisGetSingleton(returnType, giblisClassName, result, doThisOnce) \
 returnType giblisClassName(void); \
 returnType giblisClassName(void) { \
@@ -100,28 +103,36 @@ CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \
         _onceBlock(); \
 }))
 
-
 #define CFGiblisWithHashFor(gibliClassName) \
-    static CFStringRef  gibliClassName##CopyDescription(CFTypeRef cf); \
+    static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
     static void         gibliClassName##Destroy(CFTypeRef cf); \
     static Boolean      gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
     static CFHashCode   gibliClassName##Hash(CFTypeRef cf); \
+    static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
+        return gibliClassName##CopyFormatDescription(cf, kDebugDescriptionFormatOptions);\
+    }\
     \
-    CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, NULL, gibliClassName##CopyDescription, NULL, NULL, NULL)
+    CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
 
 #define CFGiblisWithCompareFor(gibliClassName) \
-    static CFStringRef  gibliClassName##CopyDescription(CFTypeRef cf); \
+    static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
     static void         gibliClassName##Destroy(CFTypeRef cf); \
     static Boolean      gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
+    static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
+        return gibliClassName##CopyFormatDescription(cf, kDebugDescriptionFormatOptions);\
+    }\
     \
-    CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, NULL, gibliClassName##CopyDescription, NULL, NULL, NULL)
+    CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
 
 
 #define CFGiblisFor(gibliClassName) \
-    static CFStringRef  gibliClassName##CopyDescription(CFTypeRef cf); \
+    static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
     static void         gibliClassName##Destroy(CFTypeRef cf); \
+    static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
+        return gibliClassName##CopyFormatDescription(cf, kDebugDescriptionFormatOptions);\
+    }\
     \
-    CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, NULL, gibliClassName##CopyDescription, NULL, NULL, NULL)
+    CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
 
 #define CFTypeAllocateWithSpace(classType, space, allocator) \
     (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), space, NULL)
@@ -130,6 +141,7 @@ CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \
     CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator)
 
 
+
 __BEGIN_DECLS
 
 //
@@ -636,7 +648,7 @@ static inline void CFDictionaryForEach(CFDictionaryRef dictionary, void (^operat
 // MARK: CFCalendar helpers
 //
 
-CFCalendarRef SecCFCalendarGetZulu();
+void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar));
 
 //
 // MARK: CFAbsoluteTime helpers
@@ -674,13 +686,21 @@ static inline CFAbsoluteTime CFAbsoluteTimeForGregorianDay(CFTimeZoneRef tz, int
 
 static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluMoment(int year, int month, int day, int hour, int minute, int second)
 {
-    return CFAbsoluteTimeForCalendarMoment(SecCFCalendarGetZulu(), year, month, day, hour, minute, second);
+    __block CFAbsoluteTime result = 0.0;
+    SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+        result = CFAbsoluteTimeForCalendarMoment(zuluCalendar, year, month, day, hour, minute, second);
+    });
+    return result;
 }
 
 
 static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluDay(int year, int month, int day)
 {
-    return CFAbsoluteTimeForCalendarDay(SecCFCalendarGetZulu(), year, month, day);
+    __block CFAbsoluteTime result = 0.0;
+    SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+        result = CFAbsoluteTimeForCalendarDay(zuluCalendar, year, month, day);
+    });
+    return result;
 }
 
 
index 4de373a7d573e8278340c0b898602317f3cd9ffb..c1aa06404695a074b311bb2b34e698fe3f3972b9 100644 (file)
@@ -151,7 +151,7 @@ static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn, int rc, CFErrorRef *er
 #pragma mark SecDbRef
 
 static CFStringRef
-SecDbCopyDescription(CFTypeRef value)
+SecDbCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
 {
     SecDbRef db = (SecDbRef)value;
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDb path:%@ connections: %@>"), db->db_path, db->connections);
@@ -944,7 +944,7 @@ bool SecDbPerformWrite(SecDbRef db, CFErrorRef *error, void (^perform)(SecDbConn
 }
 
 static CFStringRef
-SecDbConnectionCopyDescription(CFTypeRef value)
+SecDbConnectionCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
 {
     SecDbConnectionRef dbconn = (SecDbConnectionRef)value;
     return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDbConnection %s %s>"),
@@ -1098,8 +1098,9 @@ bool SecDbClearBindings(sqlite3_stmt *stmt, CFErrorRef *error) {
 }
 
 bool SecDbFinalize(sqlite3_stmt *stmt, CFErrorRef *error) {
+    sqlite3 *handle = sqlite3_db_handle(stmt);
     int s3e = sqlite3_finalize(stmt);
-    return s3e == SQLITE_OK ? true : SecDbErrorWithDb(s3e, sqlite3_db_handle(stmt), error, CFSTR("finalize: %p"), stmt);
+    return s3e == SQLITE_OK ? true : SecDbErrorWithDb(s3e, handle, error, CFSTR("finalize: %p"), stmt);
 }
 
 sqlite3_stmt *SecDbPrepareV2(SecDbConnectionRef dbconn, const char *sql, size_t sqlLen, const char **sqlTail, CFErrorRef *error) {
@@ -1158,7 +1159,7 @@ sqlite3_stmt *SecDbCopyStmt(SecDbConnectionRef dbconn, CFStringRef sql, CFString
  TODO: Better yet make a full blow SecDbStatement instance whenever SecDbCopyStmt is called.  Then, when the statement is released, in the Dispose method, we Reset and ClearBindings the sqlite3_stmt * and hand it back to the SecDb with the original CFStringRef for the sql (or hash thereof) as an argument. */
 bool SecDbReleaseCachedStmt(SecDbConnectionRef dbconn, CFStringRef sql, sqlite3_stmt *stmt, CFErrorRef *error) {
     if (stmt) {
-        return SecDbReset(stmt, error) && SecDbClearBindings(stmt, error) && SecDbFinalize(stmt, error);
+        return SecDbFinalize(stmt, error);
     }
     return true;
 }
index 08b568708f815d64cfdf8adec6e4fec3458ed95f..2df138c57cd425bd9cc8d52acbac283c3ccf6851 100644 (file)
@@ -33,7 +33,8 @@
 #include <CoreFoundation/CFCalendar.h>
 #include <math.h>
 
-#define NULL_TIME NAN
+#define NULL_TIME       NAN
+#define IS_NULL_TIME(x) isnan(x)
 
 /* Cumulative number of days in the year for months up to month i.  */
 static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
@@ -64,12 +65,16 @@ static CFAbsoluteTime SecGregorianDateGetAbsoluteTime(int year, int month, int d
 }
 
 static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *month, int *day, int *hour, int *minute, int *second, CFErrorRef *error) {
-    // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires filesystem access to timezone files when we are only doing zulu time anyway
-    if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), at, "yMdHms", year, month, day, hour, minute, second)) {
+    // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because
+    // CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires
+    // filesystem access to timezone files when we are only doing zulu time anyway
+    __block bool result;
+    SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+        result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, at, "yMdHms", year, month, day, hour, minute, second);
+    });
+    if (!result)
         SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Failed to encode date."), 0, error);
-        return false;
-    }
-    return true;
+    return result;
 }
 
 static int der_get_char(const uint8_t **der_p, const uint8_t *der_end,
@@ -215,9 +220,11 @@ static const uint8_t* der_decode_commontime_body(CFAbsoluteTime *at, CFErrorRef
             return NULL;
         }
 
-        *at = SecGregorianDateGetAbsoluteTime(year, month, day, hour, minute, second, timeZoneOffset, error) + fraction;
-        if (*at == NULL_TIME)
+        *at = SecGregorianDateGetAbsoluteTime(year, month, day, hour, minute, second, timeZoneOffset, error);
+        if (IS_NULL_TIME(*at))
             return NULL;
+
+        *at += fraction;
     }
 
     return der;
@@ -374,7 +381,7 @@ uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
     if (!SecAbsoluteTimeGetGregorianDate(at, &year, &month, &day, &hour, &minute, &second, error))
         return NULL;
 
-    return ccder_encode_decimal_quad(year, der,
+    uint8_t * result = ccder_encode_decimal_quad(year, der,
            ccder_encode_decimal_pair(month, der,
            ccder_encode_decimal_pair(day, der,
            ccder_encode_decimal_pair(hour, der,
@@ -382,6 +389,8 @@ uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
            ccder_encode_decimal_pair(second, der,
            ccder_encode_nanoseconds(at, der,
            ccder_encode_byte('Z', der, der_end))))))));
+
+    return result;
 }
 
 uint8_t* der_encode_generalizedtime(CFAbsoluteTime at, CFErrorRef *error,
index 41ab2e23638b9cd82dfdab5e465def045c26c941..cce6955355bbdae6ae60987e5d3719d0af0505f2 100644 (file)
@@ -141,18 +141,15 @@ DER_CFDateToUTCTime(CFAbsoluteTime date, SecAsn1Item * utcTime)
     utcTime->Data = d = PORT_Alloc(13);
     if (!utcTime->Data)
        return SECFailure;
-
-    int year;
-    int month;
-    int day;
-    int hour;
-    int minute;
-    int second;
     
-    if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), date, "yMdHms", &year, &month, &day, &hour, &minute, &second))
+    __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+    __block bool result;
+    SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+        result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second);
+    });
+    if (!result)
         return SECFailure;
 
-
     /* UTC time does not handle the years before 1950 */
     if (year < 1950)
         return SECFailure;
index c9dd8e708f30a9bbad1a173e1291faf2a4ec4c1c..a6c4197a7d3a51c4d587eefa6a1ab788f4182dae 100644 (file)
@@ -238,17 +238,20 @@ static CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef cl
         CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray);
         for (c = 0; c < count; c++) {
             SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c);
-            if (CFEqual(SecCertificateGetNormalizedIssuerContent(cert), issuer)) {
+            CFDataRef nic = (cert) ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
+            if (nic && CFEqual(nic, issuer)) {
                 CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
-                bool found = CFEqual(cert_serial, serial);
-                CFRelease(cert_serial);
-                if (found) {
+                if (cert_serial) {
+                 bool found = CFEqual(cert_serial, serial);
+                 CFRelease(cert_serial);
+                 if (found) {
                     CFRetain(cert);
                     ident = cert;
                     goto out;
-                }
-            }
-        }
+                 }
+               }
+           }
+       }
     }
 
        const void *keys[] = { kSecClass, kSecAttrIssuer, kSecAttrSerialNumber, kSecReturnRef };