<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0600"
- version = "1.3">
+ version = "1.8">
<BuildAction
parallelizeBuildables = "NO"
- buildImplicitDependencies = "YES">
+ buildImplicitDependencies = "YES"
+ enableAddressSanitizer = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<PreActions>
<ExecutionAction
</ActionContent>
</ExecutionAction>
</PostActions>
- <BuildableProductRunnable>
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
argument = "ssl_43_ciphers"
isEnabled = "NO">
</CommandLineArgument>
+ <CommandLineArgument
+ argument = "ssl_44_crashes"
+ isEnabled = "NO">
+ </CommandLineArgument>
<CommandLineArgument
argument = "ssl_45_tls12"
isEnabled = "NO">
argument = "otr_30_negotiation"
isEnabled = "NO">
</CommandLineArgument>
+ <CommandLineArgument
+ argument = "otr_40_edgecases"
+ isEnabled = "NO">
+ </CommandLineArgument>
+ <CommandLineArgument
+ argument = "otr_40_edgecases"
+ isEnabled = "NO">
+ </CommandLineArgument>
+ <CommandLineArgument
+ argument = "otr_50_roll"
+ isEnabled = "NO">
+ </CommandLineArgument>
+ <CommandLineArgument
+ argument = "otr_60_slowroll"
+ isEnabled = "NO">
+ </CommandLineArgument>
<CommandLineArgument
argument = "otr_otrdh"
isEnabled = "NO">
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
debugDocumentVersioning = "YES">
- <BuildableProductRunnable>
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
- <BuildableProductRunnable>
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E710C7411331946400F85568"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
- <BuildableProductRunnable>
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
72756C31175D48C100F52070 /* cloud_keychain_diagnose.c in Sources */ = {isa = PBXBuildFile; fileRef = 72756C30175D48C100F52070 /* cloud_keychain_diagnose.c */; };
72CC327B175D6E0A00217455 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72756C9E175D566800F52070 /* CoreFoundation.framework */; };
72CC327C175D6E1800217455 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 722CF215175D5E5000BCE0A5 /* Security.framework */; };
+ 7A21DAE619B7F27C0007D37F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 18270EFD14CF429600B05E7F /* IOKit.framework */; };
AAF3DCCB1666D03300376593 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18F235F715CA0D9D00060520 /* libsecurity_utilities.a */; };
AC5688BC18B4396D00F0526C /* SecCMS.h in Headers */ = {isa = PBXBuildFile; fileRef = AC5688BA18B4396D00F0526C /* SecCMS.h */; settings = {ATTRIBUTES = (Private, ); }; };
ACB6171918B5231800EBEDD7 /* libsecurity_smime_regressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ACB6171818B5231800EBEDD7 /* libsecurity_smime_regressions.a */; };
182BB5AE146FEF43000BF1F3 /* libsqlite3.dylib in Frameworks */,
182BB5AC146FEF15000BF1F3 /* libpam.dylib in Frameworks */,
182BB5AA146FEE50000BF1F3 /* CoreFoundation.framework in Frameworks */,
+ 7A21DAE619B7F27C0007D37F /* IOKit.framework in Frameworks */,
182BB4E1146F2591000BF1F3 /* libsecurity_manifest.a in Frameworks */,
182BB4E2146F2591000BF1F3 /* libsecurity_mds.a in Frameworks */,
182BB4E3146F2591000BF1F3 /* libsecurity_sd_cspdl.a in Frameworks */,
// Construct a SecCodeSigner
//
SecCodeSigner::SecCodeSigner(SecCSFlags flags)
- : mOpFlags(flags), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm)
+ : mOpFlags(flags), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm), mLimitedAsync(NULL)
{
}
//
SecCodeSigner::~SecCodeSigner() throw()
try {
+ delete mLimitedAsync;
} catch (...) {
return;
}
CFRef<CFURLRef> mTimestampService; // URL for Timestamp server
bool mWantTimeStamp; // use a Timestamp server
bool mNoTimeStampCerts; // don't request certificates with timestamping request
+ LimitedAsync *mLimitedAsync; // limited async workers for verification
};
| kSecCSEnforceRevocationChecks
| kSecCSNoNetworkAccess
| kSecCSCheckNestedCode
- | kSecCSStrictValidate);
+ | kSecCSStrictValidate
+ | kSecCSCheckGatekeeperArchitectures
+ );
if (errors)
flags |= kSecCSFullReport; // internal-use flag
kSecCSCheckNestedCode = 1 << 3,
kSecCSStrictValidate = 1 << 4,
kSecCSFullReport = 1 << 5,
+ kSecCSCheckGatekeeperArchitectures = (1 << 6) | kSecCSCheckAllArchitectures,
};
OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags,
#include "resources.h"
#include "detachedrep.h"
#include "csdatabase.h"
-#include "csutilities.h"
#include "dirscanner.h"
#include <CoreFoundation/CFURLAccess.h>
#include <Security/SecPolicyPriv.h>
#include <security_utilities/logging.h>
#include <dirent.h>
#include <sstream>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
namespace Security {
SecStaticCode::SecStaticCode(DiskRep *rep)
: mRep(rep),
mValidated(false), mExecutableValidated(false), mResourcesValidated(false), mResourcesValidContext(NULL),
- mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mEvalDetails(NULL)
+ mProgressQueue("com.apple.security.validation-progress", false, DISPATCH_QUEUE_PRIORITY_DEFAULT),
+ mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mLimitedAsync(NULL), mEvalDetails(NULL)
{
CODESIGN_STATIC_CREATE(this, rep);
CFRef<CFDataRef> codeDirectory = rep->codeDirectory();
SecStaticCode::~SecStaticCode() throw()
try {
::free(const_cast<Requirement *>(mDesignatedReq));
- if (mResourcesValidContext)
- delete mResourcesValidContext;
+ delete mResourcesValidContext;
+ delete mLimitedAsync;
} catch (...) {
return;
}
+//
+// Initialize a nested SecStaticCode object from its parent
+//
+void SecStaticCode::initializeFromParent(const SecStaticCode& parent) {
+ setMonitor(parent.monitor());
+ if (parent.mLimitedAsync)
+ mLimitedAsync = new LimitedAsync(*parent.mLimitedAsync);
+}
//
// CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
void SecStaticCode::prepareProgress(unsigned int workload)
{
- {
- StLock<Mutex> _(mCancelLock);
+ dispatch_sync(mProgressQueue, ^{
mCancelPending = false; // not cancelled
- }
+ });
if (mValidationFlags & kSecCSReportProgress) {
mCurrentWork = 0; // nothing done yet
mTotalWork = workload; // totally fake - we don't know how many files we'll get to chew
void SecStaticCode::reportProgress(unsigned amount /* = 1 */)
{
if (mMonitor && (mValidationFlags & kSecCSReportProgress)) {
- {
- // if cancellation is pending, abort now
- StLock<Mutex> _(mCancelLock);
- if (mCancelPending)
- MacOSError::throwMe(errSecCSCancelled);
- }
// update progress and report
- mCurrentWork += amount;
- mMonitor(this->handle(false), CFSTR("progress"), CFTemp<CFDictionaryRef>("{current=%d,total=%d}", mCurrentWork, mTotalWork));
+ __block bool cancel = false;
+ dispatch_sync(mProgressQueue, ^{
+ if (mCancelPending)
+ cancel = true;
+ mCurrentWork += amount;
+ mMonitor(this->handle(false), CFSTR("progress"), CFTemp<CFDictionaryRef>("{current=%d,total=%d}", mCurrentWork, mTotalWork));
+ });
+ // if cancellation is pending, abort now
+ if (cancel)
+ MacOSError::throwMe(errSecCSCancelled);
}
}
//
void SecStaticCode::cancelValidation()
{
- StLock<Mutex> _(mCancelLock);
if (!(mValidationFlags & kSecCSReportProgress)) // not using progress reporting; cancel won't make it through
MacOSError::throwMe(errSecCSInvalidFlags);
- mCancelPending = true;
+ dispatch_sync(mProgressQueue, ^{
+ mCancelPending = true;
+ });
}
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();
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;
}
if (!rules || !files)
MacOSError::throwMe(errSecCSResourcesInvalid);
+
// check for weak resource rules
bool strict = flags & kSecCSStrictValidate;
if (strict) {
if (mTolerateErrors.find(errSecCSWeakResourceEnvelope) == mTolerateErrors.end())
MacOSError::throwMe(errSecCSWeakResourceEnvelope);
}
+
+ Dispatch::Group group;
+ Dispatch::Group &groupRef = group; // (into block)
+
+ // scan through the resources on disk, checking each against the resourceDirectory
__block CFRef<CFMutableDictionaryRef> resourceMap = makeCFMutableDictionary(files);
string base = cfString(this->resourceBase());
ResourceBuilder resources(base, base, rules, codeDirectory()->hashType, strict, mTolerateErrors);
diskRep()->adjustResources(resources);
- resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, ResourceBuilder::Rule *rule) {
- validateResource(files, relpath, ent->fts_info == FTS_SL, *mResourcesValidContext, flags, version);
- reportProgress();
+
+ resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const string relpath, ResourceBuilder::Rule *rule) {
CFDictionaryRemoveValue(resourceMap, CFTempString(relpath));
+ bool isSymlink = (ent->fts_info == FTS_SL);
+
+ void (^validate)() = ^{
+ validateResource(files, relpath, isSymlink, *mResourcesValidContext, flags, version);
+ reportProgress();
+ };
+
+ mLimitedAsync->perform(groupRef, validate);
});
-
+ group.wait(); // wait until all async resources have been validated as well
+
unsigned leftovers = unsigned(CFDictionaryGetCount(resourceMap));
if (leftovers > 0) {
secdebug("staticCode", "%d sealed resource(s) not found in code", int(leftovers));
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);
return;
}
if (isOmitRule(value))
- forbiddenOmission |= !CFArrayContainsValue(allowed, range, key);
+ forbiddenOmission |= !CFArrayContainsValue(allowedRef, range, key);
});
return !coversAll || forbiddenOmission;
if (!(flags & kSecCSCheckNestedCode))
flags |= kSecCSBasicValidateOnly;
SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(cfString(path)));
- code->setMonitor(this->monitor());
+ code->initializeFromParent(*this);
code->staticValidate(flags, SecRequirement::required(req));
if (isFramework && (flags & kSecCSStrictValidate))
continue;
SecPointer<SecStaticCode> frameworkVersion = new SecStaticCode(DiskRep::bestGuess(real_full_path));
- frameworkVersion->setMonitor(this->monitor());
+ frameworkVersion->initializeFromParent(*this);
frameworkVersion->staticValidate(flags, SecRequirement::required(req));
}
}
void SecStaticCode::CollectingContext::reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value)
{
+ StLock<Mutex> _(mLock);
if (mStatus == errSecSuccess)
mStatus = rc; // record first failure for eventual error return
if (type) {
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);
});
#define _H_STATICCODE
#include "cs.h"
+#include "csutilities.h"
#include "Requirements.h"
#include "requirement.h"
#include "diskrep.h"
#include "codedirectory.h"
#include <Security/SecTrust.h>
#include <CoreFoundation/CFData.h>
+#include <security_utilities/dispatch.h>
namespace Security {
namespace CodeSigning {
private:
CFRef<CFMutableDictionaryRef> mCollection;
OSStatus mStatus;
+ Mutex mLock;
};
-
+
public:
SECCFFUNCTIONS(SecStaticCode, SecStaticCodeRef,
errSecCSInvalidObjectRef, gCFObjects().StaticCode)
SecStaticCode(DiskRep *rep);
virtual ~SecStaticCode() throw();
-
+
+ void initializeFromParent(const SecStaticCode& parent);
+
bool equal(SecCFObject &other);
CFHashCode hash();
unsigned mTotalWork; // total expected work (arbitrary units)
unsigned mCurrentWork; // currently completed work
bool mCancelPending; // cancellation was requested
- Mutex mCancelLock; // protects mCancelPending
+ Dispatch::Queue mProgressQueue; // progress reporting queue
// cached contents
CFRef<CFDataRef> mDir; // code directory data
CFRef<CFURLRef> mResourceBase; // URL form of resource base directory
SecCodeCallback mMonitor; // registered monitor callback
-
+
+ LimitedAsync *mLimitedAsync; // limited async workers for verification
+
// signature verification outcome (mTrust == NULL => not done yet)
CFRef<SecTrustRef> mTrust; // outcome of crypto validation (valid or not)
CFRef<CFArrayRef> mCertChain;
#include "bundlediskrep.h"
#include "filediskrep.h"
#include "dirscanner.h"
+#include <CoreFoundation/CFBundlePriv.h>
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFBundlePriv.h>
#include <security_utilities/cfmunge.h>
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)
// capture the path of the main executable before descending into a specific version
CFRef<CFURLRef> mainExecBefore = CFBundleCopyExecutableURL(mBundle);
+ CFRef<CFURLRef> infoPlistBefore = _CFBundleCopyInfoPlistURL(mBundle);
// validate the bundle root; fish around for the desired framework version
string root = cfStringRelease(copyCanonicalPath());
string contents = root + "/Contents";
+ string supportFiles = root + "/Support Files";
string version = root + "/Versions/"
+ ((ctx && ctx->version) ? ctx->version : "Current")
+ "/.";
} 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
// That's because you know what you are doing if you are looking at a specific version.
// This check is designed to stop someone who did a verification on an app root, from mistakenly
// verifying a framework
- if (mainExecBefore && (!ctx || !ctx->version)) {
- char main_exec_before[PATH_MAX];
- char main_exec[PATH_MAX];
- // The realpath call is important because alot of Framework bundles have a symlink
- // to their "Current" version binary in the main bundle
- if (realpath(cfString(mainExecBefore).c_str(), main_exec_before) == NULL ||
- realpath(cfString(mainExec).c_str(), main_exec) == NULL)
- MacOSError::throwMe(errSecCSInternalError);
-
- if (strcmp(main_exec_before, main_exec) != 0)
- recordStrictError(errSecCSAmbiguousBundleFormat);
+ if (!ctx || !ctx->version) {
+ if (mainExecBefore)
+ checkMoved(mainExecBefore, mainExec);
+ if (infoPlistBefore)
+ if (CFRef<CFURLRef> infoDictPath = _CFBundleCopyInfoPlistURL(mBundle))
+ checkMoved(infoPlistBefore, infoDictPath);
}
mMainExecutableURL = mainExec;
CFDataRef loadRegularFile(CFURLRef url);
void recordStrictError(OSStatus error);
void validateFrameworkRoot(std::string root);
+ void checkMoved(CFURLRef oldPath, CFURLRef newPath);
private:
CFRef<CFBundleRef> mBundle;
}
+
+// 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
#define _H_CSUTILITIES
#include <Security/Security.h>
+#include <security_utilities/dispatch.h>
#include <security_utilities/hashing.h>
#include <security_utilities/unix++.h>
#include <security_cdsa_utilities/cssmdata.h>
};
+// 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
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:
+++ /dev/null
-/*
- * Copyright (c) 2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-#import <Foundation/Foundation.h>
-#import <CrashReporterSupport/CrashReporterSupportPrivate.h>
-#import <sys/utsname.h>
-
-static bool useInternalServer() {
- struct utsname name;
- return ((uname(&name) == 0 && strstr(name.version, "DEVELOPMENT") != NULL)
- && access("/var/db/gkoverride_use_internal", F_OK) == 0);
-}
-
-@interface OverrideClient : NSObject<NSURLConnectionDelegate> {
- BOOL allow;
- NSMutableData *buffer;
- NSURLConnection *connection;
- int state;
-}
-@property NSString *currentHash;
-@property NSString *opaqueHash;
-@property NSString *bundleID;
-@property NSString *bundleVersion;
-- (NSString *)serverHost;
-- (void)sendQuery;
-- (void)sendReport;
-- (void)abort;
-@end
-
-@implementation OverrideClient
-
-- (NSString *)serverHost {
- if (useInternalServer())
- return @"gkq-stg.siri.apple.com";
- else
- return @"gkq.apple.com";
-}
-
-- (id)init {
- self = [super init];
- allow = NO;
- buffer = [NSMutableData new];
- return self;
-}
-
-- (void)sendQuery {
- state = 1;
- NSMutableURLRequest *request = [NSMutableURLRequest new];
- NSString *url = [NSString stringWithFormat:@"https://%@/q/%@/%@", [self serverHost], self.currentHash, self.opaqueHash];
- [request setURL:[NSURL URLWithString:url]];
- [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
- [request setTimeoutInterval:5];
- connection = [NSURLConnection connectionWithRequest:request delegate:self];
-}
-
-- (void)sendReport {
- state = 2;
- NSMutableURLRequest *request = [NSMutableURLRequest new];
- NSString *body = [NSString stringWithFormat:@"current=%@&bundleid=%@&version=%@",
- [self.currentHash stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
- [self.bundleID stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
- [self.bundleVersion stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
- NSString *url = [NSString stringWithFormat:@"https://%@/report", [self serverHost]];
- [request setURL:[NSURL URLWithString:url]];
- [request setTimeoutInterval:5];
- [request setHTTPMethod:@"POST"];
- [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
- connection = [NSURLConnection connectionWithRequest:request delegate:self];
-}
-
-- (BOOL)connection:(NSURLConnection *)conn canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
- SecTrustRef trust = [protectionSpace serverTrust];
- // abort if untrusted
- SecTrustResultType trustResult;
- SecTrustEvaluate(trust, &trustResult);
- if (trustResult != kSecTrustResultProceed && trustResult != kSecTrustResultUnspecified) {
- [conn cancel];
- [self abort];
- return NO;
- }
- // allow if server presented an EV cert
- NSDictionary *result = CFBridgingRelease(SecTrustCopyResult(trust));
- if (result) {
- NSNumber *ev = [result objectForKey:(__bridge id)kSecTrustExtendedValidation];
- if (ev != NULL && [ev boolValue] == YES) {
- return NO;
- }
- }
- // allow if using internal server (EV not required)
- if (useInternalServer())
- return NO;
- // otherwise abort
- [conn cancel];
- [self abort];
- return NO;
-}
-
-- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
- [buffer appendData:data];
- if ([buffer length] > 100)
- [self abort];
-}
-
-- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
- if (state == 1) {
- NSString *verdict = [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
- if ([verdict isEqualToString:@"allow"]) {
- allow = YES;
- [self abort];
- } else if (CRIsAutoSubmitEnabled()) { // "Send diagnostic & usage data to Apple" checked
- [self sendReport];
- }
- } else {
- [self abort]; // report sent
- }
-}
-
-- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
- [self abort];
-}
-
-- (void)abort {
- if (allow) {
- printf("allow\n");
- exit(42);
- } else {
- printf("deny\n");
- exit(1);
- }
-}
-
-@end
-
-int main(int argc, const char * argv[]) {
- if (argc != 5) {
- fprintf(stderr, "usage: %s <current> <opaque> <bundleid> <version>\n", argv[0]);
- return 1;
- }
- @autoreleasepool {
- OverrideClient *client = [OverrideClient new];
- client.currentHash = [NSString stringWithUTF8String:argv[1]];
- client.opaqueHash = [NSString stringWithUTF8String:argv[2]];
- client.bundleID = [NSString stringWithUTF8String:argv[3]];
- client.bundleVersion = [NSString stringWithUTF8String:argv[4]];
- [client sendQuery];
- [[NSRunLoop currentRunLoop] run];
- }
- return 0;
-}
}
}
- // 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());
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)
CFRef<SecRequirementRef> requirement;
MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
- switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly, requirement)) {
+ switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly | kSecCSCheckGatekeeperArchitectures, requirement)) {
case errSecSuccess:
break; // rule match; process below
case errSecCSReqFailed:
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
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);
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
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;
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
#include <security_utilities/cfmunge.h>
+#include <security_utilities/dispatch.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
namespace Security {
namespace CodeSigning {
CFDictionaryRef rules = cfget<CFDictionaryRef>(rulesDict, "rules");
assert(rules);
+ if (this->state.mLimitedAsync == NULL) {
+ this->state.mLimitedAsync =
+ new LimitedAsync(rep->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
+ }
+
CFDictionaryRef files2 = NULL;
if (!(state.signingFlags() & kSecCSSignV1)) {
CFCopyRef<CFDictionaryRef> rules2 = cfget<CFDictionaryRef>(rulesDict, "rules2");
"'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories
"}", rules);
}
+
+ Dispatch::Group group;
+ Dispatch::Group &groupRef = group; // (into block)
+
// build the modern (V2) resource seal
__block CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
+ CFMutableDictionaryRef filesRef = files.get(); // (into block)
ResourceBuilder resourceBuilder(root, relBase, rules2, digestAlgorithm(), strict, MacOSErrorSet());
ResourceBuilder &resources = resourceBuilder; // (into block)
rep->adjustResources(resources);
- resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, Rule *rule) {
- CFRef<CFMutableDictionaryRef> seal;
- if (ruleFlags & ResourceBuilder::nested) {
- seal.take(signNested(ent, relpath));
- } else if (ent->fts_info == FTS_SL) {
- char target[PATH_MAX];
- ssize_t len = ::readlink(ent->fts_accpath, target, sizeof(target)-1);
- if (len < 0)
- UnixError::check(-1);
- target[len] = '\0';
- seal.take(cfmake<CFMutableDictionaryRef>("{symlink=%s}", target));
- } else {
- seal.take(cfmake<CFMutableDictionaryRef>("{hash=%O}",
- CFRef<CFDataRef>(resources.hashFile(ent->fts_accpath)).get()));
- }
- if (ruleFlags & ResourceBuilder::optional)
- CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue);
- CFTypeRef hash;
- if ((hash = CFDictionaryGetValue(seal, CFSTR("hash"))) && CFDictionaryGetCount(seal) == 1) // simple form
- CFDictionaryAddValue(files, CFTempString(relpath).get(), hash);
- else
- CFDictionaryAddValue(files, CFTempString(relpath).get(), seal.get());
- code->reportProgress();
+
+ resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const std::string relpath, Rule *rule) {
+ bool isSymlink = (ent->fts_info == FTS_SL);
+ const std::string path(ent->fts_path);
+ const std::string accpath(ent->fts_accpath);
+ this->state.mLimitedAsync->perform(groupRef, ^{
+ CFRef<CFMutableDictionaryRef> seal;
+ if (ruleFlags & ResourceBuilder::nested) {
+ seal.take(signNested(path, relpath));
+ } else if (isSymlink) {
+ char target[PATH_MAX];
+ ssize_t len = ::readlink(accpath.c_str(), target, sizeof(target)-1);
+ if (len < 0)
+ UnixError::check(-1);
+ target[len] = '\0';
+ seal.take(cfmake<CFMutableDictionaryRef>("{symlink=%s}", target));
+ } else {
+ seal.take(cfmake<CFMutableDictionaryRef>("{hash=%O}",
+ CFRef<CFDataRef>(resources.hashFile(accpath.c_str())).get()));
+ }
+ if (ruleFlags & ResourceBuilder::optional)
+ CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue);
+ CFTypeRef hash;
+ StLock<Mutex> _(resourceLock);
+ if ((hash = CFDictionaryGetValue(seal, CFSTR("hash"))) && CFDictionaryGetCount(seal) == 1) // simple form
+ CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), hash);
+ else
+ CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), seal.get());
+ code->reportProgress();
+ });
});
+ group.wait();
CFDictionaryAddValue(result, CFSTR("rules2"), resourceBuilder.rules());
files2 = files;
CFDictionaryAddValue(result, CFSTR("files2"), files2);
ResourceBuilder resourceBuilder(root, relBase, rules, digestAlgorithm(), strict, MacOSErrorSet());
ResourceBuilder &resources = resourceBuilder;
rep->adjustResources(resources); // DiskRep-specific adjustments
- resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, Rule *rule) {
+ resources.scan(^(FTSENT *ent, uint32_t ruleFlags, std::string relpath, Rule *rule) {
if (ent->fts_info == FTS_F) {
CFRef<CFDataRef> hash;
if (files2) // try to get the hash from a previously-made version
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);
}
}
});
//
// Deal with one piece of nested code
//
-CFMutableDictionaryRef SecCodeSigner::Signer::signNested(FTSENT *ent, const char *relpath)
+CFMutableDictionaryRef SecCodeSigner::Signer::signNested(const std::string &path, const std::string &relpath)
{
// sign nested code and collect nesting information
try {
- SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(ent->fts_path));
+ SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(path));
if (state.signingFlags() & kSecCSSignNestedCode)
this->state.sign(code, state.signingFlags());
std::string dr = Dumper::dump(code->designatedRequirement());
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:
size_t pagesize; // size of main executable pages
CFAbsoluteTime signingTime; // signing time for CMS signature (0 => none)
bool strict; // strict validation
+ Mutex resourceLock;
};
18B965951472FE30005A4D2E /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
37DDE33C1947A4F3005CE18B /* dirscanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 37DDE33B1947A4F3005CE18B /* dirscanner.h */; };
37DDE3421947A501005CE18B /* dirscanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE3411947A501005CE18B /* dirscanner.cpp */; };
- 48674DE319EC9E610049EB7D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48674DE219EC9E610049EB7D /* Security.framework */; };
- 7A4FAF1B19C215DF00D297CB /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A4FAF1A19C215DF00D297CB /* CrashReporterSupport.framework */; };
7A9DA65C1948D1BA004635E6 /* opaquewhitelist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */; };
7A9DA65D1948D1BA004635E6 /* opaquewhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */; };
- 7AADF58919C0CED800292339 /* gkoverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AADF58819C0CED800292339 /* gkoverride.m */; };
7ACF261219958B6F00849B25 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */; };
BEC3A75C16F78D21003E5634 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */; };
C200424D15D425D9004AE0A1 /* libsecurity_codesigning.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */; };
C2F4439A14C626D4000A01E6 /* quarantine++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F4439814C626D4000A01E6 /* quarantine++.cpp */; };
C2F4439B14C626D4000A01E6 /* quarantine++.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F4439914C626D4000A01E6 /* quarantine++.h */; };
C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F6566C0BCBFB250078779E /* cserror.cpp */; };
+ CD97D27C1A2D2BFE00AE62B7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD97D27B1A2D2BFE00AE62B7 /* Security.framework */; };
EB68B111150DAEEA00B4013D /* RequirementLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB68B10B150DAEBB00B4013D /* RequirementLexer.cpp */; };
EB68B112150DAEEA00B4013D /* RequirementParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB68B10D150DAEBB00B4013D /* RequirementParser.cpp */; };
EB68B133150DB04400B4013D /* RequirementKeywords.h in Headers */ = {isa = PBXBuildFile; fileRef = EB68B10A150DAEBB00B4013D /* RequirementKeywords.h */; };
184461A2146E9AD100B12992 /* release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = "<group>"; };
37DDE33B1947A4F3005CE18B /* dirscanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirscanner.h; sourceTree = "<group>"; };
37DDE3411947A501005CE18B /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = "<group>"; };
- 48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = "../../../Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos/Security.framework"; sourceTree = "<group>"; };
+ 48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.Internal.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurity_codesigning.a; sourceTree = BUILT_PRODUCTS_DIR; };
7A4FAF1A19C215DF00D297CB /* CrashReporterSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporterSupport.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.Internal.sdk/System/Library/PrivateFrameworks/CrashReporterSupport.framework; sourceTree = DEVELOPER_DIR; };
7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaquewhitelist.cpp; sourceTree = "<group>"; };
7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opaquewhitelist.h; sourceTree = "<group>"; };
- 7AADF57D19C0CE8C00292339 /* gkoverride */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gkoverride; sourceTree = BUILT_PRODUCTS_DIR; };
- 7AADF58819C0CED800292339 /* gkoverride.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = gkoverride.m; sourceTree = "<group>"; };
BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTaskPriv.h; sourceTree = "<group>"; };
C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_codesigning.a; path = ../../../usr/local/lib/libsecurity_codesigning.a; sourceTree = "<group>"; };
C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; path = ../../../usr/local/lib/libsecurity_utilities.a; sourceTree = "<group>"; };
C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqdumper.h; sourceTree = "<group>"; };
C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeSigner.cpp; sourceTree = "<group>"; };
C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeSigner.h; sourceTree = "<group>"; };
- C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = "<group>"; };
- C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = "<group>"; };
+ C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = "<group>"; usesTabs = 1; };
+ C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = "<group>"; usesTabs = 1; };
C235340E145F1B050073F964 /* xar++.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xar++.h"; sourceTree = "<group>"; };
C2353410145F1B110073F964 /* xar++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "xar++.cpp"; sourceTree = "<group>"; };
- C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = "<group>"; };
- C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = "<group>"; };
+ C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = "<group>"; usesTabs = 1; };
+ C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = "<group>"; usesTabs = 1; };
C236E3D90AD595C2000F5140 /* signerutils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signerutils.cpp; sourceTree = "<group>"; };
C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = "<group>"; };
C24EABAA1421432800C16AA9 /* policydb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policydb.h; sourceTree = "<group>"; };
C293E2C21554653700F3E396 /* sp-watch.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "sp-watch.d"; path = "dtrace/sp-watch.d"; sourceTree = SOURCE_ROOT; };
C2A436130F2133B2007A41A6 /* slcrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slcrep.cpp; sourceTree = "<group>"; };
C2A436140F2133B2007A41A6 /* slcrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slcrep.h; sourceTree = "<group>"; };
- C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = "<group>"; };
- C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = "<group>"; };
+ C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = "<group>"; usesTabs = 1; };
+ C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = "<group>"; usesTabs = 1; };
C2BC1F260B580D3A003EC9DC /* libintegrity.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libintegrity.a; sourceTree = BUILT_PRODUCTS_DIR; };
C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcodehost.a; sourceTree = BUILT_PRODUCTS_DIR; };
C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeHostLib.h; sourceTree = "<group>"; };
C2D3832E0A237F47005C63A2 /* Code.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Code.h; sourceTree = "<group>"; };
C2D3832F0A237F47005C63A2 /* kerneldiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = kerneldiskrep.cpp; sourceTree = "<group>"; };
C2D383300A237F47005C63A2 /* kerneldiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kerneldiskrep.h; sourceTree = "<group>"; };
- C2D383310A237F47005C63A2 /* StaticCode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StaticCode.cpp; sourceTree = "<group>"; };
- C2D383320A237F47005C63A2 /* StaticCode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StaticCode.h; sourceTree = "<group>"; };
+ C2D383310A237F47005C63A2 /* StaticCode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StaticCode.cpp; sourceTree = "<group>"; usesTabs = 1; };
+ C2D383320A237F47005C63A2 /* StaticCode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StaticCode.h; sourceTree = "<group>"; usesTabs = 1; };
C2D383330A237F47005C63A2 /* reqparser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqparser.cpp; sourceTree = "<group>"; };
C2D383340A237F47005C63A2 /* reqparser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqparser.h; sourceTree = "<group>"; };
C2D383350A237F47005C63A2 /* requirement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = requirement.cpp; sourceTree = "<group>"; };
C2F6071B107D575700A83618 /* codesign-watch.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "codesign-watch.d"; path = "dtrace/codesign-watch.d"; sourceTree = SOURCE_ROOT; };
C2F6566C0BCBFB250078779E /* cserror.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cserror.cpp; sourceTree = "<group>"; };
C2F6566D0BCBFB250078779E /* cserror.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cserror.h; sourceTree = "<group>"; };
+ CD97D27B1A2D2BFE00AE62B7 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Security.framework; sourceTree = "<group>"; };
EB68B10A150DAEBB00B4013D /* RequirementKeywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequirementKeywords.h; sourceTree = "<group>"; };
EB68B10B150DAEBB00B4013D /* RequirementLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RequirementLexer.cpp; sourceTree = "<group>"; };
EB68B10C150DAEBB00B4013D /* RequirementLexer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RequirementLexer.hpp; sourceTree = "<group>"; };
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 7AADF57A19C0CE8C00292339 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 48674DE319EC9E610049EB7D /* Security.framework in Frameworks */,
- 7A4FAF1B19C215DF00D297CB /* CrashReporterSupport.framework in Frameworks */,
+ CD97D27C1A2D2BFE00AE62B7 /* Security.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */,
C209696015BF52040093035F /* gkunpack */,
EBB9FF6F1682E51300FF9774 /* com.apple.CodeSigningHelper.xpc */,
- 7AADF57D19C0CE8C00292339 /* gkoverride */,
);
name = Products;
sourceTree = "<group>";
C27360D71436868600A9A5FF /* xpcengine.h */,
C27360D41436866C00A9A5FF /* xpcengine.cpp */,
C27249D2143237CD0058B552 /* syspolicy.sql */,
- 7AADF58819C0CED800292339 /* gkoverride.m */,
);
name = "System Policy";
sourceTree = "<group>";
productReference = 4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */;
productType = "com.apple.product-type.library.static";
};
- 7AADF57C19C0CE8C00292339 /* gkoverride */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 7AADF58719C0CE8C00292339 /* Build configuration list for PBXNativeTarget "gkoverride" */;
- buildPhases = (
- 7AADF57919C0CE8C00292339 /* Sources */,
- 7AADF57A19C0CE8C00292339 /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = gkoverride;
- productName = gkoverride;
- productReference = 7AADF57D19C0CE8C00292339 /* gkoverride */;
- productType = "com.apple.product-type.tool";
- };
C209695F15BF52040093035F /* gkunpack */ = {
isa = PBXNativeTarget;
buildConfigurationList = C209696B15BF52040093035F /* Build configuration list for PBXNativeTarget "gkunpack" */;
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
- TargetAttributes = {
- 7AADF57C19C0CE8C00292339 = {
- CreatedOnToolsVersion = 6.0;
- };
- };
};
buildConfigurationList = C263E67909A2971B000043F1 /* Build configuration list for PBXProject "libsecurity_codesigning" */;
compatibilityVersion = "Xcode 3.2";
C26AC7090DAEB3A7005BFB40 /* DTrace */,
C26AC0EB143BCF01001C98CE /* SystemPolicy */,
C209695F15BF52040093035F /* gkunpack */,
- 7AADF57C19C0CE8C00292339 /* gkoverride */,
EBB9FF6E1682E51300FF9774 /* CodeSigningHelper */,
);
};
);
runOnlyForDeploymentPostprocessing = 0;
};
- 7AADF57919C0CE8C00292339 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 7AADF58919C0CED800292339 /* gkoverride.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
C209695C15BF52040093035F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
- 7AADF58119C0CE8C00292339 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = NO;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- COPY_PHASE_STRIP = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- "/Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos",
- );
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = "";
- INSTALL_PATH = /usr/libexec;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
- MTL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx.internal;
- SKIP_INSTALL = NO;
- };
- name = Debug;
- };
- 7AADF58219C0CE8C00292339 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = NO;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- "/Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos",
- );
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = "";
- INSTALL_PATH = /usr/libexec;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
- MTL_ENABLE_DEBUG_INFO = NO;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx.internal;
- SKIP_INSTALL = NO;
- };
- name = Release;
- };
C209696C15BF52040093035F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 7AADF58719C0CE8C00292339 /* Build configuration list for PBXNativeTarget "gkoverride" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 7AADF58119C0CE8C00292339 /* Debug */,
- 7AADF58219C0CE8C00292339 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
C209696B15BF52040093035F /* Build configuration list for PBXNativeTarget "gkunpack" */ = {
isa = XCConfigurationList;
buildConfigurations = (
/*
- * 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,
* 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@
*/
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;
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;
}
}
return status;
}
+static OSStatus
+_ReplaceKeychainItem(
+ SecKeychainItemRef itemToUpdate,
+ SecKeychainAttributeList *changeAttrList,
+ CFDataRef itemData)
+{
+ OSStatus status;
+ UInt32 itemID;
+ SecItemClass itemClass;
+ SecKeychainAttributeInfo *info = NULL;
+ SecKeychainAttributeList *attrList = NULL;
+ SecKeychainAttributeList newAttrList = { 0, NULL};
+ SecKeychainRef keychain = NULL;
+ SecKeychainItemRef newItem = NULL;
+
+ int priority = LOG_DEBUG;
+ const char *format = "ReplaceKeychainItem (%d) error %d";
+
+ // get existing item's keychain
+ status = SecKeychainItemCopyKeychain(itemToUpdate, &keychain);
+ if (status) { secitemlog(priority, format, 1, (int)status); }
+ require_noerr(status, replace_failed);
+
+ // get attribute info (i.e. database schema) for the item class
+ status = SecKeychainItemCopyAttributesAndData(itemToUpdate, NULL, &itemClass, NULL, NULL, NULL);
+ if (status) { secitemlog(priority, format, 2, (int)status); }
+ require_noerr(status, replace_failed);
+
+ switch (itemClass)
+ {
+ case kSecInternetPasswordItemClass:
+ itemID = CSSM_DL_DB_RECORD_INTERNET_PASSWORD;
+ break;
+ case kSecGenericPasswordItemClass:
+ itemID = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
+ break;
+ default:
+ itemID = itemClass;
+ break;
+ }
+ status = SecKeychainAttributeInfoForItemID(keychain, itemID, &info);
+ if (status) { secitemlog(priority, format, 3, (int)status); }
+
+ // get item's existing attributes (but not data!)
+ status = SecKeychainItemCopyAttributesAndData(itemToUpdate, info, &itemClass, &attrList, NULL, NULL);
+ if (status) { secitemlog(priority, format, 4, (int)status); }
+ require(attrList != NULL, replace_failed);
+
+ // move aside the item by changing a primary attribute
+ // (currently only for passwords)
+ if (itemClass == kSecInternetPasswordItemClass || itemClass == kSecGenericPasswordItemClass) {
+ CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
+ CFStringRef uuidStr = (uuid) ? CFUUIDCreateString(kCFAllocatorDefault, uuid) : CFSTR("MOVED");
+ CFReleaseSafe(uuid);
+ if (uuidStr) {
+ CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr), kCFStringEncodingUTF8) + 1;
+ char* buffer = (char*) malloc(maxLength);
+ if (buffer) {
+ if (CFStringGetCString(uuidStr, buffer, maxLength, kCFStringEncodingUTF8)) {
+ UInt32 length = (UInt32)strlen(buffer);
+ SecKeychainAttribute attrs[] = { { kSecAccountItemAttr, length, (char*)buffer }, };
+ SecKeychainAttributeList updateAttrList = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+ status = SecKeychainItemModifyAttributesAndData(itemToUpdate, &updateAttrList, 0, NULL);
+ if (status) { secitemlog(priority, format, 5, (int)status); }
+ if (status == errSecVerifyFailed) {
+ // still unable to change attrs? delete unconditionally here
+ status = SecKeychainItemDelete(itemToUpdate);
+ if (status) { secitemlog(priority, format, 6, (int)status); }
+ }
+ }
+ free(buffer);
+ }
+ CFReleaseSafe(uuidStr);
+ }
+ }
+ require_noerr(status, replace_failed);
+
+ // make attribute list for new item (the data is still owned by attrList)
+ newAttrList.count = attrList->count;
+ newAttrList.attr = (SecKeychainAttribute *) malloc(sizeof(SecKeychainAttribute) * attrList->count);
+ int i, newCount;
+ for (i=0, newCount=0; i < attrList->count; i++) {
+ if (attrList->attr[i].length > 0) {
+ newAttrList.attr[newCount++] = attrList->attr[i];
+ #if 0
+ // debugging code to log item attributes
+ SecKeychainAttrType tag = attrList->attr[i].tag;
+ SecKeychainAttrType htag=(SecKeychainAttrType)OSSwapConstInt32(tag);
+ char tmp[sizeof(SecKeychainAttrType) + 1];
+ char tmpdata[attrList->attr[i].length + 1];
+ memcpy(tmp, &htag, sizeof(SecKeychainAttrType));
+ tmp[sizeof(SecKeychainAttrType)]=0;
+ memcpy(tmpdata, attrList->attr[i].data, attrList->attr[i].length);
+ tmpdata[attrList->attr[i].length]=0;
+ secitemlog(priority, "item attr '%s' = %d bytes: \"%s\"",
+ tmp, (int)attrList->attr[i].length, tmpdata);
+ #endif
+ }
+ }
+ newAttrList.count = newCount;
+
+ // create new item in the same keychain
+ status = SecKeychainItemCreateFromContent(itemClass, &newAttrList,
+ (UInt32)((itemData) ? CFDataGetLength(itemData) : 0),
+ (const void *)((itemData) ? CFDataGetBytePtr(itemData) : NULL),
+ keychain, NULL, &newItem);
+ if (status) { secitemlog(priority, format, 7, (int)status); }
+ require_noerr(status, replace_failed);
+
+ // delete the old item unconditionally once new item exists
+ status = SecKeychainItemDelete(itemToUpdate);
+
+ // update the new item with changed attributes, if any
+ status = (changeAttrList) ? SecKeychainItemModifyContent(newItem, changeAttrList, 0, NULL) : errSecSuccess;
+ if (status) { secitemlog(priority, format, 8, (int)status); }
+ if (status == errSecSuccess) {
+ // say the item already exists, because it does now. <rdar://19063674>
+ status = errSecDuplicateItem;
+ }
+
+replace_failed:
+ if (newAttrList.attr) {
+ free(newAttrList.attr);
+ }
+ if (attrList) {
+ SecKeychainItemFreeAttributesAndData(attrList, NULL);
+ }
+ if (info) {
+ SecKeychainFreeAttributeInfo(info);
+ }
+ CFReleaseSafe(newItem);
+ CFReleaseSafe(keychain);
+
+ return status;
+}
+
static OSStatus
_UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes)
{
(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)) {
}
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);
/*
- * 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,
* 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@
*/
/* 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")
/*
- * 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,
* 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@
*/
if (mSearchLibs) {
delete mSearchLibs;
}
-
+
mPolicies = NULL;
}
context.actionData() = localActionCData;
}
+ bool hasSSLPolicy = policySpecified(mPolicies, CSSMOID_APPLE_TP_SSL);
+ bool hasEAPPolicy = policySpecified(mPolicies, CSSMOID_APPLE_TP_EAP);
+
if (!mAnchors) {
// always check trust settings if caller did not provide explicit trust anchors
actionDataP->ActionFlags |= CSSM_TP_ACTION_TRUST_SETTINGS;
}
if (mNetworkPolicy == useNetworkDefault) {
- if (policySpecified(mPolicies, CSSMOID_APPLE_TP_SSL)) {
+ if (hasSSLPolicy) {
// enable network cert fetch for SSL only: <rdar://7422356>
actionDataP->ActionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
}
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.
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
/*
- * 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,
* 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@
*/
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,
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);
}
CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
+ bool ocspEnabledOnBestAttempt,
+ bool crlEnabledOnBestAttempt,
uint32 &numAdded,
Allocator &alloc)
{
if(ocspStyle != kSecDisabled) {
doOcsp = true;
}
+ if(ocspStyle == kSecBestAttempt) {
+ doOcsp = ocspEnabledOnBestAttempt;
+ }
}
val = prefsDict->getStringValue(kSecRevocationCrlStyle);
if(val != NULL) {
if(crlStyle != kSecDisabled) {
doCrl = true;
}
+ if(crlStyle == kSecBestAttempt) {
+ doCrl = crlEnabledOnBestAttempt;
+ }
}
+
if(!doCrl && !doOcsp) {
return NULL;
}
}
}
- else {
- assert(doCrl);
+ else if(doCrl) {
CFArrayAppendValue(policies, crlPolicy->handle(false));
}
return policies;
* Caller is responsible for releasing the returned policies array.
*/
CFMutableArrayRef Trust::forceRevocationPolicies(
+ bool ocspEnabled,
+ bool crlEnabled,
uint32 &numAdded,
Allocator &alloc,
bool requirePerCert)
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;
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;
// fprintf(stderr, "%s", buffer);
dtprintf("%s", buffer);
+
+ free(buffer);
#endif
}
dtprintf("%s%s\n", signerhdr, cn);
if (cn)
free(cn);
+ CFReleaseNull(commonName);
}
else
dtprintf("%s<NULL>\n", signerhdr);
if (timestampTime)
*timestampTime = genTime;
xit:
+ if (signingCertificate)
+ CFReleaseNull(signingCertificate);
return result;
}
// See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
// Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
+ SecTrustRef trustRef = NULL;
CFTypeRef policy = CFRetainSafe(timeStampPolicy);
int result=errSecInternalError;
int rx;
for (jx = 0; jx < numberOfSigners; ++jx)
{
SecTrustResultType trustResultType;
- SecTrustRef trustRef = NULL;
CFDictionaryRef extendedResult = NULL;
CFArrayRef certChain = NULL;
uint16_t certCount = 0;
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);
}
if (trustRef)
- CFRelease (trustRef);
+ CFReleaseNull(trustRef);
}
xit:
+ if (trustRef)
+ CFReleaseNull(trustRef);
if (policy)
- CFRelease (policy);
+ CFRelease(policy);
return result;
}
{
CFArrayRef certs = NULL;
CFDataRef message;
+ CFIndex count;
// Premade message containing one certificate blob
message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
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);
return errSecSuccess;
}
-CFStringRef SSLContextCopyDescription(CFTypeRef arg)
+CFStringRef SSLContextCopyFormatDescription(CFTypeRef arg, CFDictionaryRef formatOptions)
{
SSLContext* ctx = (SSLContext*) arg;
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) {
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, */
SSLContextRef st;
bool is_server;
bool is_dtls;
- bool client_side_auth;
+ int client_side_auth;
bool dh_anonymous;
int comm;
CFArrayRef certs;
};
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);
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);
}
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));
for (p=0; p<nprotos; p++)
for (d=0;d<2; d++) /* dtls or not dtls */
- for (k=0; k<2; k++)
+ for (k=0; k<3; k++) /* client side auth mode: 0: server doesn't request , 1: server request, client provide, 2: server request, client does not provide */
{
for (i=0; ciphers[i].cipher != (SSLCipherSuite)(-1); i++)
for (l = 0; l<2; l++) {
ssl_test_handle *server, *client;
- bool client_side_auth = (k);
+ int client_side_auth = (k);
uint32_t session_id = (k+1) << 16 | (i+1);
//fprintf(stderr, "session_id: %d\n", session_id);
int ssl_42_ciphers(int argc, char *const *argv)
{
- plan_tests(2 * 2 * 2 * nprotos * (ciphers_len-1)/* client auth on/off * #configs * #ciphers */
+ plan_tests(3 * 2 * 2 * nprotos * (ciphers_len-1)/* client auth 0/1/2 * #configs * protos * #ciphers */
+ 1 /*cert*/);
* @APPLE_LICENSE_HEADER_END@
*/
-
-
#include <stdbool.h>
#include <pthread.h>
#include <fcntl.h>
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) {
} 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;
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);
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);
int ssl_44_crashes(int argc, char *const *argv)
{
- plan_tests(3*2 + 1 /*cert*/);
+ plan_tests(4*2 + 1 /*cert*/);
tests();
--- /dev/null
+/*
+ * Copyright (c) 2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// dispatch - libdispatch wrapper
+//
+#include "dispatch.h"
+#include <security_utilities/errors.h>
+
+namespace Security {
+namespace Dispatch {
+
+ExceptionAwareEnqueuing::ExceptionAwareEnqueuing()
+: mExceptionPending(false)
+{ }
+
+void ExceptionAwareEnqueuing::enqueueWithDispatcher(void (^dispatcher)(dispatch_block_t), dispatch_block_t block)
+{
+ if (mExceptionPending)
+ return;
+
+ dispatcher(^{
+ if (mExceptionPending)
+ return;
+ try {
+ block();
+ } catch (...) {
+ StLock<Mutex> _(mLock);
+ mExceptionPending = true;
+ mException = std::current_exception();
+ }
+ });
+}
+
+void ExceptionAwareEnqueuing::throwPendingException()
+{
+ if (mExceptionPending) {
+ mExceptionPending = false;
+ std::rethrow_exception(mException);
+ }
+}
+
+
+
+Queue::Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class)
+{
+ dispatch_queue_attr_t attr = concurrent ? DISPATCH_QUEUE_CONCURRENT : DISPATCH_QUEUE_SERIAL;
+ attr = dispatch_queue_attr_make_with_qos_class(attr, qos_class, 0);
+ mQueue = dispatch_queue_create(label, attr);
+}
+
+Queue::~Queue()
+{
+ dispatch_barrier_sync(mQueue, ^{});
+ dispatch_release(mQueue);
+}
+
+void Queue::enqueue(dispatch_block_t block)
+{
+ enqueuing.enqueueWithDispatcher(^(dispatch_block_t block){ dispatch_async(mQueue, block); }, block);
+}
+
+void Queue::wait()
+{
+ dispatch_barrier_sync(mQueue, ^{});
+ enqueuing.throwPendingException();
+}
+
+
+
+Group::Group()
+{
+ mGroup = dispatch_group_create();
+}
+
+Group::~Group()
+{
+ dispatch_group_wait(mGroup, DISPATCH_TIME_FOREVER);
+ dispatch_release(mGroup);
+}
+
+void Group::enqueue(dispatch_queue_t queue, dispatch_block_t block)
+{
+ enqueuing.enqueueWithDispatcher(^(dispatch_block_t block){ dispatch_group_async(mGroup, queue, block); }, block);
+}
+
+void Group::wait()
+{
+ dispatch_group_wait(mGroup, DISPATCH_TIME_FOREVER);
+ enqueuing.throwPendingException();
+}
+
+
+
+Semaphore::Semaphore(long count) {
+ mSemaphore = dispatch_semaphore_create(count);
+}
+
+Semaphore::Semaphore(Semaphore& semaphore)
+: mSemaphore(semaphore.mSemaphore)
+{
+ dispatch_retain(mSemaphore);
+}
+
+Semaphore::~Semaphore() {
+ dispatch_release(mSemaphore);
+}
+
+bool Semaphore::signal() {
+ return dispatch_semaphore_signal(mSemaphore) == 0;
+}
+
+bool Semaphore::wait(dispatch_time_t timeout) {
+ return dispatch_semaphore_wait(mSemaphore, timeout) == 0;
+}
+
+
+// Transfer ownership of held resource.
+SemaphoreWait::SemaphoreWait(SemaphoreWait &originalWait)
+: mSemaphore(originalWait.mSemaphore), mAcquired(originalWait.mAcquired)
+{
+ originalWait.mAcquired = false;
+}
+
+SemaphoreWait::SemaphoreWait(Semaphore &semaphore, dispatch_time_t timeout)
+: mSemaphore(semaphore)
+{
+ mAcquired = mSemaphore.wait(timeout);
+}
+
+SemaphoreWait::~SemaphoreWait()
+{
+ if (mAcquired)
+ mSemaphore.signal();
+}
+
+
+} // end namespace Dispatch
+} // end namespace Security
--- /dev/null
+/*
+ * Copyright (c) 2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// dispatch - libdispatch wrapper
+//
+#ifndef _H_DISPATCH
+#define _H_DISPATCH
+
+#include <dispatch/dispatch.h>
+#include <security_utilities/utilities.h>
+#include <security_utilities/threading.h>
+
+#include <exception>
+
+namespace Security {
+namespace Dispatch {
+
+
+// Wraps dispatch objects which can be used to queue blocks, i.e. dispatch groups and queues.
+// If a block throws an exception, no further blocks are enqueued and the exception is rethrown
+// after waiting for completion of all blocks.
+class ExceptionAwareEnqueuing {
+ NOCOPY(ExceptionAwareEnqueuing)
+public:
+ ExceptionAwareEnqueuing();
+
+ void enqueueWithDispatcher(void (^dispatcher)(dispatch_block_t), dispatch_block_t block);
+ void throwPendingException();
+private:
+ Mutex mLock;
+ bool mExceptionPending;
+ std::exception_ptr mException;
+};
+
+
+class Queue {
+ NOCOPY(Queue)
+public:
+ Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class = QOS_CLASS_DEFAULT);
+ virtual ~Queue();
+
+ operator dispatch_queue_t () const { return mQueue; }
+
+ void enqueue(dispatch_block_t block);
+ void wait();
+
+private:
+ ExceptionAwareEnqueuing enqueuing;
+ dispatch_queue_t mQueue;
+};
+
+
+class Group {
+ NOCOPY(Group)
+public:
+ Group();
+ virtual ~Group();
+
+ operator dispatch_group_t () const { return mGroup; }
+
+ void enqueue(dispatch_queue_t queue, dispatch_block_t block);
+ void wait();
+
+private:
+ ExceptionAwareEnqueuing enqueuing;
+ dispatch_group_t mGroup;
+};
+
+
+class Semaphore {
+ NOCOPY(Semaphore)
+public:
+ Semaphore(long count);
+ Semaphore(Semaphore& semaphore);
+ virtual ~Semaphore();
+
+ operator dispatch_semaphore_t () const { return mSemaphore; };
+
+ bool signal();
+ bool wait(dispatch_time_t timeout = DISPATCH_TIME_FOREVER);
+
+private:
+ dispatch_semaphore_t mSemaphore;
+};
+
+
+class SemaphoreWait {
+ NOCOPY(SemaphoreWait)
+public:
+ SemaphoreWait(SemaphoreWait& originalWait);
+ SemaphoreWait(Semaphore& semaphore, dispatch_time_t timeout = DISPATCH_TIME_FOREVER);
+ virtual ~SemaphoreWait();
+
+ bool acquired() const { return mAcquired; };
+
+private:
+ Semaphore &mSemaphore;
+ bool mAcquired;
+};
+
+
+} // end namespace Dispatch
+} // end namespace Security
+
+#endif // !_H_DISPATCH
void MacOSError::throwMe(int error)
{ throw MacOSError(error); }
+MacOSError MacOSError::make(int error)
+{ return MacOSError(error); }
+
//
// CFError exceptions
static void check(OSStatus status) { if (status != errSecSuccess) throwMe(status); }
static void throwMe(int err) __attribute__((noreturn));
+
+ static MacOSError make(int err);
};
typedef std::set<OSStatus> MacOSErrorSet;
const load_command *MachOBase::nextCommand(const load_command *command) const
{
using LowLevelMemoryUtilities::increment;
+ /* Do not try and increment by 0, or it will loop forever */
+ if (flip(command->cmdsize) == 0)
+ UnixError::throwMe(ENOEXEC);
command = increment<const load_command>(command, flip(command->cmdsize));
if (command >= mEndCommands) // end of load commands
return NULL;
// unix++ - C++ layer for basic UNIX facilities
//
#include "unix++.h"
+#include <security_utilities/cfutilities.h>
#include <security_utilities/memutils.h>
#include <security_utilities/debugging.h>
+#include <sys/dirent.h>
#include <sys/xattr.h>
#include <cstdarg>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
namespace Security {
}
+//
+// Device characteristics
+//
+static CFDictionaryRef deviceCharacteristics(FileDesc &fd)
+{
+ // get device name
+ AutoFileDesc::UnixStat st;
+ fd.fstat(st);
+ char buffer[MAXNAMLEN];
+ checkError(::devname_r(st.st_dev, S_IFBLK, buffer, MAXNAMLEN));
+
+ // search in IO Registry for named device
+ CFDictionaryRef matching = IOBSDNameMatching(kIOMasterPortDefault, 0, buffer);
+ if (matching) {
+ // fetch the object with the matching BSD name (consumes reference on matching)
+ io_registry_entry_t entry = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
+ if (entry != IO_OBJECT_NULL) {
+ // get device characteristics
+ CFDictionaryRef characteristics = (CFDictionaryRef)IORegistryEntrySearchCFProperty(entry,
+ kIOServicePlane,
+ CFSTR(kIOPropertyDeviceCharacteristicsKey),
+ NULL,
+ kIORegistryIterateRecursively | kIORegistryIterateParents);
+ IOObjectRelease(entry);
+ return characteristics;
+ }
+ }
+
+ return NULL; // unable to get device characteristics
+}
+
+std::string FileDesc::mediumType()
+{
+ CFRef<CFDictionaryRef> characteristics = deviceCharacteristics(*this);
+ if (characteristics) {
+ CFStringRef mediumType = (CFStringRef)CFDictionaryGetValue(characteristics, CFSTR(kIOPropertyMediumTypeKey));
+ if (mediumType)
+ return cfString(mediumType);
+ }
+ return string();
+}
+
+
//
// Signals and signal masks
//
// 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
4CA684FB0525011E00233BF2 /* url.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA684BB0525011E00233BF2 /* url.cpp */; };
4CA684FD0525011E00233BF2 /* utilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA684BD0525011E00233BF2 /* utilities.cpp */; };
4E4813D707739B0C0090D7C2 /* ccaudit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4E4813D507739B0C0090D7C2 /* ccaudit.cpp */; };
+ 7A93A12419BE6FA600F07E9A /* dispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A93A12219BE6FA600F07E9A /* dispatch.cpp */; };
+ 7A93A12519BE6FA600F07E9A /* dispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A93A12319BE6FA600F07E9A /* dispatch.h */; };
AAA4B91E16653547005DEFDC /* debugging_internal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAA4B91D16653547005DEFDC /* debugging_internal.cpp */; };
AAA4B920166535B4005DEFDC /* debugging_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AAA4B91F16653597005DEFDC /* debugging_internal.h */; settings = {ATTRIBUTES = (Public, ); }; };
AAAA499A0CC587B50099E9D4 /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = AAAA49980CC587B50099E9D4 /* crc.c */; };
4CA684BF0525011E00233BF2 /* utility_config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = utility_config.h; sourceTree = "<group>"; };
4E4813D507739B0C0090D7C2 /* ccaudit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ccaudit.cpp; sourceTree = "<group>"; };
4E4813D607739B0C0090D7C2 /* ccaudit.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ccaudit.h; sourceTree = "<group>"; };
+ 7A93A12219BE6FA600F07E9A /* dispatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dispatch.cpp; sourceTree = "<group>"; usesTabs = 1; };
+ 7A93A12319BE6FA600F07E9A /* dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dispatch.h; sourceTree = "<group>"; usesTabs = 1; };
AA3BC08D166549EA00EF1D2E /* exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = exports; sourceTree = "<group>"; };
AA5B97E70E140C3E0032C12F /* dtrace.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dtrace.mk; path = lib/dtrace.mk; sourceTree = "<group>"; usesTabs = 1; };
AAA4B91D16653547005DEFDC /* debugging_internal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugging_internal.cpp; sourceTree = "<group>"; };
AAA4B91F16653597005DEFDC /* debugging_internal.h */,
4CA6848C0525011D00233BF2 /* devrandom.h */,
4CA6848B0525011D00233BF2 /* devrandom.cpp */,
+ 7A93A12219BE6FA600F07E9A /* dispatch.cpp */,
+ 7A93A12319BE6FA600F07E9A /* dispatch.h */,
4CA6848E0525011D00233BF2 /* endian.h */,
4CA6848D0525011D00233BF2 /* endian.cpp */,
C22EC38F052B7F5D00D55C69 /* errors.h */,
181EA3BB146D1D7F00A6D320 /* dyldcache.h in Headers */,
181EA3BC146D1D7F00A6D320 /* dyld_cache_format.h in Headers */,
181EA3BD146D1D7F00A6D320 /* machserver.h in Headers */,
+ 7A93A12519BE6FA600F07E9A /* dispatch.h in Headers */,
181EA3BE146D1D7F00A6D320 /* machrunloopserver.h in Headers */,
181EA3BF146D1D8600A6D320 /* coderepository.h in Headers */,
181EA3C0146D1D8600A6D320 /* cfclass.h in Headers */,
4CA684C20525011E00233BF2 /* buffers.cpp in Sources */,
C2B9F3630D5A28CA00CAB713 /* cfmunge.cpp in Sources */,
4CA684C40525011E00233BF2 /* cfutilities.cpp in Sources */,
+ 7A93A12419BE6FA600F07E9A /* dispatch.cpp in Sources */,
4CA684C60525011E00233BF2 /* daemon.cpp in Sources */,
4CA684C80525011E00233BF2 /* debugging.cpp in Sources */,
4CA684CB0525011E00233BF2 /* devrandom.cpp in Sources */,
}
}
-static CFStringRef SOSTestDeviceCopyDescription(CFTypeRef cf) {
+static CFStringRef SOSTestDeviceCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SOSTestDeviceRef td = (SOSTestDeviceRef)cf;
CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorDefault, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SOSTestDevice %@"), td->ds->engine);
static SOSTestDeviceRef SOSTestDeviceCreateInternal(CFAllocatorRef allocator, CFStringRef engineID) {
SOSTestDeviceRef td = CFTypeAllocate(SOSTestDevice, struct __OpaqueSOSTestDevice, allocator);
td->peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
+ td->mute = false;
return td;
}
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;
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);
SOSDataSourceFactoryRef dsf;
SOSDataSourceRef ds;
CFMutableArrayRef peers;
+ bool mute;
};
CFStringRef SOSMessageCopyDigestHex(SOSMessageRef message);
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);
}
-static CFStringRef SOSAccountCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSAccountCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
SOSAccountRef a = (SOSAccountRef) aObj;
return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSAccount@%p: Gestalt: %@\n Circles: %@ CircleIDs: %@>"), a, a->gestalt, a->circles, a->circle_identities);
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);
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)) {
CFReleaseNull(c->signatures);
}
-static CFStringRef SOSCircleCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
SOSCircleRef c = (SOSCircleRef) aObj;
SOSCircleAssertStable(c);
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);
return CFHash(peer->peer_info);
}
-static CFStringRef SOSFullPeerInfoCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSFullPeerInfoCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
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));
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;
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"));
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);
return tpt;
}
-static CFStringRef SOSTransportCircleCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSTransportCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
SOSTransportCircleRef t = (SOSTransportCircleRef) aObj;
return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportCircle@%p\n>"), t);
return transport->setToNewAccount(transport);
}
-static CFStringRef SOSTransportKeyParameterCopyDescription(CFTypeRef aObj) {
+static CFStringRef SOSTransportKeyParameterCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
SOSTransportKeyParameterRef t = (SOSTransportKeyParameterRef) aObj;
return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportKeyParameter@%p\n>"), t);
}
-static CFStringRef SOSTransportMessageCopyDescription(CFTypeRef aObj){
+static CFStringRef SOSTransportMessageCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions){
SOSTransportMessageRef t = (SOSTransportMessageRef) aObj;
return t->copyDescription ? t->copyDescription(t)
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)
-#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) {
ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
if (serialize) {
serializeAndDeserialize(bobSession);
serializeAndDeserialize(aliceSession);
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);
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);
+ 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;
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
ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
"Bob DH packet failed");
- if (serialize)
- serializeAndDeserialize(aliceSession);
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
CFReleaseNull(bobStartPacket);
ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
"Alice DH packet failed");
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(bobSession);
CFReleaseNull(aliceStartPacket);
ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
"Alice DH Key packet failed");
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(bobSession);
CFReleaseNull(aliceDHKeyResponse);
ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
"Bob DH Key packet failed");
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(aliceSession);
CFReleaseNull(bobDHKeyResponse);
ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
"Bob Reveal sig failed");
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(aliceSession);
CFReleaseNull(bobRevealSigResponse);
ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
"Alice Reveal sig failed");
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(bobSession);
CFReleaseNull(aliceRevealSigResponse);
ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
"Alice Final Sig failed");
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(bobSession);
CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
CFReleaseNull(aliceFinalResponse);
CFReleaseNull(bobSigResponse);
- if (serialize)
+ if (serializeNegotiating)
serializeAndDeserialize(aliceSession);
is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
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));
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);
}
-#define kTestTestCount (9 + kNegotiateTestCount * 2)
+#define kTestTestCount (11 + kNegotiateTestCount * 6)
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);
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");
CFReleaseNull(aliceSession);
CFReleaseNull(bobSession);
+
+ CFReleaseNull(aliceCompactSession);
+ CFReleaseNull(bobCompactSession);
+
+ CFReleaseNull(aliceCompactHashesSession);
+ CFReleaseNull(bobCompactHashesSession);
}
int otr_30_negotiation(int argc, char *const *argv)
--- /dev/null
+/*
+ * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Security_regressions.h"
+
+#include <CoreFoundation/CFData.h>
+#include <Security/SecOTRSession.h>
+#include <Security/SecInternal.h>
+#include <Security/SecBasePriv.h>
+
+static void SecMPLogError(CFErrorRef error) {
+ if (error == NULL) {
+ return;
+ }
+ CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error);
+ CFIndex errorCode = CFErrorGetCode(error);
+ CFStringRef errorDomain = CFErrorGetDomain(error);
+ CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey);
+ CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey);
+ if (previousError != NULL) {
+ SecMPLogError(previousError);
+ }
+ char errorDomainStr[1024];
+ char errorStringStr[1024];
+
+ CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8);
+ CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8);
+ printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr);
+ CFReleaseSafe(tempDictionary);
+}
+
+static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
+{
+ CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ SecOTRSAppendSerialization(*thisOne, serialized);
+ CFReleaseNull(*thisOne);
+ *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
+
+ CFReleaseSafe(serialized);
+}
+
+#define renegotiateTests 9
+
+static void renegotiate(SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serializeNegotiating, CFDataRef messageDuringNegotiation){
+
+ CFMutableDataRef aliceRestartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef bobDHKeyPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ CFDataRef empty = CFDataCreate(kCFAllocatorDefault, NULL, 0);
+
+ CFMutableDataRef hopefullyNothing = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ //send a restart packet after session has successfully sent messages
+ ok_status(SecOTRSAppendRestartPacket(*aliceSession, aliceRestartPacket), "Alice restart packet");
+
+ if(serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ SKIP: {
+ skip("No messageDuringNegotiation", 1, messageDuringNegotiation);
+ is(SecOTRSVerifyAndExposeMessage(*aliceSession, messageDuringNegotiation, hopefullyNothing), errSecOTRNotReady, "Message during negotiation");
+ }
+
+ if(serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceRestartPacket, bobDHKeyPacket),
+ "Bob DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+
+ CFMutableDataRef aliceRevealSigPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyPacket, aliceRevealSigPacket),
+ "Alice DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigPacket, bobRevealSigResponse),
+ "Bob DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ // Step 4: Having gotten the reveal signature, now work for the signature
+
+ CFMutableDataRef aliceSigPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigPacket),
+ "Bob Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+
+ ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+ ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+
+ CFReleaseNull(aliceRestartPacket);
+ CFReleaseNull(aliceRevealSigPacket);
+ CFReleaseNull(aliceSigPacket);
+
+ CFReleaseNull(bobDHKeyPacket);
+ CFReleaseNull(bobRevealSigResponse);
+
+ CFReleaseNull(hopefullyNothing);
+ CFReleaseNull(empty);
+
+}
+
+
+#define sendMessagesCount(n) ((n) * 14)
+static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
+{
+ for(int count = howMany; count > 0; --count) {
+ const char* aliceToBob = "aliceToBob";
+ CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+ CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(bobDecode);
+
+ const char* bobToAlice = "i liked your silly message from me to you";
+ CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+ CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(rawBobToAlice);
+ CFReleaseNull(protectedBobToAlice);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(aliceDecode);
+
+ rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+ protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(bobDecode);
+
+ bobToAlice = "i liked your silly message from me to you";
+ rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+ protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(rawBobToAlice);
+ CFReleaseNull(protectedBobToAlice);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(aliceDecode);
+
+
+
+ CFStringRef stateString = CFCopyDescription(*bobSession);
+ ok(stateString, "getting state from bob");
+ CFReleaseNull(stateString);
+
+ stateString = CFCopyDescription(*aliceSession);
+ ok(stateString, "getting state from alice");
+ CFReleaseNull(stateString);
+ }
+}
+
+#define kNegotiateTestCount (14 + sendMessagesCount(1) * 4 \
++ renegotiateTests)
+
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, SecOTRSessionRef *brandNewBobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
+{
+ const int kEmptyMessageSize = textMode ? 6 : 0;
+
+ // Step 1: Create a start packet for each side of the transaction
+ CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ // Step 2: Exchange the start packets, forcing the DH commit messages to collide
+ CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
+ "Bob DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobStartPacket);
+
+ CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
+ "Alice DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceStartPacket);
+
+ // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+
+ CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
+ "Alice DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceDHKeyResponse);
+
+ CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
+ "Bob DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobDHKeyResponse);
+
+ // Step 4: Having gotten the reveal signature, now work for the signature
+
+ CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
+ "Bob Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobRevealSigResponse);
+
+ CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
+ "Alice Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceRevealSigResponse);
+
+ // Step 5: All the messages have been sent, now deal with any replays from the collision handling
+ CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
+ "Alice Final Sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
+ "Bob Final Sig failed");
+
+ is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
+ CFReleaseNull(aliceFinalResponse);
+ CFReleaseNull(bobSigResponse);
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
+ ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+ ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+
+ CFReleaseNull(aliceSigResponse);
+ CFReleaseNull(bobFinalResponse);
+
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ const char *bobToAlice = "i liked your silly message from me to you";
+ CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+ CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*bobSession, rawBobToAlice, protectedBobToAlice), "protected bob to alice message");
+
+ CFReleaseNull(rawBobToAlice);
+
+ renegotiate(brandNewBobSession, aliceSession, serializeNegotiating, protectedBobToAlice);
+
+ CFReleaseNull(protectedBobToAlice);
+
+}
+
+#define kEdgeCaseTestCount (10 + kNegotiateTestCount * 2)
+
+static void tryEdgeCases(uint32_t flags)
+{
+ CFErrorRef testError = NULL;
+ SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ testError = NULL;
+ SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ testError = NULL;
+
+ ok(aliceID, "create alice ID");
+ ok(bobID, "create bob ID");
+
+ SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+
+ ok(alicePublicID, "extract alice public");
+ ok(bobPublicID, "extract bob public");
+
+ SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, flags);
+ SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+ SecOTRSessionRef brandNewBobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+ SecOTRSessionRef brandNewBobSession2 = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+ SecOTRSessionRef brandNewBobSession3 = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, flags);
+
+ ok(aliceSession, "create alice session");
+ ok(bobSession, "create bob session");
+ ok(brandNewBobSession, "create new bob session");
+
+
+ // Release the IDs, sessions shouldn't need us to retain them for them.
+ CFReleaseNull(aliceID);
+ CFReleaseNull(bobID);
+
+ CFReleaseNull(alicePublicID);
+ CFReleaseNull(bobPublicID);
+
+ negotiate(&aliceSession, &bobSession, &brandNewBobSession, true, true, false, flags & kSecOTRUseAppleCustomMessageFormat);
+
+ negotiate(&aliceSession, &bobSession, &brandNewBobSession2, true, false, false, flags & kSecOTRUseAppleCustomMessageFormat);
+
+
+ const char * testMessageString = "i liked your silly message from me to you";
+ CFDataRef testMessage = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)testMessageString, (CFIndex) strlen(testMessageString));
+ CFMutableDataRef protectedTestMessage = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(aliceSession, testMessage, protectedTestMessage), "Make message");
+
+ CFMutableDataRef hopefullyNothing = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ is(SecOTRSVerifyAndExposeMessage(brandNewBobSession3, protectedTestMessage, hopefullyNothing), errSecOTRNotReady, "Message Before Negotiating");
+
+ /* cleanup keychain */
+ ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+
+ CFReleaseNull(aliceSession);
+ CFReleaseNull(bobSession);
+
+ CFReleaseNull(brandNewBobSession);
+ CFReleaseNull(brandNewBobSession2);
+ CFReleaseNull(brandNewBobSession3);
+ CFReleaseNull(testMessage);
+ CFReleaseNull(protectedTestMessage);
+ CFReleaseNull(hopefullyNothing);
+}
+
+
+#define kTestTestCount (2 * kEdgeCaseTestCount)
+
+static void tests()
+{
+ tryEdgeCases(0);
+ tryEdgeCases(kSecOTRUseAppleCustomMessageFormat);
+}
+
+int otr_40_edgecases(int argc, char *const *argv)
+{
+ plan_tests(kTestTestCount);
+
+ tests();
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Security_regressions.h"
+
+#include <CoreFoundation/CFData.h>
+#include <Security/SecOTRSession.h>
+#include <Security/SecOTRSessionPriv.h>
+#include <Security/SecInternal.h>
+#include <Security/SecBasePriv.h>
+
+static void SecMPLogError(CFErrorRef error) {
+ if (error == NULL) {
+ return;
+ }
+ CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error);
+ CFIndex errorCode = CFErrorGetCode(error);
+ CFStringRef errorDomain = CFErrorGetDomain(error);
+ CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey);
+ CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey);
+ if (previousError != NULL) {
+ SecMPLogError(previousError);
+ }
+ char errorDomainStr[1024];
+ char errorStringStr[1024];
+
+ CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8);
+ CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8);
+ printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr);
+ CFReleaseSafe(tempDictionary);
+}
+
+static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
+{
+ CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ SecOTRSAppendSerialization(*thisOne, serialized);
+ CFReleaseNull(*thisOne);
+ *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
+
+ CFReleaseSafe(serialized);
+}
+
+
+
+#define sendMessagesCount(n) ((n) * 14)
+static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
+{
+ for(int count = howMany; count > 0; --count) {
+ const char* aliceToBob = "aliceToBob";
+ CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+ CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(bobDecode);
+
+ const char* bobToAlice = "i liked your silly message from me to you";
+ CFDataRef rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+ CFMutableDataRef protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(rawBobToAlice);
+ CFReleaseNull(protectedBobToAlice);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(aliceDecode);
+
+ rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+ protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(bobDecode);
+
+ bobToAlice = "i liked your silly message from me to you";
+ rawBobToAlice = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)bobToAlice, (CFIndex) strlen(bobToAlice));
+ protectedBobToAlice = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ aliceDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawBobToAlice, protectedBobToAlice), "encode reply");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedBobToAlice, aliceDecode), "decode reply");
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawBobToAlice) == CFDataGetLength(aliceDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawBobToAlice), CFDataGetBytePtr(aliceDecode), (size_t)CFDataGetLength(rawBobToAlice)), "reply matched");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(rawBobToAlice);
+ CFReleaseNull(protectedBobToAlice);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(aliceDecode);
+
+
+
+ CFStringRef stateString = CFCopyDescription(*bobSession);
+ ok(stateString, "getting state from bob");
+ CFReleaseNull(stateString);
+
+ stateString = CFCopyDescription(*aliceSession);
+ ok(stateString, "getting state from alice");
+ CFReleaseNull(stateString);
+ }
+}
+
+#define kNegotiateTestCount (19 + sendMessagesCount(5) \
++ 2 * sendMessagesCount(5))
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
+{
+ const int kEmptyMessageSize = textMode ? 6 : 0;
+
+ // Step 1: Create a start packet for each side of the transaction
+ CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ // Step 2: Exchange the start packets, forcing the DH commit messages to collide
+ CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
+ "Bob DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobStartPacket);
+
+ CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
+ "Alice DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceStartPacket);
+
+ // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+
+ CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
+ "Alice DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceDHKeyResponse);
+
+ CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
+ "Bob DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobDHKeyResponse);
+
+ // Step 4: Having gotten the reveal signature, now work for the signature
+
+ CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
+ "Bob Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobRevealSigResponse);
+
+ CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
+ "Alice Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceRevealSigResponse);
+
+ // Step 5: All the messages have been sent, now deal with any replays from the collision handling
+ CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
+ "Alice Final Sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
+ "Bob Final Sig failed");
+
+ is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
+ CFReleaseNull(aliceFinalResponse);
+ CFReleaseNull(bobSigResponse);
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
+ ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+ ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+
+ CFReleaseNull(aliceSigResponse);
+ CFReleaseNull(bobFinalResponse);
+
+ sendMessages(5, bobSession, aliceSession, serializeMessaging);
+
+ for(int i = 0; i < 5; i++){
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+ ok(SecOTRSGetKeyID(*aliceSession) == SecOTRSGetKeyID(*bobSession));
+ }
+}
+
+
+#define kTestTestCount (11 + kNegotiateTestCount * 6)
+
+static void tests()
+{
+ CFErrorRef testError = NULL;
+ SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ testError = NULL;
+ SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ testError = NULL;
+
+ ok(aliceID, "create alice ID");
+ ok(bobID, "create bob ID");
+
+ SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+
+ ok(alicePublicID, "extract alice public");
+ ok(bobPublicID, "extract bob public");
+
+ SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRSendTextMessages);
+ SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRSendTextMessages);
+
+ ok(aliceSession, "create alice session");
+ ok(bobSession, "create bob session");
+
+ SecOTRSessionRef aliceCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat);
+ SecOTRSessionRef bobCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat);
+
+ ok(aliceCompactSession, "create alice compact session");
+ ok(bobCompactSession, "create bob compact session");
+
+ SecOTRSessionRef aliceCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
+ SecOTRSessionRef bobCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages);
+
+ ok(aliceCompactHashesSession, "create alice compact session with hashes");
+ ok(bobCompactHashesSession, "create bob compact session with hashes");
+
+ // Release the IDs, sessions shouldn't need us to retain them for them.
+ CFReleaseNull(aliceID);
+ CFReleaseNull(bobID);
+
+ CFReleaseNull(alicePublicID);
+ CFReleaseNull(bobPublicID);
+
+ negotiate(&aliceSession, &bobSession, true, true, true, false);
+
+ negotiate(&aliceSession, &bobSession, true, false, true, false);
+
+ negotiate(&aliceCompactSession, &bobCompactSession, true, true, false, true);
+
+ negotiate(&aliceCompactSession, &bobCompactSession, true, false, false, true);
+
+ negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, true, false, true);
+
+ negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, false, false, true);
+
+ /* cleanup keychain */
+ ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+
+ CFReleaseNull(aliceSession);
+ CFReleaseNull(bobSession);
+
+ CFReleaseNull(aliceCompactSession);
+ CFReleaseNull(bobCompactSession);
+
+ CFReleaseNull(aliceCompactHashesSession);
+ CFReleaseNull(bobCompactHashesSession);
+}
+
+int otr_50_roll(int argc, char *const *argv)
+{
+ plan_tests(kTestTestCount);
+
+ tests();
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Security_regressions.h"
+
+#include <CoreFoundation/CFData.h>
+#include <Security/SecOTRSession.h>
+#include <Security/SecOTRSessionPriv.h>
+#include <Security/SecInternal.h>
+#include <Security/SecBasePriv.h>
+
+static void SecMPLogError(CFErrorRef error) {
+ if (error == NULL) {
+ return;
+ }
+ CFDictionaryRef tempDictionary = CFErrorCopyUserInfo(error);
+ CFIndex errorCode = CFErrorGetCode(error);
+ CFStringRef errorDomain = CFErrorGetDomain(error);
+ CFStringRef errorString = CFDictionaryGetValue(tempDictionary, kCFErrorDescriptionKey);
+ CFErrorRef previousError = (CFErrorRef)CFDictionaryGetValue(tempDictionary, kCFErrorUnderlyingErrorKey);
+ if (previousError != NULL) {
+ SecMPLogError(previousError);
+ }
+ char errorDomainStr[1024];
+ char errorStringStr[1024];
+
+ CFStringGetCString(errorDomain, errorDomainStr, 1024, kCFStringEncodingUTF8);
+ CFStringGetCString(errorString, errorStringStr, 1024, kCFStringEncodingUTF8);
+ printf("MessageProtection: %s (%ld) -- %s\n", errorDomainStr, errorCode, errorStringStr);
+ CFReleaseSafe(tempDictionary);
+}
+
+static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
+{
+ CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ SecOTRSAppendSerialization(*thisOne, serialized);
+ CFReleaseNull(*thisOne);
+ *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);
+
+ CFReleaseSafe(serialized);
+}
+
+
+
+#define sendMessagesCount(n) ((n) * 5)
+static void sendMessages(int howMany, SecOTRSessionRef *bobSession, SecOTRSessionRef *aliceSession, bool serialize)
+{
+ for(int count = howMany; count > 0; --count) {
+ const char* aliceToBob = "aliceToBob";
+ CFDataRef rawAliceToBob = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)aliceToBob, (CFIndex) strlen(aliceToBob));
+ CFMutableDataRef protectedAliceToBob = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ CFMutableDataRef bobDecode = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSSignAndProtectMessage(*aliceSession, rawAliceToBob, protectedAliceToBob), "encode message");
+ ok_status(SecOTRSVerifyAndExposeMessage(*bobSession, protectedAliceToBob, bobDecode), "Decode message");
+
+
+ if (serialize) {
+ serializeAndDeserialize(bobSession);
+ serializeAndDeserialize(aliceSession);
+ }
+
+ ok(CFDataGetLength(rawAliceToBob) == CFDataGetLength(bobDecode)
+ && 0 == memcmp(CFDataGetBytePtr(rawAliceToBob), CFDataGetBytePtr(bobDecode), (size_t)CFDataGetLength(rawAliceToBob)), "Didn't match!");
+
+ CFReleaseNull(rawAliceToBob);
+ CFReleaseNull(protectedAliceToBob);
+ CFReleaseNull(bobDecode);
+
+ CFStringRef stateString = CFCopyDescription(*bobSession);
+ ok(stateString, "getting state from bob");
+ CFReleaseNull(stateString);
+
+ stateString = CFCopyDescription(*aliceSession);
+ ok(stateString, "getting state from alice");
+ CFReleaseNull(stateString);
+ }
+}
+
+#define kNegotiateTestCount (14 + sendMessagesCount(5) \
++ 60 + (69 * sendMessagesCount(1)))
+static void negotiate(SecOTRSessionRef* aliceSession, SecOTRSessionRef* bobSession, bool serializeNegotiating, bool serializeMessaging, bool textMode, bool compact)
+{
+ const int kEmptyMessageSize = textMode ? 6 : 0;
+
+ // Step 1: Create a start packet for each side of the transaction
+ CFMutableDataRef bobStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSAppendStartPacket(*bobSession, bobStartPacket), "Bob start packet");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFMutableDataRef aliceStartPacket = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSAppendStartPacket(*aliceSession, aliceStartPacket), "Alice start packet");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ // Step 2: Exchange the start packets, forcing the DH commit messages to collide
+ CFMutableDataRef aliceDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobStartPacket, aliceDHKeyResponse),
+ "Bob DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobStartPacket);
+
+ CFMutableDataRef bobDHKeyResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceStartPacket, bobDHKeyResponse),
+ "Alice DH packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceStartPacket);
+
+ // Step 3: With one "real" DH key message, and one replayed DH commit message, try to get a "reveal sig" out of one side
+
+ CFMutableDataRef bobRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceDHKeyResponse, bobRevealSigResponse),
+ "Alice DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceDHKeyResponse);
+
+ CFMutableDataRef aliceRevealSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobDHKeyResponse, aliceRevealSigResponse),
+ "Bob DH Key packet failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobDHKeyResponse);
+
+ // Step 4: Having gotten the reveal signature, now work for the signature
+
+ CFMutableDataRef aliceSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobRevealSigResponse, aliceSigResponse),
+ "Bob Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ CFReleaseNull(bobRevealSigResponse);
+
+ CFMutableDataRef bobSigResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceRevealSigResponse, bobSigResponse),
+ "Alice Reveal sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFReleaseNull(aliceRevealSigResponse);
+
+ // Step 5: All the messages have been sent, now deal with any replays from the collision handling
+ CFMutableDataRef bobFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*bobSession, aliceSigResponse, bobFinalResponse),
+ "Alice Final Sig failed");
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(bobSession);
+
+ CFMutableDataRef aliceFinalResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
+
+ ok_status(SecOTRSProcessPacket(*aliceSession, bobSigResponse, aliceFinalResponse),
+ "Bob Final Sig failed");
+
+ is(kEmptyMessageSize, CFDataGetLength(aliceFinalResponse), "Alice had nothing left to say");
+ CFReleaseNull(aliceFinalResponse);
+ CFReleaseNull(bobSigResponse);
+
+ if (serializeNegotiating)
+ serializeAndDeserialize(aliceSession);
+
+ is(kEmptyMessageSize, CFDataGetLength(bobFinalResponse), "Bob had nothing left to say");
+ ok(SecOTRSGetIsReadyForMessages(*bobSession), "Bob is ready");
+ ok(SecOTRSGetIsReadyForMessages(*aliceSession), "Alice is ready");
+
+ CFReleaseNull(aliceSigResponse);
+ CFReleaseNull(bobFinalResponse);
+
+ sendMessages(5, bobSession, aliceSession, serializeMessaging);
+
+ //////
+ //both sessions are kicked to roll
+ //////
+ SecOTRSKickTimeToRoll(*aliceSession);
+ SecOTRSKickTimeToRoll(*bobSession);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ SecOTRSKickTimeToRoll(*bobSession);
+ SecOTRSKickTimeToRoll(*aliceSession);
+
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ //now we make sure keys do not roll for 10 iterations
+ int aliceKeyID = SecOTRSGetKeyID(*aliceSession);
+ int bobKeyID = SecOTRSGetKeyID(*bobSession);
+
+ for(int i = 0; i< 10; i++){
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+ ok(SecOTRSGetKeyID(*aliceSession) == aliceKeyID);
+ ok(SecOTRSGetKeyID(*bobSession) == bobKeyID);
+ }
+ //////
+ //kicking sending side
+ ///////
+
+ SecOTRSKickTimeToRoll(*aliceSession);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ SecOTRSKickTimeToRoll(*bobSession);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ //now we make sure keys do not roll for 10 iterations
+ aliceKeyID = SecOTRSGetKeyID(*aliceSession);
+ bobKeyID = SecOTRSGetKeyID(*bobSession);
+
+ for(int i = 0; i< 10; i++){
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+ ok(SecOTRSGetKeyID(*aliceSession) == aliceKeyID);
+ ok(SecOTRSGetKeyID(*bobSession) == bobKeyID);
+ }
+ //////
+ //kicking receiving side
+ //////
+ SecOTRSKickTimeToRoll(*bobSession);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ SecOTRSKickTimeToRoll(*aliceSession);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+
+ aliceKeyID = SecOTRSGetKeyID(*aliceSession);
+ bobKeyID = SecOTRSGetKeyID(*bobSession);
+
+ for(int i = 0; i< 10; i++){
+ sendMessages(1, aliceSession, bobSession, serializeMessaging);
+ sendMessages(1, bobSession, aliceSession, serializeMessaging);
+
+ ok(SecOTRSGetKeyID(*aliceSession) == aliceKeyID);
+ ok(SecOTRSGetKeyID(*bobSession) == bobKeyID);
+ }
+
+}
+
+
+#define kTestTestCount (11 + kNegotiateTestCount * 6)
+
+static void tests()
+{
+ CFErrorRef testError = NULL;
+ SecOTRFullIdentityRef aliceID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ testError = NULL;
+ SecOTRFullIdentityRef bobID = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ testError = NULL;
+
+ ok(aliceID, "create alice ID");
+ ok(bobID, "create bob ID");
+
+ SecOTRPublicIdentityRef alicePublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, aliceID, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+ SecOTRPublicIdentityRef bobPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, bobID, &testError);
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+
+ ok(alicePublicID, "extract alice public");
+ ok(bobPublicID, "extract bob public");
+
+ SecOTRSessionRef aliceSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRSendTextMessages | kSecOTRSlowRoll);
+ SecOTRSessionRef bobSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRSendTextMessages | kSecOTRSlowRoll);
+
+ ok(aliceSession, "create alice session");
+ ok(bobSession, "create bob session");
+
+ SecOTRSessionRef aliceCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat | kSecOTRSlowRoll);
+ SecOTRSessionRef bobCompactSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat | kSecOTRSlowRoll);
+
+ ok(aliceCompactSession, "create alice compact session");
+ ok(bobCompactSession, "create bob compact session");
+
+ SecOTRSessionRef aliceCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, aliceID, bobPublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages | kSecOTRSlowRoll);
+ SecOTRSessionRef bobCompactHashesSession = SecOTRSessionCreateFromIDAndFlags(kCFAllocatorDefault, bobID, alicePublicID, kSecOTRUseAppleCustomMessageFormat|kSecOTRIncludeHashesInMessages | kSecOTRSlowRoll);
+
+ ok(aliceCompactHashesSession, "create alice compact session with hashes");
+ ok(bobCompactHashesSession, "create bob compact session with hashes");
+
+ // Release the IDs, sessions shouldn't need us to retain them for them.
+ CFReleaseNull(aliceID);
+ CFReleaseNull(bobID);
+
+ CFReleaseNull(alicePublicID);
+ CFReleaseNull(bobPublicID);
+
+ negotiate(&aliceSession, &bobSession, true, true, true, false);
+
+ negotiate(&aliceSession, &bobSession, true, false, true, false);
+
+ negotiate(&aliceCompactSession, &bobCompactSession, true, true, false, true);
+
+ negotiate(&aliceCompactSession, &bobCompactSession, true, false, false, true);
+
+ negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, true, false, true);
+
+ negotiate(&aliceCompactHashesSession, &bobCompactHashesSession, true, false, false, true);
+
+ /* cleanup keychain */
+ ok(SecOTRFIPurgeAllFromKeychain(&testError),"cleanup keychain");
+ SecMPLogError(testError);
+ CFReleaseNull(testError);
+
+ CFReleaseNull(aliceSession);
+ CFReleaseNull(bobSession);
+
+ CFReleaseNull(aliceCompactSession);
+ CFReleaseNull(bobCompactSession);
+
+ CFReleaseNull(aliceCompactHashesSession);
+ CFReleaseNull(bobCompactHashesSession);
+}
+
+int otr_60_slowroll(int argc, char *const *argv)
+{
+ plan_tests(kTestTestCount);
+
+ tests();
+
+ return 0;
+}
#include <Security/SecOTRMath.h>
#include <Security/SecOTRDHKey.h>
+#include <utilities/SecCFWrappers.h>
int otr_otrdh(int argc, char *const * argv)
{
- plan_tests(4);
+ plan_tests(7);
SecOTRFullDHKeyRef aliceFull = SecOTRFullDHKCreate(kCFAllocatorDefault);
SecOTRPublicDHKeyRef alicePublic = SecOTRPublicDHKCreateFromFullKey(kCFAllocatorDefault, aliceFull);
SecOTRFullDHKeyRef bobFull = SecOTRFullDHKCreate(kCFAllocatorDefault);
SecOTRPublicDHKeyRef bobPublic = SecOTRPublicDHKCreateFromFullKey(kCFAllocatorDefault, bobFull);
-
+
+ SecOTRPublicDHKeyRef aliceCompactDeserialized = NULL;
+ SecOTRPublicDHKeyRef aliceDeserialized = NULL;
+
+ CFMutableDataRef aliceCompactSerialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ SecFDHKAppendCompactPublicSerialization(aliceFull, aliceCompactSerialized);
+ size_t aliceCompactLength = CFDataGetLength(aliceCompactSerialized);
+ const uint8_t *aliceCompactSerializationStart = CFDataGetMutableBytePtr(aliceCompactSerialized);
+
+ aliceCompactDeserialized = SecOTRPublicDHKCreateFromCompactSerialization(kCFAllocatorDefault, &aliceCompactSerializationStart, &aliceCompactLength);
+ ok(CFEqualSafe(aliceCompactDeserialized, alicePublic), "Compact serialized compare to created");
+
+
+ CFMutableDataRef aliceSerialized = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ SecFDHKAppendPublicSerialization(aliceFull, aliceSerialized);
+ size_t aliceLength = CFDataGetLength(aliceSerialized);
+ const uint8_t *aliceSerializationStart = CFDataGetMutableBytePtr(aliceSerialized);
+
+ aliceDeserialized = SecOTRPublicDHKCreateFromSerialization(kCFAllocatorDefault, &aliceSerializationStart, &aliceLength);
+ ok(CFEqualSafe(aliceDeserialized, alicePublic), "Serialized compare to created");
+
+ ok(CFEqualSafe(aliceCompactDeserialized, aliceDeserialized), "Serialized compared to compact serailized");
+
uint8_t aliceMessageKeys[2][kOTRMessageKeyBytes];
uint8_t aliceMacKeys[2][kOTRMessageMacKeyBytes];
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;
}
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); } }
is_status(trustResult, kSecTrustResultUnspecified,
"trust is kSecTrustResultUnspecified");
-
+
CFDictionaryRef info = SecTrustCopyInfo(trust);
CFBooleanRef ev = (CFBooleanRef)CFDictionaryGetValue(info,
kSecTrustInfoExtendedValidationKey);
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;
}
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;
}
"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;
}
CFMutableDictionaryRef dict;
};
-static CFStringRef SecAccessControlCopyDescription(CFTypeRef cf) {
+static CFStringRef SecAccessControlCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecAccessControlRef access_control = (SecAccessControlRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecAccessControlRef: %p>"), access_control);
}
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 */
};
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));
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;
//
// OTR
//
+_SecOTRSKickTimeToRoll
+_SecOTRSGetTheirKeyID
+_SecOTRSGetKeyID
+_SecFDHKAppendCompactPublicSerialization
+_SecFDHKAppendPublicSerialization
+_SecOTRCopyIncomingBytes
+_SecOTRPublicDHKCreateFromSerialization
+_SecOTRPublicDHKCreateFromCompactSerialization
_SecOTRDHKGenerateOTRKeys
_SecOTRFullDHKCreate
_SecOTRPublicDHKCreateFromFullKey
CFGiblisWithHashFor(SecIdentity)
/* Static functions. */
-static CFStringRef SecIdentityCopyDescription(CFTypeRef cf) {
+static CFStringRef SecIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecIdentityRef identity = (SecIdentityRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("<SecIdentityRef: %p>"), identity);
#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;
return size;
}
+static CFStringRef CCNCopyAsHex(size_t n, cc_unit *value){
+ size_t bytes = ccn_write_uint_size(n, value);
+ uint8_t byte_array [bytes];
+ ccn_write_uint(n, value, bytes, byte_array);
+
+ __block CFStringRef description = NULL;
-static CFStringRef SecOTRFullDHKeyCopyDescription(CFTypeRef cf)
+ BufferPerformWithHexString(byte_array, sizeof(byte_array), ^(CFStringRef dataString) {
+ description = CFRetainSafe(dataString);
+ });
+ return description;
+}
+static void withXandY(ccec_pub_ctx_t pubKey, void (^action)(CFStringRef x, CFStringRef y)){
+ CFStringRef xString = NULL;
+ CFStringRef yString = NULL;
+ xString = CCNCopyAsHex(ccec_ctx_n(pubKey), ccec_ctx_x(pubKey));
+ yString = CCNCopyAsHex(ccec_ctx_n(pubKey), ccec_ctx_y(pubKey));
+
+ action(xString, yString);
+ CFReleaseNull(xString);
+ CFReleaseNull(yString);
+}
+static CFStringRef SecOTRFullDHKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
{
- SecOTRFullDHKeyRef session = (SecOTRFullDHKeyRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRFullDHKeyRef: %p>"), session);
+ SecOTRFullDHKeyRef fullDHKey = (SecOTRFullDHKeyRef)cf;
+ __block CFStringRef description = NULL;
+
+ withXandY(fullDHKey->_key, ^(CFStringRef x, CFStringRef y) {
+ BufferPerformWithHexString(fullDHKey->keyHash, sizeof(fullDHKey->keyHash), ^(CFStringRef dataString) {
+ description = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRFullDHKeyRef@%p: x: %@ y: %@ [%@]>"), fullDHKey, x, y, dataString);
+ });
+ });
+
+ return description;
}
static Boolean SecOTRFullDHKeyCompare(CFTypeRef leftCF, CFTypeRef rightCF)
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);
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:
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)
ccec_pub_ctx_decl(ccn_sizeof(kECKeySize), _key);
uint8_t keyHash[CCSHA1_OUTPUT_SIZE];
-
};
CFGiblisWithCompareFor(SecOTRPublicDHKey);
-static CFStringRef SecOTRPublicDHKeyCopyDescription(CFTypeRef cf) {
- SecOTRPublicDHKeyRef session = (SecOTRPublicDHKeyRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicDHKeyRef: %p>"), session);
+static CFStringRef SecOTRPublicDHKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
+ SecOTRPublicDHKeyRef publicDHKey = (SecOTRPublicDHKeyRef)cf;
+
+ __block CFStringRef description = NULL;
+ withXandY(publicDHKey->_key, ^(CFStringRef x, CFStringRef y) {
+ BufferPerformWithHexString(publicDHKey->keyHash, sizeof(publicDHKey->keyHash), ^(CFStringRef dataString) {
+ description = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicDHKeyRef@%p: x: %@ y: %@ [%@]>"), publicDHKey, x, y, dataString);
+ });
+
+ });
+ return description;
}
static Boolean SecOTRPublicDHKeyCompare(CFTypeRef leftCF, CFTypeRef rightCF)
(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);
*size -= publicKeySize;
*bytes += publicKeySize;
- ccdigest(ccsha1_di(), *size, *bytes, newPDHK->keyHash);
+ SecOTRPDHKUpdateHash(newPDHK);
return newPDHK;
fail:
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);
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFData.h>
#include <corecrypto/ccn.h>
+#include <corecrypto/ccsha1.h>
__BEGIN_DECLS
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);
CFGiblisFor(SecOTRFullIdentity);
-static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyDescription(CFTypeRef cf) {
+static CF_RETURNS_RETAINED CFStringRef SecOTRFullIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecOTRFullIdentityRef requestor = (SecOTRFullIdentityRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
requestor,
__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);
//
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:
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);
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;
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);
{
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);
{
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;
}
{
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;
}
{
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;
}
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;
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;
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;
kEvenCompactDataMessage = 0x20,
kOddCompactDataMessage = 0x21,
+
+ kEvenCompactDataMessageWithHashes = 0x30,
+ kOddCompactDataMessageWithHashes = 0x31,
kInvalidMessage = 0xFF
} OTRMessageType;
static bool sAdvertiseHashes = false;
-static CF_RETURNS_RETAINED CFStringRef SecOTRPublicIdentityCopyDescription(CFTypeRef cf) {
+static CF_RETURNS_RETAINED CFStringRef SecOTRPublicIdentityCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecOTRPublicIdentityRef requestor = (SecOTRPublicIdentityRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicIdentity: %p %02x%02x%02x%02x%02x%02x%02x%02x>"),
requestor,
#include <stdint.h>
#include <sys/types.h>
#include "utilities/comparison.h"
+#include <CoreFoundation/CFDate.h>
#include "SecOTRSession.h"
CFGiblisFor(SecOTRSession);
+static uint64_t setup_defaults_settings(){
+
+ Boolean keyExistsAndHasValue = false;
+ uint64_t seconds;
+ seconds = CFPreferencesGetAppIntegerValue(CFSTR("OTR"), CFSTR("com.apple.security"), &keyExistsAndHasValue);
+ secdebug("OTR", "Retrieving OTR default settings was success? %d value retrieved: %llu", keyExistsAndHasValue, seconds);
+ return keyExistsAndHasValue ? seconds : (kSecondsPerMinute * 15); //15 minutes by default
+}
+
+static uint64_t SecOTRGetDefaultsWriteSeconds(void) {
+ static dispatch_once_t sdOnceToken;
+ static uint64_t seconds;
+
+ dispatch_once(&sdOnceToken, ^{
+ seconds = setup_defaults_settings();
+ });
+
+ return seconds;
+}
+
+static void SecOTRSEnableTimeToRoll(SecOTRSessionRef session){
+ CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+ CFAbsoluteTime nextTimeToRoll = now + session->_stallSeconds;
+
+ if(session->_timeToRoll == 0 || session->_timeToRoll > nextTimeToRoll){
+ session->_timeToRoll = nextTimeToRoll;
+ }
+}
+
+static void SecOTRSExpireCachedKeysForFullKey(SecOTRSessionRef session, SecOTRFullDHKeyRef myKey)
+{
+ for(int i = 0; i < kOTRKeyCacheSize; ++i)
+ {
+ if (0 == constant_memcmp(session->_keyCache[i]._fullKeyHash, SecFDHKGetHash(myKey), CCSHA1_OUTPUT_SIZE)) {
+ CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
+ bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
+ }
+ }
+}
+
+static void SecOTRSExpireCachedKeysForPublicKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef theirKey)
+{
+ for(int i = 0; i < kOTRKeyCacheSize; ++i)
+ {
+ if (0 == constant_memcmp(session->_keyCache[i]._publicKeyHash, SecPDHKGetHash(theirKey), CCSHA1_OUTPUT_SIZE)) {
+ CFDataAppendBytes(session->_macKeysToExpose, session->_keyCache[i]._receiveMacKey, sizeof(session->_keyCache[i]._receiveMacKey));
+
+ bzero(&session->_keyCache[i], sizeof(session->_keyCache[i]));
+ }
+ }
+}
+
+static void SecOTRGenerateNewProposedKey(SecOTRSessionRef session)
+{
+ SecOTRSExpireCachedKeysForFullKey(session, session->_myKey);
+
+ // Swap the keys so we know the current key.
+ {
+ SecOTRFullDHKeyRef oldKey = session->_myKey;
+ session->_myKey = session->_myNextKey;
+ session->_myNextKey = oldKey;
+ }
+
+ // Derive a new next key by regenerating over the old key.
+ SecFDHKNewKey(session->_myNextKey);
+
+ session->_keyID += 1;
+}
+
+
+static void SecOTRSHandleProposalAcknowledge(SecOTRSessionRef session){
+ if(session->_missedAck){
+ SecOTRGenerateNewProposedKey(session);
+ session->_missedAck = false;
+ }
+ else{
+ session->_receivedAck = true;
+ SecOTRSEnableTimeToRoll(session);
+ }
+}
+
+static void SecOTRSRollIfTime(SecOTRSessionRef session){
+
+ CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+ CFAbsoluteTime longestTimeToRoll = now + session->_stallSeconds;
+
+ //in case time to roll becomes too large we're going to roll now!
+ if(session->_timeToRoll < now || session->_timeToRoll > longestTimeToRoll){
+ SOSOTRSRoll(session);
+ session->_timeToRoll = 0;
+ }
+}
+
+
static OTRMessageType SecOTRSGetMessageType(CFDataRef message)
{
OTRMessageType type = kInvalidMessage;
switch (firstByte) {
case kOddCompactDataMessage:
case kEvenCompactDataMessage:
+ case kOddCompactDataMessageWithHashes:
+ case kEvenCompactDataMessageWithHashes:
type = firstByte;
break;
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";
}
}
}
}
-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",
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) {
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);
{
SecOTRSessionRef newID = CFTypeAllocate(SecOTRSession, struct _SecOTRSession, allocator);
+ (void)SecOTRGetDefaultsWriteSeconds();
newID->_queue = dispatch_queue_create("OTRSession", DISPATCH_QUEUE_SERIAL);
newID->_me = myID;
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);
SecOTRPublicIdentityRef theirID,
uint32_t flags)
{
+
+ uint64_t seconds = SecOTRGetDefaultsWriteSeconds();
+
SecOTRSessionRef newID = SecOTRSessionCreateFromID(allocator, myID, theirID);
if (flags & kSecOTRSendTextMessages) {
newID->_textOutput = true;
if (flags & kSecOTRUseAppleCustomMessageFormat) {
newID->_compactAppleMessages = true;
}
+ if(flags & kSecOTRIncludeHashesInMessages)
+ {
+ newID->_includeHashes = true;
+ }
+ if(flags & kSecOTRSlowRoll)
+ {
+ newID->_stallSeconds = seconds;
+ }
+
return newID;
}
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,
{
SecOTRCacheElement* emptyKeys = NULL;
SecOTRCacheElement* cachedKeys = NULL;
-
+#if DEBUG
+ int emptyPosition = kOTRKeyCacheSize;
+#endif
+
if ((NULL == myKey) || (NULL == theirKey)) {
if (messageKey)
*messageKey = NULL;
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.
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)
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;
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);
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);
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);
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;
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);
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);
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);
+
}
});
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)
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);
case kDataMessage:
case kEvenCompactDataMessage:
case kOddCompactDataMessage:
+ case kEvenCompactDataMessageWithHashes:
+ case kOddCompactDataMessageWithHashes:
kind = kOTRDataPacket;
break;
case kDHMessage:
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);
AppendByte(destinationMessage, 0); // Flags, all zero
AppendLong(destinationMessage, session->_keyID);
- AppendLong(destinationMessage, session->_theirKeyID);
+ AppendLong(destinationMessage, theirKeyID);
SecFDHKAppendPublicSerialization(session->_myNextKey, destinationMessage);
AppendLongLong(destinationMessage, ++*counter);
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);
(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];
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) {
return result;
}
+void SecOTRSKickTimeToRoll(SecOTRSessionRef session){
+ session->_timeToRoll = CFAbsoluteTimeGetCurrent();
+}
+
static void SecOTRAcceptNewRemoteKey(SecOTRSessionRef session, SecOTRPublicDHKeyRef newKey)
{
if (session->_theirPreviousKey) {
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,
}
if (myID == (session->_keyID + 1)) {
- SecOTRGenerateNewProposedKey(session);
+ SecOTRSHandleProposalAcknowledge(session);
}
- SecOTRSPrecalculateKeysInternal(session);
+ SecOTRSRollIfTime(session);
+
+ SecOTRSPrecalculateNextKeysInternal(session);
fail:
CFReleaseNull(newKey);
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);
}
if (!useCurrentKey) {
- SecOTRGenerateNewProposedKey(session);
+ SecOTRSHandleProposalAcknowledge(session);
}
+ SecOTRSRollIfTime(session);
- SecOTRSPrecalculateKeysInternal(session);
+ SecOTRSPrecalculateNextKeysInternal(session);
fail:
CFReleaseNull(theirProposal);
{
__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;
}
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;
// 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,
};
/*!
{
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;
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFRuntime.h>
+#include <CoreFoundation/CFDate.h>
#include <Security/SecOTR.h>
#include <corecrypto/ccn.h>
#include <Security/SecOTRMath.h>
#include <Security/SecOTRDHKey.h>
+#include <Security/SecOTRSession.h>
__BEGIN_DECLS
typedef struct _SecOTRCacheElement SecOTRCacheElement;
#define kOTRKeyCacheSize 4
+#define kSecondsPerMinute 60
struct _SecOTRSession {
CFRuntimeBase _base;
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
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));
static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust);
/* Static functions. */
-static CFStringRef SecTrustCopyDescription(CFTypeRef cf) {
+static CFStringRef SecTrustCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecTrustRef trust = (SecTrustRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("<SecTrustRef: %p>"), trust);
bool _dirty; /* we've changed _trustDict since creation */
};
-static CFStringRef SecTrustSettingsCopyDescription(CFTypeRef cf) {
+static CFStringRef SecTrustSettingsCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecTrustSettingsRef ts = (SecTrustSettingsRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("<SecTrustSettings: %p>"), ts);
#include <xpc/private.h>
#include <xpc/xpc.h>
-#if TARGET_OS_MAC
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
#include <Security/SecTaskPriv.h>
#endif
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;
CD0F8AF61899BF46003E0C52 /* SOSTransportCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = CD0F8AF51899BF46003E0C52 /* SOSTransportCircle.c */; };
CD0F8AF81899BF57003E0C52 /* SOSTransportMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0F8AF71899BF57003E0C52 /* SOSTransportMessage.h */; };
CD0F8AFA1899BF63003E0C52 /* SOSTransportCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0F8AF91899BF63003E0C52 /* SOSTransportCircle.h */; };
+ CD303E301A32629700737AD7 /* otr-50-roll.c in Sources */ = {isa = PBXBuildFile; fileRef = CD303E2F1A32629700737AD7 /* otr-50-roll.c */; };
+ CD303E321A32650C00737AD7 /* otr-60-slowroll.c in Sources */ = {isa = PBXBuildFile; fileRef = CD303E311A32650C00737AD7 /* otr-60-slowroll.c */; };
CD32776B18F8AEFD006B5280 /* SOSPeerCoder.c in Sources */ = {isa = PBXBuildFile; fileRef = CD32776A18F8AEFD006B5280 /* SOSPeerCoder.c */; };
CD32776D18F8B06E006B5280 /* SOSPeerCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = CD32776C18F8B06E006B5280 /* SOSPeerCoder.h */; };
CD32776F18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c in Sources */ = {isa = PBXBuildFile; fileRef = CD32776E18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c */; };
CD32777918F8B3B4006B5280 /* SOSTransportMessageKVS.h in Headers */ = {isa = PBXBuildFile; fileRef = CD32777818F8B3B4006B5280 /* SOSTransportMessageKVS.h */; };
CD3FD10716C3064B00A83BB6 /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = E7B01B8816572579000485F1 /* SecuritydXPC.c */; };
CD86DE4E18BD554D00C90CDF /* SOSTransport.c in Sources */ = {isa = PBXBuildFile; fileRef = CD86DE4D18BD554D00C90CDF /* SOSTransport.c */; };
+ CD8E09011A2E918900A2503A /* otr-40-edgecases.c in Sources */ = {isa = PBXBuildFile; fileRef = CD8E09001A2E918900A2503A /* otr-40-edgecases.c */; };
CD95312B19228D8D005A76B2 /* SOSTransportTestTransports.c in Sources */ = {isa = PBXBuildFile; fileRef = CDAD4E9818EC8424007D4BC2 /* SOSTransportTestTransports.c */; };
CD95312C19228D92005A76B2 /* SOSTransportTestTransports.h in Headers */ = {isa = PBXBuildFile; fileRef = CDAD4E9A18EC8447007D4BC2 /* SOSTransportTestTransports.h */; };
CD95312D19228D96005A76B2 /* SOSAccountTesting.h in Headers */ = {isa = PBXBuildFile; fileRef = E7A10FAA1771245D00C4602F /* SOSAccountTesting.h */; };
4A5CCA4F15ACEFA500702357 /* libSecOtrOSX.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecOtrOSX.a; sourceTree = BUILT_PRODUCTS_DIR; };
4A824B03158FF07000F932C0 /* libSecurityRegressions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecurityRegressions.a; sourceTree = BUILT_PRODUCTS_DIR; };
4A971682158FDEB800D439B7 /* SecOTR.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTR.h; sourceTree = "<group>"; };
- 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOTRDHKey.c; path = ../../../SecOTRDHKey.c; sourceTree = "<group>"; };
+ 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRDHKey.c; sourceTree = "<group>"; };
4A971684158FDEB800D439B7 /* SecOTRDHKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTRDHKey.h; sourceTree = "<group>"; };
4A971685158FDEB800D439B7 /* SecOTRErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOTRErrors.h; sourceTree = "<group>"; };
4A971686158FDEB800D439B7 /* SecOTRFullIdentity.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRFullIdentity.c; sourceTree = "<group>"; };
CD0F8AF51899BF46003E0C52 /* SOSTransportCircle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportCircle.c; sourceTree = "<group>"; };
CD0F8AF71899BF57003E0C52 /* SOSTransportMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessage.h; sourceTree = "<group>"; };
CD0F8AF91899BF63003E0C52 /* SOSTransportCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircle.h; sourceTree = "<group>"; };
+ CD303E2F1A32629700737AD7 /* otr-50-roll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-50-roll.c"; sourceTree = "<group>"; };
+ CD303E311A32650C00737AD7 /* otr-60-slowroll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-60-slowroll.c"; sourceTree = "<group>"; };
CD32776A18F8AEFD006B5280 /* SOSPeerCoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerCoder.c; sourceTree = "<group>"; };
CD32776C18F8B06E006B5280 /* SOSPeerCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerCoder.h; sourceTree = "<group>"; };
CD32776E18F8B2FC006B5280 /* SOSTransportKeyParameterKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportKeyParameterKVS.c; sourceTree = "<group>"; };
CD32777618F8B39B006B5280 /* SOSTransportMessageKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportMessageKVS.c; sourceTree = "<group>"; };
CD32777818F8B3B4006B5280 /* SOSTransportMessageKVS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessageKVS.h; sourceTree = "<group>"; };
CD86DE4D18BD554D00C90CDF /* SOSTransport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransport.c; sourceTree = "<group>"; };
+ CD8E09001A2E918900A2503A /* otr-40-edgecases.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "otr-40-edgecases.c"; sourceTree = "<group>"; };
CDA7729616B899F10069434D /* si-69-keydesc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-69-keydesc.c"; sourceTree = "<group>"; };
CDAD4E9818EC8424007D4BC2 /* SOSTransportTestTransports.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportTestTransports.c; sourceTree = "<group>"; };
CDAD4E9A18EC8447007D4BC2 /* SOSTransportTestTransports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportTestTransports.h; sourceTree = "<group>"; };
4A824AFA158FF05900F932C0 /* Regressions */,
52D0F026169CA72800F07D79 /* SecOnOSX.h */,
4A971682158FDEB800D439B7 /* SecOTR.h */,
+ 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */,
4A971684158FDEB800D439B7 /* SecOTRDHKey.h */,
4A971685158FDEB800D439B7 /* SecOTRErrors.h */,
4A971686158FDEB800D439B7 /* SecOTRFullIdentity.c */,
4CC92A1315A3ABD400C6D578 /* otr-30-negotiation.c */,
4CC92A1415A3ABD400C6D578 /* otr-otrdh.c */,
4CC92A1515A3ABD400C6D578 /* otr-packetdata.c */,
+ CD8E09001A2E918900A2503A /* otr-40-edgecases.c */,
+ CD303E2F1A32629700737AD7 /* otr-50-roll.c */,
+ CD303E311A32650C00737AD7 /* otr-60-slowroll.c */,
);
name = otr;
path = Regressions/otr;
4CC92A4F15A3ABD400C6D578 /* si-67-sectrust-blacklist */ = {
isa = PBXGroup;
children = (
- 4A971683158FDEB800D439B7 /* SecOTRDHKey.c */,
4CC92A5015A3ABD400C6D578 /* Global Trustee.cer.h */,
4CC92A5115A3ABD400C6D578 /* UTN-USERFirst-Hardware.cer.h */,
4CC92A5215A3ABD400C6D578 /* addons.mozilla.org.cer.h */,
4CC92A6615A3ABD400C6D578 /* si-05-add.c in Sources */,
4CC92A6715A3ABD400C6D578 /* si-10-find-internet.c in Sources */,
3A70988218CDF648009FD2CC /* si_77_SecAccessControl.c in Sources */,
+ CD8E09011A2E918900A2503A /* otr-40-edgecases.c in Sources */,
4CC92A6815A3ABD400C6D578 /* si-11-update-data.c in Sources */,
4CC92A6915A3ABD400C6D578 /* si-14-dateparse.c in Sources */,
4CC92A6A15A3ABD400C6D578 /* si-15-certificate.c in Sources */,
4CC92A7615A3ABD400C6D578 /* si-24-sectrust-nist.c in Sources */,
4CC92A7715A3ABD400C6D578 /* si-24-sectrust-otatasking.c in Sources */,
4CC92A7815A3ABD400C6D578 /* si-24-sectrust-shoebox.c in Sources */,
+ CD303E321A32650C00737AD7 /* otr-60-slowroll.c in Sources */,
4CC92A7915A3ABD400C6D578 /* si-25-sectrust-ipsec-eap.c in Sources */,
4CC92A7A15A3ABD400C6D578 /* si-26-applicationsigning.c in Sources */,
4CC92A7B15A3ABD400C6D578 /* si-27-sectrust-exceptions.c in Sources */,
4CC92A8815A3ABD400C6D578 /* si-50-secrandom.c in Sources */,
4CC92A8915A3ABD400C6D578 /* si-60-cms.c in Sources */,
5DE4A7BD17441CCD0036339E /* si-71-mobile-store-policy.c in Sources */,
+ CD303E301A32629700737AD7 /* otr-50-roll.c in Sources */,
CDD565A2173193AC00B6B074 /* si-73-secpasswordgenerate.c in Sources */,
4CC92A8A15A3ABD400C6D578 /* si-61-pkcs12.c in Sources */,
4CC92A8B15A3ABD400C6D578 /* si-62-csr.c in Sources */,
CFGiblisFor(SecOTAPKI)
-static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyDescription(CFTypeRef cf)
+static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
{
SecOTAPKIRef otapkiRef = (SecOTAPKIRef)cf;
return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef->_assetVersion);
#include <AssertMacros.h>
#include <stdint.h>
-static int kTestTestCount = 1286;
+
+
+static int kTestTestCount = 1866;
__unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) {
}, 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;
#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);
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);
}
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);
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);
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) {
(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);
#include "utilities/SecCFRelease.h"
#include "utilities/array_size.h"
+#include <utilities/SecCFWrappers.h>
#include <CoreFoundation/CoreFoundation.h>
#include <corecrypto/ccder.h>
+#include <dispatch/dispatch.h>
#include "utilities_regressions.h"
}
}
+static CFCalendarRef sZuluCalendar = NULL;
+
+static CFCalendarRef SecCFCalendarGetZulu() {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
+ CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
+ CFCalendarSetTimeZone(sZuluCalendar, tz);
+ CFReleaseSafe(tz);
+ });
+ return sZuluCalendar;
+}
+
+static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *month, int *day, int *hour, int *minute, int *second, CFErrorRef *error) {
+ // TODO: Remove CFCalendarDecomposeAbsoluteTime dependancy because CFTimeZoneCreateWithTimeIntervalFromGMT is expensive and requires filesystem access to timezone files when we are only doing zulu time anyway
+ if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), at, "yMdHms", year, month, day, hour, minute, second)) {
+ SecCFDERCreateError(-1000, CFSTR("Failed to encode date."), 0, error);
+ return false;
+ }
+ return true;
+}
+
+// &year, &month, &day, &hour, &minute, &second
+CFTimeInterval referenceTimeDate = 416957062.807688; // 2014 3 19 21 24 22
+#define expectedYear 2014
+#define expectedMonth 3
+#define expectedDay 19
+#define expectedHour 21
+#define expectedMinute 24
+#define expectedSecond 22
+
+static bool parallelizeZulu(bool useSharedZuluCalendar, void(^action)(CFCalendarRef zuluCalendar, bool *STOP)) {
+ // If useSharedZuluCalendar is false, NULL will be passed to zuluCalendar parameter of action
+ int ix;
+ static int kThreadLimit = 75000; // on a J86, this took 49963 threads to fail
+ static const int64_t kFailureTimeLimit = (NSEC_PER_SEC * 10); // Assume failure after 10s
+ dispatch_time_t failTime = dispatch_time(DISPATCH_TIME_NOW, kFailureTimeLimit);
+
+ // This is a __block variable since it can get modified (due the the <rdar://problem/16372688>)
+ __block CFCalendarRef zuluCalendar = useSharedZuluCalendar ? SecCFCalendarGetZulu() : NULL;
+ __block bool stop = false;
+
+ dispatch_group_t dgroup = dispatch_group_create();
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+
+ for (ix=0;ix<kThreadLimit && !stop;ix++) {
+ dispatch_group_enter(dgroup);
+ dispatch_async(queue, ^{
+ action(zuluCalendar, &stop);
+ dispatch_group_leave(dgroup);
+ });
+ }
+ dispatch_group_wait(dgroup, failTime);
+ dispatch_release(dgroup);
+ return !stop;
+}
+
+// We expect this to fail until this is fixed:
+// <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
+//
+static void testWithUnguardedZuluCalendar() {
+ const bool useSharedZuluCalendar = true;
+ __block bool success = true;
+ __block int successCount = 0;
+
+ success &= parallelizeZulu(useSharedZuluCalendar, ^(CFCalendarRef zuluCalendar, bool *STOP) {
+ int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+ bool matches = false;
+ if (!SecAbsoluteTimeGetGregorianDate(referenceTimeDate, &year, &month, &day, &hour, &minute, &second, NULL))
+ success = false;
+ matches = year==expectedYear && month==expectedMonth && day==expectedDay &&
+ hour==expectedHour && minute==expectedMinute && second==expectedSecond;
+// assert(matches); // enable to catch crash
+ if (matches)
+ successCount++;
+ else
+ *STOP = true;
+ });
+
+ todo("<rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe, not yet fixed");
+
+ TODO: {
+ ok(success,"unexpected result from SecAbsoluteTimeGetGregorianDate, failed, successes: %d", successCount);
+ }
+}
+
+static void testDoWithZulu() {
+ const bool useSharedZuluCalendar = false;
+ int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+ __block bool success = true;
+
+ success &= parallelizeZulu(useSharedZuluCalendar, ^(CFCalendarRef zuluCalendar, bool *STOP) {
+ SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
+ bool matches = false;
+ success &= CFCalendarDecomposeAbsoluteTime(zuluCalendar, referenceTimeDate, "yMdHms", &year, &month, &day, &hour, &minute, &second);
+ matches = year==expectedYear && month==expectedMonth && day==expectedDay &&
+ hour==expectedHour && minute==expectedMinute && second==expectedSecond;
+ *STOP = !matches;
+ });
+ });
+
+ ok(success,"unexpected result from CFCalendarDecomposeAbsoluteTime");
+}
+
#define kTestsPerTestCase 12
static void one_test(const struct test_case * thisCase, int testnumber)
{
{
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;
#include <utilities/SecCFWrappers.h>
//
-// Global sigleton Zulu time.
+// Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
+// <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
//
-CFGiblisGetSingleton(CFCalendarRef, SecCFCalendarGetZulu, zuluCalendar, ^{
- *zuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
- CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
- CFCalendarSetTimeZone(*zuluCalendar, tz);
- CFReleaseSafe(tz);
-})
+static dispatch_queue_t fqueue_cf;
+static CFCalendarRef sZuluCalendar = NULL;
+static dispatch_queue_t SecCFCalendarGetZuluQueue() {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ fqueue_cf = dispatch_queue_create("ZuluCalendar", DISPATCH_QUEUE_SERIAL);
+ });
+ return fqueue_cf;
+}
+
+static CFCalendarRef SecCFCalendarGetZulu() {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ sZuluCalendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
+ CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0.0);
+ CFCalendarSetTimeZone(sZuluCalendar, tz);
+ if (tz)
+ CFRelease(tz);
+ });
+ return sZuluCalendar;
+}
+void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar)) {
+ dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
+ action(SecCFCalendarGetZulu());
+ });
+}
void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8String, size_t utf8Length)) {
const char *cstr = CFStringGetCStringPtr(inStr, kCFStringEncodingUTF8);
// 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) { \
_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)
CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator)
+
__BEGIN_DECLS
//
// MARK: CFCalendar helpers
//
-CFCalendarRef SecCFCalendarGetZulu();
+void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar));
//
// MARK: CFAbsoluteTime helpers
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;
}
#pragma mark SecDbRef
static CFStringRef
-SecDbCopyDescription(CFTypeRef value)
+SecDbCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
{
SecDbRef db = (SecDbRef)value;
return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDb path:%@ connections: %@>"), db->db_path, db->connections);
}
static CFStringRef
-SecDbConnectionCopyDescription(CFTypeRef value)
+SecDbConnectionCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
{
SecDbConnectionRef dbconn = (SecDbConnectionRef)value;
return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDbConnection %s %s>"),
}
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) {
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;
}
#include <CoreFoundation/CFCalendar.h>
#include <math.h>
-#define NULL_TIME NAN
+#define NULL_TIME NAN
+#define IS_NULL_TIME(x) isnan(x)
/* Cumulative number of days in the year for months up to month i. */
static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
}
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,
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;
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,
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,
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;
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 };