From d87e115847b84cc1c3a1ef198a20181cd85b5309 Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 10 Jun 2015 06:04:57 +0000 Subject: [PATCH] Security-57031.20.26.tar.gz --- .../xcshareddata/xcschemes/Debug.xcscheme | 32 +- .../xcshareddata/xcschemes/Release.xcscheme | 6 +- Security/Security.xcodeproj/project.pbxproj | 2 + .../lib/CodeSigner.cpp | 3 +- .../libsecurity_codesigning/lib/CodeSigner.h | 1 + .../lib/SecStaticCode.cpp | 4 +- .../lib/SecStaticCode.h | 1 + .../lib/StaticCode.cpp | 88 ++- .../libsecurity_codesigning/lib/StaticCode.h | 15 +- .../lib/bundlediskrep.cpp | 36 +- .../lib/bundlediskrep.h | 1 + .../lib/csutilities.cpp | 45 ++ .../libsecurity_codesigning/lib/csutilities.h | 27 + .../lib/dirscanner.cpp | 4 +- .../libsecurity_codesigning/lib/gkoverride.m | 168 ------ .../lib/opaquewhitelist.cpp | 39 -- .../lib/policyengine.cpp | 2 +- .../libsecurity_codesigning/lib/resources.cpp | 6 +- .../libsecurity_codesigning/lib/resources.h | 2 +- .../libsecurity_codesigning/lib/signer.cpp | 80 ++- Security/libsecurity_codesigning/lib/signer.h | 3 +- .../project.pbxproj | 158 +---- Security/libsecurity_keychain/lib/SecItem.cpp | 172 +++++- .../libsecurity_keychain/lib/SecTrust.cpp | 8 +- .../libsecurity_keychain/lib/SecTrustPriv.h | 2 +- Security/libsecurity_keychain/lib/Trust.cpp | 28 +- Security/libsecurity_keychain/lib/Trust.h | 18 +- .../lib/TrustRevocation.cpp | 18 +- Security/libsecurity_smime/lib/tsaSupport.c | 14 +- .../regressions/smime-cms-test.c | 7 +- Security/libsecurity_ssl/lib/sslContext.c | 2 +- Security/libsecurity_ssl/lib/sslCrypto.c | 18 +- .../regressions/ssl-42-ciphers.c | 16 +- .../regressions/ssl-44-crashes.c | 26 +- .../libsecurity_utilities/lib/dispatch.cpp | 159 +++++ Security/libsecurity_utilities/lib/dispatch.h | 126 ++++ Security/libsecurity_utilities/lib/errors.cpp | 3 + Security/libsecurity_utilities/lib/errors.h | 2 + .../libsecurity_utilities/lib/macho++.cpp | 3 + Security/libsecurity_utilities/lib/unix++.cpp | 48 ++ Security/libsecurity_utilities/lib/unix++.h | 3 + .../project.pbxproj | 8 + .../sec/SOSCircle/Regressions/SOSTestDevice.c | 30 +- .../sec/SOSCircle/Regressions/SOSTestDevice.h | 4 + .../SOSCircle/SecureObjectSync/SOSAccount.c | 6 +- .../SecureObjectSync/SOSAccountUpdate.c | 2 +- .../SOSCircle/SecureObjectSync/SOSCircle.c | 2 +- .../SOSCircle/SecureObjectSync/SOSEngine.c | 4 +- .../SecureObjectSync/SOSFullPeerInfo.c | 2 +- .../SOSCircle/SecureObjectSync/SOSManifest.c | 2 +- .../SOSCircle/SecureObjectSync/SOSMessage.c | 2 +- .../sec/SOSCircle/SecureObjectSync/SOSPeer.c | 2 +- .../SOSCircle/SecureObjectSync/SOSPeerInfo.c | 2 +- .../SecureObjectSync/SOSTransportCircle.c | 2 +- .../SOSTransportKeyParameter.c | 2 +- .../SecureObjectSync/SOSTransportMessage.c | 2 +- .../Regressions/Security_regressions.h | 3 + .../Regressions/otr/otr-30-negotiation.c | 114 +++- .../Regressions/otr/otr-40-edgecases.c | 466 ++++++++++++++ .../Security/Regressions/otr/otr-50-roll.c | 378 ++++++++++++ .../Regressions/otr/otr-60-slowroll.c | 374 ++++++++++++ .../sec/Security/Regressions/otr/otr-otrdh.c | 34 +- .../Regressions/secitem/si-23-sectrust-ocsp.c | 300 ++++++++- Security/sec/Security/SecAccessControl.c | 2 +- Security/sec/Security/SecBasePriv.h | 1 + Security/sec/Security/SecCertificatePath.c | 2 +- Security/sec/Security/SecCertificateRequest.c | 15 +- Security/sec/Security/SecExports.exp-in | 8 + Security/sec/Security/SecIdentity.c | 2 +- Security/sec/Security/SecOTRDHKey.c | 85 ++- Security/sec/Security/SecOTRDHKey.h | 3 + Security/sec/Security/SecOTRFullIdentity.c | 2 +- Security/sec/Security/SecOTRPacketData.h | 151 +++-- Security/sec/Security/SecOTRPackets.h | 3 + Security/sec/Security/SecOTRPublicIdentity.c | 2 +- Security/sec/Security/SecOTRSession.c | 570 ++++++++++++++---- Security/sec/Security/SecOTRSession.h | 6 +- Security/sec/Security/SecOTRSessionAKE.c | 4 +- Security/sec/Security/SecOTRSessionPriv.h | 17 + Security/sec/Security/SecPolicy.c | 2 +- Security/sec/Security/SecTrust.c | 2 +- Security/sec/Security/SecTrustSettings.c | 2 +- Security/sec/ipc/server.c | 4 +- Security/sec/sec.xcodeproj/project.pbxproj | 16 +- Security/sec/securityd/OTATrustUtilities.c | 2 +- .../securityd/Regressions/secd-70-engine.c | 26 +- Security/sec/securityd/SecCAIssuerRequest.c | 3 +- Security/sec/securityd/SecDbItem.c | 2 +- Security/sec/securityd/SecDbKeychainItem.c | 4 +- Security/sec/securityd/SecOCSPResponse.c | 2 +- Security/sec/securityd/SecTrustServer.c | 4 +- .../utilities/Regressions/su-16-cfdate-der.c | 111 +++- Security/utilities/src/SecCFWrappers.c | 35 +- Security/utilities/src/SecCFWrappers.h | 40 +- Security/utilities/src/SecDb.c | 9 +- Security/utilities/src/der_date.c | 27 +- libsecurity_smime/lib/cmssiginfo.c | 15 +- libsecurity_smime/lib/crypto-embedded.c | 17 +- 98 files changed, 3487 insertions(+), 846 deletions(-) delete mode 100644 Security/libsecurity_codesigning/lib/gkoverride.m create mode 100644 Security/libsecurity_utilities/lib/dispatch.cpp create mode 100644 Security/libsecurity_utilities/lib/dispatch.h create mode 100644 Security/sec/Security/Regressions/otr/otr-40-edgecases.c create mode 100644 Security/sec/Security/Regressions/otr/otr-50-roll.c create mode 100644 Security/sec/Security/Regressions/otr/otr-60-slowroll.c diff --git a/Security.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme index 24a82cc5..42cabb3d 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme @@ -1,10 +1,11 @@ + version = "1.8"> + buildImplicitDependencies = "YES" + enableAddressSanitizer = "NO"> - + + + @@ -568,6 +575,22 @@ argument = "otr_30_negotiation" isEnabled = "NO"> + + + + + + + + @@ -602,7 +625,8 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "Debug" debugDocumentVersioning = "YES"> - + - + - + 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 }; diff --git a/Security/libsecurity_codesigning/lib/SecStaticCode.cpp b/Security/libsecurity_codesigning/lib/SecStaticCode.cpp index 6d71272c..cc4e8c17 100644 --- a/Security/libsecurity_codesigning/lib/SecStaticCode.cpp +++ b/Security/libsecurity_codesigning/lib/SecStaticCode.cpp @@ -115,7 +115,9 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se | kSecCSEnforceRevocationChecks | kSecCSNoNetworkAccess | kSecCSCheckNestedCode - | kSecCSStrictValidate); + | kSecCSStrictValidate + | kSecCSCheckGatekeeperArchitectures + ); if (errors) flags |= kSecCSFullReport; // internal-use flag diff --git a/Security/libsecurity_codesigning/lib/SecStaticCode.h b/Security/libsecurity_codesigning/lib/SecStaticCode.h index 397de4ff..7eae837a 100644 --- a/Security/libsecurity_codesigning/lib/SecStaticCode.h +++ b/Security/libsecurity_codesigning/lib/SecStaticCode.h @@ -148,6 +148,7 @@ enum { kSecCSCheckNestedCode = 1 << 3, kSecCSStrictValidate = 1 << 4, kSecCSFullReport = 1 << 5, + kSecCSCheckGatekeeperArchitectures = (1 << 6) | kSecCSCheckAllArchitectures, }; OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags, diff --git a/Security/libsecurity_codesigning/lib/StaticCode.cpp b/Security/libsecurity_codesigning/lib/StaticCode.cpp index f7503184..f221e5be 100644 --- a/Security/libsecurity_codesigning/lib/StaticCode.cpp +++ b/Security/libsecurity_codesigning/lib/StaticCode.cpp @@ -34,7 +34,6 @@ #include "resources.h" #include "detachedrep.h" #include "csdatabase.h" -#include "csutilities.h" #include "dirscanner.h" #include #include @@ -51,6 +50,7 @@ #include #include #include +#include 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 codeDirectory = rep->codeDirectory(); @@ -104,12 +105,20 @@ SecStaticCode::SecStaticCode(DiskRep *rep) SecStaticCode::~SecStaticCode() throw() try { ::free(const_cast(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 _(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 _(mCancelLock); - if (mCancelPending) - MacOSError::throwMe(errSecCSCancelled); - } // update progress and report - mCurrentWork += amount; - mMonitor(this->handle(false), CFSTR("progress"), CFTemp("{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("{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 _(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 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 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 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 _(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); }); diff --git a/Security/libsecurity_codesigning/lib/StaticCode.h b/Security/libsecurity_codesigning/lib/StaticCode.h index b9eac887..90e0718c 100644 --- a/Security/libsecurity_codesigning/lib/StaticCode.h +++ b/Security/libsecurity_codesigning/lib/StaticCode.h @@ -28,12 +28,14 @@ #define _H_STATICCODE #include "cs.h" +#include "csutilities.h" #include "Requirements.h" #include "requirement.h" #include "diskrep.h" #include "codedirectory.h" #include #include +#include namespace Security { namespace CodeSigning { @@ -93,8 +95,9 @@ protected: private: CFRef 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 mDir; // code directory data @@ -251,7 +256,9 @@ private: CFRef 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 mTrust; // outcome of crypto validation (valid or not) CFRef mCertChain; diff --git a/Security/libsecurity_codesigning/lib/bundlediskrep.cpp b/Security/libsecurity_codesigning/lib/bundlediskrep.cpp index aaf8bc06..b70059f1 100644 --- a/Security/libsecurity_codesigning/lib/bundlediskrep.cpp +++ b/Security/libsecurity_codesigning/lib/bundlediskrep.cpp @@ -23,6 +23,7 @@ #include "bundlediskrep.h" #include "filediskrep.h" #include "dirscanner.h" +#include #include #include #include @@ -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 mainExecBefore = CFBundleCopyExecutableURL(mBundle); + CFRef 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 infoDictPath = _CFBundleCopyInfoPlistURL(mBundle)) + checkMoved(infoPlistBefore, infoDictPath); } mMainExecutableURL = mainExec; diff --git a/Security/libsecurity_codesigning/lib/bundlediskrep.h b/Security/libsecurity_codesigning/lib/bundlediskrep.h index 66542394..3b810dd9 100644 --- a/Security/libsecurity_codesigning/lib/bundlediskrep.h +++ b/Security/libsecurity_codesigning/lib/bundlediskrep.h @@ -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 mBundle; diff --git a/Security/libsecurity_codesigning/lib/csutilities.cpp b/Security/libsecurity_codesigning/lib/csutilities.cpp index 092ec1ed..dfa6e3a5 100644 --- a/Security/libsecurity_codesigning/lib/csutilities.cpp +++ b/Security/libsecurity_codesigning/lib/csutilities.cpp @@ -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 diff --git a/Security/libsecurity_codesigning/lib/csutilities.h b/Security/libsecurity_codesigning/lib/csutilities.h index f9556a5a..6f039d4b 100644 --- a/Security/libsecurity_codesigning/lib/csutilities.h +++ b/Security/libsecurity_codesigning/lib/csutilities.h @@ -31,6 +31,7 @@ #define _H_CSUTILITIES #include +#include #include #include #include @@ -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 diff --git a/Security/libsecurity_codesigning/lib/dirscanner.cpp b/Security/libsecurity_codesigning/lib/dirscanner.cpp index 12756ab3..0d16d74f 100644 --- a/Security/libsecurity_codesigning/lib/dirscanner.cpp +++ b/Security/libsecurity_codesigning/lib/dirscanner.cpp @@ -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 index 47a7066e..00000000 --- a/Security/libsecurity_codesigning/lib/gkoverride.m +++ /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 -#import -#import - -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 { - 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 \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; -} diff --git a/Security/libsecurity_codesigning/lib/opaquewhitelist.cpp b/Security/libsecurity_codesigning/lib/opaquewhitelist.cpp index e8f50afa..cf453ea3 100644 --- a/Security/libsecurity_codesigning/lib/opaquewhitelist.cpp +++ b/Security/libsecurity_codesigning/lib/opaquewhitelist.cpp @@ -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) diff --git a/Security/libsecurity_codesigning/lib/policyengine.cpp b/Security/libsecurity_codesigning/lib/policyengine.cpp index 286199b2..6e03d8f2 100644 --- a/Security/libsecurity_codesigning/lib/policyengine.cpp +++ b/Security/libsecurity_codesigning/lib/policyengine.cpp @@ -144,7 +144,7 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author CFRef 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: diff --git a/Security/libsecurity_codesigning/lib/resources.cpp b/Security/libsecurity_codesigning/lib/resources.cpp index 8d26b6e1..8fffbb7f 100644 --- a/Security/libsecurity_codesigning/lib/resources.cpp +++ b/Security/libsecurity_codesigning/lib/resources.cpp @@ -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 diff --git a/Security/libsecurity_codesigning/lib/resources.h b/Security/libsecurity_codesigning/lib/resources.h index 05344a50..e3a5475b 100644 --- a/Security/libsecurity_codesigning/lib/resources.h +++ b/Security/libsecurity_codesigning/lib/resources.h @@ -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; diff --git a/Security/libsecurity_codesigning/lib/signer.cpp b/Security/libsecurity_codesigning/lib/signer.cpp index 59d0e05b..68b02b39 100644 --- a/Security/libsecurity_codesigning/lib/signer.cpp +++ b/Security/libsecurity_codesigning/lib/signer.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include namespace Security { namespace CodeSigning { @@ -284,6 +286,11 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase CFDictionaryRef rules = cfget(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 rules2 = cfget(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 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 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("{symlink=%s}", target)); - } else { - seal.take(cfmake("{hash=%O}", - CFRef(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 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("{symlink=%s}", target)); + } else { + seal.take(cfmake("{hash=%O}", + CFRef(resources.hashFile(accpath.c_str())).get())); + } + if (ruleFlags & ResourceBuilder::optional) + CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue); + CFTypeRef hash; + StLock _(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 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 code = new SecStaticCode(DiskRep::bestGuess(ent->fts_path)); + SecPointer code = new SecStaticCode(DiskRep::bestGuess(path)); if (state.signingFlags() & kSecCSSignNestedCode) this->state.sign(code, state.signingFlags()); std::string dr = Dumper::dump(code->designatedRequirement()); diff --git a/Security/libsecurity_codesigning/lib/signer.h b/Security/libsecurity_codesigning/lib/signer.h index c7ac989c..f3a8b9ef 100644 --- a/Security/libsecurity_codesigning/lib/signer.h +++ b/Security/libsecurity_codesigning/lib/signer.h @@ -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; }; diff --git a/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj b/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj index bd92c79d..8dca872d 100644 --- a/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj +++ b/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj @@ -73,11 +73,8 @@ 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 */; }; @@ -160,6 +157,7 @@ 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 */; }; @@ -373,13 +371,11 @@ 184461A2146E9AD100B12992 /* release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = ""; }; 37DDE33B1947A4F3005CE18B /* dirscanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirscanner.h; sourceTree = ""; }; 37DDE3411947A501005CE18B /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = ""; }; - 48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = "../../../Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos/Security.framework"; sourceTree = ""; }; + 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 = ""; }; 7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opaquewhitelist.h; sourceTree = ""; }; - 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 = ""; }; BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTaskPriv.h; sourceTree = ""; }; C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_codesigning.a; path = ../../../usr/local/lib/libsecurity_codesigning.a; sourceTree = ""; }; C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; path = ../../../usr/local/lib/libsecurity_utilities.a; sourceTree = ""; }; @@ -393,12 +389,12 @@ C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqdumper.h; sourceTree = ""; }; C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeSigner.cpp; sourceTree = ""; }; C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeSigner.h; sourceTree = ""; }; - C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = ""; }; - C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = ""; }; + C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = ""; usesTabs = 1; }; + C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = ""; usesTabs = 1; }; C235340E145F1B050073F964 /* xar++.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xar++.h"; sourceTree = ""; }; C2353410145F1B110073F964 /* xar++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "xar++.cpp"; sourceTree = ""; }; - C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = ""; }; - C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = ""; }; + C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = ""; usesTabs = 1; }; + C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = ""; usesTabs = 1; }; C236E3D90AD595C2000F5140 /* signerutils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signerutils.cpp; sourceTree = ""; }; C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = ""; }; C24EABAA1421432800C16AA9 /* policydb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policydb.h; sourceTree = ""; }; @@ -433,8 +429,8 @@ 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 = ""; }; C2A436140F2133B2007A41A6 /* slcrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slcrep.h; sourceTree = ""; }; - C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = ""; }; - C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = ""; }; + C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = ""; usesTabs = 1; }; + C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = ""; 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 = ""; }; @@ -485,8 +481,8 @@ C2D3832E0A237F47005C63A2 /* Code.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Code.h; sourceTree = ""; }; C2D3832F0A237F47005C63A2 /* kerneldiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = kerneldiskrep.cpp; sourceTree = ""; }; C2D383300A237F47005C63A2 /* kerneldiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kerneldiskrep.h; sourceTree = ""; }; - C2D383310A237F47005C63A2 /* StaticCode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StaticCode.cpp; sourceTree = ""; }; - C2D383320A237F47005C63A2 /* StaticCode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StaticCode.h; sourceTree = ""; }; + C2D383310A237F47005C63A2 /* StaticCode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StaticCode.cpp; sourceTree = ""; usesTabs = 1; }; + C2D383320A237F47005C63A2 /* StaticCode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StaticCode.h; sourceTree = ""; usesTabs = 1; }; C2D383330A237F47005C63A2 /* reqparser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqparser.cpp; sourceTree = ""; }; C2D383340A237F47005C63A2 /* reqparser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqparser.h; sourceTree = ""; }; C2D383350A237F47005C63A2 /* requirement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = requirement.cpp; sourceTree = ""; }; @@ -506,6 +502,7 @@ 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 = ""; }; C2F6566D0BCBFB250078779E /* cserror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cserror.h; sourceTree = ""; }; + CD97D27B1A2D2BFE00AE62B7 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Security.framework; sourceTree = ""; }; EB68B10A150DAEBB00B4013D /* RequirementKeywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequirementKeywords.h; sourceTree = ""; }; EB68B10B150DAEBB00B4013D /* RequirementLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RequirementLexer.cpp; sourceTree = ""; }; EB68B10C150DAEBB00B4013D /* RequirementLexer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RequirementLexer.hpp; sourceTree = ""; }; @@ -626,15 +623,7 @@ 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; }; @@ -741,7 +730,6 @@ C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */, C209696015BF52040093035F /* gkunpack */, EBB9FF6F1682E51300FF9774 /* com.apple.CodeSigningHelper.xpc */, - 7AADF57D19C0CE8C00292339 /* gkoverride */, ); name = Products; sourceTree = ""; @@ -771,7 +759,6 @@ C27360D71436868600A9A5FF /* xpcengine.h */, C27360D41436866C00A9A5FF /* xpcengine.cpp */, C27249D2143237CD0058B552 /* syspolicy.sql */, - 7AADF58819C0CED800292339 /* gkoverride.m */, ); name = "System Policy"; sourceTree = ""; @@ -1253,22 +1240,6 @@ 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" */; @@ -1344,11 +1315,6 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0500; - TargetAttributes = { - 7AADF57C19C0CE8C00292339 = { - CreatedOnToolsVersion = 6.0; - }; - }; }; buildConfigurationList = C263E67909A2971B000043F1 /* Build configuration list for PBXProject "libsecurity_codesigning" */; compatibilityVersion = "Xcode 3.2"; @@ -1380,7 +1346,6 @@ C26AC7090DAEB3A7005BFB40 /* DTrace */, C26AC0EB143BCF01001C98CE /* SystemPolicy */, C209695F15BF52040093035F /* gkunpack */, - 7AADF57C19C0CE8C00292339 /* gkoverride */, EBB9FF6E1682E51300FF9774 /* CodeSigningHelper */, ); }; @@ -1594,14 +1559,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 7AADF57919C0CE8C00292339 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7AADF58919C0CED800292339 /* gkoverride.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; C209695C15BF52040093035F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1680,88 +1637,6 @@ /* 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 = { @@ -2073,15 +1948,6 @@ /* 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 = ( diff --git a/Security/libsecurity_keychain/lib/SecItem.cpp b/Security/libsecurity_keychain/lib/SecItem.cpp index 87fe7af3..537b92b7 100644 --- a/Security/libsecurity_keychain/lib/SecItem.cpp +++ b/Security/libsecurity_keychain/lib/SecItem.cpp @@ -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, ¤tAppRef); 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. + 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); diff --git a/Security/libsecurity_keychain/lib/SecTrust.cpp b/Security/libsecurity_keychain/lib/SecTrust.cpp index 0c56946d..94a58092 100644 --- a/Security/libsecurity_keychain/lib/SecTrust.cpp +++ b/Security/libsecurity_keychain/lib/SecTrust.cpp @@ -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@ */ diff --git a/Security/libsecurity_keychain/lib/SecTrustPriv.h b/Security/libsecurity_keychain/lib/SecTrustPriv.h index a4ee4e7b..ac0b7952 100644 --- a/Security/libsecurity_keychain/lib/SecTrustPriv.h +++ b/Security/libsecurity_keychain/lib/SecTrustPriv.h @@ -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") diff --git a/Security/libsecurity_keychain/lib/Trust.cpp b/Security/libsecurity_keychain/lib/Trust.cpp index 1a6f96c2..04a27c24 100644 --- a/Security/libsecurity_keychain/lib/Trust.cpp +++ b/Security/libsecurity_keychain/lib/Trust.cpp @@ -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: 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 diff --git a/Security/libsecurity_keychain/lib/Trust.h b/Security/libsecurity_keychain/lib/Trust.h index ad7662b8..1df98146 100644 --- a/Security/libsecurity_keychain/lib/Trust.h +++ b/Security/libsecurity_keychain/lib/Trust.h @@ -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); diff --git a/Security/libsecurity_keychain/lib/TrustRevocation.cpp b/Security/libsecurity_keychain/lib/TrustRevocation.cpp index 591ff209..3202d2fb 100644 --- a/Security/libsecurity_keychain/lib/TrustRevocation.cpp +++ b/Security/libsecurity_keychain/lib/TrustRevocation.cpp @@ -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; diff --git a/Security/libsecurity_smime/lib/tsaSupport.c b/Security/libsecurity_smime/lib/tsaSupport.c index a92e956b..1d2db833 100644 --- a/Security/libsecurity_smime/lib/tsaSupport.c +++ b/Security/libsecurity_smime/lib/tsaSupport.c @@ -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\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 Bubble up SecTrustEvaluate of timestamp response to high level callers // Also 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; } diff --git a/Security/libsecurity_smime/regressions/smime-cms-test.c b/Security/libsecurity_smime/regressions/smime-cms-test.c index 7d743c59..7c9296a8 100644 --- a/Security/libsecurity_smime/regressions/smime-cms-test.c +++ b/Security/libsecurity_smime/regressions/smime-cms-test.c @@ -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); diff --git a/Security/libsecurity_ssl/lib/sslContext.c b/Security/libsecurity_ssl/lib/sslContext.c index 826fdaf2..b4161e70 100644 --- a/Security/libsecurity_ssl/lib/sslContext.c +++ b/Security/libsecurity_ssl/lib/sslContext.c @@ -292,7 +292,7 @@ SSLDisposeContext (SSLContextRef context) return errSecSuccess; } -CFStringRef SSLContextCopyDescription(CFTypeRef arg) +CFStringRef SSLContextCopyFormatDescription(CFTypeRef arg, CFDictionaryRef formatOptions) { SSLContext* ctx = (SSLContext*) arg; diff --git a/Security/libsecurity_ssl/lib/sslCrypto.c b/Security/libsecurity_ssl/lib/sslCrypto.c index 07457375..600916cc 100644 --- a/Security/libsecurity_ssl/lib/sslCrypto.c +++ b/Security/libsecurity_ssl/lib/sslCrypto.c @@ -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, */ diff --git a/Security/libsecurity_ssl/regressions/ssl-42-ciphers.c b/Security/libsecurity_ssl/regressions/ssl-42-ciphers.c index e2f442dd..9eadbcbc 100644 --- a/Security/libsecurity_ssl/regressions/ssl-42-ciphers.c +++ b/Security/libsecurity_ssl/regressions/ssl-42-ciphers.c @@ -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 #include #include @@ -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 index 00000000..97224e9c --- /dev/null +++ b/Security/libsecurity_utilities/lib/dispatch.cpp @@ -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 + +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 _(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 index 00000000..558e5f09 --- /dev/null +++ b/Security/libsecurity_utilities/lib/dispatch.h @@ -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 +#include +#include + +#include + +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 diff --git a/Security/libsecurity_utilities/lib/errors.cpp b/Security/libsecurity_utilities/lib/errors.cpp index 57695adb..eab27f83 100644 --- a/Security/libsecurity_utilities/lib/errors.cpp +++ b/Security/libsecurity_utilities/lib/errors.cpp @@ -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 diff --git a/Security/libsecurity_utilities/lib/errors.h b/Security/libsecurity_utilities/lib/errors.h index 6ff8ac45..cbc2bd62 100644 --- a/Security/libsecurity_utilities/lib/errors.h +++ b/Security/libsecurity_utilities/lib/errors.h @@ -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 MacOSErrorSet; diff --git a/Security/libsecurity_utilities/lib/macho++.cpp b/Security/libsecurity_utilities/lib/macho++.cpp index cfd448ab..2959da4a 100644 --- a/Security/libsecurity_utilities/lib/macho++.cpp +++ b/Security/libsecurity_utilities/lib/macho++.cpp @@ -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(command, flip(command->cmdsize)); if (command >= mEndCommands) // end of load commands return NULL; diff --git a/Security/libsecurity_utilities/lib/unix++.cpp b/Security/libsecurity_utilities/lib/unix++.cpp index d00dee77..6fb3a445 100644 --- a/Security/libsecurity_utilities/lib/unix++.cpp +++ b/Security/libsecurity_utilities/lib/unix++.cpp @@ -26,10 +26,15 @@ // unix++ - C++ layer for basic UNIX facilities // #include "unix++.h" +#include #include #include +#include #include #include +#include +#include +#include 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 characteristics = deviceCharacteristics(*this); + if (characteristics) { + CFStringRef mediumType = (CFStringRef)CFDictionaryGetValue(characteristics, CFSTR(kIOPropertyMediumTypeKey)); + if (mediumType) + return cfString(mediumType); + } + return string(); +} + + // // Signals and signal masks // diff --git a/Security/libsecurity_utilities/lib/unix++.h b/Security/libsecurity_utilities/lib/unix++.h index c7e098b9..26360eb7 100644 --- a/Security/libsecurity_utilities/lib/unix++.h +++ b/Security/libsecurity_utilities/lib/unix++.h @@ -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 diff --git a/Security/libsecurity_utilities/libsecurity_utilities.xcodeproj/project.pbxproj b/Security/libsecurity_utilities/libsecurity_utilities.xcodeproj/project.pbxproj index 03c008f1..e6e63382 100644 --- a/Security/libsecurity_utilities/libsecurity_utilities.xcodeproj/project.pbxproj +++ b/Security/libsecurity_utilities/libsecurity_utilities.xcodeproj/project.pbxproj @@ -119,6 +119,8 @@ 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 */; }; @@ -235,6 +237,8 @@ 4CA684BF0525011E00233BF2 /* utility_config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = utility_config.h; sourceTree = ""; }; 4E4813D507739B0C0090D7C2 /* ccaudit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ccaudit.cpp; sourceTree = ""; }; 4E4813D607739B0C0090D7C2 /* ccaudit.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ccaudit.h; sourceTree = ""; }; + 7A93A12219BE6FA600F07E9A /* dispatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dispatch.cpp; sourceTree = ""; usesTabs = 1; }; + 7A93A12319BE6FA600F07E9A /* dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dispatch.h; sourceTree = ""; usesTabs = 1; }; AA3BC08D166549EA00EF1D2E /* exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = exports; sourceTree = ""; }; AA5B97E70E140C3E0032C12F /* dtrace.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dtrace.mk; path = lib/dtrace.mk; sourceTree = ""; usesTabs = 1; }; AAA4B91D16653547005DEFDC /* debugging_internal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugging_internal.cpp; sourceTree = ""; }; @@ -364,6 +368,8 @@ 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 */, @@ -593,6 +599,7 @@ 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 */, @@ -703,6 +710,7 @@ 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 */, diff --git a/Security/sec/SOSCircle/Regressions/SOSTestDevice.c b/Security/sec/SOSCircle/Regressions/SOSTestDevice.c index e8aa5e2b..a92c2015 100644 --- a/Security/sec/SOSCircle/Regressions/SOSTestDevice.c +++ b/Security/sec/SOSCircle/Regressions/SOSTestDevice.c @@ -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("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); diff --git a/Security/sec/SOSCircle/Regressions/SOSTestDevice.h b/Security/sec/SOSCircle/Regressions/SOSTestDevice.h index 8af4e172..bb653ffd 100644 --- a/Security/sec/SOSCircle/Regressions/SOSTestDevice.h +++ b/Security/sec/SOSCircle/Regressions/SOSTestDevice.h @@ -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); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c index 52d4a632..9b1bfdfe 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c @@ -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(""), 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); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c index 5b23afa5..21c8df95 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c @@ -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)) { diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c b/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c index 3f167d23..0c099933 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c @@ -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); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c b/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c index a033cad8..4c8b7ceb 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c @@ -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); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c b/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c index a59314c8..c34e3533 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c @@ -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(""), fpi, fpi->peer_info); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSManifest.c b/Security/sec/SOSCircle/SecureObjectSync/SOSManifest.c index 0e0aee28..ea333f33 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSManifest.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSManifest.c @@ -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)); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSMessage.c b/Security/sec/SOSCircle/SecureObjectSync/SOSMessage.c index d5e69d1c..d5023fb0 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSMessage.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSMessage.c @@ -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; diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSPeer.c b/Security/sec/SOSCircle/SecureObjectSync/SOSPeer.c index 07f10cb7..fe6b0b83 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSPeer.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSPeer.c @@ -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")); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c b/Security/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c index d4db2ae9..a51a2478 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c @@ -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); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c index 13abb72b..60d3ef0b 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c @@ -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(""), t); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c index ece0dcd0..f57b366f 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c @@ -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(""), t); diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c index 0fcb2f05..14be9ef7 100644 --- a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c @@ -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) diff --git a/Security/sec/Security/Regressions/Security_regressions.h b/Security/sec/Security/Regressions/Security_regressions.h index 87884aaf..0cb73edc 100644 --- a/Security/sec/Security/Regressions/Security_regressions.h +++ b/Security/sec/Security/Regressions/Security_regressions.h @@ -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) diff --git a/Security/sec/Security/Regressions/otr/otr-30-negotiation.c b/Security/sec/Security/Regressions/otr/otr-30-negotiation.c index 5b09d0e5..bac5680e 100644 --- a/Security/sec/Security/Regressions/otr/otr-30-negotiation.c +++ b/Security/sec/Security/Regressions/otr/otr-30-negotiation.c @@ -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 index 00000000..6729cb10 --- /dev/null +++ b/Security/sec/Security/Regressions/otr/otr-40-edgecases.c @@ -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 +#include +#include +#include + +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 index 00000000..b07c4eee --- /dev/null +++ b/Security/sec/Security/Regressions/otr/otr-50-roll.c @@ -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 +#include +#include +#include +#include + +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 index 00000000..53a9c1be --- /dev/null +++ b/Security/sec/Security/Regressions/otr/otr-60-slowroll.c @@ -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 +#include +#include +#include +#include + +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; +} diff --git a/Security/sec/Security/Regressions/otr/otr-otrdh.c b/Security/sec/Security/Regressions/otr/otr-otrdh.c index b2bde0c9..e852ff06 100644 --- a/Security/sec/Security/Regressions/otr/otr-otrdh.c +++ b/Security/sec/Security/Regressions/otr/otr-otrdh.c @@ -26,17 +26,40 @@ #include #include +#include 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; } diff --git a/Security/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c b/Security/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c index d29dff66..c8a8b1d0 100644 --- a/Security/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c +++ b/Security/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c @@ -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; } diff --git a/Security/sec/Security/SecAccessControl.c b/Security/sec/Security/SecAccessControl.c index 357c0b29..0f2ea2c8 100644 --- a/Security/sec/Security/SecAccessControl.c +++ b/Security/sec/Security/SecAccessControl.c @@ -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(""), access_control); } diff --git a/Security/sec/Security/SecBasePriv.h b/Security/sec/Security/SecBasePriv.h index ae6e2f7f..77ad6cda 100644 --- a/Security/sec/Security/SecBasePriv.h +++ b/Security/sec/Security/SecBasePriv.h @@ -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 */ }; diff --git a/Security/sec/Security/SecCertificatePath.c b/Security/sec/Security/SecCertificatePath.c index f634500c..ba700d3c 100644 --- a/Security/sec/Security/SecCertificatePath.c +++ b/Security/sec/Security/SecCertificatePath.c @@ -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)); diff --git a/Security/sec/Security/SecCertificateRequest.c b/Security/sec/Security/SecCertificateRequest.c index 7cf9f916..f9b82190 100644 --- a/Security/sec/Security/SecCertificateRequest.c +++ b/Security/sec/Security/SecCertificateRequest.c @@ -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; diff --git a/Security/sec/Security/SecExports.exp-in b/Security/sec/Security/SecExports.exp-in index 35fd8cfb..8e929c86 100644 --- a/Security/sec/Security/SecExports.exp-in +++ b/Security/sec/Security/SecExports.exp-in @@ -328,6 +328,14 @@ _SecGenerateSelfSignedCertificate // // OTR // +_SecOTRSKickTimeToRoll +_SecOTRSGetTheirKeyID +_SecOTRSGetKeyID +_SecFDHKAppendCompactPublicSerialization +_SecFDHKAppendPublicSerialization +_SecOTRCopyIncomingBytes +_SecOTRPublicDHKCreateFromSerialization +_SecOTRPublicDHKCreateFromCompactSerialization _SecOTRDHKGenerateOTRKeys _SecOTRFullDHKCreate _SecOTRPublicDHKCreateFromFullKey diff --git a/Security/sec/Security/SecIdentity.c b/Security/sec/Security/SecIdentity.c index 7668a5e9..ed2f9d68 100644 --- a/Security/sec/Security/SecIdentity.c +++ b/Security/sec/Security/SecIdentity.c @@ -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(""), identity); diff --git a/Security/sec/Security/SecOTRDHKey.c b/Security/sec/Security/SecOTRDHKey.c index fb5d2e25..5bb75172 100644 --- a/Security/sec/Security/SecOTRDHKey.c +++ b/Security/sec/Security/SecOTRDHKey.c @@ -36,6 +36,18 @@ #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(""), 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(""), 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(""), 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(""), 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); diff --git a/Security/sec/Security/SecOTRDHKey.h b/Security/sec/Security/SecOTRDHKey.h index 14d1ae87..39773ebd 100644 --- a/Security/sec/Security/SecOTRDHKey.h +++ b/Security/sec/Security/SecOTRDHKey.h @@ -27,6 +27,7 @@ #include #include #include +#include __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); diff --git a/Security/sec/Security/SecOTRFullIdentity.c b/Security/sec/Security/SecOTRFullIdentity.c index 538862ed..21e458b1 100644 --- a/Security/sec/Security/SecOTRFullIdentity.c +++ b/Security/sec/Security/SecOTRFullIdentity.c @@ -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(""), requestor, diff --git a/Security/sec/Security/SecOTRPacketData.h b/Security/sec/Security/SecOTRPacketData.h index c7b3d67f..5cf2ebd0 100644 --- a/Security/sec/Security/SecOTRPacketData.h +++ b/Security/sec/Security/SecOTRPacketData.h @@ -42,36 +42,79 @@ __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; diff --git a/Security/sec/Security/SecOTRPackets.h b/Security/sec/Security/SecOTRPackets.h index 334ba51e..45bf8d25 100644 --- a/Security/sec/Security/SecOTRPackets.h +++ b/Security/sec/Security/SecOTRPackets.h @@ -43,6 +43,9 @@ typedef enum { kEvenCompactDataMessage = 0x20, kOddCompactDataMessage = 0x21, + + kEvenCompactDataMessageWithHashes = 0x30, + kOddCompactDataMessageWithHashes = 0x31, kInvalidMessage = 0xFF } OTRMessageType; diff --git a/Security/sec/Security/SecOTRPublicIdentity.c b/Security/sec/Security/SecOTRPublicIdentity.c index 89cfb17c..aeefde2c 100644 --- a/Security/sec/Security/SecOTRPublicIdentity.c +++ b/Security/sec/Security/SecOTRPublicIdentity.c @@ -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(""), requestor, diff --git a/Security/sec/Security/SecOTRSession.c b/Security/sec/Security/SecOTRSession.c index 1f7d80a3..b15cac39 100644 --- a/Security/sec/Security/SecOTRSession.c +++ b/Security/sec/Security/SecOTRSession.c @@ -25,6 +25,7 @@ #include #include #include "utilities/comparison.h" +#include #include "SecOTRSession.h" @@ -69,6 +70,100 @@ 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; diff --git a/Security/sec/Security/SecOTRSession.h b/Security/sec/Security/SecOTRSession.h index 5b60f81e..3d2aab63 100644 --- a/Security/sec/Security/SecOTRSession.h +++ b/Security/sec/Security/SecOTRSession.h @@ -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, }; /*! diff --git a/Security/sec/Security/SecOTRSessionAKE.c b/Security/sec/Security/SecOTRSessionAKE.c index 0613d815..5d666af2 100644 --- a/Security/sec/Security/SecOTRSessionAKE.c +++ b/Security/sec/Security/SecOTRSessionAKE.c @@ -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; diff --git a/Security/sec/Security/SecOTRSessionPriv.h b/Security/sec/Security/SecOTRSessionPriv.h index 357890eb..bf0b28c1 100644 --- a/Security/sec/Security/SecOTRSessionPriv.h +++ b/Security/sec/Security/SecOTRSessionPriv.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include +#include __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 diff --git a/Security/sec/Security/SecPolicy.c b/Security/sec/Security/SecPolicy.c index 31ba7388..7cf760f5 100644 --- a/Security/sec/Security/SecPolicy.c +++ b/Security/sec/Security/SecPolicy.c @@ -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)); diff --git a/Security/sec/Security/SecTrust.c b/Security/sec/Security/SecTrust.c index a7138f50..8c3d253f 100644 --- a/Security/sec/Security/SecTrust.c +++ b/Security/sec/Security/SecTrust.c @@ -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(""), trust); diff --git a/Security/sec/Security/SecTrustSettings.c b/Security/sec/Security/SecTrustSettings.c index 92fb3354..fb8663f1 100644 --- a/Security/sec/Security/SecTrustSettings.c +++ b/Security/sec/Security/SecTrustSettings.c @@ -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(""), ts); diff --git a/Security/sec/ipc/server.c b/Security/sec/ipc/server.c index 0ea6e155..d62a180d 100644 --- a/Security/sec/ipc/server.c +++ b/Security/sec/ipc/server.c @@ -65,7 +65,7 @@ #include #include -#if TARGET_OS_MAC +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) #include #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; diff --git a/Security/sec/sec.xcodeproj/project.pbxproj b/Security/sec/sec.xcodeproj/project.pbxproj index 7a78c02a..8bad5462 100644 --- a/Security/sec/sec.xcodeproj/project.pbxproj +++ b/Security/sec/sec.xcodeproj/project.pbxproj @@ -276,6 +276,8 @@ 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 */; }; @@ -286,6 +288,7 @@ 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 */; }; @@ -529,7 +532,7 @@ 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 = ""; }; - 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOTRDHKey.c; path = ../../../SecOTRDHKey.c; sourceTree = ""; }; + 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRDHKey.c; sourceTree = ""; }; 4A971684158FDEB800D439B7 /* SecOTRDHKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTRDHKey.h; sourceTree = ""; }; 4A971685158FDEB800D439B7 /* SecOTRErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTRErrors.h; sourceTree = ""; }; 4A971686158FDEB800D439B7 /* SecOTRFullIdentity.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRFullIdentity.c; sourceTree = ""; }; @@ -731,6 +734,8 @@ CD0F8AF51899BF46003E0C52 /* SOSTransportCircle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportCircle.c; sourceTree = ""; }; CD0F8AF71899BF57003E0C52 /* SOSTransportMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessage.h; sourceTree = ""; }; CD0F8AF91899BF63003E0C52 /* SOSTransportCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircle.h; sourceTree = ""; }; + CD303E2F1A32629700737AD7 /* otr-50-roll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-50-roll.c"; sourceTree = ""; }; + CD303E311A32650C00737AD7 /* otr-60-slowroll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-60-slowroll.c"; sourceTree = ""; }; CD32776A18F8AEFD006B5280 /* SOSPeerCoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerCoder.c; sourceTree = ""; }; CD32776C18F8B06E006B5280 /* SOSPeerCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerCoder.h; sourceTree = ""; }; CD32776E18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportKeyParameterKVS.c; sourceTree = ""; }; @@ -740,6 +745,7 @@ CD32777618F8B39B006B5280 /* SOSTransportMessageKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportMessageKVS.c; sourceTree = ""; }; CD32777818F8B3B4006B5280 /* SOSTransportMessageKVS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessageKVS.h; sourceTree = ""; }; CD86DE4D18BD554D00C90CDF /* SOSTransport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransport.c; sourceTree = ""; }; + CD8E09001A2E918900A2503A /* otr-40-edgecases.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-40-edgecases.c"; sourceTree = ""; }; CDA7729616B899F10069434D /* si-69-keydesc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-69-keydesc.c"; sourceTree = ""; }; CDAD4E9818EC8424007D4BC2 /* SOSTransportTestTransports.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportTestTransports.c; sourceTree = ""; }; CDAD4E9A18EC8447007D4BC2 /* SOSTransportTestTransports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportTestTransports.h; sourceTree = ""; }; @@ -1014,6 +1020,7 @@ 4A824AFA158FF05900F932C0 /* Regressions */, 52D0F026169CA72800F07D79 /* SecOnOSX.h */, 4A971682158FDEB800D439B7 /* SecOTR.h */, + 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */, 4A971684158FDEB800D439B7 /* SecOTRDHKey.h */, 4A971685158FDEB800D439B7 /* SecOTRErrors.h */, 4A971686158FDEB800D439B7 /* SecOTRFullIdentity.c */, @@ -1205,6 +1212,9 @@ 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; @@ -1315,7 +1325,6 @@ 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 */, @@ -2284,6 +2293,7 @@ 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 */, @@ -2306,6 +2316,7 @@ 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 */, @@ -2327,6 +2338,7 @@ 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 */, diff --git a/Security/sec/securityd/OTATrustUtilities.c b/Security/sec/securityd/OTATrustUtilities.c index e3eaa575..6bddb1f2 100644 --- a/Security/sec/securityd/OTATrustUtilities.c +++ b/Security/sec/securityd/OTATrustUtilities.c @@ -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(""), otapkiRef->_assetVersion); diff --git a/Security/sec/securityd/Regressions/secd-70-engine.c b/Security/sec/securityd/Regressions/secd-70-engine.c index 4922f549..e49f9988 100644 --- a/Security/sec/securityd/Regressions/secd-70-engine.c +++ b/Security/sec/securityd/Regressions/secd-70-engine.c @@ -44,7 +44,9 @@ #include #include -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); diff --git a/Security/sec/securityd/SecCAIssuerRequest.c b/Security/sec/securityd/SecCAIssuerRequest.c index e0cf2e54..dcb30f50 100644 --- a/Security/sec/securityd/SecCAIssuerRequest.c +++ b/Security/sec/securityd/SecCAIssuerRequest.c @@ -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); } diff --git a/Security/sec/securityd/SecDbItem.c b/Security/sec/securityd/SecDbItem.c index 077f0d48..d8713b3c 100644 --- a/Security/sec/securityd/SecDbItem.c +++ b/Security/sec/securityd/SecDbItem.c @@ -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); diff --git a/Security/sec/securityd/SecDbKeychainItem.c b/Security/sec/securityd/SecDbKeychainItem.c index 39c38ef6..9e69d245 100644 --- a/Security/sec/securityd/SecDbKeychainItem.c +++ b/Security/sec/securityd/SecDbKeychainItem.c @@ -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); diff --git a/Security/sec/securityd/SecOCSPResponse.c b/Security/sec/securityd/SecOCSPResponse.c index 2b663652..fb24c8a9 100644 --- a/Security/sec/securityd/SecOCSPResponse.c +++ b/Security/sec/securityd/SecOCSPResponse.c @@ -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) { diff --git a/Security/sec/securityd/SecTrustServer.c b/Security/sec/securityd/SecTrustServer.c index f5bb542d..3b5a7663 100644 --- a/Security/sec/securityd/SecTrustServer.c +++ b/Security/sec/securityd/SecTrustServer.c @@ -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); diff --git a/Security/utilities/Regressions/su-16-cfdate-der.c b/Security/utilities/Regressions/su-16-cfdate-der.c index 86080d0e..19d1227e 100644 --- a/Security/utilities/Regressions/su-16-cfdate-der.c +++ b/Security/utilities/Regressions/su-16-cfdate-der.c @@ -28,9 +28,11 @@ #include "utilities/SecCFRelease.h" #include "utilities/array_size.h" +#include #include #include +#include #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 ) + __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 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(" 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; diff --git a/Security/utilities/src/SecCFWrappers.c b/Security/utilities/src/SecCFWrappers.c index 0c33c803..de37f87a 100644 --- a/Security/utilities/src/SecCFWrappers.c +++ b/Security/utilities/src/SecCFWrappers.c @@ -25,16 +25,37 @@ #include // -// Global sigleton Zulu time. +// Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef +// 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); diff --git a/Security/utilities/src/SecCFWrappers.h b/Security/utilities/src/SecCFWrappers.h index e18413f2..7d51175f 100644 --- a/Security/utilities/src/SecCFWrappers.h +++ b/Security/utilities/src/SecCFWrappers.h @@ -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; } diff --git a/Security/utilities/src/SecDb.c b/Security/utilities/src/SecDb.c index 4de373a7..c1aa0640 100644 --- a/Security/utilities/src/SecDb.c +++ b/Security/utilities/src/SecDb.c @@ -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(""), 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(""), @@ -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; } diff --git a/Security/utilities/src/der_date.c b/Security/utilities/src/der_date.c index 08b56870..2df138c5 100644 --- a/Security/utilities/src/der_date.c +++ b/Security/utilities/src/der_date.c @@ -33,7 +33,8 @@ #include #include -#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, diff --git a/libsecurity_smime/lib/cmssiginfo.c b/libsecurity_smime/lib/cmssiginfo.c index 41ab2e23..cce69553 100644 --- a/libsecurity_smime/lib/cmssiginfo.c +++ b/libsecurity_smime/lib/cmssiginfo.c @@ -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; diff --git a/libsecurity_smime/lib/crypto-embedded.c b/libsecurity_smime/lib/crypto-embedded.c index c9dd8e70..a6c4197a 100644 --- a/libsecurity_smime/lib/crypto-embedded.c +++ b/libsecurity_smime/lib/crypto-embedded.c @@ -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 }; -- 2.45.2