Update Source To Security-59754.140.13

This commit is contained in:
Thomas A 2022-12-12 19:51:23 -08:00
parent a8ddb01e80
commit 9bba1c54a7
2373 changed files with 92262 additions and 64216 deletions

49
.swiftlint.yml Normal file
View File

@ -0,0 +1,49 @@
indentation: 4
disabled_rules:
- cyclomatic_complexity
- file_length
- function_body_length
- function_parameter_count
- identifier_name
- implicit_return
- large_tuple
- line_length
- todo
- type_body_length
- type_name
opt_in_rules:
- anyobject_protocol
- array_init
- attributes
#- closure_end_indentation ## commented as --format removes option
- closure_spacing
- conditional_returns_on_newline
- contains_over_range_nil_comparison
- empty_count
- empty_string
- explicit_init
- fatal_error_message
- first_where
- implicitly_unwrapped_optional
- joined_default_parameter
#- literal_expression_end_indentation ## commented as --format removes option
- legacy_random
- let_var_whitespace
- lower_acl_than_parent
- multiline_function_chains
- operator_usage_whitespace
- pattern_matching_keywords
- redundant_nil_coalescing
- redundant_type_annotation
- sorted_imports
- trailing_closure
- unneeded_parentheses_in_closure_argument
- untyped_error_in_catch
- vertical_whitespace_closing_braces
- xct_specific_matcher
- yoda_condition
trailing_comma:
mandatory_comma: true
excluded:
- keychain/trust/cuttlefish/
- keychain/Trieste/OctagonTriesteTests/.build

View File

@ -35,6 +35,9 @@ void LKAReportKeychainUpgradeOutcomeWithError(int fromversion, int toversion, LK
void LKABackupReportStart(bool hasKeybag, bool hasPasscode, bool isEMCS);
void LKABackupReportEnd(bool hasBackup, CFErrorRef error);
// For tests only
void LKAForceClose(void);
#if __OBJC2__
#import <Foundation/Foundation.h>
@ -44,6 +47,8 @@ typedef NSString* LKAnalyticsFailableEvent NS_STRING_ENUM;
typedef NSString* LKAnalyticsMetric NS_STRING_ENUM;
extern LKAnalyticsFailableEvent const LKAEventUpgrade;
extern LKAnalyticsFailableEvent const LKAEventStash;
extern LKAnalyticsFailableEvent const LKAEventStashLoad;
@interface LocalKeychainAnalytics : SFAnalytics

View File

@ -8,10 +8,6 @@
#include <utilities/SecFileLocations.h>
#include <utilities/SecAKSWrappers.h>
#ifdef DARLING
#import <Foundation/Foundation.h>
#endif
@interface LKAUpgradeOutcomeReport : NSObject
@property LKAKeychainUpgradeOutcome outcome;
@property NSDictionary* attributes;
@ -28,7 +24,6 @@
}
@end
#if !defined(DARLING) || defined(__OBJC2__)
// Approved event types
// rdar://problem/41745059 SFAnalytics: collect keychain upgrade outcome information
LKAnalyticsFailableEvent const LKAEventUpgrade = (LKAnalyticsFailableEvent)@"LKAEventUpgrade";
@ -37,6 +32,10 @@ LKAnalyticsFailableEvent const LKAEventUpgrade = (LKAnalyticsFailableEvent)@"LKA
LKAnalyticsFailableEvent const LKAEventBackup = (LKAnalyticsFailableEvent)@"LKAEventBackup";
LKAnalyticsMetric const LKAMetricBackupDuration = (LKAnalyticsMetric)@"LKAMetricBackupDuration";
// <rdar://problem/60767235> SFAnalytics: Collect keychain masterkey stash success/failure rates and failure codes on macOS SUs
LKAnalyticsFailableEvent const LKAEventStash = (LKAnalyticsFailableEvent)@"LKAEventStash";
LKAnalyticsFailableEvent const LKAEventStashLoad = (LKAnalyticsFailableEvent)@"LKAEventStashLoad";
// Internal consts
NSString* const LKAOldSchemaKey = @"oldschema";
NSString* const LKANewSchemaKey = @"newschema";
@ -156,40 +155,41 @@ NSString* const LKABackupLastSuccessDate = @"backupLastSuccess";
[self logSuccessForEventNamed:LKAEventBackup timestampBucket:SFAnalyticsTimestampBucketHour];
} else {
NSInteger daysSinceSuccess = [SFAnalytics fuzzyDaysSinceDate:[self datePropertyForKey:LKABackupLastSuccessDate]];
[self logResultForEvent:LKAEventBackup
hardFailure:YES
result:error
withAttributes:@{@"daysSinceSuccess" : @(daysSinceSuccess),
@"duration" : @(backupDuration),
@"type" : @(_backupType),
}
timestampBucket:SFAnalyticsTimestampBucketHour];
// Backups fail all the time due to devices being locked. If a backup has happened recently,
// let's not even report it, to avoid crowding out more useful data
bool boringError = error.code == errSecInteractionNotAllowed && daysSinceSuccess == 0;
if(!boringError) {
[self logResultForEvent:LKAEventBackup
hardFailure:YES
result:error
withAttributes:@{@"daysSinceSuccess" : @(daysSinceSuccess),
@"duration" : @(backupDuration),
@"type" : @(_backupType),
}
timestampBucket:SFAnalyticsTimestampBucketHour];
}
}
}
@end
#endif
// MARK: C Bridging
void LKAReportKeychainUpgradeOutcome(int fromversion, int toversion, LKAKeychainUpgradeOutcome outcome) {
#if !defined(DARLING) || defined(__OBJC2__)
@autoreleasepool {
[[LocalKeychainAnalytics logger] reportKeychainUpgradeFrom:fromversion to:toversion outcome:outcome error:NULL];
}
#endif
}
void LKAReportKeychainUpgradeOutcomeWithError(int fromversion, int toversion, LKAKeychainUpgradeOutcome outcome, CFErrorRef error) {
#if !defined(DARLING) || defined(__OBJC2__)
@autoreleasepool {
[[LocalKeychainAnalytics logger] reportKeychainUpgradeFrom:fromversion to:toversion outcome:outcome error:(__bridge NSError*)error];
}
#endif
}
void LKABackupReportStart(bool hasKeybag, bool hasPasscode, bool isEMCS) {
#if !defined(DARLING) || defined(__OBJC2__)
LKAKeychainBackupType type;
if (isEMCS) {
type = LKAKeychainBackupTypeEMCS;
@ -207,13 +207,17 @@ void LKABackupReportStart(bool hasKeybag, bool hasPasscode, bool isEMCS) {
@autoreleasepool {
[[LocalKeychainAnalytics logger] reportKeychainBackupStartWithType:type];
}
#endif
}
void LKABackupReportEnd(bool hasBackup, CFErrorRef error) {
#if !defined(DARLING) || defined(__OBJC2__)
@autoreleasepool {
[[LocalKeychainAnalytics logger] reportKeychainBackupEnd:hasBackup error:(__bridge NSError*)error];
}
#endif
}
void LKAForceClose(void)
{
@autoreleasepool {
[[LocalKeychainAnalytics logger] removeState];
}
}

View File

@ -26,7 +26,7 @@
#define SOSAnalytics_h
#import <Foundation/Foundation.h>
#import "Analytics/SFAnalytics.h"
#import <Security/SFAnalytics.h>
extern NSString* const CKDKVSPerformanceCountersSampler;

View File

@ -31,6 +31,7 @@
@interface SFAnalytics (Internal)
- (void)logMetric:(NSNumber*)metric withName:(NSString*)metricName oncePerReport:(BOOL)once;
+ (NSString*)hwModelID;
@end

View File

@ -26,9 +26,9 @@
#define SFAnalytics_h
#import <Foundation/Foundation.h>
#import "SFAnalyticsSampler.h"
#import "SFAnalyticsMultiSampler.h"
#import "SFAnalyticsActivityTracker.h"
#import <Security/SFAnalyticsSampler.h>
#import <Security/SFAnalyticsMultiSampler.h>
#import <Security/SFAnalyticsActivityTracker.h>
NS_ASSUME_NONNULL_BEGIN
@ -66,10 +66,18 @@ typedef NS_ENUM(uint32_t, SFAnalyticsTimestampBucket) {
+ (instancetype _Nullable)logger;
+ (NSInteger)fuzzyDaysSinceDate:(NSDate*)date;
// Rounds to the nearest 5 (unless 1 or 2, that rounds to 5 as well)
+ (NSInteger)fuzzyInteger:(NSInteger)num;
+ (NSNumber*)fuzzyNumber:(NSNumber*)num;
+ (void)addOSVersionToEvent:(NSMutableDictionary*)event;
// Help for the subclass to pick a prefered location
+ (NSString *)defaultAnalyticsDatabasePath:(NSString *)basename;
+ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename uuid:(NSUUID * __nullable)userUuid;
+ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename; // uses current user UUID for path
- (void)dailyCoreAnalyticsMetrics:(NSString *)eventName;
// Log event-based metrics: create an event corresponding to some event in your feature

View File

@ -40,6 +40,13 @@
#import <utilities/SecCoreAnalytics.h>
#if TARGET_OS_OSX
#include <sys/sysctl.h>
#include <membership.h>
#else
#import <sys/utsname.h>
#endif
// SFAnalyticsDefines constants
NSString* const SFAnalyticsTableSuccessCount = @"success_count";
NSString* const SFAnalyticsTableHardFailures = @"hard_failures";
@ -53,6 +60,7 @@ NSString* const SFAnalyticsColumnSoftFailureCount = @"soft_failure_count";
NSString* const SFAnalyticsColumnSampleValue = @"value";
NSString* const SFAnalyticsColumnSampleName = @"name";
NSString* const SFAnalyticsPostTime = @"postTime";
NSString* const SFAnalyticsEventTime = @"eventTime";
NSString* const SFAnalyticsEventType = @"eventType";
NSString* const SFAnalyticsEventTypeErrorEvent = @"errorEvent";
@ -73,6 +81,7 @@ NSString* const SFAnalyticsTopicCloudServices = @"CloudServicesTopic";
NSString* const SFAnalyticsTopicKeySync = @"KeySyncTopic";
NSString* const SFAnalyticsTopicTrust = @"TrustTopic";
NSString* const SFAnalyticsTopicTransparency = @"TransparencyTopic";
NSString* const SFAnalyticsTopicNetworking = @"NetworkingTopic";
NSString* const SFAnalyticsTableSchema = @"CREATE TABLE IF NOT EXISTS hard_failures (\n"
@"id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
@ -130,6 +139,7 @@ NSString* const SFAnalyticsErrorDomain = @"com.apple.security.sfanalytics";
// Local constants
NSString* const SFAnalyticsEventBuild = @"build";
NSString* const SFAnalyticsEventProduct = @"product";
NSString* const SFAnalyticsEventModelID = @"modelid";
NSString* const SFAnalyticsEventInternal = @"internal";
const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
@ -175,7 +185,8 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
{
WithPathInKeychainDirectory(CFSTR("Analytics"), ^(const char *path) {
#if TARGET_OS_IPHONE
mode_t permissions = 0775;
/* We need _securityd, _trustd, and root all to be able to write. They share no groups. */
mode_t permissions = 0777;
#else
mode_t permissions = 0700;
#endif // TARGET_OS_IPHONE
@ -189,6 +200,62 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)path) path];
}
+ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename uuid:(NSUUID * __nullable)userUuid
{
// Create the top-level directory with full access
NSMutableString *directory = [NSMutableString stringWithString:@"sfanalytics"];
WithPathInProtectedDirectory((__bridge CFStringRef)directory, ^(const char *path) {
mode_t permissions = 0777;
int ret = mkpath_np(path, permissions);
if (!(ret == 0 || ret == EEXIST)) {
secerror("could not create path: %s (%s)", path, strerror(ret));
}
chmod(path, permissions);
});
// create per-user directory
if (userUuid) {
[directory appendString:@"/"];
[directory appendString:[userUuid UUIDString]];
WithPathInProtectedDirectory((__bridge CFStringRef)directory, ^(const char *path) {
#if TARGET_OS_IPHONE
/* We need _securityd, _trustd, and root all to be able to write. They share no groups. */
mode_t permissions = 0777;
#else
mode_t permissions = 0700;
if (geteuid() == 0 || geteuid() == 282) {
// Root/_trustd user directory needs to be read/write for group so that user supd can upload system data
permissions = 0775;
}
#endif // TARGET_OS_IPHONE
int ret = mkpath_np(path, permissions);
if (!(ret == 0 || ret == EEXIST)) {
secerror("could not create path: %s (%s)", path, strerror(ret));
}
chmod(path, permissions);
});
}
NSString *path = [NSString stringWithFormat:@"%@/%@.db", directory, basename];
return [(__bridge_transfer NSURL*)SecCopyURLForFileInProtectedDirectory((__bridge CFStringRef)path) path];
}
+ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename
{
#if TARGET_OS_OSX
uid_t euid = geteuid();
uuid_t currentUserUuid;
int ret = mbr_uid_to_uuid(euid, currentUserUuid);
if (ret != 0) {
secerror("failed to get UUID for user(%d) - %d", euid, ret);
return [SFAnalytics defaultProtectedAnalyticsDatabasePath:basename uuid:nil];
}
NSUUID *userUuid = [[NSUUID alloc] initWithUUIDBytes:currentUserUuid];
return [SFAnalytics defaultProtectedAnalyticsDatabasePath:basename uuid:userUuid];
#else
return [SFAnalytics defaultProtectedAnalyticsDatabasePath:basename uuid:nil];
#endif // TARGET_OS_IPHONE
}
+ (NSInteger)fuzzyDaysSinceDate:(NSDate*)date
{
// Sentinel: it didn't happen at all
@ -222,6 +289,38 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
}
}
+ (NSInteger)fuzzyInteger:(NSInteger)num
{
NSInteger sign = 1;
if(num < 0) {
sign = -1;
num = -num;
}
// Differentiate zero and non-zero....
if(num == 0) {
return 0;
}
if(num <= 5) {
return sign*5;
}
// Otherwise, round to the nearest five
NSInteger mod = num % 5;
if(mod <= 2) {
return sign*(num - mod);
} else {
return sign*(num + (5-mod));
}
}
+ (NSNumber*)fuzzyNumber:(NSNumber*)num
{
return [NSNumber numberWithInteger:[self fuzzyInteger:[num integerValue]]];
}
// Instantiate lazily so unit tests can have clean databases each
- (SFAnalyticsSQLiteStore*)database
{
@ -314,11 +413,37 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
return result;
}
+ (NSString*)hwModelID
{
static NSString *hwModel = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
#if TARGET_OS_SIMULATOR
// Asking for a real value in the simulator gives the results for the underlying mac. Not particularly useful.
hwModel = [NSString stringWithFormat:@"%s", getenv("SIMULATOR_MODEL_IDENTIFIER")];
#elif TARGET_OS_OSX
size_t size;
sysctlbyname("hw.model", NULL, &size, NULL, 0);
char *sysctlString = malloc(size);
sysctlbyname("hw.model", sysctlString, &size, NULL, 0);
hwModel = [[NSString alloc] initWithUTF8String:sysctlString];
free(sysctlString);
#else
struct utsname systemInfo;
uname(&systemInfo);
hwModel = [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
#endif
});
return hwModel;
}
+ (void)addOSVersionToEvent:(NSMutableDictionary*)eventDict {
static dispatch_once_t onceToken;
static NSString *build = NULL;
static NSString *product = NULL;
static NSString *modelID = nil;
static BOOL internal = NO;
dispatch_once(&onceToken, ^{
NSDictionary *version = CFBridgingRelease(_CFCopySystemVersionDictionary());
@ -327,6 +452,8 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
build = version[(__bridge NSString *)_kCFSystemVersionBuildVersionKey];
product = version[(__bridge NSString *)_kCFSystemVersionProductNameKey];
internal = os_variant_has_internal_diagnostics("com.apple.security");
modelID = [self hwModelID];
});
if (build) {
eventDict[SFAnalyticsEventBuild] = build;
@ -334,6 +461,9 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
if (product) {
eventDict[SFAnalyticsEventProduct] = product;
}
if (modelID) {
eventDict[SFAnalyticsEventModelID] = modelID;
}
if (internal) {
eventDict[SFAnalyticsEventInternal] = @YES;
}

View File

@ -4,6 +4,8 @@
<dict>
<key>KeySyncTopic</key>
<dict>
<key>uploadSizeLimit</key>
<real>1000000</real>
<key>splunk_allowInsecureCertificate</key>
<false/>
<key>splunk_topic</key>
@ -13,6 +15,8 @@
</dict>
<key>CloudServicesTopic</key>
<dict>
<key>uploadSizeLimit</key>
<real>1000000</real>
<key>splunk_allowInsecureCertificate</key>
<false/>
<key>splunk_topic</key>
@ -24,6 +28,8 @@
</dict>
<key>TrustTopic</key>
<dict>
<key>uploadSizeLimit</key>
<real>1000000</real>
<key>splunk_allowInsecureCertificate</key>
<false/>
<key>splunk_topic</key>
@ -35,6 +41,8 @@
</dict>
<key>TransparencyTopic</key>
<dict>
<key>uploadSizeLimit</key>
<real>10000</real>
<key>splunk_allowInsecureCertificate</key>
<false/>
<key>splunk_topic</key>
@ -42,5 +50,18 @@
<key>splunk_bagURL</key>
<string>https://metrics-config.icloud.com/config/TransparencyAnalytics</string>
</dict>
<key>NetworkingTopic</key>
<dict>
<key>uploadSizeLimit</key>
<real>1000000</real>
<key>splunk_allowInsecureCertificate</key>
<false/>
<key>splunk_topic</key>
<string>xp_swe_network_perf</string>
<key>splunk_bagURL</key>
<string>https://xp.apple.com/config/1/report/xp_swe_network_perf</string>
<key>disableClientId</key>
<true/>
</dict>
</dict>
</plist>

View File

@ -38,6 +38,7 @@ extern NSString* const SFAnalyticsColumnSoftFailureCount;
extern NSString* const SFAnalyticsColumnSampleValue;
extern NSString* const SFAnalyticsColumnSampleName;
extern NSString* const SFAnalyticsPostTime;
extern NSString* const SFAnalyticsEventTime;
extern NSString* const SFAnalyticsEventType;
extern NSString* const SFAnalyticsEventTypeErrorEvent;
@ -60,6 +61,7 @@ extern NSString* const SFAnalyticsTopicCloudServices;
extern NSString* const SFAnalyticsTopicKeySync;
extern NSString* const SFAnalyticsTopicTrust;
extern NSString* const SFAnalyticsTopicTransparency;
extern NSString* const SFAnalyticsTopicNetworking;
typedef NS_ENUM(NSInteger, SFAnalyticsEventClass) {
SFAnalyticsEventClassSuccess,

View File

@ -23,8 +23,8 @@
#if __OBJC2__
#import "Analytics/SQLite/SFSQLite.h"
#import "SFAnalytics.h"
#import <Security/SFSQLite.h>
#import <Security/SFAnalytics.h>
@interface SFAnalyticsSQLiteStore : SFSQLite

View File

@ -79,6 +79,7 @@ NSString* const SFAnalyticsUploadDate = @"upload_date";
if (!self.isOpen) {
NSError* error = nil;
if (![self openWithError:&error]) {
secerror("SFAnalytics: failed to open analytics db: %@", error);
return NO;
}
secnotice("SFAnalytics", "successfully opened analytics db");

View File

@ -28,6 +28,7 @@
#include <sqlite3.h>
#include <CommonCrypto/CommonDigest.h>
#import "utilities/debugging.h"
#import "utilities/simulatecrash_assert.h"
#include <os/transaction_private.h>
#define kSFSQLiteBusyTimeout (5*60*1000)
@ -300,7 +301,6 @@ allDone:
*/
- (void)attemptProperDatabasePermissions
{
#if TARGET_OS_IPHONE
NSFileManager* fm = [NSFileManager defaultManager];
[fm setAttributes:@{NSFilePosixPermissions : [NSNumber numberWithShort:0666]}
ofItemAtPath:_path
@ -311,7 +311,6 @@ allDone:
[fm setAttributes:@{NSFilePosixPermissions : [NSNumber numberWithShort:0666]}
ofItemAtPath:[NSString stringWithFormat:@"%@-shm",_path]
error:nil];
#endif
}
- (BOOL)openWithError:(NSError **)error {
@ -340,7 +339,12 @@ allDone:
#endif
int rc = sqlite3_open_v2([arcSafePath fileSystemRepresentation], &_db, flags, NULL);
if (rc != SQLITE_OK) {
localError = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error opening db at %@, rc=%d(0x%x)", _path, rc, rc]}];
int reportedErrno = sqlite3_system_errno(_db);
localError = [NSError errorWithDomain:NSCocoaErrorDomain code:rc userInfo:@{
NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error opening db at %@, rc=%d(0x%x), errno=%d(0x%x)",
_path, rc, rc, reportedErrno, reportedErrno],
}];
goto done;
}
@ -911,7 +915,7 @@ done:
- (NSString *)_tableNameForClass:(Class)objectClass {
NSString *className = [objectClass SFSQLiteClassName];
if (![className hasPrefix:_objectClassPrefix]) {
secerror("sfsqlite: %@", [NSString stringWithFormat:@"Object class \"%@\" does not have prefix \"%@\"", className, _objectClassPrefix]);
secerror("sfsqlite: Object class \"%@\" does not have prefix \"%@\"", className, _objectClassPrefix);
return nil;
}
return [className substringFromIndex:_objectClassPrefix.length];

View File

@ -68,7 +68,7 @@ typedef CF_ENUM(uint32_t, CMSSignerStatus) {
* Create a CMSDecoder. Result must eventually be freed via CFRelease().
*/
OSStatus CMSDecoderCreate(CMSDecoderRef * __nonnull CF_RETURNS_RETAINED cmsDecoderOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Feed raw bytes of the message to be decoded into the decoder. Can be called
@ -80,7 +80,7 @@ OSStatus CMSDecoderUpdateMessage(
CMSDecoderRef cmsDecoder,
const void *msgBytes,
size_t msgBytesLen)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
@ -89,7 +89,7 @@ OSStatus CMSDecoderUpdateMessage(
* message.
*/
OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* A signed CMS message optionally includes the data which was signed. If the
@ -105,7 +105,7 @@ OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder)
OSStatus CMSDecoderSetDetachedContent(
CMSDecoderRef cmsDecoder,
CFDataRef detachedContent)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the detached content specified in CMSDecoderSetDetachedContent().
@ -115,7 +115,7 @@ OSStatus CMSDecoderSetDetachedContent(
OSStatus CMSDecoderCopyDetachedContent(
CMSDecoderRef cmsDecoder,
CFDataRef * __nonnull CF_RETURNS_RETAINED detachedContentOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
#if SEC_OS_OSX
/*
@ -125,7 +125,7 @@ OSStatus CMSDecoderCopyDetachedContent(
OSStatus CMSDecoderSetSearchKeychain(
CMSDecoderRef cmsDecoder,
CFTypeRef keychainOrArray)
API_DEPRECATED_WITH_REPLACEMENT("SecKeychainSetSearchList",macos(10.5, 10.13)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_DEPRECATED_WITH_REPLACEMENT("SecKeychainSetSearchList",macos(10.5, 10.13)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#endif // SEC_OS_OSX
/*
@ -136,7 +136,7 @@ OSStatus CMSDecoderSetSearchKeychain(
OSStatus CMSDecoderGetNumSigners(
CMSDecoderRef cmsDecoder,
size_t *numSignersOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the status of a CMS message's signature. A CMS message can
@ -220,7 +220,7 @@ OSStatus CMSDecoderCopySignerStatus(
CMSSignerStatus * __nullable signerStatusOut, /* optional; RETURNED */
SecTrustRef * __nullable CF_RETURNS_RETAINED secTrustOut, /* optional; RETURNED */
OSStatus * __nullable certVerifyResultCodeOut) /* optional; RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the email address of signer 'signerIndex' of a CMS message, if
@ -235,7 +235,7 @@ OSStatus CMSDecoderCopySignerEmailAddress(
CMSDecoderRef cmsDecoder,
size_t signerIndex,
CFStringRef * __nonnull CF_RETURNS_RETAINED signerEmailAddressOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the certificate of signer 'signerIndex' of a CMS message, if
@ -250,7 +250,7 @@ OSStatus CMSDecoderCopySignerCert(
CMSDecoderRef cmsDecoder,
size_t signerIndex,
SecCertificateRef * __nonnull CF_RETURNS_RETAINED signerCertOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Determine whether a CMS message was encrypted. Returns TRUE if so, FALSE if not.
@ -262,7 +262,7 @@ OSStatus CMSDecoderCopySignerCert(
OSStatus CMSDecoderIsContentEncrypted(
CMSDecoderRef cmsDecoder,
Boolean *isEncryptedOut)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
@ -274,7 +274,7 @@ OSStatus CMSDecoderIsContentEncrypted(
OSStatus CMSDecoderCopyEncapsulatedContentType(
CMSDecoderRef cmsDecoder,
CFDataRef * __nonnull CF_RETURNS_RETAINED eContentTypeOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain an array of all of the certificates in a message. Elements of the
@ -287,7 +287,7 @@ OSStatus CMSDecoderCopyEncapsulatedContentType(
OSStatus CMSDecoderCopyAllCerts(
CMSDecoderRef cmsDecoder,
CFArrayRef * __nonnull CF_RETURNS_RETAINED certsOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the actual message content (payload), if any. If the message was
@ -298,7 +298,7 @@ OSStatus CMSDecoderCopyAllCerts(
OSStatus CMSDecoderCopyContent(
CMSDecoderRef cmsDecoder,
CFDataRef * __nonnull CF_RETURNS_RETAINED contentOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the signing time of signer 'signerIndex' of a CMS message, if
@ -314,7 +314,7 @@ OSStatus CMSDecoderCopySignerSigningTime(
CMSDecoderRef cmsDecoder,
size_t signerIndex,
CFAbsoluteTime *signingTime) /* RETURNED */
__API_AVAILABLE(macos(10.8)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.8)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the timestamp of signer 'signerIndex' of a CMS message, if
@ -330,7 +330,7 @@ OSStatus CMSDecoderCopySignerTimestamp(
CMSDecoderRef cmsDecoder,
size_t signerIndex,
CFAbsoluteTime *timestamp) /* RETURNED */
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
/*
* Obtain the timestamp of signer 'signerIndex' of a CMS message, if
@ -347,7 +347,7 @@ OSStatus CMSDecoderCopySignerTimestampWithPolicy(
CFTypeRef __nullable timeStampPolicy,
size_t signerIndex, /* usually 0 */
CFAbsoluteTime *timestamp) /* RETURNED */
API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
/*
* Obtain an array of the certificates in a timestamp response. Elements of the
@ -365,7 +365,7 @@ OSStatus CMSDecoderCopySignerTimestampCertificates(
CMSDecoderRef cmsDecoder,
size_t signerIndex, /* usually 0 */
CFArrayRef * __nonnull CF_RETURNS_RETAINED certificateRefs) /* RETURNED */
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
CF_ASSUME_NONNULL_END

View File

@ -62,13 +62,13 @@ CF_ASSUME_NONNULL_BEGIN
typedef struct CF_BRIDGED_TYPE(id) _CMSEncoder *CMSEncoderRef;
CFTypeID CMSEncoderGetTypeID(void)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Create a CMSEncoder. Result must eventually be freed via CFRelease().
*/
OSStatus CMSEncoderCreate(CMSEncoderRef * __nonnull CF_RETURNS_RETAINED cmsEncoderOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
extern const CFStringRef kCMSEncoderDigestAlgorithmSHA1;
extern const CFStringRef kCMSEncoderDigestAlgorithmSHA256;
@ -76,7 +76,7 @@ extern const CFStringRef kCMSEncoderDigestAlgorithmSHA256;
OSStatus CMSEncoderSetSignerAlgorithm(
CMSEncoderRef cmsEncoder,
CFStringRef digestAlgorithm)
__API_AVAILABLE(macos(10.11)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.11)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Specify signers of the CMS message; implies that the message will be signed.
@ -91,7 +91,7 @@ OSStatus CMSEncoderSetSignerAlgorithm(
OSStatus CMSEncoderAddSigners(
CMSEncoderRef cmsEncoder,
CFTypeRef signerOrArray)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain an array of signers as specified in CMSEncoderSetSigners().
@ -101,7 +101,7 @@ OSStatus CMSEncoderAddSigners(
OSStatus CMSEncoderCopySigners(
CMSEncoderRef cmsEncoder,
CFArrayRef * __nonnull CF_RETURNS_RETAINED signersOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Specify recipients of the message. Implies that the message will
@ -117,7 +117,7 @@ OSStatus CMSEncoderCopySigners(
OSStatus CMSEncoderAddRecipients(
CMSEncoderRef cmsEncoder,
CFTypeRef recipientOrArray)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain an array of recipients as specified in CMSEncoderSetRecipients().
@ -128,7 +128,7 @@ OSStatus CMSEncoderAddRecipients(
OSStatus CMSEncoderCopyRecipients(
CMSEncoderRef cmsEncoder,
CFArrayRef * __nonnull CF_RETURNS_RETAINED recipientsOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* A signed message optionally includes the data to be signed. If the message
@ -144,7 +144,7 @@ OSStatus CMSEncoderCopyRecipients(
OSStatus CMSEncoderSetHasDetachedContent(
CMSEncoderRef cmsEncoder,
Boolean detachedContent)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain a Boolean indicating whether the current message will have detached
@ -155,7 +155,7 @@ OSStatus CMSEncoderSetHasDetachedContent(
OSStatus CMSEncoderGetHasDetachedContent(
CMSEncoderRef cmsEncoder,
Boolean *detachedContentOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
#if SEC_OS_OSX
/*
@ -173,7 +173,7 @@ OSStatus CMSEncoderGetHasDetachedContent(
OSStatus CMSEncoderSetEncapsulatedContentType(
CMSEncoderRef cmsEncoder,
const CSSM_OID *eContentType)
API_DEPRECATED_WITH_REPLACEMENT("CMSEncoderSetEncapsulatedContentTypeOID", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_DEPRECATED_WITH_REPLACEMENT("CMSEncoderSetEncapsulatedContentTypeOID", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#endif // SEC_OS_OSX
/*
@ -191,7 +191,7 @@ OSStatus CMSEncoderSetEncapsulatedContentType(
OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
CMSEncoderRef cmsEncoder,
CFTypeRef eContentTypeOID)
__API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType().
@ -204,7 +204,7 @@ OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
OSStatus CMSEncoderCopyEncapsulatedContentType(
CMSEncoderRef cmsEncoder,
CFDataRef * __nonnull CF_RETURNS_RETAINED eContentTypeOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Signed CMS messages can contain arbitrary sets of certificates beyond those
@ -229,7 +229,7 @@ OSStatus CMSEncoderCopyEncapsulatedContentType(
OSStatus CMSEncoderAddSupportingCerts(
CMSEncoderRef cmsEncoder,
CFTypeRef certOrArray)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts().
@ -240,7 +240,7 @@ OSStatus CMSEncoderAddSupportingCerts(
OSStatus CMSEncoderCopySupportingCerts(
CMSEncoderRef cmsEncoder,
CFArrayRef * __nonnull CF_RETURNS_RETAINED certsOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Standard signed attributes, optionally specified in
@ -285,7 +285,7 @@ typedef CF_OPTIONS(uint32_t, CMSSignedAttributes) {
OSStatus CMSEncoderAddSignedAttributes(
CMSEncoderRef cmsEncoder,
CMSSignedAttributes signedAttributes)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Specification of what certificates to include in a signed message.
@ -313,7 +313,7 @@ typedef CF_ENUM(uint32_t, CMSCertificateChainMode) {
OSStatus CMSEncoderSetCertificateChainMode(
CMSEncoderRef cmsEncoder,
CMSCertificateChainMode chainMode)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Obtain indication of which signer certs are to be included
@ -322,7 +322,7 @@ OSStatus CMSEncoderSetCertificateChainMode(
OSStatus CMSEncoderGetCertificateChainMode(
CMSEncoderRef cmsEncoder,
CMSCertificateChainMode *chainModeOut)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Feed content bytes into the encoder.
@ -333,7 +333,7 @@ OSStatus CMSEncoderUpdateContent(
CMSEncoderRef cmsEncoder,
const void *content,
size_t contentLen)
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
/*
* Finish encoding the message and obtain the encoded result.
@ -342,7 +342,7 @@ OSStatus CMSEncoderUpdateContent(
OSStatus CMSEncoderCopyEncodedContent(
CMSEncoderRef cmsEncoder,
CFDataRef * __nonnull CF_RETURNS_RETAINED encodedContentOut) /* RETURNED */
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
#if TARGET_OS_OSX
/*
@ -377,7 +377,7 @@ OSStatus CMSEncode(
const void * content,
size_t contentLen,
CFDataRef * __nonnull CF_RETURNS_RETAINED encodedContentOut) /* RETURNED */
API_DEPRECATED_WITH_REPLACEMENT("CMSEncodeContent", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_DEPRECATED_WITH_REPLACEMENT("CMSEncodeContent", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#endif // TARGET_OS_OSX
/*
@ -410,20 +410,20 @@ OSStatus CMSEncodeContent(
const void *content,
size_t contentLen,
CFDataRef * __nullable CF_RETURNS_RETAINED encodedContentOut) /* RETURNED */
__API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
__API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
OSStatus CMSEncoderCopySignerTimestamp(
CMSEncoderRef cmsEncoder,
size_t signerIndex, /* usually 0 */
CFAbsoluteTime *timestamp) /* RETURNED */
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
OSStatus CMSEncoderCopySignerTimestampWithPolicy(
CMSEncoderRef cmsEncoder,
CFTypeRef __nullable timeStampPolicy,
size_t signerIndex, /* usually 0 */
CFAbsoluteTime *timestamp) /* RETURNED */
API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
CF_ASSUME_NONNULL_END

View File

@ -115,7 +115,7 @@ OSStatus CMSEncoderSetAppleExpirationTime(
void
CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, macCatalyst);
/***
*** Private CMSDecoder routines

View File

@ -69,9 +69,9 @@ typedef SecAsn1AlgId SECAlgorithmID;
@discussion XXX This should probably move to SecKey.h
*/
#if TARGET_OS_OSX
typedef SecKeyRef SecSymmetricKeyRef API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
typedef SecKeyRef SecSymmetricKeyRef API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else
typedef void * SecSymmetricKeyRef API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
typedef void * SecSymmetricKeyRef API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif
/*!
@ -173,7 +173,7 @@ typedef void (*SecCmsContentCallback)(void *arg, const char *buf, size_t len);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
typedef SecSymmetricKeyRef(*SecCmsGetDecryptKeyCallback)(void *arg, SECAlgorithmID *algid)
API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
/*!

View File

@ -71,7 +71,7 @@ SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo);
*/
extern CSSM_DATA_PTR
SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -80,7 +80,7 @@ SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
*/
extern const SecAsn1Item *
SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
/*!
@ -99,7 +99,7 @@ SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo);
*/
extern CSSM_OID *
SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -108,7 +108,7 @@ SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
*/
extern SecAsn1Oid *
SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
/*!
@ -143,7 +143,7 @@ SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo)
*/
extern OSStatus
SecCmsContentInfoSetContentData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, CSSM_DATA_PTR data, Boolean detached)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -157,7 +157,7 @@ SecCmsContentInfoSetContentData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinf
*/
extern OSStatus
SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef data, Boolean detached)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
@ -173,7 +173,7 @@ SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef data, Bool
*/
extern OSStatus
SecCmsContentInfoSetContentSignedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -186,7 +186,7 @@ SecCmsContentInfoSetContentSignedData(SecCmsMessageRef cmsg, SecCmsContentInfoRe
*/
extern OSStatus
SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // TARGET_OS_OSX
#if TARGET_OS_OSX
@ -202,7 +202,7 @@ SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDa
*/
extern OSStatus
SecCmsContentInfoSetContentEnvelopedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -215,7 +215,7 @@ SecCmsContentInfoSetContentEnvelopedData(SecCmsMessageRef cmsg, SecCmsContentInf
*/
extern OSStatus
SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
@ -231,7 +231,7 @@ SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvel
*/
extern OSStatus
SecCmsContentInfoSetContentDigestedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -244,7 +244,7 @@ SecCmsContentInfoSetContentDigestedData(SecCmsMessageRef cmsg, SecCmsContentInfo
*/
extern OSStatus
SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
@ -260,7 +260,7 @@ SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigest
*/
extern OSStatus
SecCmsContentInfoSetContentEncryptedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -273,41 +273,41 @@ SecCmsContentInfoSetContentEncryptedData(SecCmsMessageRef cmsg, SecCmsContentInf
*/
extern OSStatus
SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
OSStatus
SecCmsContentInfoSetContentOther(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, CSSM_DATA_PTR data, Boolean detached, const CSSM_OID *eContentType)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
OSStatus
SecCmsContentInfoSetContentOther(SecCmsContentInfoRef cinfo, SecAsn1Item *data, Boolean detached, const SecAsn1Oid *eContentType)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
extern OSStatus
SecCmsContentInfoSetContentEncAlg(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo,
SECOidTag bulkalgtag, CSSM_DATA_PTR parameters, int keysize)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
extern OSStatus
SecCmsContentInfoSetContentEncAlg(SecCmsContentInfoRef cinfo,
SECOidTag bulkalgtag, const SecAsn1Item *parameters, int keysize)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
extern OSStatus
SecCmsContentInfoSetContentEncAlgID(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo,
SECAlgorithmID *algid, int keysize)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
extern OSStatus
SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
SECAlgorithmID *algid, int keysize)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !!TARGET_OS_OSX
/*!
@ -315,14 +315,14 @@ SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
*/
extern void
SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey)
API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
/*!
@function
*/
extern SecSymmetricKeyRef
SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo)
API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
/*!
@function

View File

@ -68,7 +68,7 @@ SecCmsDecoderCreate(SecArenaPoolRef arena,
SecCmsGetDecryptKeyCallback decrypt_key_cb, void
*decrypt_key_cb_arg,
SecCmsDecoderRef *outDecoder)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
/*!
@function
@ -94,7 +94,7 @@ SecCmsDecoderCreate(SecCmsContentCallback cb, void *cb_arg,
SecCmsGetDecryptKeyCallback decrypt_key_cb, void
*decrypt_key_cb_arg,
SecCmsDecoderRef *outDecoder)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
/*!
@ -161,7 +161,7 @@ SecCmsMessageDecode(const CSSM_DATA *encodedMessage,
PK11PasswordFunc pwfn, void *pwfn_arg,
SecCmsGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
SecCmsMessageRef *outMessage)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
/*!
@ -190,7 +190,7 @@ SecCmsMessageDecode(const SecAsn1Item *encodedMessage,
PK11PasswordFunc pwfn, void *pwfn_arg,
SecCmsGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
SecCmsMessageRef *outMessage)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX

View File

@ -44,7 +44,7 @@ __BEGIN_DECLS
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
extern SecCmsDigestContextRef
SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs)
API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
/*!
@ -70,7 +70,7 @@ SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx);
*/
extern void
SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // TARGET_OS_IPHONE
#if TARGET_OS_OSX
@ -83,7 +83,7 @@ SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx)
extern OSStatus
SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef arena,
CSSM_DATA_PTR **digestsp)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#endif // TARGET_OS_OSX

View File

@ -51,7 +51,7 @@ __BEGIN_DECLS
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
extern SecCmsDigestedDataRef
SecCmsDigestedDataCreate(SecCmsMessageRef cmsg, SECAlgorithmID *digestalg)
API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
/*!

View File

@ -77,7 +77,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg,
SecCmsGetDecryptKeyCallback encrypt_key_cb, void *encrypt_key_cb_arg,
SECAlgorithmID **detached_digestalgs, CSSM_DATA_PTR *detached_digests,
SecCmsEncoderRef *outEncoder)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
/*!
@ -107,7 +107,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg,
PK11PasswordFunc pwfn, void *pwfn_arg,
SecCmsGetDecryptKeyCallback encrypt_key_cb, void *encrypt_key_cb_arg,
SecCmsEncoderRef *outEncoder)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
/*!
@ -157,7 +157,7 @@ SecCmsEncoderFinish(SecCmsEncoderRef encoder);
extern OSStatus
SecCmsMessageEncode(SecCmsMessageRef cmsg, const CSSM_DATA *input, SecArenaPoolRef arena,
CSSM_DATA_PTR outBer)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
/*!
@ -172,7 +172,7 @@ SecCmsMessageEncode(SecCmsMessageRef cmsg, const CSSM_DATA *input, SecArenaPoolR
extern OSStatus
SecCmsMessageEncode(SecCmsMessageRef cmsg, const SecAsn1Item *input,
CFMutableDataRef outBer)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
__END_DECLS

View File

@ -55,7 +55,7 @@ __BEGIN_DECLS
*/
extern SecCmsMessageRef
SecCmsMessageCreate(SecArenaPoolRef poolp)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
@ -69,7 +69,7 @@ SecCmsMessageCreate(SecArenaPoolRef poolp)
*/
extern SecCmsMessageRef
SecCmsMessageCreate(void)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
@ -119,7 +119,7 @@ SecCmsMessageGetContentInfo(SecCmsMessageRef cmsg);
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
extern CSSM_DATA_PTR
SecCmsMessageGetContent(SecCmsMessageRef cmsg)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
/*!
@ -130,7 +130,7 @@ SecCmsMessageGetContent(SecCmsMessageRef cmsg)
*/
extern const SecAsn1Item *
SecCmsMessageGetContent(SecCmsMessageRef cmsg)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
/*!

View File

@ -47,7 +47,7 @@ __BEGIN_DECLS
*/
extern SecCmsRecipientInfoRef
SecCmsRecipientInfoCreate(SecCmsMessageRef cmsg, SecCertificateRef cert)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
@ -59,7 +59,7 @@ SecCmsRecipientInfoCreate(SecCmsMessageRef cmsg, SecCertificateRef cert)
*/
extern SecCmsRecipientInfoRef
SecCmsRecipientInfoCreate(SecCmsEnvelopedDataRef envd, SecCertificateRef cert)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
@ -70,14 +70,14 @@ extern SecCmsRecipientInfoRef
SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg,
CSSM_DATA_PTR subjKeyID,
SecPublicKeyRef pubKey)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
extern SecCmsRecipientInfoRef
SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
const SecAsn1Item *subjKeyID,
SecPublicKeyRef pubKey)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
@ -85,12 +85,12 @@ SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
extern SecCmsRecipientInfoRef
SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsMessageRef cmsg,
SecCertificateRef cert)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OS_OSX
extern SecCmsRecipientInfoRef
SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd,
SecCertificateRef cert)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX

View File

@ -165,7 +165,7 @@ SecCmsSignedDataContainsCertsOrCrls(SecCmsSignedDataRef sigd);
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
extern CSSM_DATA_PTR *
SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
/*!
@ -174,7 +174,7 @@ SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
*/
extern SecAsn1Item * *
SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
/*!
@ -200,7 +200,7 @@ SecCmsSignedDataCreateCertsOnly(SecCmsMessageRef cmsg, SecCertificateRef cert, B
*/
extern OSStatus SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd,
SecCmsDigestContextRef digestContext)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macos, iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macos, macCatalyst);
#endif
#if TARGET_OS_OSX
@ -214,7 +214,7 @@ extern OSStatus
SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd,
SECAlgorithmID **digestalgs,
CSSM_DATA_PTR *digests)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#endif

View File

@ -44,13 +44,13 @@ __BEGIN_DECLS
#if TARGET_OS_OSX
extern SecCmsSignerInfoRef
SecCmsSignerInfoCreate(SecCmsMessageRef cmsg, SecIdentityRef identity, SECOidTag digestalgtag)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#else // !TARGET_OSX
extern SecCmsSignerInfoRef
SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd, SecIdentityRef identity, SECOidTag digestalgtag)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
@ -58,12 +58,12 @@ SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd, SecIdentityRef identity, SECOid
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
extern SecCmsSignerInfoRef
SecCmsSignerInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
#pragma clang diagnostic pop
#else // !TARGET_OS_OSX
extern SecCmsSignerInfoRef
SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd, const SecAsn1Item *subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
#endif // !TARGET_OS_OSX
#if TARGET_OS_OSX
@ -73,7 +73,7 @@ SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd, const SecAsn1Item
*/
extern void
SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si)
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#endif
/*!
@ -291,26 +291,26 @@ SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSign
extern OSStatus
SecCmsSignerInfoVerifyUnAuthAttrs(SecCmsSignerInfoRef signerinfo)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
extern OSStatus
SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
extern CSSM_DATA *
SecCmsSignerInfoGetEncDigest(SecCmsSignerInfoRef signerinfo)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#pragma clang diagnostic pop
extern CFArrayRef
SecCmsSignerInfoGetTimestampCertList(SecCmsSignerInfoRef signerinfo)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
extern SecCertificateRef
SecCmsSignerInfoGetTimestampSigningCert(SecCmsSignerInfoRef signerinfo)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
/*!
@function
@ -321,7 +321,7 @@ SecCmsSignerInfoGetTimestampSigningCert(SecCmsSignerInfoRef signerinfo)
*/
OSStatus
SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
/*!
@function
@ -332,7 +332,7 @@ SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stim
*/
OSStatus
SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo, CFTypeRef timeStampPolicy, CFAbsoluteTime *stime)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
/*!
@function
@ -342,7 +342,7 @@ SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo, CFTypeRef
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
OSStatus
SecCmsSignerInfoAddTimeStamp(SecCmsSignerInfoRef signerinfo, CSSM_DATA *tstoken)
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
#pragma clang diagnostic pop
#endif // TARGET_OS_OSX

View File

@ -13,14 +13,10 @@
-(id)initWithPeerInfo:(SOSPeerInfoRef)peerInfo
{
self = [super init];
if (!self) {
return self;
if ((self = [super init])) {
self.rawPeerInfo = CFRetainSafe(peerInfo);
self.applicantUIState = ApplicantWaiting;
}
self.rawPeerInfo = CFRetainSafe(peerInfo);
self.applicantUIState = ApplicantWaiting;
return self;
}

View File

@ -31,8 +31,7 @@
#import <CloudServices/SecureBackup.h>
#import <CoreFoundation/CFUserNotification.h>
#import <Foundation/Foundation.h>
#import <ManagedConfiguration/MCProfileConnection.h>
#import <ManagedConfiguration/MCFeatures.h>
#import <ManagedConfiguration/ManagedConfiguration.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <MobileCoreServices/LSApplicationWorkspace.h>
#import <MobileGestalt.h>
@ -144,6 +143,8 @@ static void keybagDidUnlock()
NSError *localError = nil;
CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair];
CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init];
secnotice("followup", "Posting a follow up (for SOS) of type repair");
[cdpd postFollowUpWithContext:context error:&localError ];
secnotice("cjr", "account is icdp");
if(localError){
@ -628,6 +629,8 @@ static void kickOutChoice(CFUserNotificationRef userNotification, CFOptionFlags
CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init];
NSError *localError = nil;
CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair];
secnotice("followup", "Posting a follow up (for SOS) of type repair");
[cdpd postFollowUpWithContext:context error:&localError ];
if(localError){
secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError);
@ -772,6 +775,8 @@ static void askForCDPFollowup() {
NSError *localError = nil;
CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init];
CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair];
secnotice("followup", "Posting a follow up (for SOS) of type repair");
[cdpd postFollowUpWithContext:context error:&localError ];
if(localError){
secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError);
@ -910,6 +915,8 @@ static bool processEvents()
NSError *localError = nil;
CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init];
CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair];
secnotice("followup", "Posting a follow up (for SOS) of type repair");
[cdpd postFollowUpWithContext:context error:&localError ];
if(localError){
secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError);

0
ISACLProtectedItems/KeychainItemsAclTest.sh Normal file → Executable file
View File

View File

@ -31,9 +31,7 @@
}
- (instancetype)init {
self = [super init];
if (self) {
if ((self = [super init])) {
XPCNotificationDispatcher* dispatcher = [XPCNotificationDispatcher dispatcher];
_queue = dispatch_queue_create("CKDAKSLockMonitor", NULL);
@ -86,6 +84,7 @@
}
- (void) _onqueueRecheck {
dispatch_assert_queue(_queue);
CFErrorRef aksError = NULL;
bool locked = true; // Assume locked if we get an error

View File

@ -40,12 +40,10 @@
#include "keychain/SecureObjectSync/SOSARCDefines.h"
#include "keychain/SecureObjectSync/SOSKVSKeys.h"
#include <utilities/SecCFWrappers.h>
#include <utilities/SecPLWrappers.h>
#include "SOSCloudKeychainConstants.h"
#include <utilities/SecAKSWrappers.h>
#include <utilities/SecADWrapper.h>
#include <utilities/SecNSAdditions.h>
#import "XPCNotificationDispatcher.h"
@ -202,7 +200,7 @@ static NSString *kMonitorWroteInTimeSlice = @"TimeSlice";
}
- (void)synchronizeStore {
[self.store pushWrites];
[self.store pushWrites:[NSArray array] requiresForceSync:YES];
}
- (id) objectForKey: (NSString*) key {
@ -336,9 +334,9 @@ static NSString *kMonitorWroteInTimeSlice = @"TimeSlice";
[[self store] addOneToOutGoing];
[self.store setObject:obj forKey:key];
}
}];
}];
[self.store pushWrites];
[self.store pushWrites:[mutableValues allKeys] requiresForceSync:NO];
}
- (void)setObjectsFromDictionary:(NSDictionary<NSString*, NSObject*> *)values

View File

@ -25,7 +25,7 @@
- (NSDictionary<NSString *, id>*) copyAsDictionary;
- (void)pushWrites;
- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync;
- (BOOL)pullUpdates:(NSError**) failure;
- (void)kvsStoreChanged: (NSNotification*) notification;

View File

@ -19,6 +19,9 @@
#import "Analytics/Clients/SOSAnalytics.h"
#include "keychain/SecureObjectSync/SOSKVSKeys.h"
#include <Security/OTConstants.h>
struct CKDKVSCounters {
uint64_t synchronize;
uint64_t synchronizeWithCompletionHandler;
@ -29,8 +32,6 @@ struct CKDKVSCounters {
uint64_t synchronizeFailures;
};
@interface CKDKVSStore ()
@property (readwrite, weak) UbiqitousKVSProxy* proxy;
@property (readwrite) NSUbiquitousKeyValueStore* cloudStore;
@ -45,20 +46,20 @@ struct CKDKVSCounters {
}
- (instancetype)init {
self = [super init];
if ((self = [super init])) {
self->_cloudStore = [NSUbiquitousKeyValueStore defaultStore];
self->_proxy = nil;
self->_cloudStore = [NSUbiquitousKeyValueStore defaultStore];
self->_proxy = nil;
if (!self.cloudStore) {
secerror("NO NSUbiquitousKeyValueStore defaultStore!!!");
return nil;
if (!self.cloudStore) {
secerror("NO NSUbiquitousKeyValueStore defaultStore!!!");
return nil;
}
self.perfQueue = dispatch_queue_create("CKDKVSStorePerfQueue", NULL);
self.perfCounters = calloc(1, sizeof(struct CKDKVSCounters));
[self setupSamplers];
}
self.perfQueue = dispatch_queue_create("CKDKVSStorePerfQueue", NULL);
self.perfCounters = calloc(1, sizeof(struct CKDKVSCounters));
[self setupSamplers];
return self;
}
@ -106,13 +107,70 @@ struct CKDKVSCounters {
}];
}
- (void)pushWrites {
[[self cloudStore] synchronize];
- (void)forceSynchronizeWithKVS
{
secnoticeq("pushWrites", "requesting force synchronization with KVS on CloudKit");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSError *error = nil;
bool success = [self pullUpdates:&error];
if(!success || error != nil) {
secerror("pushWrites: failed to synchronize with KVS: %@", error);
} else {
secnoticeq("pushWrites", "successfully synced with KVS!");
}
});
dispatch_async(self.perfQueue, ^{
self.perfCounters->synchronize++;
});
}
- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync
{
secnoticeq("pushWrites", "Push writes");
if (SecKVSOnCloudKitIsEnabled() == NO) {
secnoticeq("pushWrites", "KVS on CloudKit not enabled");
[[self cloudStore] synchronize];
dispatch_async(self.perfQueue, ^{
self.perfCounters->synchronize++;
});
return;
}
if(requiresForceSync == YES) {
secnoticeq("pushWrites", "requested to force synchronize");
[self forceSynchronizeWithKVS];
return;
}
//if KVS on CK is enabled we should only force sync rings, circles, and key parameters
secnoticeq("pushWrites", "KVS on CloudKit enabled. Evaluating changed keys");
if (keys == nil || [keys count] == 0){
secnoticeq("pushWrites", "key set is empty, returning");
return;
}
__block BOOL proceedWithSync = NO;
[keys enumerateObjectsUsingBlock:^(NSString *kvsKey, NSUInteger idx, BOOL *stop) {
if ([kvsKey containsString:(__bridge_transfer NSString*)sRingPrefix] ||
[kvsKey containsString:(__bridge_transfer NSString*)sCirclePrefix] ||
[kvsKey containsString:(__bridge_transfer NSString*)kSOSKVSKeyParametersKey]) {
proceedWithSync = YES;
}
}];
if (proceedWithSync == NO) {
secnoticeq("pushWrites", "no keys to force push, returning");
return;
}
[self forceSynchronizeWithKVS];
}
// Runs on the same thread that posted the notification, and that thread _may_ be the
// kdkvsproxy_queue (see 30470419). Avoid deadlock by bouncing through global queue.
- (void)kvsStoreChangedAsync:(NSNotification *)notification
@ -217,8 +275,10 @@ struct CKDKVSCounters {
self.perfCounters->synchronize++;
});
secnotice("fresh", "%s RETURNING FROM syncdefaultsd SWCH: %@", kWAIT2MINID, self);
[[self cloudStore] synchronize]; // Per olivier in <rdar://problem/13412631>, sync before getting values
secnotice("fresh", "%s RETURNING FROM syncdefaultsd SYNC: %@", kWAIT2MINID, self);
if(SecKVSOnCloudKitIsEnabled() == NO) {
[[self cloudStore] synchronize]; // Per olivier in <rdar://problem/13412631>, sync before getting values
secnotice("fresh", "%s RETURNING FROM syncdefaultsd SYNC: %@", kWAIT2MINID, self);
}
}
dispatch_semaphore_signal(freshSemaphore);
}];

View File

@ -22,7 +22,7 @@
- (NSDictionary<NSString *, id>*) copyAsDictionary;
- (void)pushWrites;
- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync;
- (BOOL)pullUpdates:(NSError**) failure;
- (void)perfCounters:(void(^)(NSDictionary *counters))callback;

View File

@ -61,9 +61,7 @@ static const char *kXPCNotificationNameKey = "Notification";
}
- (instancetype) init {
self = [super init];
if (self) {
if ((self = [super init])) {
self.queue = dispatch_queue_create("XPC Notification Dispatch", DISPATCH_QUEUE_SERIAL);
self.listeners = [NSPointerArray weakObjectsPointerArray];
__weak typeof(self) weakSelf = self;

View File

@ -70,51 +70,128 @@
#import "CKDSecuritydAccount.h"
#import "CKDKVSStore.h"
#import "CKDAKSLockMonitor.h"
#import "SOSCloudKeychainConstants.h"
#include <utilities/simulatecrash_assert.h>
void finalize_connection(void *not_used);
void handle_connection_event(const xpc_connection_t peer);
static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event);
static bool operation_put_dictionary(xpc_object_t event);
static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event);
int ckdproxymain(int argc, const char *argv[]);
#define PROXYXPCSCOPE "xpcproxy"
static void describeXPCObject(char *prefix, xpc_object_t object)
{
//#ifndef NDEBUG
// This is useful for debugging.
if (object)
{
char *desc = xpc_copy_description(object);
secdebug(PROXYXPCSCOPE, "%s%s\n", prefix, desc);
free(desc);
}
else
secdebug(PROXYXPCSCOPE, "%s<NULL>\n", prefix);
@interface CloudKeychainProxy : NSObject
-(id _Nullable) init;
//#endif
@property (nonatomic, retain) UbiqitousKVSProxy *proxyID;
@property (nonatomic, retain) xpc_connection_t listener;
@property (nonatomic, retain) dispatch_source_t sigterm_source;
@property (nonatomic, retain) NSURL *registrationFileName;
+ (CloudKeychainProxy *) sharedObject;
- (void) cloudkeychainproxy_peer_dictionary_handler: (const xpc_connection_t) peer forEvent: (xpc_object_t) event;
@end
static void cloudkeychainproxy_event_handler(xpc_connection_t peer)
{
if (xpc_get_type(peer) != XPC_TYPE_CONNECTION) {
secinfo(PROXYXPCSCOPE, "expected XPC_TYPE_CONNECTION");
return;
}
xpc_object_t ent = xpc_connection_copy_entitlement_value(peer, "com.apple.CloudKeychainProxy.client");
if (ent == NULL || xpc_get_type(ent) != XPC_TYPE_BOOL || xpc_bool_get_value(ent) != true) {
secnotice(PROXYXPCSCOPE, "cloudkeychainproxy_event_handler: rejected client %d", xpc_connection_get_pid(peer));
xpc_connection_cancel(peer);
return;
}
xpc_connection_set_target_queue(peer, [[CloudKeychainProxy sharedObject].proxyID ckdkvsproxy_queue]);
xpc_connection_set_event_handler(peer, ^(xpc_object_t event)
{
// We could handle other peer events (e.g.) disconnects,
// but we don't keep per-client state so there is no need.
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
[[CloudKeychainProxy sharedObject] cloudkeychainproxy_peer_dictionary_handler: peer forEvent: event];
}
});
// This will tell the connection to begin listening for events. If you
// have some other initialization that must be done asynchronously, then
// you can defer this call until after that initialization is done.
xpc_connection_resume(peer);
}
static NSObject *CreateNSObjectForCFXPCObjectFromKey(xpc_object_t xdict, const char * _Nonnull key)
{
xpc_object_t xObj = xpc_dictionary_get_value(xdict, key);
static void finalize_connection(void *not_used) {
secinfo(PROXYXPCSCOPE, "finalize_connection");
[[CloudKeychainProxy sharedObject].proxyID synchronizeStore];
xpc_transaction_end();
}
@implementation CloudKeychainProxy
static CFStringRef kRegistrationFileName = CFSTR("com.apple.security.cloudkeychainproxy3.keysToRegister.plist");
+ (CloudKeychainProxy *) sharedObject {
static CloudKeychainProxy *sharedCKP = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedCKP = [CloudKeychainProxy new];
});
return sharedCKP;
}
-(id _Nullable) init {
if ((self = [super init])) {
_registrationFileName = (NSURL *)CFBridgingRelease(SecCopyURLForFileInPreferencesDirectory(kRegistrationFileName));
_proxyID = [UbiqitousKVSProxy withAccount: [CKDSecuritydAccount securitydAccount]
store: [CKDKVSStore kvsInterface]
lockMonitor: [CKDAKSLockMonitor monitor]
persistence: _registrationFileName];
_listener = xpc_connection_create_mach_service(kCKPServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
xpc_connection_set_finalizer_f(_listener, finalize_connection);
xpc_connection_set_event_handler(_listener, ^(xpc_object_t object){ cloudkeychainproxy_event_handler(object); });
// It looks to me like there is insufficient locking to allow a request to come in on the XPC connection while doing the initial all items.
// Therefore I'm leaving the XPC connection suspended until that has time to process.
xpc_connection_resume(_listener);
(void)signal(SIGTERM, SIG_IGN);
_sigterm_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGTERM, 0, _proxyID.ckdkvsproxy_queue);
dispatch_source_set_event_handler(_sigterm_source, ^{
secnotice(PROXYXPCSCOPE, "exiting due to SIGTERM");
xpc_transaction_exit_clean();
});
dispatch_activate(_sigterm_source);
}
return self;
}
- (void) describeXPCObject: (char *) prefix withObject: (xpc_object_t) object {
if(object) {
char *desc = xpc_copy_description(object);
secinfo(PROXYXPCSCOPE, "%s%s", prefix, desc);
free(desc);
} else {
secinfo(PROXYXPCSCOPE, "%s<NULL>", prefix);
}
}
- (NSObject *) CreateNSObjectForCFXPCObjectFromKey: (xpc_object_t) xdict withKey: (const char * _Nonnull) key {
xpc_object_t xObj = xpc_dictionary_get_value(xdict, key);
if (!xObj) {
return nil;
}
return (__bridge_transfer NSObject *)(_CFXPCCreateCFObjectFromXPCObject(xObj));
}
static NSArray<NSString*> *CreateArrayOfStringsForCFXPCObjectFromKey(xpc_object_t xdict, const char * _Nonnull key) {
NSObject * possibleArray = CreateNSObjectForCFXPCObjectFromKey(xdict, key);
- (NSArray<NSString*> *) CreateArrayOfStringsForCFXPCObjectFromKey: (xpc_object_t) xdict withKey: (const char * _Nonnull) key {
NSObject * possibleArray = [self CreateNSObjectForCFXPCObjectFromKey: xdict withKey: key];
if (![possibleArray isNSArray__])
if (![possibleArray isNSArray__]) {
return nil;
}
__block bool onlyStrings = true;
[(NSArray*) possibleArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
@ -127,208 +204,187 @@ static NSArray<NSString*> *CreateArrayOfStringsForCFXPCObjectFromKey(xpc_object_
return onlyStrings ? (NSArray<NSString*>*) possibleArray : nil;
}
static CFStringRef kRegistrationFileName = CFSTR("com.apple.security.cloudkeychainproxy3.keysToRegister.plist");
static UbiqitousKVSProxy *SharedProxy(void) {
static UbiqitousKVSProxy *sProxy = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sProxy = [UbiqitousKVSProxy withAccount: [CKDSecuritydAccount securitydAccount]
store: [CKDKVSStore kvsInterface]
lockMonitor: [CKDAKSLockMonitor monitor]
persistence: (NSURL *)CFBridgingRelease(SecCopyURLForFileInPreferencesDirectory(kRegistrationFileName))];
});
return sProxy;
}
static void sendAckResponse(const xpc_connection_t peer, xpc_object_t event) {
- (void) sendAckResponse: (const xpc_connection_t) peer forEvent: (xpc_object_t) event {
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
if (replyMessage) // Caller wanted an ACK, so give one
{
if (replyMessage) { // Caller wanted an ACK, so give one
xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK");
xpc_connection_send_message(peer, replyMessage);
}
}
static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event)
{
- (void) cloudkeychainproxy_peer_dictionary_handler: (const xpc_connection_t) peer forEvent: (xpc_object_t) event {
bool result = false;
int err = 0;
require_action_string(xpc_get_type(event) == XPC_TYPE_DICTIONARY, xit, err = -51, "expected XPC_TYPE_DICTIONARY");
@autoreleasepool {
const char *operation = xpc_dictionary_get_string(event, kMessageKeyOperation);
require_action(operation, xit, result = false);
require_action_string(xpc_get_type(event) == XPC_TYPE_DICTIONARY, xit, err = -51, "expected XPC_TYPE_DICTIONARY");
// Check protocol version
uint64_t version = xpc_dictionary_get_uint64(event, kMessageKeyVersion);
secdebug(PROXYXPCSCOPE, "Reply version: %lld\n", version);
require_action(version == kCKDXPCVersion, xit, result = false);
const char *operation = xpc_dictionary_get_string(event, kMessageKeyOperation);
require_action(operation, xit, result = false);
// Operations
secdebug(PROXYXPCSCOPE, "Handling %s operation", operation);
// Check protocol version
uint64_t version = xpc_dictionary_get_uint64(event, kMessageKeyVersion);
secinfo(PROXYXPCSCOPE, "Reply version: %lld", version);
require_action(version == kCKDXPCVersion, xit, result = false);
// Operations
secinfo(PROXYXPCSCOPE, "Handling %s operation", operation);
if (!strcmp(operation, kOperationPUTDictionary))
{
operation_put_dictionary(event);
sendAckResponse(peer, event);
}
else if (!strcmp(operation, kOperationGETv2))
{
operation_get_v2(peer, event);
// operationg_get_v2 sends the response
}
else if (!strcmp(operation, kOperationClearStore))
{
[SharedProxy() clearStore];
sendAckResponse(peer, event);
}
else if (!strcmp(operation, kOperationSynchronize))
{
[SharedProxy() synchronizeStore];
sendAckResponse(peer, event);
}
else if (!strcmp(operation, kOperationSynchronizeAndWait))
{
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
secnotice(XPROXYSCOPE, "%s XPC request: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
[SharedProxy() waitForSynchronization:^(__unused NSDictionary *values, NSError *error)
{
secnotice(PROXYXPCSCOPE, "%s Result from [Proxy waitForSynchronization:]: %@", kWAIT2MINID, error);
if (replyMessage) // Caller wanted an ACK, so give one
{
if (error)
{
xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error));
xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj);
} else {
xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK");
}
xpc_connection_send_message(peer, replyMessage);
}
}];
}
else if (!strcmp(operation, kOperationRegisterKeys))
{
xpc_object_t xkeysToRegisterDict = xpc_dictionary_get_value(event, kMessageKeyValue);
xpc_object_t xKTRallkeys = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageAllKeys);
NSString* accountUUID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyAccountUUID);
if (![accountUUID isKindOfClass:[NSString class]]) {
accountUUID = nil;
}
NSDictionary *KTRallkeys = (__bridge_transfer NSDictionary *)(_CFXPCCreateCFObjectFromXPCObject(xKTRallkeys));
[SharedProxy() registerKeys: KTRallkeys forAccount: accountUUID];
sendAckResponse(peer, event);
secdebug(PROXYXPCSCOPE, "RegisterKeys message sent");
}
else if (!strcmp(operation, kOperationRemoveKeys))
{
xpc_object_t xkeysToRemoveDict = xpc_dictionary_get_value(event, kMessageKeyValue);
NSString* accountUUID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyAccountUUID);
if (![accountUUID isKindOfClass:[NSString class]]) {
accountUUID = nil;
}
NSArray *KTRallkeys = (__bridge_transfer NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xkeysToRemoveDict));
[SharedProxy() removeKeys:KTRallkeys forAccount:accountUUID];
sendAckResponse(peer, event);
secdebug(PROXYXPCSCOPE, "RemoveKeys message sent");
}
else if (!strcmp(operation, kOperationRequestSyncWithPeers))
{
NSArray<NSString*> * peerIDs = CreateArrayOfStringsForCFXPCObjectFromKey(event, kMessageKeyPeerIDList);
NSArray<NSString*> * backupPeerIDs = CreateArrayOfStringsForCFXPCObjectFromKey(event, kMesssgeKeyBackupPeerIDList);
require_action(peerIDs && backupPeerIDs, xit, (secnotice(XPROXYSCOPE, "Bad call to sync with peers"), result = false));
[SharedProxy() requestSyncWithPeerIDs: peerIDs backupPeerIDs: backupPeerIDs];
sendAckResponse(peer, event);
secdebug(PROXYXPCSCOPE, "RequestSyncWithAllPeers reply sent");
}
else if (!strcmp(operation, kOperationHasPendingSyncWithPeer)) {
NSString *peerID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyPeerID);
BOOL hasPending = [SharedProxy() hasSyncPendingFor: peerID];
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
if (replyMessage)
if (!strcmp(operation, kOperationPUTDictionary))
{
xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
xpc_connection_send_message(peer, replyMessage);
secdebug(PROXYXPCSCOPE, "HasPendingSyncWithPeer reply sent");
[self operation_put_dictionary: event];
[self sendAckResponse: peer forEvent: event];
}
}
else if (!strcmp(operation, kOperationHasPendingKey)) {
NSString *peerID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyPeerID);
BOOL hasPending = [SharedProxy() hasPendingKey: peerID];
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
if (replyMessage)
else if (!strcmp(operation, kOperationGETv2))
{
xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
xpc_connection_send_message(peer, replyMessage);
secdebug(PROXYXPCSCOPE, "HasIncomingMessageFromPeer reply sent");
[self operation_get_v2: peer forEvent: event];
// operationg_get_v2 sends the response
}
}
else if (!strcmp(operation, kOperationRequestEnsurePeerRegistration))
{
[SharedProxy() requestEnsurePeerRegistration];
sendAckResponse(peer, event);
secdebug(PROXYXPCSCOPE, "RequestEnsurePeerRegistration reply sent");
}
else if (!strcmp(operation, kOperationFlush))
{
[SharedProxy() doAfterFlush:^{
sendAckResponse(peer, event);
secdebug(PROXYXPCSCOPE, "flush reply sent");
}];
}
else if (!strcmp(operation, kOperationPerfCounters)) {
[SharedProxy() perfCounters:^(NSDictionary *counters){
else if (!strcmp(operation, kOperationClearStore))
{
[_proxyID clearStore];
[self sendAckResponse: peer forEvent: event];
}
else if (!strcmp(operation, kOperationSynchronize))
{
[_proxyID synchronizeStore];
[self sendAckResponse: peer forEvent: event];
}
else if (!strcmp(operation, kOperationSynchronizeAndWait))
{
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
xpc_object_t object = _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)counters);
xpc_dictionary_set_value(replyMessage, kMessageKeyValue, object);
xpc_connection_send_message(peer, replyMessage);
}];
}
else
{
char *description = xpc_copy_description(event);
secdebug(PROXYXPCSCOPE, "Unknown op=%s request from pid %d: %s", operation, xpc_connection_get_pid(peer), description);
free(description);
}
result = true;
secnotice(XPROXYSCOPE, "%s XPC request: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
[_proxyID waitForSynchronization:^(__unused NSDictionary *values, NSError *error)
{
secnotice(PROXYXPCSCOPE, "%s Result from [Proxy waitForSynchronization:]: %@", kWAIT2MINID, error);
if (replyMessage) // Caller wanted an ACK, so give one
{
if (error)
{
xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error));
xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj);
} else {
xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK");
}
xpc_connection_send_message(peer, replyMessage);
}
}];
}
else if (!strcmp(operation, kOperationRegisterKeys))
{
xpc_object_t xkeysToRegisterDict = xpc_dictionary_get_value(event, kMessageKeyValue);
xpc_object_t xKTRallkeys = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageAllKeys);
NSString* accountUUID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey:event withKey: kMessageKeyAccountUUID];
if (![accountUUID isKindOfClass:[NSString class]]) {
accountUUID = nil;
}
NSDictionary *KTRallkeys = (__bridge_transfer NSDictionary *)(_CFXPCCreateCFObjectFromXPCObject(xKTRallkeys));
[_proxyID registerKeys: KTRallkeys forAccount: accountUUID];
[self sendAckResponse: peer forEvent: event];
secinfo(PROXYXPCSCOPE, "RegisterKeys message sent");
}
else if (!strcmp(operation, kOperationRemoveKeys))
{
xpc_object_t xkeysToRemoveDict = xpc_dictionary_get_value(event, kMessageKeyValue);
NSString* accountUUID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey: event withKey: kMessageKeyAccountUUID];
if (![accountUUID isKindOfClass:[NSString class]]) {
accountUUID = nil;
}
NSArray *KTRallkeys = (__bridge_transfer NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xkeysToRemoveDict));
[_proxyID removeKeys:KTRallkeys forAccount:accountUUID];
[self sendAckResponse: peer forEvent: event];
secinfo(PROXYXPCSCOPE, "RemoveKeys message sent");
}
else if (!strcmp(operation, kOperationRequestSyncWithPeers))
{
NSArray<NSString*> * peerIDs = [self CreateArrayOfStringsForCFXPCObjectFromKey: event withKey: kMessageKeyPeerIDList];
NSArray<NSString*> * backupPeerIDs = [self CreateArrayOfStringsForCFXPCObjectFromKey: event withKey: kMesssgeKeyBackupPeerIDList];
require_action(peerIDs && backupPeerIDs, xit, (secnotice(XPROXYSCOPE, "Bad call to sync with peers"), result = false));
[_proxyID requestSyncWithPeerIDs: peerIDs backupPeerIDs: backupPeerIDs];
[self sendAckResponse: peer forEvent: event];
secinfo(PROXYXPCSCOPE, "RequestSyncWithAllPeers reply sent");
}
else if (!strcmp(operation, kOperationHasPendingSyncWithPeer)) {
NSString *peerID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey: event withKey: kMessageKeyPeerID];
BOOL hasPending = [_proxyID hasSyncPendingFor: peerID];
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
if (replyMessage)
{
xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
xpc_connection_send_message(peer, replyMessage);
secinfo(PROXYXPCSCOPE, "HasPendingSyncWithPeer reply sent");
}
}
else if (!strcmp(operation, kOperationHasPendingKey)) {
NSString *peerID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey: event withKey: kMessageKeyPeerID];
BOOL hasPending = [_proxyID hasPendingKey: peerID];
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
if (replyMessage)
{
xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
xpc_connection_send_message(peer, replyMessage);
secinfo(PROXYXPCSCOPE, "HasIncomingMessageFromPeer reply sent");
}
}
else if (!strcmp(operation, kOperationRequestEnsurePeerRegistration))
{
[_proxyID requestEnsurePeerRegistration];
[self sendAckResponse: peer forEvent: event];
secinfo(PROXYXPCSCOPE, "RequestEnsurePeerRegistration reply sent");
}
else if (!strcmp(operation, kOperationFlush))
{
[_proxyID doAfterFlush:^{
[self sendAckResponse: peer forEvent: event];
secinfo(PROXYXPCSCOPE, "flush reply sent");
}];
}
else if (!strcmp(operation, kOperationPerfCounters)) {
[_proxyID perfCounters:^(NSDictionary *counters){
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
xpc_object_t object = _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)counters);
xpc_dictionary_set_value(replyMessage, kMessageKeyValue, object);
xpc_connection_send_message(peer, replyMessage);
}];
}
else
{
char *description = xpc_copy_description(event);
secinfo(PROXYXPCSCOPE, "Unknown op=%s request from pid %d: %s", operation, xpc_connection_get_pid(peer), description);
free(description);
}
result = true;
xit:
if (!result)
describeXPCObject("handle_operation fail: ", event);
if (!result) {
[self describeXPCObject: "handle_operation fail: " withObject: event];
}
}
}
void finalize_connection(void *not_used)
{
secdebug(PROXYXPCSCOPE, "finalize_connection");
[SharedProxy() synchronizeStore];
xpc_transaction_end();
}
static bool operation_put_dictionary(xpc_object_t event)
{
- (bool) operation_put_dictionary: (xpc_object_t) event {
// PUT a set of objects into the KVS store. Return false if error
xpc_object_t xvalue = xpc_dictionary_get_value(event, kMessageKeyValue);
if (!xvalue) {
@ -337,29 +393,28 @@ static bool operation_put_dictionary(xpc_object_t event)
NSObject* object = (__bridge_transfer NSObject*) _CFXPCCreateCFObjectFromXPCObject(xvalue);
if (![object isKindOfClass:[NSDictionary<NSString*, NSObject*> class]]) {
describeXPCObject("operation_put_dictionary unable to convert to CF: ", xvalue);
[self describeXPCObject: "operation_put_dictionary unable to convert to CF: " withObject: xvalue];
return false;
}
[SharedProxy() setObjectsFromDictionary: (NSDictionary<NSString*, NSObject*> *)object];
[_proxyID setObjectsFromDictionary: (NSDictionary<NSString*, NSObject*> *)object];
return true;
}
static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
{
- (bool) operation_get_v2: (xpc_connection_t) peer forEvent: (xpc_object_t) event {
// GET a set of objects from the KVS store. Return false if error
xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
if (!replyMessage)
{
secdebug(PROXYXPCSCOPE, "can't create replyMessage");
secinfo(PROXYXPCSCOPE, "can't create replyMessage");
assert(false); //must have a reply handler
return false;
}
xpc_object_t returnedValues = xpc_dictionary_create(NULL, NULL, 0);
if (!returnedValues)
{
secdebug(PROXYXPCSCOPE, "can't create returnedValues");
secinfo(PROXYXPCSCOPE, "can't create returnedValues");
assert(false); // must have a spot for the returned values
return false;
}
@ -367,18 +422,18 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
xpc_object_t xvalue = xpc_dictionary_get_value(event, kMessageKeyValue);
if (!xvalue)
{
secdebug(PROXYXPCSCOPE, "missing \"value\" key");
secinfo(PROXYXPCSCOPE, "missing \"value\" key");
return false;
}
xpc_object_t xkeystoget = xpc_dictionary_get_value(xvalue, kMessageKeyKeysToGet);
if (xkeystoget)
{
secdebug(PROXYXPCSCOPE, "got xkeystoget");
secinfo(PROXYXPCSCOPE, "got xkeystoget");
CFTypeRef keystoget = _CFXPCCreateCFObjectFromXPCObject(xkeystoget);
if (!keystoget || (CFGetTypeID(keystoget)!=CFArrayGetTypeID())) // not "getAll", this is an error of some kind
{
secdebug(PROXYXPCSCOPE, "can't convert keystoget or is not an array");
secinfo(PROXYXPCSCOPE, "can't convert keystoget or is not an array");
CFReleaseSafe(keystoget);
return false;
}
@ -386,16 +441,16 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
[(__bridge NSArray *)keystoget enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL *stop)
{
NSString *key = (NSString *)obj;
id object = [SharedProxy() objectForKey:key];
secdebug(PROXYXPCSCOPE, "get: key: %@, object: %@", key, object);
id object = [_proxyID objectForKey:key];
secinfo(PROXYXPCSCOPE, "get: key: %@, object: %@", key, object);
xpc_object_t xobject = object ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)object) : xpc_null_create();
xpc_dictionary_set_value(returnedValues, [key UTF8String], xobject);
}];
}
else // get all values from kvs
{
secdebug(PROXYXPCSCOPE, "get all values from kvs");
NSDictionary *all = [SharedProxy() copyAsDictionary];
secinfo(PROXYXPCSCOPE, "get all values from kvs");
NSDictionary *all = [_proxyID copyAsDictionary];
[all enumerateKeysAndObjectsUsingBlock: ^ (id key, id obj, BOOL *stop)
{
xpc_object_t xobject = obj ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)obj) : xpc_null_create();
@ -410,53 +465,23 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
return true;
}
static void cloudkeychainproxy_event_handler(xpc_connection_t peer)
{
if (xpc_get_type(peer) != XPC_TYPE_CONNECTION)
{
secdebug(PROXYXPCSCOPE, "expected XPC_TYPE_CONNECTION");
return;
}
xpc_object_t ent = xpc_connection_copy_entitlement_value(peer, "com.apple.CloudKeychainProxy.client");
if (ent == NULL || xpc_get_type(ent) != XPC_TYPE_BOOL || xpc_bool_get_value(ent) != true) {
secnotice(PROXYXPCSCOPE, "cloudkeychainproxy_event_handler: rejected client %d", xpc_connection_get_pid(peer));
xpc_connection_cancel(peer);
return;
}
@end
xpc_connection_set_target_queue(peer, [SharedProxy() ckdkvsproxy_queue]);
xpc_connection_set_event_handler(peer, ^(xpc_object_t event)
{
// We could handle other peer events (e.g.) disconnects,
// but we don't keep per-client state so there is no need.
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
cloudkeychainproxy_peer_dictionary_handler(peer, event);
}
});
// This will tell the connection to begin listening for events. If you
// have some other initialization that must be done asynchronously, then
// you can defer this call until after that initialization is done.
xpc_connection_resume(peer);
}
static void diagnostics(int argc, const char *argv[])
{
@autoreleasepool
{
NSDictionary *all = [SharedProxy() copyAsDictionary];
static void diagnostics(int argc, const char *argv[]) {
@autoreleasepool {
NSDictionary *all = [[CloudKeychainProxy sharedObject].proxyID copyAsDictionary];
NSLog(@"All: %@",all);
}
}
int ckdproxymain(int argc, const char *argv[])
{
secdebug(PROXYXPCSCOPE, "Starting CloudKeychainProxy");
int main(int argc, const char *argv[]) {
secinfo(PROXYXPCSCOPE, "Starting CloudKeychainProxy");
char *wait4debugger = getenv("WAIT4DEBUGGER");
if (wait4debugger && !strcasecmp("YES", wait4debugger))
{
if (wait4debugger && !strcasecmp("YES", wait4debugger)) {
syslog(LOG_ERR, "Waiting for debugger");
kill(getpid(), SIGTSTP);
}
@ -466,30 +491,17 @@ int ckdproxymain(int argc, const char *argv[])
return 0;
}
UbiqitousKVSProxy* proxyID = SharedProxy();
if (proxyID) { // nothing bad happened when initializing
xpc_connection_t listener = xpc_connection_create_mach_service(kCKPServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
xpc_connection_set_event_handler(listener, ^(xpc_object_t object){ cloudkeychainproxy_event_handler(object); });
// It looks to me like there is insufficient locking to allow a request to come in on the XPC connection while doing the initial all items.
// Therefore I'm leaving the XPC connection suspended until that has time to process.
xpc_connection_resume(listener);
@autoreleasepool
{
secdebug(PROXYXPCSCOPE, "Starting mainRunLoop");
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[runLoop run];
}
CloudKeychainProxy *ckp = nil;
@autoreleasepool {
ckp = [CloudKeychainProxy sharedObject];
}
secdebug(PROXYXPCSCOPE, "Exiting CloudKeychainProxy");
if (ckp) { // nothing bad happened when initializing
secinfo(PROXYXPCSCOPE, "Starting mainRunLoop");
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[runLoop run];
}
secinfo(PROXYXPCSCOPE, "Exiting CloudKeychainProxy");
return EXIT_FAILURE;
}
int main(int argc, const char *argv[])
{
return ckdproxymain(argc, argv);
}

View File

@ -162,29 +162,28 @@ static NSString* KCDSEpoch= @"epoch";
freeWhenDone: false];
});
self = [super init];
if ((self = [super init])) {
self.asSender = sender;
self.secret = sharedSecret;
self.send = malloc(ccgcm_context_size(ccaes_gcm_encrypt_mode()));
self.receive = malloc(ccgcm_context_size(ccaes_gcm_decrypt_mode()));
self.context = context;
self.asSender = sender;
self.secret = sharedSecret;
self.send = malloc(ccgcm_context_size(ccaes_gcm_encrypt_mode()));
self.receive = malloc(ccgcm_context_size(ccaes_gcm_decrypt_mode()));
self.context = context;
_pairingUUID = pairingUUID;
_piggybackingVersion = piggybackingVersion;
_epoch = epoch;
_pairingUUID = pairingUUID;
_piggybackingVersion = piggybackingVersion;
_epoch = epoch;
if (self.send == nil || self.receive == nil) {
return nil;
}
if (self.send == nil || self.receive == nil) {
return nil;
derive_and_init(ccaes_gcm_encrypt_mode(),
self.send, self.secret,
sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
derive_and_init(ccaes_gcm_decrypt_mode(),
self.receive, self.secret,
!sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
}
derive_and_init(ccaes_gcm_encrypt_mode(),
self.send, self.secret,
sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
derive_and_init(ccaes_gcm_decrypt_mode(),
self.receive, self.secret,
!sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
return self;
}

View File

@ -18,6 +18,8 @@ typedef enum {
kUnexpectedMessage,
kInternalError,
kDERUnknownVersion,
kProcessApplicationFailure,
kUnsupportedTrustPlatform,
} KCJoiningError;
@interface NSError(KCJoiningError)

View File

@ -31,6 +31,9 @@
#import "KCJoiningSession.h"
@interface KCJoiningAcceptSession (Internal)
- (KCAESGCMDuplexSession*)accessSession;
-(void)setControlObject:(OTControl*)control;
- (void)setConfiguration:(OTJoiningConfiguration *)config;
@end

View File

@ -20,7 +20,6 @@
#include <corecrypto/ccsha2.h>
#include <corecrypto/ccdh_gp.h>
#include <utilities/debugging.h>
#include <CommonCrypto/CommonRandomSPI.h>
#include <notify.h>
#if OCTAGON
@ -30,6 +29,9 @@
#import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
#import "keychain/ot/proto/generated_source/OTPairingMessage.h"
#endif
@ -103,38 +105,39 @@ typedef enum {
dsid: (uint64_t) dsid
rng: (struct ccrng_state *)rng
error: (NSError**) error {
self = [super init];
if ((self = [super init])) {
secnotice("accepting", "initWithSecretDelegate");
secnotice("accepting", "initWithSecretDelegate");
NSString* name = [NSString stringWithFormat: @"%llu", dsid];
NSString* name = [NSString stringWithFormat: @"%llu", dsid];
self->_context = [[KCSRPServerContext alloc] initWithUser: name
password: [secretDelegate secret]
digestInfo: ccsha256_di()
group: ccsrp_gp_rfc5054_3072()
randomSource: rng];
self.secretDelegate = secretDelegate;
self.circleDelegate = circleDelegate;
self->_state = kExpectingA;
self->_dsid = dsid;
self->_piggy_uuid = nil;
self->_defaults = [NSMutableDictionary dictionary];
self->_context = [[KCSRPServerContext alloc] initWithUser: name
password: [secretDelegate secret]
digestInfo: ccsha256_di()
group: ccsrp_gp_rfc5054_3072()
randomSource: rng];
self.secretDelegate = secretDelegate;
self.circleDelegate = circleDelegate;
self->_state = kExpectingA;
self->_dsid = dsid;
self->_piggy_uuid = nil;
self->_defaults = [NSMutableDictionary dictionary];
#if OCTAGON
self->_otControl = [OTControl controlObject:true error:error];
self->_piggy_version = KCJoiningOctagonPiggybackingEnabled()? kPiggyV2 : kPiggyV1;
self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
uniqueDeviceID:@"acceptor-deviceid"
uniqueClientID:@"requester-deviceid"
containerName:nil
contextID:OTDefaultContext
epoch:0
isInitiator:false];
self->_otControl = [OTControl controlObject:true error:error];
self->_piggy_version = KCJoiningOctagonPiggybackingEnabled()? kPiggyV2 : kPiggyV1;
self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
uniqueDeviceID:@"acceptor-deviceid"
uniqueClientID:@"requester-deviceid"
pairingUUID:[[NSUUID UUID] UUIDString]
containerName:nil
contextID:OTDefaultContext
epoch:0
isInitiator:false];
#else
self->_piggy_version = kPiggyV1;
self->_piggy_version = kPiggyV1;
#endif
}
return self;
}
@ -242,8 +245,14 @@ typedef enum {
captureError = epochError;
}else{
OTPairingMessage* responseMessage = [[OTPairingMessage alloc] init];
responseMessage.supportsSOS = [[OTSupportSOSMessage alloc] init];
responseMessage.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
responseMessage.epoch = [[OTSponsorToApplicantRound1M2 alloc] init];
responseMessage.epoch.epoch = epoch;
responseMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
responseMessage.supportsOctagon.supported = OTSupportType_supported;
next = responseMessage.data;
}
dispatch_semaphore_signal(sema);
@ -402,7 +411,58 @@ typedef enum {
}
#endif
- (NSData*) createTLKRequestResponse: (NSError**) error {
NSError* localError = NULL;
NSData* initialSync = [self.circleDelegate circleGetInitialSyncViews:kSOSInitialSyncFlagTLKsRequestOnly error:&localError];
if (!initialSync) {
secnotice("joining", "Failed to get initial sync view: %@", localError);
if ( error!=NULL && localError != NULL )
*error = localError;
return nil;
}
NSData* encryptedOutgoing = [self.session encrypt:initialSync error:&localError];
if (!encryptedOutgoing) {
secnotice("joining", "TLK request failed to encrypt: %@", localError);
if ( error!=NULL && localError != NULL )
*error = localError;
return nil;
}
self->_state = kAcceptDone;
secnotice("joining", "TLKRequest done.");
return [[KCJoiningMessage messageWithType:kTLKRequest
data:encryptedOutgoing
error:error] der];
}
- (BOOL)shouldProcessSOSApplication:(KCJoiningMessage*)message pairingMessage:(OTPairingMessage*)pairingMessage
{
BOOL shouldProcess = YES;
if (OctagonPlatformSupportsSOS() == NO) {
secnotice("joining", "platform does not support SOS");
shouldProcess = NO;
} else if (message.secondData == nil) {
secnotice("joining", "message does not contain SOS data");
shouldProcess = NO;
} else if (pairingMessage.hasSupportsSOS && pairingMessage.supportsSOS.supported == OTSupportType_not_supported) {
secnotice("joining", "requester explicitly does not support SOS");
shouldProcess = NO;
}
return shouldProcess;
}
- (NSData*) processApplication: (KCJoiningMessage*) message error:(NSError**) error {
if ([message type] == kTLKRequest) {
return [self createTLKRequestResponse: error];
}
if ([message type] != kPeerInfo) {
KCJoiningErrorCreate(kUnexpectedMessage, error, @"Expected peerInfo!");
return nil;
@ -441,9 +501,14 @@ typedef enum {
localError = err;
}else{
OTPairingMessage *pairingResponse = [[OTPairingMessage alloc] init];
pairingResponse.supportsSOS = [[OTSupportSOSMessage alloc] init];
pairingResponse.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
pairingResponse.voucher = [[OTSponsorToApplicantRound2M2 alloc] init];
pairingResponse.voucher.voucher = voucher;
pairingResponse.voucher.voucherSignature = voucherSig;
pairingMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
pairingMessage.supportsOctagon.supported = OTSupportType_supported;
next = pairingResponse.data;
}
dispatch_semaphore_signal(sema);
@ -461,17 +526,19 @@ typedef enum {
}
NSData* encryptedOutgoing = nil;
if (OctagonPlatformSupportsSOS() && message.secondData) {
if ([self shouldProcessSOSApplication:message pairingMessage:pairingMessage]) {
secnotice("joining", "doing SOS processSOSApplication");
//note we are stuffing SOS into the payload "secondData"
encryptedOutgoing = [self processSOSApplication: message.secondData error:error];
} else {
secnotice("joining", "no platform support processSOSApplication, peer sent data: %s",
message.secondData ? "yes" : "no");
if (encryptedOutgoing == nil) {
secerror("joining: failed to process SOS application: %@", error && *error ? *error : nil);
KCJoiningErrorCreate(kProcessApplicationFailure, error, @"message failed to process application");
return nil;
}
}
self->_state = kAcceptDone;
//note we are stuffing SOS into the payload
return [[KCJoiningMessage messageWithType:kCircleBlob
data:next
payload:encryptedOutgoing
@ -531,6 +598,11 @@ typedef enum {
{
self.joiningConfiguration = config;
}
- (KCAESGCMDuplexSession*)accessSession
{
return self.session;
}
#endif
@end

View File

@ -9,7 +9,7 @@
// Initial messages are versioned and not typed for negotiation.
NS_ASSUME_NONNULL_BEGIN
NSData* extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString* _Nullable * _Nullable uuidString, NSData* _Nullable * _Nullable octagon, NSError** error);
NSData* _Nullable extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString* _Nullable * _Nullable uuidString, NSData* _Nullable * _Nullable octagon, NSError** error);
size_t sizeof_initialmessage(NSData*data);
size_t sizeof_initialmessage_version1(NSData*data, uint64_t version1, NSData *uuid);
@ -84,6 +84,8 @@ typedef enum {
kPeerInfo = 4,
kCircleBlob = 5,
kTLKRequest = 6,
kError = 0,
kUnknown = 255,
@ -109,7 +111,7 @@ typedef enum {
+ (nullable instancetype) messageWithType: (KCJoiningMessageType) type
data: (NSData*) firstData
payload: (NSData*) secondData
payload: (nullable NSData*) secondData
error: (NSError**) error;

View File

@ -32,14 +32,14 @@
+ (nullable instancetype) messageWithType: (KCJoiningMessageType) type
data: (NSData*) firstData
secondData: (NSData*) secondData
secondData: (nullable NSData*) secondData
error: (NSError**) error {
return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error];
}
+ (nullable instancetype) messageWithType: (KCJoiningMessageType) type
data: (NSData*) firstData
payload: (NSData*) secondData
payload: (nullable NSData*) secondData
error: (NSError**) error {
return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error];
@ -140,10 +140,9 @@
- (nullable instancetype) initWithDER: (NSData*) message
error: (NSError**) error {
self = [super init];
self->_der = [NSData dataWithData: message];
if ((self = [super init])) {
self->_der = [NSData dataWithData: message];
}
return [self inflatePartsOfEncoding: error] ? self : nil;
}
@ -151,14 +150,13 @@
data: (NSData*) firstData
payload: (nullable NSData*) secondData
error: (NSError**) error {
self = [super init];
self->_der = [KCJoiningMessage encodeToDERType:type
data:firstData
payload:secondData
error:error];
if (self->_der == nil) return nil;
if ((self = [super init])) {
self->_der = [KCJoiningMessage encodeToDERType:type
data:firstData
payload:secondData
error:error];
if (self->_der == nil) return nil;
}
return [self inflatePartsOfEncoding: error] ? self : nil;
}
@ -262,7 +260,8 @@
@end
NSData* extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString** uuidString, NSData** octagon, NSError** error) {
NSData* _Nullable extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString** uuidString, NSData** octagon, NSError** error)
{
NSData* result = nil;
const uint8_t *der = [initialMessage bytes];
const uint8_t *der_end = der + [initialMessage length];

View File

@ -26,6 +26,9 @@
#import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
#import "keychain/ot/proto/generated_source/OTPairingMessage.h"
#endif
#import <KeychainCircle/NSError+KCCreationHelpers.h>
@ -52,9 +55,13 @@ typedef enum {
- (void)setControlObject:(OTControl *)control{
self.otControl = control;
}
- (void)setJoiningConfigurationObject:(OTJoiningConfiguration *)joiningConfiguration
- (void)setContextIDOnJoiningConfiguration:(NSString*)contextID
{
self.joiningConfiguration = joiningConfiguration;
self.joiningConfiguration.contextID = contextID;
}
- (KCAESGCMDuplexSession*)accessSession
{
return self.session;
}
#endif
@ -98,6 +105,7 @@ typedef enum {
return [self->_session encrypt:initialMessage.data error:error];
}
- (nullable NSData*) initialMessage: (NSError**) error {
secnotice("joining", "joining: KCJoiningRequestCircleSession initialMessage called");
@ -125,6 +133,8 @@ typedef enum {
localError = err;
} else{
OTPairingMessage *pairingMessage = [[OTPairingMessage alloc]init];
pairingMessage.supportsSOS = [[OTSupportSOSMessage alloc] init];
pairingMessage.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
OTApplicantToSponsorRound2M1 *prepareMessage = [[OTApplicantToSponsorRound2M1 alloc]init];
prepareMessage.peerID = peerID;
prepareMessage.permanentInfo = permanentInfo;
@ -133,6 +143,10 @@ typedef enum {
prepareMessage.stableInfoSig = stableInfoSig;
pairingMessage.prepare = prepareMessage;
pairingMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
pairingMessage.supportsOctagon.supported = OTSupportType_supported;
next = pairingMessage.data;
}
dispatch_semaphore_signal(sema);
@ -158,7 +172,7 @@ typedef enum {
self->_state = kExpectingCircleBlob;
NSData *encryptedInitialMessage = [self encryptedInitialMessage:next error:error];
return [[KCJoiningMessage messageWithType: kPeerInfo
return [[KCJoiningMessage messageWithType:kPeerInfo
data:encryptedInitialMessage
payload:encryptedPi
error:error] der];
@ -176,13 +190,34 @@ typedef enum {
}
- (void) attemptSosUpgrade
- (void) waitForOctagonUpgrade
{
[self.otControl attemptSosUpgrade:self.joiningConfiguration.containerName context:self.joiningConfiguration.contextID reply:^(NSError *error) {
#if OCTAGON
[self.otControl waitForOctagonUpgrade:self.joiningConfiguration.containerName context:self.joiningConfiguration.contextID reply:^(NSError *error) {
if(error){
secerror("pairing: failed to upgrade initiator into Octagon: %@", error);
}
}];
#endif
}
- (BOOL)shouldJoinSOS:(KCJoiningMessage*)message pairingMessage:(OTPairingMessage*)pairingMessage
{
BOOL shouldJoin = YES;
if (OctagonPlatformSupportsSOS() == NO) {
secnotice("joining", "platform does not support SOS");
shouldJoin = NO;
} else if (message.secondData == nil) {
secnotice("joining", "message does not contain SOS data");
shouldJoin = NO;
} else if (pairingMessage.hasSupportsSOS && pairingMessage.supportsSOS.supported == OTSupportType_not_supported) {
secnotice("joining", "acceptor explicitly does not support SOS");
shouldJoin = NO;
}
return shouldJoin;
}
- (NSData*) handleCircleBlob: (KCJoiningMessage*) message error: (NSError**) error {
@ -202,10 +237,14 @@ typedef enum {
secerror("octagon: expected voucher! returning from piggybacking.");
return nil;
}
OTSponsorToApplicantRound2M2 *voucher = pairingMessage.voucher;
//handle voucher message then join octagon
[self.otControl rpcJoinWithConfiguration:self.joiningConfiguration vouchData:voucher.voucher vouchSig:voucher.voucherSignature preapprovedKeys:voucher.preapprovedKeys reply:^(NSError * _Nullable err) {
[self.otControl rpcJoinWithConfiguration:self.joiningConfiguration
vouchData:voucher.voucher
vouchSig:voucher.voucherSignature
reply:^(NSError * _Nullable err) {
if(err){
secerror("octagon: error joining octagon: %@", err);
localError = err;
@ -221,16 +260,18 @@ typedef enum {
return nil;
}
if (OctagonPlatformSupportsSOS()) {
if ([self shouldJoinSOS:message pairingMessage:pairingMessage]) {
secnotice("joining", "doing SOS processCircleJoinData");
//note we are stuffing SOS into the payload "secondData"
NSData* circleBlob = [self.session decryptAndVerify:message.secondData error:error];
if (circleBlob == nil) return nil;
if (![self.circleDelegate processCircleJoinData: circleBlob version:kPiggyV1 error:error])
if (circleBlob == nil) {
secnotice("joining", "decryptAndVerify failed: %@", error && *error ? *error : nil);
return nil;
} else {
secnotice("joining", "platform doesn't support SOS");
}
if (![self.circleDelegate processCircleJoinData: circleBlob version:kPiggyV1 error:error]){
secerror("joining: processCircleJoinData failed %@", error && *error ? *error : nil);
return nil;
}
}
self->_state = kRequestCircleDone;
@ -250,10 +291,12 @@ typedef enum {
return nil;
} else {
secnotice("joining", "joined the SOS circle!");
#if OCTAGON
if(OctagonIsEnabled()) {
secnotice("joining", "kicking off SOS Upgrade into Octagon!");
[self attemptSosUpgrade];
[self waitForOctagonUpgrade];
}
#endif
}
self->_state = kRequestCircleDone;
@ -304,27 +347,26 @@ typedef enum {
error:(NSError**) error
{
secnotice("joining", "joining: KCJoiningRequestCircleSession initWithCircleDelegate called, uuid=%@", session.pairingUUID);
self = [super init];
self->_circleDelegate = circleDelegate;
self->_session = session;
self.state = kExpectingCircleBlob;
if ((self = [super init])) {
self->_circleDelegate = circleDelegate;
self->_session = session;
self.state = kExpectingCircleBlob;
#if OCTAGON
self->_otControl = otcontrol;
self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
uniqueDeviceID:@"requester-id"
uniqueClientID:@"requester-id"
pairingUUID:session.pairingUUID
containerName:nil
contextID:OTDefaultContext
epoch:session.epoch
isInitiator:true];
self->_otControl = otcontrol;
self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
uniqueDeviceID:@"requester-id"
uniqueClientID:@"requester-id"
pairingUUID:session.pairingUUID
containerName:nil
contextID:OTDefaultContext
epoch:session.epoch
isInitiator:true];
self->_piggy_version = session.piggybackingVersion;
self->_piggy_version = session.piggybackingVersion;
#else
self->_piggy_version = kPiggyV1;
self->_piggy_version = kPiggyV1;
#endif
}
return self;
}

View File

@ -18,7 +18,6 @@
#include <corecrypto/ccsha2.h>
#include <corecrypto/ccdh_gp.h>
#include <corecrypto/ccder.h>
#include <CommonCrypto/CommonRandomSPI.h>
#import <Security/SecureObjectSync/SOSTypes.h>
#include <utilities/debugging.h>
@ -33,6 +32,9 @@
#import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
#import "keychain/ot/proto/generated_source/OTPairingMessage.h"
#endif
#import <KeychainCircle/NSError+KCCreationHelpers.h>
@ -70,8 +72,9 @@ bool KCJoiningOctagonPiggybackingEnabled() {
@property (readwrite) uint64_t epoch;
@property (readwrite) NSData* challenge;
@property (readwrite) NSData* salt;
@property (readwrite) NSString* sessionUUID;
#if OCTAGON
@property (nonatomic, strong) OTJoiningConfiguration* joiningConfiguration;
@property (nonatomic, strong) OTControl *otControl;
#endif
@property (nonatomic, strong) NSMutableDictionary *defaults;
@ -147,7 +150,7 @@ bool KCJoiningOctagonPiggybackingEnabled() {
}
self->_session = [KCAESGCMDuplexSession sessionAsSender:key context:self.dsid];
self.session.pairingUUID = self.joiningConfiguration.pairingUUID;
self.session.pairingUUID = self.sessionUUID;
self.session.piggybackingVersion = self.piggy_version;
return self.session != nil;
@ -211,17 +214,16 @@ bool KCJoiningOctagonPiggybackingEnabled() {
}
#if OCTAGON
//handle octagon data if it exists
if(KCJoiningOctagonPiggybackingEnabled()){
if (KCJoiningOctagonPiggybackingEnabled()){
self.piggy_version = [message secondData] ? kPiggyV2 : kPiggyV1;
// The session may or may not exist at this point. If it doesn't, the version will be set at object creation time.
self.session.piggybackingVersion = self.piggy_version;
if(self.piggy_version == kPiggyV2){
if (self.piggy_version == kPiggyV2){
OTPairingMessage* pairingMessage = [[OTPairingMessage alloc]initWithData: [message secondData]];
if(pairingMessage.epoch.epoch){
secnotice("octagon", "received epoch");
if (pairingMessage.hasEpoch) {
secnotice("octagon", "received epoch message: %@", [pairingMessage.epoch dictionaryRepresentation]);
self.epoch = pairingMessage.epoch.epoch;
}
else{
@ -340,36 +342,30 @@ bool KCJoiningOctagonPiggybackingEnabled() {
rng: (struct ccrng_state *)rng
error: (NSError**)error {
secnotice("joining", "joining: initWithSecretDelegate called");
self = [super init];
self->_secretDelegate = secretDelegate;
self->_state = kExpectingB;
self->_dsid = dsid;
self->_defaults = [NSMutableDictionary dictionary];
if ((self = [super init])) {
self->_secretDelegate = secretDelegate;
self->_state = kExpectingB;
self->_dsid = dsid;
self->_defaults = [NSMutableDictionary dictionary];
#if OCTAGON
self->_piggy_version = KCJoiningOctagonPiggybackingEnabled() ? kPiggyV2 : kPiggyV1;
self->_otControl = [OTControl controlObject:true error:error];
self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:OTProtocolPiggybacking
uniqueDeviceID:@"requester-id"
uniqueClientID:@"requester-id"
containerName:nil
contextID:OTDefaultContext
epoch:0
isInitiator:true];
self->_piggy_version = KCJoiningOctagonPiggybackingEnabled() ? kPiggyV2 : kPiggyV1;
self->_otControl = [OTControl controlObject:true error:error];
_sessionUUID = [[NSUUID UUID] UUIDString];
#else
self->_piggy_version = kPiggyV1;
self->_piggy_version = kPiggyV1;
#endif
secnotice("joining", "joining: initWithSecretDelegate called, uuid=%@", self.joiningConfiguration.pairingUUID);
secnotice("joining", "joining: initWithSecretDelegate called, uuid=%@", self.sessionUUID);
NSString* name = [NSString stringWithFormat: @"%llu", dsid];
self->_context = [[KCSRPClientContext alloc] initWithUser: name
digestInfo: ccsha256_di()
group: ccsrp_gp_rfc5054_3072()
randomSource: rng];
NSString* name = [NSString stringWithFormat: @"%llu", dsid];
self->_context = [[KCSRPClientContext alloc] initWithUser: name
digestInfo: ccsha256_di()
group: ccsrp_gp_rfc5054_3072()
randomSource: rng];
}
return self;
}
@ -391,11 +387,6 @@ bool KCJoiningOctagonPiggybackingEnabled() {
{
self.otControl = control;
}
- (void)setConfiguration:(OTJoiningConfiguration *)config
{
self.joiningConfiguration = config;
}
#endif
@end

View File

@ -32,13 +32,14 @@
@interface KCJoiningRequestSecretSession (Internal)
- (void)setControlObject:(OTControl*)control;
- (void)setConfiguration:(OTJoiningConfiguration *)config;
@end
@interface KCJoiningRequestCircleSession (Internal)
- (KCAESGCMDuplexSession*)accessSession;
- (void)setControlObject:(OTControl*)control;
- (void)setJoiningConfigurationObject:(OTJoiningConfiguration *)config;
- (void)setContextIDOnJoiningConfiguration:(NSString*)contextID;
@end
#endif /* Header_h */
#endif

View File

@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
// Returns an NSData that refers to the key in the context.
// It becomes invalid when this context is released.
- (NSData*) getKey;
- (NSData* _Nullable) getKey;
@end

View File

@ -50,14 +50,13 @@ static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding;
group: (ccsrp_const_gp_t) gp
randomSource: (struct ccrng_state *) rng
{
self = [super init];
self.context = malloc(ccsrp_sizeof_srp(di, gp));
ccsrp_ctx_init(self.context, di, gp);
self.user = user;
self.rng = rng;
if ((self = [super init])) {
self.context = malloc(ccsrp_sizeof_srp(di, gp));
ccsrp_ctx_init(self.context, di, gp);
self.user = user;
self.rng = rng;
}
return self;
}
@ -72,7 +71,8 @@ static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding;
}
#pragma clang diagnostic pop
- (NSData*) getKey {
- (NSData* _Nullable)getKey
{
size_t key_length = 0;
const void * key = ccsrp_get_session_key(self.context, &key_length);
@ -179,15 +179,14 @@ static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NS
digestInfo: (const struct ccdigest_info *) di
group: (ccsrp_const_gp_t) gp
randomSource: (struct ccrng_state *) rng {
self = [super initWithUser: user
digestInfo: di
group: gp
randomSource: rng];
if (![self resetWithPassword:password error:nil]) {
return nil;
if ((self = [super initWithUser: user
digestInfo: di
group: gp
randomSource: rng])) {
if (![self resetWithPassword:password error:nil]) {
return nil;
}
}
return self;
}
@ -197,14 +196,13 @@ static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NS
digestInfo: (const struct ccdigest_info *) di
group: (ccsrp_const_gp_t) gp
randomSource: (struct ccrng_state *) rng {
self = [super initWithUser: user
digestInfo: di
group: gp
randomSource: rng];
self.verifier = verifier;
self->_salt = salt;
if ((self = [super initWithUser: user
digestInfo: di
group: gp
randomSource: rng])) {
self.verifier = verifier;
self->_salt = salt;
}
return self;
}

View File

@ -61,5 +61,9 @@ extern KCPairingIntent_Type KCPairingIntent_Type_UserDriven;
- (void)setOctagonMessageFailForTesting:(BOOL)value;
+ (bool)isSupportedPlatform;
- (void)setSessionSupportsOctagonForTesting:(bool)value;
+ (NSData *)pairingChannelCompressData:(NSData *)data;
+ (NSData *)pairingChannelDecompressData:(NSData *)data;
@end

View File

@ -11,17 +11,19 @@
#import <Security/SecureObjectSync/SOSTypes.h>
#import <utilities/debugging.h>
#import <utilities/SecCFWrappers.h>
#import "utilities/SecCoreAnalytics.h"
#import <ipc/securityd_client.h>
#import "keychain/ot/OTManager.h"
#import "keychain/ot/OctagonControlServer.h"
#import "keychain/ot/OTControl.h"
#import "keychain/ot/OctagonControlServer.h"
#import "keychain/ot/OTJoiningConfiguration.h"
#import "keychain/ot/proto/generated_source/OTPairingMessage.h"
#import "keychain/ot/proto/generated_source/OTSOSMessage.h"
#import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
#import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
#import "keychain/ot/proto/generated_source/OTPairingMessage.h"
#include <notify.h>
@ -30,7 +32,6 @@
#import <MobileGestalt.h>
#endif
#import "utilities/SecADWrapper.h"
KCPairingIntent_Type KCPairingIntent_Type_None = @"none";
KCPairingIntent_Type KCPairingIntent_Type_SilentRepair = @"repair";
@ -79,8 +80,7 @@ typedef void(^OTNextState)(NSData *inData, OTPairingInternalCompletion complete)
- (nullable instancetype)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self) {
if ((self = [super init])) {
_model = [decoder decodeObjectOfClass:[NSString class] forKey:@"model"];
_modelVersion = [decoder decodeObjectOfClass:[NSString class] forKey:@"modelVersion"];
_modelClass = [decoder decodeObjectOfClass:[NSString class] forKey:@"modelClass"];
@ -109,6 +109,7 @@ typedef void(^OTNextState)(NSData *inData, OTPairingInternalCompletion complete)
@property (assign) bool initiator;
@property (assign) unsigned counter;
@property (assign) bool acceptorWillSendInitialSyncCredentials;
@property (assign) uint32_t acceptorInitialSyncCredentialsFlags;
@property (strong) NSXPCConnection *connection;
@property (strong) OTControl *otControl;
@property (strong) NSString* contextID;
@ -170,6 +171,7 @@ typedef void(^OTNextState)(NSData *inData, OTPairingInternalCompletion complete)
_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:OTProtocolPairing
uniqueDeviceID:peerVersionContext.uniqueDeviceID
uniqueClientID:peerVersionContext.uniqueClientID
pairingUUID:[[NSUUID UUID] UUIDString]
containerName:nil
contextID:OTDefaultContext
epoch:0
@ -207,7 +209,7 @@ typedef void(^OTNextState)(NSData *inData, OTPairingInternalCompletion complete)
const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
#define EXTRA_SIZE 100
- (NSData *)compressData:(NSData *)data
+ (NSData *)pairingChannelCompressData:(NSData *)data
{
NSMutableData *scratch = [NSMutableData dataWithLength:compression_encode_scratch_buffer_size(pairingCompression)];
@ -226,7 +228,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
return o;
}
- (NSData *)decompressData:(NSData *)data
+ (NSData *)pairingChannelDecompressData:(NSData *)data
{
NSMutableData *scratch = [NSMutableData dataWithLength:compression_decode_scratch_buffer_size(pairingCompression)];
@ -255,9 +257,9 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
//MARK: - Initiator
- (void) attemptSosUpgrade
- (void) waitForOctagonUpgrade
{
[self.otControl attemptSosUpgrade:nil context:self.contextID reply:^(NSError *error) {
[self.otControl waitForOctagonUpgrade:nil context:self.contextID reply:^(NSError *error) {
if(error){
secerror("pairing: failed to upgrade initiator into Octagon: %@", error);
}
@ -406,12 +408,17 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
return;
} else {
OTPairingMessage *octagonMessage = [[OTPairingMessage alloc]init];
octagonMessage.supportsSOS = [[OTSupportSOSMessage alloc] init];
octagonMessage.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
OTApplicantToSponsorRound2M1 *prepare = [[OTApplicantToSponsorRound2M1 alloc] init];
prepare.peerID = peerID;
prepare.permanentInfo = permanentInfo;
prepare.permanentInfoSig = permanentInfoSig;
prepare.stableInfo = stableInfo;
prepare.stableInfoSig = stableInfoSig;
octagonMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
octagonMessage.supportsOctagon.supported = OTSupportType_supported;
octagonMessage.prepare = prepare;
if(application){
secnotice(pairingScope, "initiatorCompleteSecondPacketOctagon returning octagon and sos data");
@ -464,7 +471,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
} else {
//kick off SOS ugprade
if(OctagonIsEnabled() && !self.sessionSupportsOctagon) {
[self attemptSosUpgrade];
[self waitForOctagonUpgrade];
}
typeof(self) strongSelf = weakSelf;
secnotice("pairing", "initiator circle join complete, more data: %s: %@",
@ -499,7 +506,10 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
OTSponsorToApplicantRound2M2 *voucher = pairingMessage.voucher;
//handle voucher and join octagon
[self.otControl rpcJoinWithConfiguration:self.joiningConfiguration vouchData:voucher.voucher vouchSig:voucher.voucherSignature preapprovedKeys:voucher.preapprovedKeys reply:^(NSError *error) {
[self.otControl rpcJoinWithConfiguration:self.joiningConfiguration
vouchData:voucher.voucher
vouchSig:voucher.voucherSignature
reply:^(NSError *error) {
if (error || self.testFailOctagon) {
secerror("ot-pairing: failed to create %d message: %@", self.counter, error);
complete(true, NULL, error);
@ -507,7 +517,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
}else{
secnotice(pairingScope, "initiatorThirdPacket successfully joined Octagon");
typeof(self) strongSelf = weakSelf;
if(OctagonPlatformSupportsSOS() && strongSelf->_acceptorWillSendInitialSyncCredentials == true) {
if(OctagonPlatformSupportsSOS() && strongSelf->_acceptorWillSendInitialSyncCredentials) {
strongSelf.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){
[weakSelf initiatorFourthPacket:nsdata complete:kscomplete];
};
@ -567,6 +577,11 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
if (self.sessionSupportsSOS && indata[@"d"]) {
secnotice("pairing", "acceptor initialSyncCredentials requested");
self.acceptorWillSendInitialSyncCredentials = true;
self.acceptorInitialSyncCredentialsFlags =
SOSControlInitialSyncFlagTLK|
SOSControlInitialSyncFlagPCS|
SOSControlInitialSyncFlagBluetoothMigration;
}
if (indata[@"o"] == nil) {
@ -647,10 +662,13 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
[weakSelf acceptorSecondPacket:nsdata complete:kscomplete];
};
OTPairingMessage *response = [[OTPairingMessage alloc] init];
response.supportsSOS = [[OTSupportSOSMessage alloc] init];
response.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
response.epoch = [[OTSponsorToApplicantRound1M2 alloc] init];
response.epoch.epoch = epoch;
response.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
response.supportsOctagon.supported = OTSupportType_supported;
reply[@"o"] = response.data;
secnotice("pairing", "acceptor reply to packet 1");
complete(false, reply, error);
}
@ -746,9 +764,19 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
finished = false;
}
OTPairingMessage *response = [[OTPairingMessage alloc] init];
response.supportsSOS = [[OTSupportSOSMessage alloc] init];
response.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
response.voucher = [[OTSponsorToApplicantRound2M2 alloc] init];
response.voucher.voucher = voucher;
response.voucher.voucherSignature = voucherSig;
response.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
response.supportsOctagon.supported = OTSupportType_supported;
if (self.acceptorWillSendInitialSyncCredentials) {
// no need to share TLKs over the pairing channel, that's provided by octagon
self.acceptorInitialSyncCredentialsFlags &= ~(SOSControlInitialSyncFlagTLK | SOSControlInitialSyncFlagPCS);
}
reply[@"o"] = response.data;
secnotice("pairing", "acceptor reply to packet 2");
@ -761,10 +789,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
{
secnotice("pairing", "acceptor packet 3");
const uint32_t initialSyncCredentialsFlags =
SOSControlInitialSyncFlagTLK|
SOSControlInitialSyncFlagPCS|
SOSControlInitialSyncFlagBluetoothMigration;
const uint32_t initialSyncCredentialsFlags = self.acceptorInitialSyncCredentialsFlags;
[[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
complete(true, NULL, error);
@ -824,7 +849,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
if (inputCompressedData) {
NSData *data = [self decompressData:inputCompressedData];
NSData *data = [[self class] pairingChannelDecompressData:inputCompressedData];
if (data == NULL) {
secnotice("pairing", "failed to decompress");
complete(true, NULL, NULL);
@ -849,12 +874,12 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
if (outdata == NULL && error)
error = error2;
if (outdata)
compressedData = [self compressData:outdata];
compressedData = [[self class] pairingChannelCompressData:outdata];
if (compressedData) {
NSString *key = [NSString stringWithFormat:@"com.apple.ckks.pairing.packet-size.%s.%u",
self->_initiator ? "initiator" : "acceptor", self->_counter];
SecADClientPushValueForDistributionKey((__bridge CFStringRef)key, [compressedData length]);
[SecCoreAnalytics sendEvent:key event:@{SecCoreAnalyticsValue: [NSNumber numberWithUnsignedInteger:[compressedData length]]}];
secnotice("pairing", "pairing packet size %lu", (unsigned long)[compressedData length]);
}
}

View File

@ -4,8 +4,7 @@
@implementation FakeNSXPCConnection
- (instancetype) initWithControl:(id<SOSControlProtocol>)control
{
self = [super init];
if (self) {
if ((self = [super init])) {
_control = control;
}
return self;
@ -131,12 +130,29 @@
- (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete
{
complete(@[], NULL);
// Make up a fake TLK
NSMutableArray<NSDictionary *> *items = [NSMutableArray array];
if (flags & SOSControlInitialSyncFlagTLK) {
NSString *tlkUUID = [[NSUUID UUID] UUIDString];
NSDictionary *fakeTLK = @{
@"class": @"inet",
@"agrp": @"com.apple.security.ckks",
@"vwht": @"PCS-master",
@"pdmn": @"ck",
@"desc": @"tlk",
@"srvr": @"fakeZone",
@"acct": tlkUUID,
@"path": tlkUUID,
@"v_Data": [NSData data],
};
[items addObject:fakeTLK];
}
complete(items, nil);
}
- (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete
{
complete(true, NULL);
complete(true, nil);
}
- (void)rpcTriggerSync:(NSArray<NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
@ -328,6 +344,14 @@
complete(nil, nil);
}
- (void)iCloudIdentityStatus_internal: (void(^)(NSDictionary *tableSpid, NSError *error))complete {
complete(nil, nil);
}
- (void) iCloudIdentityStatus: (void(^)(NSData *json, NSError *error))complete {
complete(nil, nil);
}
- (void)rpcTriggerBackup:(NSArray<NSString *> *)backupPeers complete:(void (^)(NSError *))complete {
complete(nil);
}
@ -336,5 +360,8 @@
complete(nil);
}
- (void)removeV0Peers:(void (^)(bool, NSError *))reply {
reply(true, nil);
}
@end

View File

@ -17,26 +17,6 @@
#include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
#include <CommonCrypto/CommonRandomSPI.h>
__unused static SOSFullPeerInfoRef SOSNSFullPeerInfoCreate(NSDictionary* gestalt,
NSData* backupKey, SecKeyRef signingKey,
SecKeyRef octagonSigningKey,
SecKeyRef octagonEncryptionKey,
NSError**error)
{
CFErrorRef errorRef = NULL;
SOSFullPeerInfoRef result = SOSFullPeerInfoCreate(NULL, (__bridge CFDictionaryRef) gestalt, (__bridge CFDataRef) backupKey, signingKey, octagonSigningKey, octagonEncryptionKey, &errorRef);
if (errorRef && error) {
*error = (__bridge_transfer NSError*) errorRef;
errorRef = NULL;
}
return result;
}
static SecKeyRef GenerateFullECKey_internal(int keySize, NSError** error)
{
@ -106,25 +86,26 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
- (id) initWithSecret: (NSString*) secret
incorrectSecret: (NSString*) incorrectSecret
incorrectTries: (int) retries {
self = [super init];
if ((self = [super init])) {
SecKeyRef signingKey = GenerateFullECKey(256, NULL);
SecKeyRef octagonSigningKey = GenerateFullECKey(384, NULL);
SecKeyRef octagonEncryptionKey = GenerateFullECKey(384, NULL);
SecKeyRef signingKey = GenerateFullECKey(256, NULL);
SecKeyRef octagonSigningKey = GenerateFullECKey(384, NULL);
SecKeyRef octagonEncryptionKey = GenerateFullECKey(384, NULL);
SOSPeerInfoRef newPeerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, octagonSigningKey, octagonEncryptionKey, NULL);
SOSPeerInfoRef newPeerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, octagonSigningKey, octagonEncryptionKey, NULL);
if (newPeerInfo == NULL) {
return nil;
}
self.peerInfo = newPeerInfo;
CFRelease(newPeerInfo);
newPeerInfo = NULL;
self.sharedSecret = secret;
self.incorrectSecret = incorrectSecret;
self.incorrectTries = retries;
if (newPeerInfo == NULL) {
return nil;
}
self.peerInfo = newPeerInfo;
CFRelease(newPeerInfo);
newPeerInfo = NULL;
self.sharedSecret = secret;
self.incorrectSecret = incorrectSecret;
self.incorrectTries = retries;
return self;
}
@ -206,18 +187,17 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
}
- (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
self = [super init];
if ((self = [super init])) {
self->_secrets = secrets;
self.currentSecret = 0;
self->_retriesPerSecret = retries;
self->_retriesLeft = self.retriesPerSecret;
self->_secrets = secrets;
self.currentSecret = 0;
self->_retriesPerSecret = retries;
self->_retriesLeft = self.retriesPerSecret;
self->_codeToUse = code;
uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
self->_codeToUse = code;
uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
}
return self;
}
@ -288,7 +268,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
dsid:dsid
rng:ccDRBGGetRngState()
rng:ccrng(NULL)
error:&error];
NSData* initialMessage = [requestSession initialMessage: &error];
@ -300,7 +280,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
circleDelegate:acceptDelegate
dsid:dsid
rng:ccDRBGGetRngState()
rng:ccrng(NULL)
error:&error];
error = nil;
@ -383,7 +363,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret incorrectSecret:@"777888" incorrectTries:3];
KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
dsid:dsid
rng:ccDRBGGetRngState()
rng:ccrng(NULL)
error:&error];
NSData* initialMessage = [requestSession initialMessage: &error];
@ -395,7 +375,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
circleDelegate:acceptDelegate
dsid:dsid
rng:ccDRBGGetRngState()
rng:ccrng(NULL)
error:&error];
error = nil;
@ -489,7 +469,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
dsid:dsid
rng:ccDRBGGetRngState()
rng:ccrng(NULL)
error:&error];
NSData* initialMessage = [requestSession initialMessage: &error];
@ -501,7 +481,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
circleDelegate:acceptDelegate
dsid:dsid
rng:ccDRBGGetRngState()
rng:ccrng(NULL)
error:&error];
error = nil;

View File

@ -24,7 +24,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testSecPairBasicTest KCPairing.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string>NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES</string>
<string>-XCTest</string>
<string>testSecPairBasicTest</string>
<string>KCPairing.xctest</string>
</array>
</dict>
</array>

View File

@ -10,7 +10,6 @@
#include <corecrypto/ccrng.h>
#include <corecrypto/ccsha2.h>
#include <corecrypto/ccdh_gp.h>
#include <CommonCrypto/CommonRandomSPI.h>
@interface KCSRPTests : XCTestCase
@ -102,7 +101,7 @@
[self negotiateWithUser: @"TestUser"
digestInfo: ccsha256_di()
group: ccsrp_gp_rfc5054_3072()
randomSource: ccDRBGGetRngState()];
randomSource: ccrng(NULL)];
}
@end

View File

@ -0,0 +1,304 @@
#import <XCTest/XCTest.h>
#import <Foundation/Foundation.h>
#import <KeychainCircle/KCJoiningSession.h>
#import <KeychainCircle/KCAccountKCCircleDelegate.h>
#import <KeychainCircle/KCError.h>
#import <KeychainCircle/KCJoiningMessages.h>
#import <KeychainCircle/NSError+KCCreationHelpers.h>
#import <KeychainCircle/KCAESGCMDuplexSession.h>
#include <Security/SecBase.h>
#include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
#include <CommonCrypto/CommonRandomSPI.h>
static NSData* createTlkRequestMessage (KCAESGCMDuplexSession* aesSession) {
char someData[] = {1,2,3,4,5,6};
NSError* error = NULL;
NSData* rndPadding = [NSData dataWithBytes:(void*)someData length:sizeof(someData)];
KCJoiningMessage* tlkRequestMessage = [KCJoiningMessage messageWithType: kTLKRequest data:rndPadding error:&error];
return [tlkRequestMessage der];
}
@interface KCJoiningRequestTestDelegate : NSObject <KCJoiningRequestSecretDelegate, KCJoiningRequestCircleDelegate>
@property (readwrite) NSString* sharedSecret;
@property (readonly) NSString* accountCode;
@property (readonly) NSData* circleJoinData;
@property (readwrite) NSString* incorrectSecret;
@property (readwrite) int incorrectTries;
+ (id) requestDelegateWithSecret:(NSString*) secret;
- (id) init NS_UNAVAILABLE;
- (id) initWithSecret: (NSString*) secret
incorrectSecret: (NSString*) wrongSecret
incorrectTries: (int) retries NS_DESIGNATED_INITIALIZER;
- (NSString*) secret;
- (NSString*) verificationFailed: (bool) codeChanged;
- (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error;
- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error ;
- (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error;
@end
@implementation KCJoiningRequestTestDelegate
+ (id) requestDelegateWithSecret:(NSString*) secret {
return [[KCJoiningRequestTestDelegate alloc] initWithSecret:secret
incorrectSecret:@""
incorrectTries:0];
}
+ (id) requestDelegateWithSecret:(NSString*) secret
incorrectSecret:(NSString*) wrongSecret
incorrectTries:(int) retries {
return [[KCJoiningRequestTestDelegate alloc] initWithSecret:secret
incorrectSecret:wrongSecret
incorrectTries:retries];
}
- (id) initWithSecret: (NSString*) secret
incorrectSecret: (NSString*) incorrectSecret
incorrectTries: (int) retries {
if ( self = [super init] ) {
self.sharedSecret = secret;
self.incorrectSecret = incorrectSecret;
self.incorrectTries = retries;
}
return self;
}
- (NSString*) nextSecret {
if (self.incorrectTries > 0) {
self.incorrectTries -= 1;
return self.incorrectSecret;
}
return self.sharedSecret;
}
- (NSString*) secret {
return [self nextSecret];
}
- (NSString*) verificationFailed: (bool) codeChanged {
return [self nextSecret];
}
- (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error {
return NULL;
}
- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error {
self->_circleJoinData = circleJoinData;
return true;
}
- (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error {
self->_accountCode = accountCode;
return true;
}
@end
@interface KCJoiningAcceptTestDelegate : NSObject <KCJoiningAcceptSecretDelegate, KCJoiningAcceptCircleDelegate>
@property (readonly) NSArray<NSString*>* secrets;
@property (readwrite) NSUInteger currentSecret;
@property (readwrite) int retriesLeft;
@property (readwrite) int retriesPerSecret;
@property (readonly) NSString* codeToUse;
@property (readonly) NSData* circleJoinData;
@property (readonly) SOSPeerInfoRef peerInfo;
+ (id) acceptDelegateWithSecret: (NSString*) secret code: (NSString*) code;
+ (id) acceptDelegateWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code;
- (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code NS_DESIGNATED_INITIALIZER;
- (NSString*) secret;
- (NSString*) accountCode;
- (KCRetryOrNot) verificationFailed: (NSError**) error;
- (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer
error: (NSError**) error;
- (id) init NS_UNAVAILABLE;
@end
@implementation KCJoiningAcceptTestDelegate
+ (id) acceptDelegateWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
return [[KCJoiningAcceptTestDelegate alloc] initWithSecrets:secrets retries:retries code:code];
}
+ (id) acceptDelegateWithSecret: (NSString*) secret code: (NSString*) code {
return [[KCJoiningAcceptTestDelegate alloc] initWithSecret:secret code:code];
}
- (id) initWithSecret: (NSString*) secret code: (NSString*) code {
return [self initWithSecrets:@[secret] retries:3 code:code];
}
- (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
if ((self = [super init])) {
self->_secrets = secrets;
self.currentSecret = 0;
self->_retriesPerSecret = retries;
self->_retriesLeft = self.retriesPerSecret;
self->_codeToUse = code;
uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
}
return self;
}
- (KCRetryOrNot) advanceSecret {
if (self.retriesLeft == 0) {
self.currentSecret += 1;
if (self.currentSecret >= [self.secrets count]) {
self.currentSecret = [self.secrets count] - 1;
}
self.retriesLeft = self.retriesPerSecret;
return kKCRetryWithNewChallenge;
} else {
self.retriesLeft -= 1;
return kKCRetryWithSameChallenge;
}
}
- (NSString*) secret {
return self.secrets[self.currentSecret];
}
- (NSString*) accountCode {
return self.codeToUse;
}
- (KCRetryOrNot) verificationFailed: (NSError**) error {
return [self advanceSecret];
}
- (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer
error: (NSError**) error {
uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
self->_peerInfo = peer;
return [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
}
-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{
char testData[] = {0,1,2,3,4,5,6,7,8,9};
return [NSData dataWithBytes:testData length:sizeof(testData)];
//return [[KCJoiningAcceptAccountCircleDelegate delegate] circleGetInitialSyncViews:flags error:error]; //Need security entitlements!
}
@end
@interface KCTLKRequestTest : XCTestCase
@end
@implementation KCTLKRequestTest
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testTLKRequest {
NSError* error = nil;
NSString* secret = @"123456";
NSString* code = @"987654";
uint64_t dsid = 0x1234567887654321;
KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
dsid:dsid
rng:ccDRBGGetRngState()
error:&error];
NSData* initialMessage = [requestSession initialMessage: &error];
XCTAssertNotNil(initialMessage, @"No initial message");
XCTAssertNil(error, @"Got error %@", error);
KCJoiningAcceptTestDelegate* acceptDelegate = [KCJoiningAcceptTestDelegate acceptDelegateWithSecret:secret code:code];
KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
circleDelegate:acceptDelegate
dsid:dsid
rng:ccDRBGGetRngState()
error:&error];
error = nil;
NSData* challenge = [acceptSession processMessage: initialMessage error: &error];
XCTAssertNotNil(challenge, @"No initial message");
XCTAssertNil(error, @"Got error %@", error);
error = nil;
NSData* response = [requestSession processMessage: challenge error: &error];
XCTAssertNotNil(response, @"No response message");
XCTAssertNil(error, @"Got error %@", error);
error = nil;
NSData* verification = [acceptSession processMessage: response error: &error];
XCTAssertNotNil(verification, @"No verification message");
XCTAssertNil(error, @"Got error %@", error);
error = nil;
NSData* doneMessage = [requestSession processMessage: verification error: &error];
XCTAssertNotNil(doneMessage, @"No response message");
XCTAssertNil(error, @"Got error %@", error);
XCTAssertTrue([requestSession isDone], @"SecretSession done");
XCTAssertFalse([acceptSession isDone], @"Unexpected accept session done");
KCAESGCMDuplexSession* aesSession = [requestSession session];
requestSession = nil;
KCJoiningRequestCircleSession* requestSecretSession = [KCJoiningRequestCircleSession sessionWithCircleDelegate:requestDelegate session:aesSession error:&error];
XCTAssertNotNil(requestSecretSession, @"No request secret session");
XCTAssertNil(error, @"Got error %@", error);
NSData* tlkRequestMessage = createTlkRequestMessage(aesSession);
XCTAssertNotNil(tlkRequestMessage, @"No TLKRequest message");
NSData* tlkMessage = [acceptSession processMessage:tlkRequestMessage error:&error];
XCTAssertNotNil(tlkMessage, @"No tlkData message");
XCTAssertNil(error, @"Got error %@", error);
KCJoiningMessage* receivedKCJoinMessage = [KCJoiningMessage messageWithDER:tlkMessage error:&error];
XCTAssertNotNil(receivedKCJoinMessage, @"No receivedKCJoinMessage message");
XCTAssertNil(error, @"Got error %@", error);
NSData* tlkDecryptedData = [aesSession decryptAndVerify:receivedKCJoinMessage.firstData error:&error];
XCTAssertNotNil(tlkDecryptedData, @"No tlkDecryptedData message");
XCTAssertNil(error, @"Got error %@", error);
//check for tlkc content
NSData* initialSync = [acceptDelegate circleGetInitialSyncViews:kSOSInitialSyncFlagTLKs error:&error];
XCTAssertNotNil(initialSync, @"No initialSync data");
XCTAssertNil(error, @"Got error %@", error);
XCTAssertEqualObjects(initialSync, tlkDecryptedData, @"TLK data is different.");
}
@end

View File

@ -24,7 +24,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest KCDerTest KeychainCircleTests.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string>NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES</string>
<string>-XCTest</string>
<string>KCDerTest</string>
<string>KeychainCircleTests.xctest</string>
</array>
</dict>
<dict>
@ -38,7 +45,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testAESGCMDuplex KeychainCircleTests.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string>NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES</string>
<string>-XCTest</string>
<string>testAESGCMDuplex</string>
<string>KeychainCircleTests.xctest</string>
</array>
</dict>
<dict>
@ -52,7 +66,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testAESGCMDuplexCoding KeychainCircleTests.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string>NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES</string>
<string>-XCTest</string>
<string>testAESGCMDuplexCoding</string>
<string>KeychainCircleTests.xctest</string>
</array>
</dict>
<dict>
@ -66,7 +87,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testJoiningSession KeychainCircleTests.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string>NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES</string>
<string>-XCTest</string>
<string>testJoiningSession</string>
<string>KeychainCircleTests.xctest</string>
</array>
</dict>
<dict>
@ -80,7 +108,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testJoiningSessionRetry KeychainCircleTests.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string>NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES</string>
<string>-XCTest</string>
<string>testJoiningSessionRetry</string>
<string>KeychainCircleTests.xctest</string>
</array>
</dict>
<dict>
@ -94,7 +129,14 @@
<false/>
<key>Command</key>
<array>
<string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testJoiningSessionCodeChange KeychainCircleTests.xctest</string>
<string>BATS_XCTEST_CMD</string>
<string>-NSTreatUnknownArgumentsAsOpen</string>
<string> NO</string>
<string>-ApplePersistenceIgnoreState</string>
<string>YES </string>
<string>-XCTest</string>
<string>testJoiningSessionCodeChange</string>
<string>KeychainCircleTests.xctest</string>
</array>
</dict>
</array>

View File

@ -1,17 +0,0 @@
//
// AppDelegate.h
// KeychainEntitledTestApp_ios
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View File

@ -1,51 +0,0 @@
//
// AppDelegate.m
// KeychainEntitledTestApp_ios
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end

View File

@ -1,98 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -1,15 +0,0 @@
//
// ViewController.h
// KeychainEntitledTestApp_ios
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

View File

@ -1,29 +0,0 @@
//
// ViewController.m
// KeychainEntitledTestApp_ios
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end

View File

@ -1,15 +0,0 @@
//
// AppDelegate.h
// KeychainEntitledTestApp_mac
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end

View File

@ -1,27 +0,0 @@
//
// AppDelegate.m
// KeychainEntitledTestApp_mac
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
@end

View File

@ -1,15 +0,0 @@
//
// ViewController.h
// KeychainEntitledTestApp_mac
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import <Cocoa/Cocoa.h>
@interface ViewController : NSViewController
@end

View File

@ -1,13 +0,0 @@
//
// main.m
// KeychainEntitledTestApp_mac
//
// Copyright (c) 2017 Apple Inc. All rights reserved.
//
//
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
return NSApplicationMain(argc, argv);
}

View File

@ -30,10 +30,12 @@
// was asked to file this radar for accounts: <rdar://problem/40176124> Invoke DataclassOwner when enabling or signing into an account
- (void)account:(ACAccount *)account didChangeWithType:(ACAccountChangeType)changeType inStore:(ACDAccountStore *)store oldAccount:(ACAccount *)oldAccount {
if((changeType == kACAccountChangeTypeAdded || changeType == kACAccountChangeTypeModified) &&
if((changeType == kACAccountChangeTypeAdded || changeType == kACAccountChangeTypeModified || changeType == kACAccountChangeTypeWarmingUp) &&
[account.accountType.identifier isEqualToString: ACAccountTypeIdentifierAppleAccount] &&
[self accountIsPrimary:account]) {
SOSCCLoggedIntoAccount(NULL);
#if OCTAGON
if(OctagonIsEnabled()){
NSString* altDSID = [account aa_altDSID];

View File

@ -0,0 +1,6 @@
framework module OctagonTrust [system] {
umbrella header "OctagonTrust.h"
export *
module * { export * }
}

View File

@ -1,4 +1,4 @@
framework module Security [extern_c] {
framework module Security [extern_c][system] {
umbrella header "Security.h"
export *

View File

@ -1,4 +1,4 @@
framework module Security [extern_c] {
framework module Security [extern_c][system] {
umbrella header "Security.h"
export *

View File

@ -1,4 +1,4 @@
module Security.SecTask [extern_c] {
module Security.SecTask [extern_c][system] {
header "SecTask.h"
export *
}

View File

@ -1,99 +0,0 @@
Breadcrumbs
===========
simple defintions:
old password
new password
K = random 16 byte key
EK = Encrypted K
EKold = ECB(PBKDF2(password_old), K)
EKnew = ECB(PBKDF2(password_new), K)
Breadcrumb = AES-GCM(K, old password)
Breadcrumbs are to make life easier when using AppleID password as
local password by allowing upgrade of keychains from old password to new
password.
When changing the password on one machine, the keychains for the user are
still encrypted (AES-GCM, key derived using PBKDF2) with the old password on
all machines.
This happens for one machine when changing password on the AppleID.apple.com webpage.
An EK is stored on the apple server. Each machine have its own EK stored on the web server.
When user change the password on the AppleID.apple.com website, the
web server will unwrap the key K with the old password and then rewrap
it with the new password.
unwrap(EKold, old password) -> K
wrap(K, new password) -> EKnew
This means that if the user changes password more then ones, the computer can still upgrade the keychain to the current password since K will be the same until a new EK is uploaded the the computer.
PKDF2 is used to avoid prebuilt lists of string2key tables attacks on
the breadcrumb + encryptedKey if the attacker possesses both.
Breadcrumb contain current password that encrypts the keychain. The breadcrumb itself is encrypted with a machine-specific key K.
The breadcrumb is stored on the local machine and never leaves the
local machine.
When the computer have upgrade keychain to the current password and new K, EK, and breadcrumb is generated.
Format
======
K = Random 16 byte
EK = ECB(PBKDF2(pw), key K) (16byte) | pbkdf-salt (20byte) | 4byte int network order of pbdf-iter
Breadcrumb = version (1) 1byte | AES-GCM-ENC(key K, password length (4byte, network order) | password | pad ) | tag
The encrypted key (EK) is a PKDF2 salt + iteration count + random AES-128 key (K)
encrypted with ECB of the PKDF2(salt, iteration, password).
There is no integrity on this encryption on purpose since that would make the
EK an verifier.
The format of the EncryptedKey is
ECB(PBKDF2(pw), key K) (16byte) | pbkdf-salt (20byte) | 4byte int network order of pbdf-iter
The random key (K) is used to encrypt a breadcrumb that is stored
locally on the machine. The breadcrumb allows you to recover the old
password if you know the new password and have the encrypted key.
The client machine encrypts the password with AES-GCM using key K. The data
is padded to 256 bytes to no tell password length.
The format of the breadcrumb
version (1) 1byte | AES-GCM-ENC(key K, password length (4byte, network order) | password | pad ) | tag
tag is the 16 byte GCM tag
key is the key (K) from the EncryptedKey (EK)
assoc data i AES-GCM covers version byte
Password length including up to pad is encrypted with AES-GCM
Password is padded to paddingSize (256) to avoid exposing length of password.
The PBKDF2 function is PBKDF2-HMAC-SHA256.
Updating the Encrypted Key (EK) on server
=========================================
When a user update the password on the apple id server the server
updates the breadcrumb for each machine that the user have associsated
with the account.
1. The server takes the old password generates a the key using PBKDF2
using the salt and interation count.
2. The server takes the new password generates a the key using PBKDF2
using the same salt and interation count.
3. Decrypts the first block with the key of old password and
re-encrypt with the key of new password.

View File

@ -1,397 +0,0 @@
/*
* Copyright (c) 2014 - 2016 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/Security.h>
#include <Security/SecBreadcrumb.h>
#include <Security/SecRandom.h>
#include <corecrypto/ccaes.h>
#include <corecrypto/ccpbkdf2.h>
#include <corecrypto/ccmode.h>
#include <corecrypto/ccmode_factory.h>
#include <corecrypto/ccsha2.h>
#include <CommonCrypto/CommonRandomSPI.h>
#import "SecCFAllocator.h"
#define CFReleaseNull(CF) ({ __typeof__(CF) *const _pcf = &(CF), _cf = *_pcf; (_cf ? (*_pcf) = ((__typeof__(CF))0), (CFRelease(_cf), ((__typeof__(CF))0)) : _cf); })
#define kBCKeySize CCAES_KEY_SIZE_128
#define kBCSaltSize 20
#define kBCIterations 5000
#define BCTagLen 16
#define BCIVLen 16
#define BCversion1 1
#define BCversion2 2
#define BCPaddingSize 256
#define BCMaxSize 1024
Boolean
SecBreadcrumbCreateFromPassword(CFStringRef inPassword,
CFDataRef *outBreadcrumb,
CFDataRef *outEncryptedKey,
CFErrorRef *outError)
{
const struct ccmode_ecb *ecb = ccaes_ecb_encrypt_mode();
const struct ccmode_gcm *gcm = ccaes_gcm_encrypt_mode();
uint8_t iv[BCIVLen];
CFMutableDataRef key, npw;
CFDataRef pw;
*outBreadcrumb = NULL;
*outEncryptedKey = NULL;
if (outError)
*outError = NULL;
key = CFDataCreateMutable(SecCFAllocatorZeroize(), 0);
if (key == NULL)
return false;
CFDataSetLength(key, kBCKeySize + kBCSaltSize + 4);
if (SecRandomCopyBytes(kSecRandomDefault, CFDataGetLength(key) - 4, CFDataGetMutableBytePtr(key)) != 0) {
CFReleaseNull(key);
return false;
}
if (SecRandomCopyBytes(kSecRandomDefault, BCIVLen, iv) != 0) {
CFReleaseNull(key);
return false;
}
uint32_t size = htonl(kBCIterations);
memcpy(CFDataGetMutableBytePtr(key) + kBCKeySize + kBCSaltSize, &size, sizeof(size));
/*
* Create data for password
*/
pw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), inPassword, kCFStringEncodingUTF8, 0);
if (pw == NULL) {
CFReleaseNull(key);
return false;
}
const CFIndex passwordLength = CFDataGetLength(pw);
if (passwordLength > BCMaxSize) {
CFReleaseNull(pw);
CFReleaseNull(key);
return false;
}
CFIndex paddedSize = passwordLength + BCPaddingSize - (passwordLength % BCPaddingSize);
const CFIndex outLength = 1 + BCIVLen + 4 + paddedSize + BCTagLen;
npw = CFDataCreateMutable(NULL, outLength);
if (npw == NULL) {
CFReleaseNull(pw);
CFReleaseNull(key);
return false;
}
CFDataSetLength(npw, outLength);
cc_clear(outLength, CFDataGetMutableBytePtr(npw));
CFDataGetMutableBytePtr(npw)[0] = BCversion2;
memcpy(CFDataGetMutableBytePtr(npw) + 1, iv, BCIVLen);
size = htonl(passwordLength);
memcpy(CFDataGetMutableBytePtr(npw) + 1 + BCIVLen, &size, sizeof(size));
memcpy(CFDataGetMutableBytePtr(npw) + 1 + BCIVLen + 4, CFDataGetBytePtr(pw), passwordLength);
/*
* Now create a GCM encrypted password using the random key
*/
ccgcm_ctx_decl(gcm->size, ctx);
ccgcm_init(gcm, ctx, kBCKeySize, CFDataGetMutableBytePtr(key));
ccgcm_set_iv(gcm, ctx, BCIVLen, iv);
ccgcm_gmac(gcm, ctx, 1, CFDataGetMutableBytePtr(npw));
ccgcm_update(gcm, ctx, outLength - BCTagLen - BCIVLen - 1, CFDataGetMutableBytePtr(npw) + 1 + BCIVLen, CFDataGetMutableBytePtr(npw) + 1 + BCIVLen);
ccgcm_finalize(gcm, ctx, BCTagLen, CFDataGetMutableBytePtr(npw) + outLength - BCTagLen);
ccgcm_ctx_clear(gcm->size, ctx);
/*
* Wrapping key is PBKDF2(sha256) over password
*/
const struct ccdigest_info *di = ccsha256_di();
uint8_t rawkey[CCSHA256_OUTPUT_SIZE];
_Static_assert(sizeof(rawkey) >= kBCKeySize, "keysize changed w/o updating digest");
if (sizeof(rawkey) != di->output_size) abort();
if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw),
kBCSaltSize, CFDataGetMutableBytePtr(key) + kBCKeySize,
kBCIterations,
sizeof(rawkey), rawkey) != 0)
abort();
/*
* Wrap the random key with one round of ECB cryto
*/
ccecb_ctx_decl(ccecb_context_size(ecb), ecbkey);
ccecb_init(ecb, ecbkey, kBCKeySize, rawkey);
ccecb_update(ecb, ecbkey, 1, CFDataGetMutableBytePtr(key), CFDataGetMutableBytePtr(key));
ccecb_ctx_clear(ccecb_context_size(ecb), ecbkey);
/*
*
*/
cc_clear(sizeof(rawkey), rawkey);
CFReleaseNull(pw);
*outBreadcrumb = npw;
*outEncryptedKey = key;
return true;
}
Boolean
SecBreadcrumbCopyPassword(CFStringRef inPassword,
CFDataRef inBreadcrumb,
CFDataRef inEncryptedKey,
CFStringRef *outPassword,
CFErrorRef *outError)
{
const struct ccmode_ecb *ecb = ccaes_ecb_decrypt_mode();
CFMutableDataRef gcmkey, oldpw;
CFIndex outLength;
CFDataRef pw;
uint32_t size;
*outPassword = NULL;
if (outError)
*outError = NULL;
if (CFDataGetLength(inEncryptedKey) < kBCKeySize + kBCSaltSize + 4) {
return false;
}
if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion1) {
if (CFDataGetLength(inBreadcrumb) < 1 + 4 + BCPaddingSize + BCTagLen)
return false;
outLength = CFDataGetLength(inBreadcrumb) - 1 - BCTagLen;
} else if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion2) {
if (CFDataGetLength(inBreadcrumb) < 1 + BCIVLen + 4 + BCPaddingSize + BCTagLen)
return false;
outLength = CFDataGetLength(inBreadcrumb) - 1 - BCIVLen - BCTagLen;
} else {
return false;
}
gcmkey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, inEncryptedKey);
if (gcmkey == NULL) {
return false;
}
if ((outLength % 16) != 0 && outLength < 4) {
CFReleaseNull(gcmkey);
return false;
}
oldpw = CFDataCreateMutable(SecCFAllocatorZeroize(), outLength);
if (oldpw == NULL) {
CFReleaseNull(gcmkey);
return false;
}
CFDataSetLength(oldpw, outLength);
/*
* Create data for password
*/
pw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), inPassword, kCFStringEncodingUTF8, 0);
if (pw == NULL) {
CFReleaseNull(oldpw);
CFReleaseNull(gcmkey);
return false;
}
/*
* Wrapping key is HMAC(sha256) over password
*/
const struct ccdigest_info *di = ccsha256_di();
uint8_t rawkey[CCSHA256_OUTPUT_SIZE];
_Static_assert(sizeof(rawkey) >= kBCKeySize, "keysize changed w/o updating digest");
if (sizeof(rawkey) != di->output_size) abort();
memcpy(&size, CFDataGetMutableBytePtr(gcmkey) + kBCKeySize + kBCSaltSize, sizeof(size));
size = ntohl(size);
if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw),
kBCSaltSize, CFDataGetMutableBytePtr(gcmkey) + kBCKeySize,
size,
sizeof(rawkey), rawkey) != 0)
abort();
CFReleaseNull(pw);
/*
* Unwrap the random key with one round of ECB cryto
*/
ccecb_ctx_decl(ccecb_context_size(ecb), ecbkey);
ccecb_init(ecb, ecbkey, kBCKeySize, rawkey);
ccecb_update(ecb, ecbkey, 1, CFDataGetMutableBytePtr(gcmkey), CFDataGetMutableBytePtr(gcmkey));
ccecb_ctx_clear(ccecb_context_size(ecb), ecbkey);
/*
* GCM unwrap
*/
uint8_t tag[BCTagLen];
if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion1) {
memcpy(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, BCTagLen);
ccgcm_one_shot_legacy(ccaes_gcm_decrypt_mode(), kBCKeySize, CFDataGetMutableBytePtr(gcmkey), 0, NULL, 1, CFDataGetBytePtr(inBreadcrumb),
outLength, CFDataGetBytePtr(inBreadcrumb) + 1, CFDataGetMutableBytePtr(oldpw), BCTagLen, tag);
if (memcmp(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, BCTagLen) != 0) {
CFReleaseNull(oldpw);
CFReleaseNull(gcmkey);
return false;
}
} else {
const uint8_t *iv = CFDataGetBytePtr(inBreadcrumb) + 1;
int res;
memcpy(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + BCIVLen + outLength, BCTagLen);
res = ccgcm_one_shot(ccaes_gcm_decrypt_mode(), kBCKeySize, CFDataGetMutableBytePtr(gcmkey),
BCIVLen, iv,
1, CFDataGetBytePtr(inBreadcrumb),
outLength, CFDataGetBytePtr(inBreadcrumb) + 1 + BCIVLen, CFDataGetMutableBytePtr(oldpw),
BCTagLen, tag);
if (res) {
CFReleaseNull(gcmkey);
CFReleaseNull(oldpw);
CFReleaseNull(gcmkey);
return false;
}
}
CFReleaseNull(gcmkey);
memcpy(&size, CFDataGetMutableBytePtr(oldpw), sizeof(size));
size = ntohl(size);
if ((ssize_t) size > outLength - 4) {
CFReleaseNull(oldpw);
return false;
}
memmove(CFDataGetMutableBytePtr(oldpw), CFDataGetMutableBytePtr(oldpw) + 4, size);
CFDataSetLength(oldpw, size);
*outPassword = CFStringCreateFromExternalRepresentation(SecCFAllocatorZeroize(), oldpw, kCFStringEncodingUTF8);
CFReleaseNull(oldpw);
return true;
}
CFDataRef
SecBreadcrumbCreateNewEncryptedKey(CFStringRef oldPassword,
CFStringRef newPassword,
CFDataRef encryptedKey,
CFErrorRef *outError)
{
const struct ccmode_ecb *enc = ccaes_ecb_encrypt_mode();
const struct ccmode_ecb *dec = ccaes_ecb_decrypt_mode();
const struct ccdigest_info *di = ccsha256_di();
uint8_t rawkey[CCSHA256_OUTPUT_SIZE];
CFDataRef newpw = NULL, oldpw = NULL;
CFMutableDataRef newEncryptedKey;
_Static_assert(sizeof(rawkey) >= kBCKeySize, "keysize changed w/o updating digest");
if (sizeof(rawkey) != di->output_size) abort();
if (CFDataGetLength(encryptedKey) < kBCKeySize + kBCSaltSize + 4) {
return NULL;
}
newEncryptedKey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, encryptedKey);
if (newEncryptedKey == NULL) {
return NULL;
}
oldpw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), oldPassword, kCFStringEncodingUTF8, 0);
if (oldpw == NULL) {
CFReleaseNull(newEncryptedKey);
return false;
}
newpw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), newPassword, kCFStringEncodingUTF8, 0);
if (newpw == NULL) {
CFReleaseNull(newEncryptedKey);
CFReleaseNull(oldpw);
return false;
}
/*
* Unwrap with new key
*/
uint32_t iter;
memcpy(&iter, CFDataGetMutableBytePtr(newEncryptedKey) + kBCKeySize + kBCSaltSize, sizeof(iter));
iter = ntohl(iter);
if (ccpbkdf2_hmac(di, CFDataGetLength(oldpw), CFDataGetBytePtr(oldpw),
kBCSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kBCKeySize,
iter,
sizeof(rawkey), rawkey) != 0)
abort();
CFReleaseNull(oldpw);
ccecb_ctx_decl(dec->size, deckey);
ccecb_init(dec, deckey, kBCKeySize, rawkey);
ccecb_update(dec, deckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey));
ccecb_ctx_clear(ccecb_context_size(dec), deckey);
cc_clear(sizeof(rawkey), rawkey);
/*
* Re-wrap with new key
*/
if (ccpbkdf2_hmac(di, CFDataGetLength(newpw), CFDataGetBytePtr(newpw),
kBCSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kBCKeySize,
iter,
sizeof(rawkey), rawkey) != 0)
abort();
CFReleaseNull(newpw);
ccecb_ctx_decl(enc->size, enckey);
ccecb_init(enc, enckey, kBCKeySize, rawkey);
ccecb_update(enc, enckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey));
ccecb_ctx_clear(ccecb_context_size(enc), enckey);
cc_clear(sizeof(rawkey), rawkey);
return newEncryptedKey;
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2014 - 2016 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@
*/
/*!
@function SecBreadcrumbCreateFromPassword
@abstract Encryptes the password using a random key and then returns
the encrypted password (breadcrumb) and the password encrypted random key.
@param inPassword is the password to encrypt and use to encrypt the random key.
@param outBreadcrumb is the password encrypted using a random key.
@param outEncryptedKey is the random key encrypted using inPassword.
@param outError An optional pointer to a CFErrorRef. This value is set
if an error occurred. If not NULL, the caller is responsible for
releasing the CFErrorRef.
@result On return a Boolean indicating success or failure.
@discussion This function generates the breadcrumb that will be used to
update the user's keychain password when their Apple ID Login password
is changed on appleid.apple.com.
*/
Boolean
SecBreadcrumbCreateFromPassword(CFStringRef inPassword,
CFDataRef *outBreadcrumb,
CFDataRef *outEncryptedKey,
CFErrorRef *outError);
/*!
@function SecBreadcrumbCopyPassword
@abstract Decryptes the encrypted key using the password and uses the key to
decrypt the breadcrumb and returns the password stored in the breadcrumb.
@param inPassword is the password to decrypt the encrypted random key.
@param inBreadcrumb is the breadcrumb encrypted by the key. It contains
and encrypted version of the users old password.
@param inEncryptedKey is an encrypted version of the key used to encrypt the
breadcrumb.
@param outPassword is the cleartext password that was stored in the breadcrumb.
@param outError An optional pointer to a CFErrorRef. This value is set
if an error occurred. If not NULL, the caller is responsible for
releasing the CFErrorRef.
@result On return a Boolean indicating success or failure.
@discussion This function uses the password to decrypt the encrypted key and then
uses that key to decrypt the breadcrumb.
*/
Boolean
SecBreadcrumbCopyPassword(CFStringRef inPassword,
CFDataRef inBreadcrumb,
CFDataRef inEncryptedKey,
CFStringRef *outPassword,
CFErrorRef *outError);
/*
* Change password used to encrypt the key from old password to new password
*/
CFDataRef
SecBreadcrumbCreateNewEncryptedKey(CFStringRef oldPassword,
CFStringRef newPassword,
CFDataRef encryptedKey,
CFErrorRef *outError);

View File

@ -1,105 +0,0 @@
/*
* Copyright (c) 2014 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <Foundation/Foundation.h>
#include <Security/Security.h>
#include <Security/SecBreadcrumb.h>
#include <utilities/SecCFRelease.h>
#include "breadcrumb_regressions.h"
static NSString *after1 = @"XAKyA0TbLKpDOBl+Ur1CQpjGDtn3wp8bYiM07iJSGVIhaaG4AAATiA==";
static NSString *bc1 = @"AdSXILtQrtsD+eT/UjMxxu4QTjlIJjvFDhpMXfk2eZ1CCJVhCuAhNcoL4DsU85DgSBCAswzVcSEU+bLMt+DT1jJfjJKVBus1Hd5lCA+N4wVtC66w3GK/WDQdGvLZ+BL86GkeRM2/+wH4/t5qOtxIJPS5SYZhnM5EP8xFYg30MLqXZqpwZhqYBJmVPMqEbLuihYAcAJreiZm4NN09CxvD36mvU3NyQOdHzAiQ+ADMiVI84qjU0qFH1KaZEoMHn3AqjAdviHUTOaNQXNepidedBZhSl4QBeuT2CaCYHjCXny9BYT+hCEU1yXn3RYeWyjcmFKmIz8gRvWf3ckF3XaSVL7MwqfsWw1tdI9OPi7zhauqphRGELw==";
static NSString *after2 = @"l/y+EOCUEeQHudNLQd5SoCJ2s/+rfH/kdbxbwZ7YGGb/U2FMAAATiA==";
static NSString *bc2 = @"AuuaJCuKmffY3XAqTYNygSFQ4QnlkSqTHGYUMaxDRA1lQhbxJh58zAOvcsahYH9lSb4+YoMR6G7hDmqlKae8h3jrn0vhT4FlIySFS3MUPvmGOuhUecb+Gi2AYwc9x1uz7f0FSRxxL+v04r2AkmH1Cv6cL7pvued7vxUjzX4VrexFj+uF7i/HSGStg2+D3L+CRs2+dKZZ9BqiKjavsX9XPkvJAD0r8rKHncOBrRxL7A3+ysBTZi2VCi/8QTDSGp6DmpXEJ4NTo/IrZ+trOXe0MuocLMg+Jf6V8jy5ZfaQoGTuM3fJiD6EFGT68QtLrjqU9KdtHhQdCmFVi60zbWqEBRNN7IyRNyPJX48NqFPZuAUW7BL0YbuhdUX2Oj7+hFz99vch1T0=";
#define kTestCount 10
int bc_10_password(int argc, char *const *argv)
{
CFDataRef breadcrumb = NULL, encryptedKey = NULL;
CFStringRef oldPassword = NULL;
CFStringRef password = CFSTR("password");
CFStringRef newpassword = CFSTR("newpassword");
CFErrorRef error = NULL;
plan_tests(kTestCount);
ok(SecBreadcrumbCreateFromPassword(password, &breadcrumb, &encryptedKey, &error), "wrap failed");
ok(SecBreadcrumbCopyPassword(password, breadcrumb, encryptedKey, &oldPassword, NULL), "unwrap failed");
ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
CFReleaseSafe(oldPassword);
CFDataRef newEncryptedKey;
printf("changing password from \"password\" to \"newpassword\"\n");
newEncryptedKey = SecBreadcrumbCreateNewEncryptedKey(password,
newpassword,
encryptedKey,
&error);
ok(newEncryptedKey, "no new encrypted key");
ok(SecBreadcrumbCopyPassword(newpassword, breadcrumb, newEncryptedKey, &oldPassword, NULL), "unwrap failed");
ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
CFReleaseSafe(breadcrumb);
CFReleaseSafe(oldPassword);
CFReleaseSafe(newEncryptedKey);
/*
* Check KAT for IV less operation (version1)
*/
breadcrumb = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:bc1 options:0]);
newEncryptedKey = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:after1 options:0]);
ok(SecBreadcrumbCopyPassword(newpassword, breadcrumb, newEncryptedKey, &oldPassword, NULL), "unwrap failed");
ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
CFReleaseSafe(breadcrumb);
CFReleaseSafe(oldPassword);
CFReleaseSafe(newEncryptedKey);
/*
* Check KAT for IV less operation (version2)
*/
breadcrumb = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:bc2 options:0]);
newEncryptedKey = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:after2 options:0]);
ok(SecBreadcrumbCopyPassword(newpassword, breadcrumb, newEncryptedKey, &oldPassword, NULL), "unwrap failed");
ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
CFReleaseSafe(breadcrumb);
CFReleaseSafe(oldPassword);
CFReleaseSafe(newEncryptedKey);
return 0;
}

View File

@ -1,7 +0,0 @@
/* To add a test:
1) add it here
2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes
*/
#include <regressions/test/testmore.h>
ONE_TEST(bc_10_password)

View File

@ -104,6 +104,8 @@ static void PSKeychainSyncIsUsingICDP(void)
NSError *localError = NULL;
CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init];
CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair];
secnotice("followup", "Posting a follow up (for SOS) of type repair");
[cdpd postFollowUpWithContext:context error:&localError ];
if(localError){
secnotice("kcn", "request to CoreCDP to follow up failed: %@", localError);

View File

@ -1,9 +1,9 @@
.Dd November 02, 2016
.Dt Keychain Circle Notification 8
.Dt Keychain\ Circle\ Notification 8
.Os
.Sh NAME
.Nm Keychain Circle Notification
.Nd part of iCloud Keychain syncing.
.Nd Part of iCloud Keychain syncing.
.Sh DESCRIPTION
.Nm
part of iCloud Keychain syncing.
Part of iCloud Keychain syncing.

View File

@ -38,16 +38,12 @@
-(id)initWithPeerObject:(id)peerObject
{
self = [super init];
if (!self) {
return self;
}
self.peerObject = peerObject;
self.name = (__bridge NSString *)(SOSPeerInfoGetPeerName((__bridge SOSPeerInfoRef)peerObject));
self.idString = (__bridge NSString *)(SOSPeerInfoGetPeerID((__bridge SOSPeerInfoRef)peerObject));
return self;
if ((self = [super init])) {
self.peerObject = peerObject;
self.name = (__bridge NSString *)(SOSPeerInfoGetPeerName((__bridge SOSPeerInfoRef)peerObject));
self.idString = (__bridge NSString *)(SOSPeerInfoGetPeerID((__bridge SOSPeerInfoRef)peerObject));
}
return self;
}
-(NSString*)description

View File

@ -160,14 +160,15 @@ typedef void (^applicantBlock)(id applicant);
-(id)init
{
self = [super init];
int token;
if ((self = [super init])) {
int token;
self->_queue_ = dispatch_queue_create([[NSString stringWithFormat:@"KDSecCircle@%p", self] UTF8String], NULL);
self->_callbacks = [NSMutableArray new];
notify_register_dispatch(kSOSCCCircleChangedNotification, &token, self.queue_, ^(int token1){
[self updateCheck];
});
self->_queue_ = dispatch_queue_create([[NSString stringWithFormat:@"KDSecCircle@%p", self] UTF8String], NULL);
self->_callbacks = [NSMutableArray new];
notify_register_dispatch(kSOSCCCircleChangedNotification, &token, self.queue_, ^(int token1) {
[self updateCheck];
});
}
return self;
}

View File

@ -1 +0,0 @@
../Modules

View File

@ -44,5 +44,11 @@
<string>123456.test.group2</string>
<string>com.apple.bluetooth</string>
</array>
<key>com.apple.private.AuthorizationServices</key>
<array>
<string>com.apple.trust-settings.admin</string>
</array>
<key>com.apple.private.security.storage.Keychains</key>
<true/>
</dict>
</plist>

View File

@ -1,7 +1,6 @@
/* Don't prevent multiple inclusion of this file. */
#include <libsecurity_ssl/regressions/ssl_regressions.h>
#include <libsecurity_keychain/regressions/keychain_regressions.h>
#include <Breadcrumb/breadcrumb_regressions.h>
#include <libsecurity_cms/regressions/cms_regressions.h>
#include <libsecurity_transform/regressions/transform_regressions.h>
#include <shared_regressions/shared_regressions.h>

View File

@ -0,0 +1,8 @@
//
// PreloginUserDb.h
// authd
//
OSStatus preloginudb_copy_userdb(const char * _Nullable uuid, UInt32 flags, CFArrayRef _Nonnull * _Nonnull output);
OSStatus prelogin_copy_pref_value(const char * _Nullable uuid, const char * _Nullable user, const char * _Nonnull domain, const char * _Nonnull item, CFTypeRef _Nonnull * _Nonnull output);
OSStatus prelogin_smartcardonly_override(const char * _Nonnull uuid, unsigned char operation, Boolean * _Nullable status);

884
OSX/authd/PreloginUserDb.m Normal file
View File

@ -0,0 +1,884 @@
//
// PreloginUserDb.m
// authd
//
// Copyright © 2019 Apple. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <libgen.h>
#import <APFS/APFS.h>
#import <DiskManagement/DiskManagement.h>
#import "PreloginUserDb.h"
#import <LocalAuthentication/LAContext+Private.h>
#import <SoftLinking/SoftLinking.h>
#import "debugging.h"
#import <Security/Authorization.h>
#import <Security/AuthorizationPriv.h>
#import <Security/AuthorizationTagsPriv.h>
#import <libaks_filevault.h>
#import "authutilities.h"
AUTHD_DEFINE_LOG
SOFT_LINK_FRAMEWORK(Frameworks, LocalAuthentication)
SOFT_LINK_FRAMEWORK(PrivateFrameworks, DiskManagement)
SOFT_LINK_FRAMEWORK(Frameworks, DiskArbitration)
SOFT_LINK_FRAMEWORK(PrivateFrameworks, APFS)
SOFT_LINK_CLASS(LocalAuthentication, LAContext)
SOFT_LINK_CLASS(DiskManagement, DMManager)
SOFT_LINK_CLASS(DiskManagement, DMAPFS)
SOFT_LINK_FUNCTION(APFS, APFSVolumeGetUnlockRecord, soft_APFSVolumeGetUnlockRecord, errno_t, (const char *disk, uuid_t wrecUUID, CFDataRef *data), (disk, wrecUUID, data))
SOFT_LINK_FUNCTION(DiskArbitration, DADiskMount, soft_DADiskMount, void, ( DADiskRef disk, CFURLRef __nullable path, DADiskMountOptions options, DADiskMountCallback __nullable callback, void * __nullable context), (disk, path, options, callback, context ))
SOFT_LINK_FUNCTION(DiskArbitration, DADiskUnmount, soft_DADiskUnmount, void, ( DADiskRef disk, DADiskUnmountOptions options, DADiskUnmountCallback __nullable callback, void * __nullable context), (disk, options, callback, context ))
SOFT_LINK_FUNCTION(DiskArbitration, DADissenterGetStatusString, soft_DADissenterGetStatusString, CFStringRef __nullable, ( DADissenterRef dissenter ), ( dissenter ))
SOFT_LINK_FUNCTION(DiskManagement, DMUnlocalizedTechnicalErrorString, soft_DMUnlocalizedTechnicalErrorString, NSString *, ( DMDiskErrorType inError ), ( inError ))
SOFT_LINK_FUNCTION(DiskArbitration, DASessionCreate, soft_DASessionCreate, DASessionRef __nullable, ( CFAllocatorRef __nullable allocator ), ( allocator ))
SOFT_LINK_FUNCTION(DiskArbitration, DADissenterGetStatus, soft_DADissenterGetStatus, DAReturn, ( DADissenterRef dissenter ), ( dissenter ))
SOFT_LINK_FUNCTION(DiskArbitration, DASessionSetDispatchQueue, soft_DASessionSetDispatchQueue, void, ( DASessionRef session, dispatch_queue_t __nullable queue ), ( session, queue ))
static NSString *kVekItemName = @"SecureAccessToken";
static NSString *kGUIDItemName = @"GeneratedUID";
static NSString *kAuthenticationAuthority = @"AuthenticationAuthority";
static NSString *kIsAdmintemName = @"Admin";
static NSString *kSCUnlockDataItemName = @"FVTokenSecret";
static NSString *kSCEnforcementItemName = @"SmartCardEnforcement";
static NSString *kSCUacItemName = @"userAccountControl";
static NSString *kLongNameItemName = @"RealName";
static NSString *kUidItemName = @"UID";
static NSString *kVekFile = @"%@/%@/var/db/secureaccesstoken.plist";
static NSString *kUsersFile = @"%@/%@/var/db/AllUsersInfo.plist";
static NSString *kUsersGUID = @"UserIdent";
static NSString *kUsersNameSection = @"UserNamesData";
static NSString *kUsersSection = @"CryptoUsers";
static NSString *globalConfigPath = @"%@/%@/Library/Preferences";
static NSString *managedConfigPath = @"%@/%@/Library/Managed Preferences";
static NSString *homeDirPath = @"%@/%@/Users";
static NSString *fvunlockOverrideScEnforcementPrefsName = @"com.apple.smartcard.fvunlock";
static NSString *fvunlockOverrideScEnforcementFileName = @"%@/%@/var/db/.scnotenforced";
@interface PreloginUserDb : NSObject {
Boolean scEnforcementOverriden;
}
- (instancetype)init;
- (BOOL) loadWithError:(NSError **)error;
- (NSArray<NSDictionary *> *) users;
- (NSArray<NSDictionary *> *) users:(NSString *)volumeUuid;
- (NSDictionary *) globalPrefs:(NSString *)uuid domain:(NSString *)domain;
- (NSDictionary *) managedPrefs:(NSString *)uuid domain:(NSString *)domain;
- (NSDictionary *) userPrefs:(NSString *)uuid user:(NSString *)user domain:(NSString *)domain;
@end
typedef void (^AIRDBDACommonCompletionHandler)(DADissenterRef dissenter);
static void _commonDACompletionCallback(DADiskRef disk, DADissenterRef dissenter, void *context)
{
AIRDBDACommonCompletionHandler handler = (__bridge AIRDBDACommonCompletionHandler)context;
handler(dissenter);
}
OSStatus preloginDb(PreloginUserDb * _Nonnull * _Nonnull _Nonnulldb);
@implementation PreloginUserDb {
DMManager *_diskMgr;
id _daSession;
NSMutableDictionary<NSString *, NSDictionary *> *_globalPrefs; // NSString *prefDomain indexed by volume UUID (NSString *)
NSMutableDictionary<NSString *, NSDictionary *> *_userPrefs; // NSString *username indexed by volume UUID (NSString *)
NSMutableDictionary<NSString *, NSDictionary *> *_managedPrefs; // NSString *prefDomain indexed by volume UUID (NSString *)
NSMutableDictionary<NSString *, NSMutableArray *> *_dbDataDict; // NSDictionary indexed by volume UUID (NSString *)
NSMutableDictionary<NSString *, NSString *> *_dbVolumeGroupMap;
dispatch_queue_t _queue;
}
- (instancetype)init
{
if ((self = [super init])) {
_queue = dispatch_queue_create("com.apple.PLUDB", DISPATCH_QUEUE_SERIAL);
if (!_queue) {
os_log_error(AUTHD_LOG, "Failed to create queue");
return nil;
}
_diskMgr = [[getDMManagerClass() alloc] init];
if (!_diskMgr) {
os_log_error(AUTHD_LOG, "Failed to get DM");
return nil;
}
_daSession = (__bridge_transfer id)soft_DASessionCreate(kCFAllocatorDefault);
if (!_daSession) {
os_log_error(AUTHD_LOG, "Failed to get DA");
return nil;
}
soft_DASessionSetDispatchQueue((__bridge DASessionRef _Nullable)_daSession, _queue);
[_diskMgr setDefaultDASession:(__bridge DASessionRef _Nullable)(_daSession)];
_dbDataDict = [NSMutableDictionary new];
_dbVolumeGroupMap = [NSMutableDictionary new];
_userPrefs = [NSMutableDictionary new];
_globalPrefs = [NSMutableDictionary new];
_managedPrefs = [NSMutableDictionary new];
}
return self;
}
- (BOOL)loadWithError:(NSError **)err
{
// get all preboot volumes
NSArray *prebootVolumes = [self allPrebootVolumes];
if (prebootVolumes.count == 0) {
os_log_error(AUTHD_LOG, "Failed to get preboot volumes for Prelogin userDB");
if (err) {
*err = [NSError errorWithDomain:@"com.apple.authorization" code:-1000 userInfo:@{ NSLocalizedDescriptionKey : @"Failed to get preboot volumes for Prelogin userDB"}];
}
return NO;
}
NSUUID *uuid = [self currentRecoveryVolumeUUID];
os_log_info(AUTHD_LOG, "Current Recovery Volume UUID: %{public}@", uuid);
OSStatus (^volumeWorker)(NSUUID *volumeUuid, NSString *mountPoint) = ^OSStatus(NSUUID *volumeUuid, NSString *mountPoint) {
[self processVolumeData:volumeUuid mountPoint:mountPoint];
return noErr;
};
[self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:uuid worker:volumeWorker];
if (_dbDataDict.count == 0 && uuid != nil) {
os_log(AUTHD_LOG, "No admins found. Try to load all preboot partitions");
_dbDataDict = [NSMutableDictionary new];
[self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:nil worker:volumeWorker]; // load admins from ALL preboot partitions
}
if (err) {
*err = nil;
}
return YES;
}
- (NSArray<NSDictionary *> *)users
{
return [self users:nil];
}
- (NSArray<NSDictionary *> *)users:(NSString *)requestedUuid
{
if (!_dbDataDict.allValues) {
return nil;
}
if (requestedUuid && !_dbDataDict[requestedUuid]) {
NSString *realUuid = _dbVolumeGroupMap[requestedUuid];
if (!realUuid) {
os_log_info(AUTHD_LOG, "Requested volume %{public}@ was not found and is not volumeGroup", requestedUuid);
NSArray *keys = [_dbVolumeGroupMap allKeysForObject:requestedUuid];
for(NSString *uuid in keys) {
if (_dbDataDict[uuid]) {
realUuid = uuid;
break;
}
}
if (!realUuid) {
os_log_info(AUTHD_LOG, "Requested volumeGroup %{public}@ was not found", requestedUuid);
return nil; // no users for requested partition and no mapping for VolumeGroup or vice versa
}
}
os_log_info(AUTHD_LOG, "Requested volume %{public}@ has no users, trying volume %{public}@", requestedUuid, realUuid);
requestedUuid = realUuid;
}
NSMutableArray *allUsers = [NSMutableArray new];
for (NSString *uuid in _dbDataDict) {
if (requestedUuid && ![requestedUuid isEqualToString:uuid]) {
os_log_info(AUTHD_LOG, "Requested volume %{public}@ so ignoring volume %{public}@", requestedUuid, uuid);
continue;
}
[allUsers addObjectsFromArray:_dbDataDict[uuid]];
}
return allUsers;
}
- (NSDictionary *)globalPrefs:(NSString *)uuid domain:(NSString *)domain
{
NSDictionary *volumeGlobalPrefs = _globalPrefs[uuid];
if (!volumeGlobalPrefs) {
os_log_debug(AUTHD_LOG, "No global prefs for volume %{public}@ were found", uuid);
return nil;
}
return volumeGlobalPrefs[domain];
}
- (NSDictionary *)managedPrefs:(NSString *)uuid domain:(NSString *)domain
{
NSDictionary *volumeManagedPrefs = _managedPrefs[uuid];
if (!volumeManagedPrefs) {
return nil;
}
return volumeManagedPrefs[domain];
}
- (NSDictionary *)userPrefs:(NSString *)uuid user:(NSString *)user domain:(NSString *)domain
{
NSDictionary *volumeUserPrefs = _userPrefs[uuid];
if (!volumeUserPrefs) {
os_log_debug(AUTHD_LOG, "No user prefs for volume %{public}@ were found", uuid);
return nil;
}
NSDictionary *userPrefs = volumeUserPrefs[user];
if (!userPrefs) {
os_log_debug(AUTHD_LOG, "No user prefs for volume %{public}@ and user %{public}@ were found", uuid, user);
return nil;
}
return userPrefs[domain];
}
- (OSStatus)setEnforcedSmartcardOverride:(NSUUID *)uuid operation:(unsigned char)operation status:(Boolean *)status internal:(Boolean)internal
{
if (!isInFVUnlock()) {
if (operation == kAuthorizationOverrideOperationQuery && !internal) {
if (status) {
*status = scEnforcementOverriden;
}
return noErr;
} else if (!internal) {
os_log_error(AUTHD_LOG, "SmartCard enforcement can be set only from Recovery");
return errSecNotAvailable;
}
}
NSArray *prebootVolumes = [self allPrebootVolumes];
__block OSStatus retval = errAuthorizationInternal;
OSStatus (^volumeWorker)(NSUUID *volumeUuid, NSString *mountPoint) = ^OSStatus(NSUUID *volumeUuid, NSString *mountPoint) {
NSString *usersPath = [NSString stringWithFormat:kUsersFile, mountPoint, volumeUuid.UUIDString];
if (access(usersPath.UTF8String, F_OK)) {
os_log_info(AUTHD_LOG, "This preboot volume is not usable for FVUnlock");
return errSecInvalidItemRef;
}
os_log_info(AUTHD_LOG, "Preboot volume %{public}@ is usable for FVUnlock", volumeUuid);
NSString *filePath = [NSString stringWithFormat:fvunlockOverrideScEnforcementFileName, mountPoint, volumeUuid.UUIDString];
BOOL overrideFileExists = !access(filePath.UTF8String, F_OK);
switch(operation) {
case kAuthorizationOverrideOperationSet: // set
{
if (overrideFileExists) {
os_log(AUTHD_LOG, "SmartCard enforcement override is already active.");
retval = noErr;
} else {
mode_t mode = S_IRUSR | S_IWUSR;
int fd = creat(filePath.UTF8String, mode);
if (fd != -1) {
os_log(AUTHD_LOG, "SmartCard enforcement override turned on");
retval = noErr;
close(fd);
} else {
os_log_error(AUTHD_LOG, "Unable to write override file: %d", errno);
retval = errno;
}
}
break;
}
case kAuthorizationOverrideOperationReset: // reset
{
if (!overrideFileExists) {
os_log(AUTHD_LOG, "SmartCard enforcement override not active.");
retval = errSecNoSuchAttr;
} else {
os_log(AUTHD_LOG, "SmartCard enforcement override turned off");
retval = (OSStatus)remove(filePath.UTF8String);
}
break;
}
case kAuthorizationOverrideOperationQuery: // status
{
if (!status) {
break;
}
*status = overrideFileExists;
os_log_debug(AUTHD_LOG, "SmartCard enforcement override status %d", overrideFileExists);
retval = noErr;
break;
}
default: {
os_log_error(AUTHD_LOG, "Unknown operation %d", operation);
}
}
return retval;
};
[self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:uuid worker:volumeWorker];
return retval;
}
#pragma mark - Private Methods
- (void)processPrebootVolumes:(NSArray*)prebootVolumes currentRecoveryVolumeUUID:(NSUUID *)currentRecoveryVolumeUUID worker:(OSStatus (^)(NSUUID *volumeUuid, NSString *mountPoint))workerBlock
{
// process each preboot volume
for (id prebootVolume in prebootVolumes) {
// mount the preboot volume. If it fails it could be already mounted. Try to get mountPoint anyway.
Boolean mounted = [self mountPrebootVolume:prebootVolume];
// get a mount point of the preboot volume
NSString *mountPoint = [self mountPointForPrebootVolume:prebootVolume];
if (!mountPoint) {
os_log_info(AUTHD_LOG, "Volume %{public}@ has no mountpoint", prebootVolume);
continue;
}
// process the preboot volume
NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:mountPoint isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
for (NSURL *url in dirEnumerator) {
BOOL isDir = NO;
[[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir];
if (!isDir) {
os_log_info(AUTHD_LOG, "Skipping file %{public}@ (not a directory)", url.path);
continue;
}
NSUUID *volumeUUID = [[NSUUID alloc] initWithUUIDString:url.lastPathComponent]; // the dir has the name as UUID
if (!volumeUUID) {
os_log_info(AUTHD_LOG, "Ignoring folder %{public}@ (not UUID)", url);
continue;
}
if (currentRecoveryVolumeUUID && ![currentRecoveryVolumeUUID isEqualTo:volumeUUID]) {
os_log_info(AUTHD_LOG, "The preboot volume skipped: %{public}@ (not the currentRecoveryVolumeUUID %{public}@)", url, currentRecoveryVolumeUUID);
continue;
}
if (workerBlock) {
workerBlock(volumeUUID, mountPoint);
}
}
// unmount the preboot volume
if (mounted) {
[self unmountPrebootVolume:prebootVolume];
}
}
}
#define kEFISystemVolumeUUIDVariableName "SystemVolumeUUID"
- (NSUUID *)currentRecoveryVolumeUUID
{
NSData *data;
NSString * const LANVRAMNamespaceStartupManager = @"5EEB160F-45FB-4CE9-B4E3-610359ABF6F8";
NSString *key = [NSString stringWithFormat:@"%@:%@", LANVRAMNamespaceStartupManager, @kEFISystemVolumeUUIDVariableName];
io_registry_entry_t match = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
if (match) {
CFTypeRef entry = IORegistryEntryCreateCFProperty(match, (__bridge CFStringRef)key, kCFAllocatorDefault, 0);
IOObjectRelease(match);
if (entry)
{
if (CFGetTypeID(entry) == CFDataGetTypeID())
data = CFBridgingRelease(entry);
else
CFRelease(entry);
}
}
os_log_info(AUTHD_LOG, "Current boot volume: %{public}@", data);
if (data) {
return [[NSUUID alloc] initWithUUIDBytes:data.bytes];
} else {
return nil;
}
}
- (NSArray *)allPrebootVolumes
{
NSMutableArray* result = [NSMutableArray new];
DMAPFS* dmAPFS = [[getDMAPFSClass() alloc] initWithManager:_diskMgr];
for (id tmp in _diskMgr.disks) {
DADiskRef diskRef = (__bridge DADiskRef)(tmp);
os_log_info(AUTHD_LOG, "Found disk %{public}@", diskRef);
BOOL preboot;
DMDiskErrorType diskErr = [dmAPFS isPrebootVolume:diskRef prebootRole:&preboot];
if (diskErr) {
os_log(AUTHD_LOG, "Failed to determine preboot state for %{public}@: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
continue;
}
if (!preboot) {
os_log_info(AUTHD_LOG, "Not a preboot volume: %{public}@", diskRef);
continue;
}
id prebootVolume = CFBridgingRelease([_diskMgr copyBooterDiskForDisk:diskRef error:&diskErr]);
if (prebootVolume) {
os_log_info(AUTHD_LOG, "Found APFS preboot %{public}@", prebootVolume);
[result addObject:prebootVolume];
} else {
os_log_error(AUTHD_LOG, "Failed to copy preboot for disk %{public}@, err: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
}
}
return result;
}
- (BOOL)mountPrebootVolume:(id)preboot
{
__block BOOL success = NO;
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
AIRDBDACommonCompletionHandler completionHandler = ^(DADissenterRef dissenter) {
success = (dissenter == NULL);
if (dissenter != NULL) {
os_log(AUTHD_LOG, "Failed to mount preboot volume %{public}@ (status: 0x%x, reason: \"%{public}@\").", preboot, soft_DADissenterGetStatus(dissenter), soft_DADissenterGetStatusString(dissenter));
}
dispatch_semaphore_signal(sem);
};
soft_DADiskMount((__bridge DADiskRef _Nonnull)(preboot), NULL, kDADiskMountOptionDefault, _commonDACompletionCallback, (__bridge void * _Nullable)(completionHandler));
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return success;
}
- (NSString *)mountPointForPrebootVolume:(id)preboot
{
DMDiskErrorType diskErr;
NSString* result = [_diskMgr mountPointForDisk:(__bridge DADiskRef _Nonnull)(preboot) error:&diskErr];
if (result) {
os_log_info(AUTHD_LOG, "Mounted preboot partition %{public}@ at %{public}@", preboot, result);
} else {
os_log_error(AUTHD_LOG, "Failed to get preboot mount point: %{public}@", soft_DMUnlocalizedTechnicalErrorString(diskErr));
}
return result;
}
- (void)unmountPrebootVolume:(id)preboot
{
soft_DADiskUnmount((__bridge DADiskRef _Nonnull)(preboot), kDADiskUnmountOptionDefault, nil, nil);
os_log_info(AUTHD_LOG, "Preboot partition unmounted: %{public}@", preboot);
}
- (NSString *)deviceNodeForVolumeWithUUID:(NSUUID *)volumeUuid diskRef:(DADiskRef *)diskRef
{
DMDiskErrorType diskErr;
DADiskRef localDiskRef = [_diskMgr copyDiskForVolumeUUID:volumeUuid.UUIDString error:&diskErr];
if (!localDiskRef) {
os_log_error(AUTHD_LOG, "Failed to find disk with volume %{public}@: %{public}@", volumeUuid, soft_DMUnlocalizedTechnicalErrorString(diskErr));
return nil;
}
if (diskRef) {
*diskRef = localDiskRef;
CFRetain(*diskRef);
}
os_log_info(AUTHD_LOG, "Found disk %{public}@ with volume UUID %{public}@", localDiskRef, volumeUuid);
NSString* deviceNode = [self deviceNodeForDisk:localDiskRef];
CFRelease(localDiskRef);
return deviceNode;
}
- (NSString *)deviceNodeForDisk:(DADiskRef)diskRef
{
DMDiskErrorType diskErr;
NSString *deviceNode = [_diskMgr deviceNodeForDisk:diskRef error:&diskErr];
if (!deviceNode) {
os_log_error(AUTHD_LOG, "Failed to find device node for disk %{public}@: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
return nil;
}
os_log_info(AUTHD_LOG, "Device node found: %{public}@", deviceNode);
return deviceNode;
}
- (NSData *)loadVEKforVolumeWithUUID:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
{
NSString *vekPath = [NSString stringWithFormat:kVekFile, mountPoint, volumeUuid.UUIDString];
NSDictionary *vekDict = [NSDictionary dictionaryWithContentsOfFile:vekPath];
NSData *vek = vekDict[kVekItemName];
if (!vek) {
os_log_error(AUTHD_LOG, "Failed to load DiskToken from %{public}@", vekPath);
return nil;
}
os_log_info(AUTHD_LOG, "Loaded DiskToken from %{public}@", vekPath);
return vek;
}
- (NSData *)loadKEKforUuid:(NSString *)userUuid deviceNode:(NSString *)deviceNode
{
NSUUID *nsUuid = [[NSUUID alloc] initWithUUIDString:userUuid];
uuid_t uuid;
[nsUuid getUUIDBytes:uuid];
CFDataRef dataCF;
errno_t err = soft_APFSVolumeGetUnlockRecord(deviceNode.UTF8String, uuid, &dataCF);
if(err != 0) {
os_log_error(AUTHD_LOG, "Failed to find SecureToken on device node %{public}@ and UUID %{public}@ (%d)", deviceNode, userUuid, err);
return nil;
}
os_log_info(AUTHD_LOG, "Loaded SecureToken from device node %{public}@", deviceNode);
NSData *kek = CFBridgingRelease(dataCF);
return kek;
}
- (NSDictionary *)loadUserDatabaseForVolumeUUID:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
{
NSString *usersPath = [NSString stringWithFormat:kUsersFile, mountPoint, volumeUuid.UUIDString];
NSDictionary *users = [NSDictionary dictionaryWithContentsOfFile:usersPath];
if (users.count == 0) {
os_log_error(AUTHD_LOG, "Failed to find user records in file %{public}@", usersPath);
return nil;
}
os_log_debug(AUTHD_LOG, "Loaded %lu user records from file %{public}@", (unsigned long)users.count, usersPath);
return users;
}
- (void)processVolumeData:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
{
os_log_info(AUTHD_LOG, "Processing volume data: %{public}@", volumeUuid);
NSData *vek = [self loadVEKforVolumeWithUUID:volumeUuid mountPoint:mountPoint];
if (!vek) {
return;
}
DADiskRef cfDiskRef = NULL;
NSString* deviceNode = [self deviceNodeForVolumeWithUUID:volumeUuid diskRef:&cfDiskRef];
id diskRef = CFBridgingRelease(cfDiskRef);
if (!deviceNode) {
return;
}
NSString *volumeGroupUuid;
DMAPFS* dmAPFS = [[getDMAPFSClass() alloc] initWithManager:_diskMgr];
DMDiskErrorType diskErr = [dmAPFS volumeGroupForVolume:(__bridge DADiskRef _Nonnull)(diskRef) id:&volumeGroupUuid];
if (diskErr != kDiskErrorNoError || volumeGroupUuid == nil) {
os_log_error(AUTHD_LOG, "Error %d while trying to get volume group for %{public}@", diskErr, volumeUuid);
} else {
if ([volumeUuid.UUIDString isEqualTo:volumeGroupUuid]) {
NSArray *systemVolumeDisks = nil;
diskErr = [dmAPFS disksForVolumeGroup:volumeGroupUuid volumeDisks:nil systemVolumeDisks:&systemVolumeDisks dataVolumeDisks:nil userVolumeDisks:nil container:nil];
if (diskErr != kDiskErrorNoError || systemVolumeDisks == nil) {
os_log_error(AUTHD_LOG, "Error %d while trying to get volume group disks for %{public}@", diskErr, volumeGroupUuid);
} else {
// There should be only one systemVolume, but the API returns an array so we'll process as many as it wants to give us
for (id tmp in systemVolumeDisks) {
DADiskRef systemVolumeDiskRef = (__bridge DADiskRef)(tmp);
NSString *systemVolumeUuid = nil;
diskErr = [dmAPFS volumeUUIDForVolume:systemVolumeDiskRef UUID:&systemVolumeUuid];
if (diskErr != kDiskErrorNoError || systemVolumeUuid == nil) {
os_log_error(AUTHD_LOG, "Error %d while trying to get volume uuid disks for some system volumes of group %{public}@", diskErr, volumeGroupUuid);
} else {
os_log(AUTHD_LOG, "Volume %{public}@ belongs to the group %{public}@", systemVolumeUuid, volumeGroupUuid);
_dbVolumeGroupMap[systemVolumeUuid] = volumeGroupUuid;
}
}
}
}
}
NSDictionary *users = [self loadUserDatabaseForVolumeUUID:volumeUuid mountPoint:mountPoint];
for (NSString *userName in users) {
NSDictionary *userData = users[userName];
os_log_debug(AUTHD_LOG, "Processing user: %{public}@", userData);
NSString *userGuid = userData[kGUIDItemName];
if (userGuid == nil) {
os_log_error(AUTHD_LOG, "Failed to find GUID for user %{public}@", userName);
continue;
}
NSData* kek = [self loadKEKforUuid:userGuid deviceNode:deviceNode];
if (!kek) {
os_log_error(AUTHD_LOG, "Failed to find SecureToken for user %{public}@", userName);
continue;
}
NSArray *aauthority = userData[kAuthenticationAuthority];
NSMutableDictionary *dict = @{}.mutableCopy;
if (aauthority) {
dict[@PLUDB_SCPAIR] = aauthority;
os_log_debug(AUTHD_LOG, "Using authority: %{public}@", aauthority);
}
Boolean owner;
struct aks_fv_param_s params = {};
aks_fv_blob_state_s verifier_state = {};
struct aks_fv_data_s kekData = { .data = (void *)kek.bytes, .len = kek.length };
int res = aks_fv_get_blob_state(&params, &kekData, &verifier_state);
if (res) {
os_log_error(AUTHD_LOG, "Blob state failed: %x", res);
owner = NO;
} else {
owner = ((verifier_state.flags & aks_fv_state_is_owner) == aks_fv_state_is_owner);
}
dict[@PLUDB_USERNAME] = userName;
dict[@PLUDB_GUID] = userGuid;
dict[@PLUDB_ADMIN] = userData[kIsAdmintemName];
dict[@PLUDB_KEK] = kek;
dict[@PLUDB_VEK] = vek;
dict[@PLUDB_DNODE] = deviceNode;
dict[@PLUDB_OWNER] = @(owner);
if ([userData.allKeys containsObject:kSCUnlockDataItemName]) {
dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCUnlockDataItemName];
}
if ([userData.allKeys containsObject:kSCEnforcementItemName]) {
dict[@PLUDB_SCENF] = userData[kSCEnforcementItemName];
}
if ([userData.allKeys containsObject:kSCUacItemName]) {
dict[@PLUDB_SCUAC] = userData[kSCUacItemName];
}
if ([userData.allKeys containsObject:kLongNameItemName]) {
dict[@PLUDB_LUSERNAME] = userData[kLongNameItemName];
}
NSMutableArray *array = _dbDataDict[volumeUuid.UUIDString];
if (array == nil) {
array = [NSMutableArray new];
if (!array) {
os_log_error(AUTHD_LOG, "Failed to create users array");
return;
}
_dbDataDict[volumeUuid.UUIDString] = array;
}
os_log_info(AUTHD_LOG, "Prelogin UserDB added entry: %{public}@", dict);
[array addObject:dict];
}
// check for SC override
scEnforcementOverriden = NO;
[self setEnforcedSmartcardOverride:volumeUuid operation:kAuthorizationOverrideOperationQuery status:&scEnforcementOverriden internal:YES];
os_log_info(AUTHD_LOG, "SC enforcement override: %d", scEnforcementOverriden);
if (!isInFVUnlock()) {
os_log_debug(AUTHD_LOG, "Not processing prefs");
// remove SCenforcement override flag
if (scEnforcementOverriden) {
[self setEnforcedSmartcardOverride:volumeUuid operation:kAuthorizationOverrideOperationReset status:nil internal:YES];
}
return; // do not process prefs when not in FVUnlock
}
// process preferences
// global prefs
NSMutableDictionary *global = @{}.mutableCopy;
NSString *filePath = [NSString stringWithFormat:globalConfigPath, mountPoint, volumeUuid.UUIDString];
NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:filePath isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
for (NSURL *url in dirEnumerator) {
BOOL isDir = NO;
[[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir];
if (isDir) {
os_log_info(AUTHD_LOG, "Skipping dir %{public}@ (not a file)", url.path);
continue;
}
NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:url.path];
if (prefs) {
NSString *prefName = url.URLByDeletingPathExtension.lastPathComponent;
global[prefName] = prefs;
}
}
if (scEnforcementOverriden) {
os_log_info(AUTHD_LOG, "SC enforcement overriden for this boot");
global[fvunlockOverrideScEnforcementPrefsName] = @{ @"overrideScEnforcement": @YES };
}
if (global.count) {
_globalPrefs[volumeUuid.UUIDString] = global;
}
// managed prefs
NSMutableDictionary *managed = @{}.mutableCopy;
filePath = [NSString stringWithFormat:managedConfigPath, mountPoint, volumeUuid.UUIDString];
dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:filePath isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
for (NSURL *url in dirEnumerator) {
BOOL isDir = NO;
[[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir];
if (isDir) {
os_log_info(AUTHD_LOG, "Skipping dir %{public}@ (not a file)", url.path);
continue;
}
NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:url.path];
if (prefs) {
NSString *prefName = url.URLByDeletingPathExtension.lastPathComponent;
managed[prefName] = prefs;
}
}
if (managed.count) {
_managedPrefs[volumeUuid.UUIDString] = managed;
}
// per user prefs
NSMutableDictionary *user = @{}.mutableCopy;
filePath = [NSString stringWithFormat:homeDirPath, mountPoint, volumeUuid.UUIDString];
dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:filePath isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
for (NSURL *url in dirEnumerator) {
BOOL isDir = NO;
[[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir];
if (!isDir) {
os_log_info(AUTHD_LOG, "Skipping file %{public}@ (not a directory)", url.path);
continue;
}
NSMutableDictionary *userPrefs = @{}.mutableCopy;
NSString *userName = url.lastPathComponent;
NSString *userPrefPath = [NSString stringWithFormat:@"%@/Library/Preferences", url.path];
NSDirectoryEnumerator *dirEnumerator2 = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:userPrefPath isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
for (NSURL *userUrl in dirEnumerator2) {
isDir = NO;
[[NSFileManager defaultManager] fileExistsAtPath:userUrl.path isDirectory:&isDir];
if (isDir) {
os_log_info(AUTHD_LOG, "Skipping dir %{public}@ (not a file)", userUrl.path);
continue;
}
NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:userUrl.path];
if (prefs) {
NSString *prefName = userUrl.URLByDeletingPathExtension.lastPathComponent;
userPrefs[prefName] = prefs;
}
}
if (userPrefs.count) {
user[userName] = userPrefs;
}
}
if (user.count) {
_userPrefs[volumeUuid.UUIDString] = user;
}
os_log_debug(AUTHD_LOG, "Global prefs for volume %@: %@", volumeUuid.UUIDString, global);
os_log_debug(AUTHD_LOG, "Managed prefs for volume %@: %@", volumeUuid.UUIDString, managed);
os_log_debug(AUTHD_LOG, "User prefs for volume %@: %@", volumeUuid.UUIDString, user);
}
@end
OSStatus preloginDb(PreloginUserDb **db)
{
static PreloginUserDb *database;
static OSStatus loadError = errAuthorizationSuccess;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
os_log_info(AUTHD_LOG, "Going to load User DB");
database = [[PreloginUserDb alloc] init];
if (!database) {
loadError = errAuthorizationInvalidSet;
} else {
NSError *error;
if ([database loadWithError:&error]) {
loadError = (int)error.code;
}
}
});
if (loadError) {
return loadError;
}
if (db) {
*db = database;
}
return noErr;
}
OSStatus preloginudb_copy_userdb(const char *uuid, UInt32 flags, CFArrayRef *output)
{
if (!output) {
return errAuthorizationBadAddress;
}
PreloginUserDb *database;
OSStatus retval = preloginDb(&database);
if (retval) {
os_log_error(AUTHD_LOG, "Unable to read db");
return retval;
}
os_log_debug(AUTHD_LOG, "Processing user db for volume %{public}s with flags %d", uuid, flags);
*output = CFBridgingRetain([database users:uuid ? [NSString stringWithUTF8String:uuid] : nil]);
return errAuthorizationSuccess;
}
OSStatus prelogin_copy_pref_value(const char * _Nullable uuid, const char *user, const char *domain, const char *item, CFTypeRef *output)
{
if (!output || !uuid) {
return errAuthorizationBadAddress;
}
PreloginUserDb *database;
OSStatus retval = preloginDb(&database);
if (retval) {
os_log_error(AUTHD_LOG, "Unable to read db");
return retval;
}
NSDictionary *prefs;
NSDictionary *managed;
NSString *_domain = [NSString stringWithUTF8String:domain];
NSString *_uuid = [NSString stringWithUTF8String:uuid];
if (user) {
os_log_debug(AUTHD_LOG, "Reading user pref volume %{public}s %{public}s/%{public}s for user %s", uuid, domain, item, user);
prefs = [database userPrefs:_uuid user:[NSString stringWithUTF8String:user] domain:_domain];
} else {
os_log_debug(AUTHD_LOG, "Reading global pref volume %{public}s %{public}s/%{public}s", uuid, domain, item);
managed = [database managedPrefs:_uuid domain:_domain];
prefs = [database globalPrefs:_uuid domain:_domain];
}
if (!prefs && !managed) {
os_log_debug(AUTHD_LOG, "No pref found");
return errAuthorizationInvalidSet;
}
id value = managed[[NSString stringWithUTF8String:item]];
if (value) {
os_log_info(AUTHD_LOG, "Using managed prefs for %{public}s", item);
} else {
os_log_debug(AUTHD_LOG, "Using global prefs for %{public}s", item);
value = prefs[[NSString stringWithUTF8String:item]];
}
if (!value) {
os_log_debug(AUTHD_LOG, "No pref value with name %{public}s was found", item);
return errAuthorizationInvalidTag;
}
*output = CFBridgingRetain(value);
return errAuthorizationSuccess;
}
OSStatus prelogin_smartcardonly_override(const char *uuid, unsigned char operation, Boolean *status)
{
if (!uuid) {
os_log_error(AUTHD_LOG, "No volume UUID provided");
return errSecParam;
}
NSUUID *volumeUuid = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:uuid]];
if (!volumeUuid) {
os_log_error(AUTHD_LOG, "Invalid volume UUID provided: %{public}s", uuid);
return errSecParam;
}
PreloginUserDb *database;
OSStatus retval = preloginDb(&database);
if (retval) {
os_log_error(AUTHD_LOG, "Unable to read db");
return retval;
}
return [database setEnforcedSmartcardOverride:volumeUuid operation:operation status:status internal:NO];
}

View File

@ -2,9 +2,15 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.keystore.console</key>
<true/>
<key>com.apple.private.LocalAuthentication.ExtractCredential</key>
<true/>
<key>com.apple.keystore.console</key>
<key>com.apple.private.security.clear-library-validation</key>
<true/>
<key>com.apple.keystore.filevault</key>
<true/>
<key>com.apple.rootless.volume.Preboot</key>
<true/>
</dict>
</plist>

View File

@ -106,7 +106,10 @@ enum {
AUTHORIZATION_DISMISS,
AUTHORIZATION_SETUP,
AUTHORIZATION_ENABLE_SMARTCARD,
AUTHORIZATION_PREAUTHORIZE_CREDENTIALS
AUTHORIZATION_COPY_PRELOGIN_USERDB,
AUTHORIZATION_COPY_PRELOGIN_PREFS,
AUTHORIZATION_COPY_RIGHT_PROPERTIES,
AUTHORIZATION_PRELOGIN_SC_OVERRIDE,
};
#if defined(__cplusplus)

View File

@ -277,6 +277,18 @@ static void _repair_all_kofns(authdb_connection_t dbconn, auth_items_t config)
CFRelease(plist);
}
static void _check_for_db_update(authdb_connection_t dbconn)
{
const char *rightName = "com.apple.installassistant.requestpassword";
rule_t right = rule_create_with_string(rightName, dbconn);
if (!right || rule_get_class(right) != RC_USER || rule_get_shared(right) != false || rule_get_type(right) != RT_RIGHT) {
os_log_fault(AUTHD_LOG, "Old and not updated database found");
} else {
os_log(AUTHD_LOG, "Database check OK");
}
CFReleaseNull(right);
}
static void _db_load_data(authdb_connection_t dbconn, auth_items_t config)
{
CFAbsoluteTime ts = 0;
@ -289,6 +301,9 @@ static void _db_load_data(authdb_connection_t dbconn, auth_items_t config)
auth_items_set_double(update, "data_ts", ts);
authdb_set_key_value(dbconn, "config", update);
CFReleaseSafe(update);
int32_t rc = sqlite3_db_cacheflush(dbconn->handle);
os_log_debug(AUTHD_LOG, "Flush result: %d", rc);
_check_for_db_update(dbconn);
}
}
CFReleaseSafe(plist);
@ -362,9 +377,12 @@ static int32_t _db_maintenance(authdb_connection_t dbconn)
if (currentVersion < AUTHDB_VERSION) {
os_log_debug(AUTHD_LOG, "authdb: upgrading schema");
s3e = _db_upgrade_from_version(dbconn, (int32_t)currentVersion);
auth_items_set_int64(config, "version", AUTHDB_VERSION);
authdb_set_key_value(dbconn, "config", config);
if (s3e != SQLITE_OK) {
os_log_error(AUTHD_LOG, "authdb: failed to upgrade DB schema %i", s3e);
} else {
auth_items_set_int64(config, "version", AUTHDB_VERSION);
authdb_set_key_value(dbconn, "config", config);
}
}
done:
@ -943,13 +961,18 @@ _import_rules(authdb_connection_t dbconn, CFMutableArrayRef rules, bool version_
if (version_check) {
if (rule_get_id(rule) != 0) { // rule already exists see if we need to update
rule_t current = rule_create_with_string(rule_get_name(rule), dbconn);
if (rule_get_version(rule) > rule_get_version(current)) {
int64_t currVer = rule_get_version(current);
int64_t newVer = rule_get_version(rule);
if (newVer > currVer) {
update = true;
}
CFReleaseSafe(current);
if (!update) {
continue;
} else {
os_log(AUTHD_LOG, "authdb: right %{public}s new version %lld vs existing version %lld, will update", rule_get_name(rule), newVer, currVer);
}
}
}
@ -977,7 +1000,7 @@ _import_rules(authdb_connection_t dbconn, CFMutableArrayRef rules, bool version_
if (!delayCommit) {
bool success = rule_sql_commit(rule, dbconn, now, NULL);
os_log_debug(AUTHD_LOG, "authdb: %{public}s %{public}s %{public}s %{public}s",
os_log(AUTHD_LOG, "authdb: %{public}s %{public}s %{public}s %{public}s",
update ? "updating" : "importing",
rule_get_type(rule) == RT_RULE ? "rule" : "right",
rule_get_name(rule), success ? "success" : "FAIL");

View File

@ -6,9 +6,12 @@
#include "authutilities.h"
#include <Security/AuthorizationTags.h>
#include <Security/AuthorizationTagsPriv.h>
#include <dispatch/private.h>
#include <CommonCrypto/CommonCrypto.h>
#include <security_utilities/simulatecrash_assert.h>
AUTHD_DEFINE_LOG
typedef struct _auth_item_s * auth_item_t;
@ -48,7 +51,7 @@ auth_item_copy_auth_item_xpc(auth_item_t item)
xpc_dictionary_set_string(xpc_data, AUTH_XPC_ITEM_NAME, item->data.name);
if (item->data.value) {
// <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
bool sensitive = strcmp(item->data.name, "password") == 0;
bool sensitive = strcmp(item->data.name, AGENT_PASSWORD) == 0;
if (sensitive) {
vm_address_t vmBytes = 0;
size_t xpcOutOfBandBlockSize = (item->data.valueLength > 32768 ? item->data.valueLength : 32768); // min 16K on 64-bit systems and 12K on 32-bit systems

View File

@ -578,14 +578,19 @@ See remaining rules for examples.
</dict>
<key>com.apple.trust-settings.admin</key>
<dict>
<key>allow-root</key>
<true/>
<key>class</key>
<string>user</string>
<key>comment</key>
<string>For modifying Trust Settings in the Local Admin domain.</string>
<key>group</key>
<string>admin</string>
<string>For modifying Trust Settings in the Admin domain. Requires entitlement or admin authentication.</string>
<key>class</key>
<string>rule</string>
<key>k-of-n</key>
<integer>1</integer>
<key>rule</key>
<array>
<string>entitled</string>
<string>authenticate-admin</string>
</array>
<key>version</key>
<integer>1</integer>
</dict>
<key>com.apple.trust-settings.user</key>
<dict>
@ -596,10 +601,14 @@ See remaining rules for examples.
</dict>
<key>com.apple.uninstalld.uninstall</key>
<dict>
<key>authenticate-user</key>
<false/>
<key>class</key>
<string>rule</string>
<key>rule</key>
<string>entitled-admin-or-authenticate-admin</string>
<string>user</string>
<key>entitled</key>
<true/>
<key>version</key>
<integer>1</integer>
</dict>
<key>config.add.</key>
<dict>
@ -675,6 +684,23 @@ See remaining rules for examples.
<key>comment</key>
<string>For burning media.</string>
</dict>
<key>com.apple.installassistant.requestpassword</key>
<dict>
<key>authenticate-user</key>
<true/>
<key>class</key>
<string>user</string>
<key>comment</key>
<string>Authenticate as an administrator, password only.</string>
<key>group</key>
<string>admin</string>
<key>password-only</key>
<true/>
<key>shared</key>
<false/>
<key>timeout</key>
<integer>0</integer>
</dict>
<key>system.csfde.requestpassword.weak</key>
<dict>
<key>class</key>
@ -825,7 +851,7 @@ See remaining rules for examples.
<key>class</key>
<string>rule</string>
<key>comment</key>
<string>Checked when user is installing Apple-provided software.</string>
<string>Checked when user is installing Apple software.</string>
<key>rule</key>
<string>root-or-entitled-admin-or-authenticate-admin</string>
</dict>
@ -914,6 +940,7 @@ See remaining rules for examples.
<key>mechanisms</key>
<array>
<string>builtin:policy-banner</string>
<string>builtin:prelogin</string>
<string>loginwindow:login</string>
<string>builtin:login-begin</string>
<string>builtin:reset-password,privileged</string>
@ -931,7 +958,24 @@ See remaining rules for examples.
<string>loginwindow:done</string>
</array>
<key>version</key>
<integer>7</integer>
<integer>8</integer>
</dict>
<key>system.login.filevault</key>
<dict>
<key>class</key>
<string>evaluate-mechanisms</string>
<key>comment</key>
<string>Login mechanism based rule for Filevault.</string>
<key>mechanisms</key>
<array>
<string>builtin:policy-banner</string>
<string>loginwindow:login</string>
<string>builtin:login-begin</string>
<string>builtin:authenticate,privileged</string>
<string>builtin:login-success</string>
<string>loginwindow:success</string>
<string>loginwindow:done</string>
</array>
</dict>
<key>system.login.fus</key>
<dict>
@ -1601,6 +1645,36 @@ See remaining rules for examples.
<key>version</key>
<integer>1</integer>
</dict>
<key>com.apple.configurationprofiles.deviceenrollment.install</key>
<dict>
<key>class</key>
<string>user</string>
<key>comment</key>
<string>This right is used by UserManagement to ask for an admin password.</string>
<key>group</key>
<string>admin</string>
<key>password-only</key>
<true/>
<key>shared</key>
<false/>
<key>version</key>
<integer>1</integer>
</dict>
<key>com.apple.configurationprofiles.deviceenrollment.uninstall</key>
<dict>
<key>class</key>
<string>user</string>
<key>comment</key>
<string>This right is used by UserManagement to ask for an admin password.</string>
<key>group</key>
<string>admin</string>
<key>password-only</key>
<true/>
<key>shared</key>
<false/>
<key>version</key>
<integer>1</integer>
</dict>
<key>com.apple.safaridriver.allow</key>
<dict>
<key>comment</key>
@ -1670,7 +1744,18 @@ See remaining rules for examples.
<key>timeout</key>
<integer>300</integer>
</dict>
<key>com.apple.system-extensions.admin</key>
<key>com.apple.tcc.util.admin</key>
<dict>
<key>comment</key>
<string>For modification of TCC settings.</string>
<key>class</key>
<string>rule</string>
<key>rule</key>
<string>authenticate-admin-nonshared</string>
<key>shared</key>
<false/>
</dict>
<key>com.apple.system-extensions.admin</key>
<dict>
<key>comment</key>
<string>Authorize a 3rd party application which wants to manipulate system extensions.</string>
@ -1681,7 +1766,40 @@ See remaining rules for examples.
<key>shared</key>
<false/>
</dict>
</dict>
<key>com.apple.system-migration.launch</key>
<dict>
<key>comment</key>
<string>Used by Migration Assistant.</string>
<key>class</key>
<string>rule</string>
<key>rule</key>
<string>authenticate-admin-nonshared</string>
<key>shared</key>
<false/>
</dict>
<key>com.apple.system-migration.launch-password</key>
<dict>
<key>comment</key>
<string>Used by Migration Assistant.</string>
<key>class</key>
<string>rule</string>
<key>rule</key>
<string>authenticate-admin-nonshared-password</string>
<key>shared</key>
<false/>
</dict>
<key>com.apple.system-migration.cleanup</key>
<dict>
<key>comment</key>
<string>Used by System Migration.</string>
<key>class</key>
<string>rule</string>
<key>rule</key>
<string>authenticate-admin-nonshared</string>
<key>shared</key>
<false/>
</dict>
</dict>
<key>rules</key>
<dict>
<key>admin</key>
@ -1730,8 +1848,9 @@ See remaining rules for examples.
<string>builtin:authenticate</string>
<string>builtin:reset-password,privileged</string>
<string>builtin:authenticate,privileged</string>
<string>PKINITMechanism:auth,privileged</string>
</array>
<key>version</key>
<integer>1</integer>
</dict>
<key>kcunlock</key>
<dict>
@ -1773,6 +1892,21 @@ See remaining rules for examples.
<key>version</key>
<integer>1</integer>
</dict>
<key>authenticate-admin-nonshared-password</key>
<dict>
<key>class</key>
<string>user</string>
<key>comment</key>
<string>Authenticate as an administrator with the password.</string>
<key>group</key>
<string>admin</string>
<key>password-only</key>
<true/>
<key>timeout</key>
<integer>30</integer>
<key>version</key>
<integer>1</integer>
</dict>
<key>_mbsetupuser-nonshared</key>
<dict>
<key>class</key>

View File

@ -13,6 +13,8 @@
#include <Security/SecBase.h>
#include <sandbox.h>
#include <security_utilities/simulatecrash_assert.h>
AUTHD_DEFINE_LOG
static Boolean AuthTokenEqualCallBack(const void *value1, const void *value2)
@ -395,6 +397,7 @@ auth_token_has_entitlement(auth_token_t auth, const char * entitlement)
entitled = process_has_entitlement(auth->creator, entitlement);
}
});
os_log_debug(AUTHD_LOG, "authtoken: PID %d is%{public}s entitled for %{public}s", auth->auditInfo.pid, entitled ? "":" not", entitlement);
return entitled;
}
@ -409,6 +412,7 @@ auth_token_has_entitlement_for_right(auth_token_t auth, const char * right)
entitled = process_has_entitlement_for_right(auth->creator, right);
}
});
os_log_debug(AUTHD_LOG, "authtoken: PID %d is%{public}s entitled for right %{public}s", auth->auditInfo.pid, entitled ? "":" not", right);
return entitled;
}

View File

@ -5,7 +5,6 @@
#include "debugging.h"
#include <AssertMacros.h>
#include <assert.h>
AUTHD_DEFINE_LOG
@ -23,6 +22,11 @@ SerializeItemSet(const AuthorizationItemSet * itemSet)
xpc_object_t item = xpc_dictionary_create(NULL, NULL, 0);
require(item != NULL, done);
if (itemSet->items[i].name == NULL) {
os_log_error(AUTHD_LOG, "ItemSet - item #%d name is NULL", i);
xpc_release(item);
continue;
}
xpc_dictionary_set_string(item, AUTH_XPC_ITEM_NAME, itemSet->items[i].name);
xpc_dictionary_set_uint64(item, AUTH_XPC_ITEM_FLAGS, itemSet->items[i].flags);
xpc_dictionary_set_data(item, AUTH_XPC_ITEM_VALUE, itemSet->items[i].value, itemSet->items[i].valueLength);
@ -305,3 +309,9 @@ done:
free_safe(values);
return result;
}
bool isInFVUnlock()
{
// temporary solution until we find a better way
return getenv("__OSINSTALL_ENVIRONMENT") != NULL;
}

View File

@ -27,6 +27,8 @@ bool _cf_set_iterate(CFSetRef, bool(^iterator)(CFTypeRef value));
bool _cf_bag_iterate(CFBagRef, bool(^iterator)(CFTypeRef value));
bool _cf_dictionary_iterate(CFDictionaryRef, bool(^iterator)(CFTypeRef key,CFTypeRef value));
bool isInFVUnlock(void);
#if defined(__cplusplus)
}
#endif

View File

@ -9,7 +9,8 @@
(allow file-read*)
(allow file-read* file-write*
(allow file-write*
(regex #"^(/System)?/Volumes/Preboot/.*/var/db/\.scnotenforced")
(regex #"^/private/var/db/auth\.db.*$")
(literal "/private/var/db/mds/system/mds.lock")
(subpath (param "TMP_DIR")))
@ -27,7 +28,9 @@
(global-name "com.apple.security.authhost")
(global-name "com.apple.SecurityServer")
(global-name "com.apple.system.opendirectoryd.api")
(global-name "com.apple.ocspd"))
(global-name "com.apple.ocspd")
(global-name "com.apple.DiskArbitration.diskarbitrationd")
(global-name "com.apple.diskmanagementd"))
(allow ipc-posix-shm
(ipc-posix-name "apple.shm.notification_center")
@ -40,3 +43,7 @@
(preference-domain "com.apple.authd"))
(allow system-audit system-sched)
(allow iokit-open
(iokit-user-client-class "AppleAPFSUserClient")
(iokit-user-client-class "AppleKeyStoreUserClient"))

View File

@ -19,7 +19,7 @@ crc64_init()
AUTH_INLINE uint64_t
crc64_final(uint64_t crc)
{
return crc ^= xorout;
return crc ^ xorout;
}
AUTH_INLINE AUTH_NONNULL_ALL uint64_t

View File

@ -2,6 +2,8 @@
#include "credential.h"
#include "authutilities.h"
#include "authitems.h"
#include <Security/AuthorizationTagsPriv.h>
#include "debugging.h"
#include "crc.h"
@ -141,6 +143,23 @@ done:
return cred;
}
credential_t
credential_create_fvunlock(auth_items_t context, bool session)
{
credential_t cred = NULL;
cred = _credential_create();
require(cred != NULL, done);
const char *username = session ? "system session" : auth_items_get_string(context, AGENT_USERNAME);
cred->uid = session ? 0 : -500;
cred->name = _copy_string(username);
cred->realName = _copy_string(username);
cred->valid = false;
done:
return cred;
}
credential_t
credential_create_with_credential(credential_t srcCred, bool shared)
{
@ -220,9 +239,14 @@ credential_is_right(credential_t cred)
}
bool
credential_check_membership(credential_t cred,const char* group)
credential_check_membership(credential_t cred, const char* group)
{
bool result = false;
if (isInFVUnlock()) {
return false; // cannot succeed in FVUnlock as we do not have group data
}
CFStringRef cachedGroup = NULL;
require(group != NULL, done);
require(cred->uid != 0 || cred->uid != (uid_t)-2, done);

View File

@ -20,6 +20,9 @@ credential_t credential_create_with_credential(credential_t,bool);
AUTH_WARN_RESULT AUTH_MALLOC AUTH_NONNULL_ALL AUTH_RETURNS_RETAINED
credential_t credential_create_with_right(const char *);
AUTH_WARN_RESULT AUTH_MALLOC AUTH_RETURNS_RETAINED
credential_t credential_create_fvunlock(auth_items_t context, bool session);
AUTH_NONNULL_ALL
uid_t credential_get_uid(credential_t);

View File

@ -37,8 +37,8 @@ static void _set_auth_token_hints(auth_items_t, auth_items_t, auth_token_t);
static OSStatus _evaluate_user_credential_for_rule(engine_t, credential_t, rule_t, bool, bool, enum Reason *);
static void _engine_set_credential(engine_t, credential_t, bool);
static OSStatus _evaluate_rule(engine_t, rule_t, bool *);
static bool _preevaluate_class_rule(engine_t engine, rule_t rule);
static bool _preevaluate_rule(engine_t engine, rule_t rule);
static bool _preevaluate_class_rule(engine_t engine, rule_t rule, const char **group);
static bool _preevaluate_rule(engine_t engine, rule_t rule, const char **group);
static uint64_t global_engine_count;
@ -65,7 +65,6 @@ struct _engine_s {
auth_rights_t grantedRights;
CFTypeRef la_context;
bool preauthorizing;
enum Reason reason;
int32_t tries;
@ -156,14 +155,16 @@ engine_create(connection_t conn, auth_token_t auth)
engine->reason = noReason;
engine->preauthorizing = false;
engine->la_context = NULL;
engine->now = CFAbsoluteTimeGetCurrent();
session_update(auth_token_get_session(engine->auth));
engine->sessionCredential = credential_create(session_get_uid(auth_token_get_session(engine->auth)));
if (isInFVUnlock()) {
engine->sessionCredential = credential_create_fvunlock(NULL, true);
} else {
engine->sessionCredential = credential_create(session_get_uid(auth_token_get_session(engine->auth)));
}
engine->credentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
engine->effectiveCredentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
@ -313,6 +314,27 @@ _evaluate_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, b
}
}
static bool _is_fvunlock_user_in_group(engine_t engine, rule_t rule)
{
if (!isInFVUnlock()) {
return false;
}
const char *group = rule_get_group(rule);
if (!(group && strcmp(group, "admin") == 0)) {
os_log_error(AUTHD_LOG, "Group %{public}s not supported in FV mode (engine %lld)", group, engine->engine_index);
return false;
}
const char *data = auth_items_get_string(engine->context, kAuthorizationFVAdmin);
if (!data) {
os_log_error(AUTHD_LOG, "User is not member of the group %{public}s (engine %lld)", group, engine->engine_index);
return false;
}
return (strcmp(data, "1") == 0);
}
static OSStatus
_evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, bool ignoreShared, bool sessionOwner, enum Reason * reason)
{
@ -329,7 +351,7 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru
return errAuthorizationDenied;
}
if (credential_get_valid(cred) != true) {
if (credential_get_valid(cred) != true && !isInFVUnlock()) {
os_log(AUTHD_LOG, "%{public}s %i invalid (does NOT satisfy rule) (engine %lld)", cred_label, credential_get_uid(cred), engine->engine_index);
if (reason) { *reason = invalidPassphrase; }
return errAuthorizationDenied;
@ -376,7 +398,7 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru
}
}
if (credential_check_membership(cred, rule_get_group(rule))) {
if (credential_check_membership(cred, rule_get_group(rule)) || _is_fvunlock_user_in_group(engine, rule)) {
os_log(AUTHD_LOG, "%{public}s %i is member of group %{public}s (does satisfy rule) (engine %lld)", cred_label, credential_get_uid(cred), rule_get_group(rule), engine->engine_index);
return errAuthorizationSuccess;
} else {
@ -612,6 +634,7 @@ _evaluate_mechanisms(engine_t engine, CFArrayRef mechanisms)
}
done:
auth_items_set_flags(context, AGENT_CONTEXT_AP_PAM_SERVICE_NAME, kAuthorizationContextFlagExtractable);
if ((result == kAuthorizationResultUserCanceled) || (result == kAuthorizationResultAllow)) {
// only make non-sticky context values available externally
auth_items_set_flags(context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagVolatile);
@ -650,11 +673,16 @@ done:
static OSStatus
_evaluate_authentication(engine_t engine, rule_t rule)
{
os_log_debug(AUTHD_LOG, "engine %lld: FV mode %d", engine->engine_index, isInFVUnlock());
OSStatus status = errAuthorizationDenied;
ccaudit_t ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthint);
os_log_debug(AUTHD_LOG, "engine %lld: evaluate authentication", engine->engine_index);
_set_rule_hints(engine->hints, rule);
_set_session_hints(engine, rule);
if (!isInFVUnlock()) {
// we do not need to set hints in FVUnlock as we do not know which user will be authenticated
_set_session_hints(engine, rule);
}
CFArrayRef mechanisms = rule_get_mechanisms(rule);
if (!(CFArrayGetCount(mechanisms) > 0)) {
@ -683,10 +711,14 @@ _evaluate_authentication(engine_t engine, rule_t rule)
status = errAuthorizationDenied;
credential_t newCred = NULL;
if (auth_items_exist(engine->context, "uid")) {
newCred = credential_create(auth_items_get_uint(engine->context, "uid"));
if (isInFVUnlock() && auth_items_exist(engine->context, kAuthorizationFVAdmin)) {
os_log_debug(AUTHD_LOG, "Credentials for FV unlock (engine %lld)", engine->engine_index);
newCred = credential_create_fvunlock(engine->context, false);
} else if (auth_items_exist(engine->context, AGENT_CONTEXT_UID)) {
newCred = credential_create(auth_items_get_uint(engine->context, AGENT_CONTEXT_UID));
} else {
os_log_info(AUTHD_LOG, "Mechanism failed to return a valid uid (engine %lld)", engine->engine_index);
os_log_error(AUTHD_LOG, "Mechanism failed to return a valid UID (engine %lld)", engine->engine_index);
if (engine->la_context) {
// sheet failed so remove sheet reference and next time, standard dialog will be displayed
CFReleaseNull(engine->la_context);
@ -694,12 +726,12 @@ _evaluate_authentication(engine_t engine, rule_t rule)
}
if (newCred) {
if (credential_get_valid(newCred)) {
os_log(AUTHD_LOG, "UID %u authenticated as user %{public}s (UID %u) for right '%{public}s'", auth_token_get_uid(engine->auth), credential_get_name(newCred), credential_get_uid(newCred), engine->currentRightName);
if (credential_get_valid(newCred) || isInFVUnlock()) {
os_log(AUTHD_LOG, "UID %u authenticated as user %{public}s (UID %i) for right '%{public}s'", auth_token_get_uid(engine->auth), credential_get_name(newCred), credential_get_uid(newCred), engine->currentRightName);
ccaudit_log_success(ccaudit, newCred, engine->currentRightName);
} else {
os_log(AUTHD_LOG, "UID %u failed to authenticate as user '%{public}s' for right '%{public}s'", auth_token_get_uid(engine->auth), auth_items_get_string(engine->context, "username"), engine->currentRightName);
ccaudit_log_failure(ccaudit, auth_items_get_string(engine->context, "username"), engine->currentRightName);
os_log(AUTHD_LOG, "UID %u failed to authenticate as user '%{public}s' for right '%{public}s'", auth_token_get_uid(engine->auth), auth_items_get_string(engine->context, AGENT_USERNAME), engine->currentRightName);
ccaudit_log_failure(ccaudit, auth_items_get_string(engine->context, AGENT_USERNAME), engine->currentRightName);
}
status = _evaluate_user_credential_for_rule(engine, newCred, rule, true, false, &engine->reason);
@ -798,10 +830,12 @@ _evaluate_class_user(engine_t engine, rule_t rule)
}
if (!rule_get_authenticate_user(rule)) {
status = _evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL);
if (!isInFVUnlock()) {
status = _evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL);
if (status == errAuthorizationSuccess) {
return errAuthorizationSuccess;
if (status == errAuthorizationSuccess) {
return errAuthorizationSuccess;
}
}
return errAuthorizationDenied;
@ -859,22 +893,22 @@ _evaluate_class_user(engine_t engine, rule_t rule)
return errAuthorizationSuccess;
}
if (!engine->preauthorizing) {
if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) {
if (!(engine->flags & kAuthorizationFlagSheet)) {
if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) {
os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (kAuthorizationFlagInteractionAllowed not set) (engine %lld)", engine->engine_index);
return errAuthorizationInteractionNotAllowed;
}
return errAuthorizationInteractionNotAllowed;
}
if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) {
os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (session has no ui access) (engine %lld)", engine->engine_index);
return errAuthorizationInteractionNotAllowed;
}
if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) {
os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (session has no ui access) (engine %lld)", engine->engine_index);
return errAuthorizationInteractionNotAllowed;
}
if (server_in_dark_wake() && !(engine->flags & kAuthorizationFlagIgnoreDarkWake)) {
os_log_error(AUTHD_LOG, "Fatal: authorization denied (DW) (engine %lld)", engine->engine_index);
return errAuthorizationDenied;
}
}
if (server_in_dark_wake() && !(engine->flags & kAuthorizationFlagIgnoreDarkWake)) {
os_log_error(AUTHD_LOG, "Fatal: authorization denied (DW) (engine %lld)", engine->engine_index);
return errAuthorizationDenied;
}
}
return _evaluate_authentication(engine, rule);
}
@ -924,15 +958,14 @@ _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd)
}
static bool
_preevaluate_class_rule(engine_t engine, rule_t rule)
_preevaluate_class_rule(engine_t engine, rule_t rule, const char **group)
{
os_log_debug(AUTHD_LOG, "engine %lld: _preevaluate_class_rule %{public}s", engine->engine_index, rule_get_name(rule));
__block bool password_only = false;
rule_delegates_iterator(rule, ^bool(rule_t delegate) {
if (_preevaluate_rule(engine, delegate)) {
if (_preevaluate_rule(engine, delegate, group)) {
password_only = true;
return false;
}
return true;
});
@ -971,8 +1004,8 @@ _evaluate_class_mechanism(engine_t engine, rule_t rule)
if (status == errAuthorizationSuccess) {
credential_t newCred = NULL;
if (auth_items_exist(engine->context, "uid")) {
newCred = credential_create(auth_items_get_uint(engine->context, "uid"));
if (auth_items_exist(engine->context, AGENT_CONTEXT_UID)) {
newCred = credential_create(auth_items_get_uint(engine->context, AGENT_CONTEXT_UID));
} else {
os_log_info(AUTHD_LOG, "Mechanism did not return a uid (engine %lld)", engine->engine_index);
}
@ -1048,7 +1081,7 @@ _evaluate_rule(engine_t engine, rule_t rule, bool *save_pwd)
// returns true if this rule or its children contain RC_USER rule with password_only==true
static bool
_preevaluate_rule(engine_t engine, rule_t rule)
_preevaluate_rule(engine_t engine, rule_t rule, const char **group)
{
os_log_debug(AUTHD_LOG, "engine %lld: _preevaluate_rule %{public}s", engine->engine_index, rule_get_name(rule));
@ -1057,9 +1090,12 @@ _preevaluate_rule(engine_t engine, rule_t rule)
case RC_DENY:
return false;
case RC_USER:
if (group && !*group) {
*group = rule_get_group(rule);
}
return rule_get_password_only(rule);
case RC_RULE:
return _preevaluate_class_rule(engine, rule);
return _preevaluate_class_rule(engine, rule, group);
case RC_MECHANISM:
return false;
default:
@ -1182,129 +1218,49 @@ static bool _verify_sandbox(engine_t engine, const char * right)
#pragma mark -
#pragma mark engine methods
OSStatus engine_preauthorize(engine_t engine, auth_items_t credentials)
OSStatus engine_get_right_properties(engine_t engine, const char *rightName, CFDictionaryRef *output)
{
os_log(AUTHD_LOG, "engine %lld: preauthorizing", engine->engine_index);
OSStatus status = errAuthorizationInternal;
OSStatus status = errAuthorizationDenied;
bool save_password = false;
CFMutableDictionaryRef properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
require(properties != NULL, done);
require(rightName != NULL, done);
engine->flags = kAuthorizationFlagExtendRights;
engine->preauthorizing = true;
CFAssignRetained(engine->la_context, engine_copy_context(engine, credentials));
_extract_password_from_la(engine);
// first check if any of rights uses rule with password-only set to true
// if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc.
authdb_connection_t dbconn = authdb_connection_acquire(server_get_database()); // get db handle
const char *user = auth_items_get_string(credentials, kAuthorizationEnvironmentUsername);
require(user, done);
os_log_debug(AUTHD_LOG, "engine %lld: get right properties %{public}s", engine->engine_index, rightName);
rule_t rule = _find_rule(engine, dbconn, rightName);
auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, user);
struct passwd *pwd = getpwnam(user);
require(pwd, done);
if (rule) {
const char *group = NULL;
bool passwordOnly = _preevaluate_rule(engine, rule, &group);
CFDictionarySetValue(properties, CFSTR(kAuthorizationRuleParameterPasswordOnly), passwordOnly ? kCFBooleanTrue : kCFBooleanFalse);
if (group) {
CFStringRef groupCf = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8);
if (groupCf) {
CFDictionarySetValue(properties, CFSTR(kAuthorizationRuleParameterGroup), groupCf);
CFRelease(groupCf);
}
}
CFRelease(rule);
status = errAuthorizationSuccess;
} else {
os_log_debug(AUTHD_LOG, "engine %lld: cannot get right properties %{public}s", engine->engine_index, rightName);
status = errAuthorizationInvalidRef;
}
auth_items_set_int(engine->context, AGENT_CONTEXT_UID, pwd->pw_uid);
const char *service = auth_items_get_string(credentials, AGENT_CONTEXT_AP_PAM_SERVICE_NAME);
if (service) {
auth_items_set_string(engine->context, AGENT_CONTEXT_AP_USER_NAME, user);
auth_items_set_string(engine->context, AGENT_CONTEXT_AP_PAM_SERVICE_NAME, service);
}
if (auth_items_exist(credentials, AGENT_CONTEXT_AP_TOKEN)) {
size_t datalen = 0;
const void *data = auth_items_get_data(credentials, AGENT_CONTEXT_AP_TOKEN, &datalen);
if (data) {
auth_items_set_data(engine->context, AGENT_CONTEXT_AP_TOKEN, data, datalen);
}
}
auth_items_t decrypted_items = auth_items_create();
require_action(decrypted_items != NULL, done, os_log_error(AUTHD_LOG, "Unable to create items (engine %lld)", engine->engine_index));
auth_items_content_copy(decrypted_items, auth_token_get_context(engine->auth));
auth_items_decrypt(decrypted_items, auth_token_get_encryption_key(engine->auth));
auth_items_copy(engine->context, decrypted_items);
CFReleaseSafe(decrypted_items);
engine->dismissed = false;
auth_rights_clear(engine->grantedRights);
rule_t rule = rule_create_preauthorization();
engine->currentRightName = rule_get_name(rule);
engine->currentRule = rule;
status = _evaluate_rule(engine, rule, &save_password);
switch (status) {
case errAuthorizationSuccess:
os_log(AUTHD_LOG, "Succeeded preauthorizing client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (engine %lld)",
process_get_code_url(engine->proc), process_get_pid(engine->proc),
auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), engine->engine_index);
status = errAuthorizationSuccess;
break;
case errAuthorizationDenied:
case errAuthorizationInteractionNotAllowed:
case errAuthorizationCanceled:
os_log(AUTHD_LOG, "Failed to preauthorize client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i) (engine %lld)",
process_get_code_url(engine->proc), process_get_pid(engine->proc),
auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), (int)status, engine->engine_index);
break;
default:
os_log_error(AUTHD_LOG, "Preauthorize returned %d => returning errAuthorizationInternal (engine %lld)", (int)status, engine->engine_index);
status = errAuthorizationInternal;
break;
}
CFReleaseSafe(rule);
if (engine->dismissed) {
os_log_error(AUTHD_LOG, "Engine dismissed (engine %lld)", engine->engine_index);
status = errAuthorizationDenied;
}
os_log_debug(AUTHD_LOG, "engine %lld: preauthorize result: %d", engine->engine_index, (int)status);
_cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
credential_t cred = (credential_t)value;
// skip all uid credentials when running in least privileged
if (auth_token_least_privileged(engine->auth) && !credential_is_right(cred))
return true;
session_t session = auth_token_get_session(engine->auth);
auth_token_set_credential(engine->auth, cred);
if (credential_get_shared(cred)) {
session_set_credential(session, cred);
}
if (credential_is_right(cred)) {
os_log(AUTHD_LOG, "engine %lld: adding least privileged %{public}scredential %{public}s to authorization", engine->engine_index, credential_get_shared(cred) ? "shared " : "", credential_get_name(cred));
} else {
os_log(AUTHD_LOG, "engine %lld: adding %{public}scredential %{public}s (%i) to authorization", engine->engine_index, credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred));
}
return true;
});
if (status == errAuthorizationSuccess && save_password) {
auth_items_set_flags(engine->context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagExtractable);
}
if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) {
auth_items_t encrypted_items = auth_items_create();
require_action(encrypted_items != NULL, done, os_log_error(AUTHD_LOG, "Unable to create items (engine %lld)", engine->engine_index));
auth_items_content_copy_with_flags(encrypted_items, engine->context, kAuthorizationContextFlagExtractable);
#if DEBUG
os_log_debug(AUTHD_LOG, "engine %lld: ********** Dumping preauthorized context for encryption **********", engine->engine_index);
os_log_debug(AUTHD_LOG, "%@", encrypted_items);
#endif
auth_items_encrypt(encrypted_items, auth_token_get_encryption_key(engine->auth));
auth_items_copy_with_flags(auth_token_get_context(engine->auth), encrypted_items, kAuthorizationContextFlagExtractable);
os_log_debug(AUTHD_LOG, "engine %lld: encrypted preauthorization context data", engine->engine_index);
CFReleaseSafe(encrypted_items);
}
authdb_connection_release(&dbconn); // release db handle
os_log_debug(AUTHD_LOG, "engine %lld: right properties %@", engine->engine_index, properties);
if (output && status == errAuthorizationSuccess) {
*output = properties;
CFRetain(*output);
}
done:
engine->preauthorizing = false;
auth_items_clear(engine->context);
auth_items_clear(engine->sticky_context);
CFDictionaryRemoveAllValues(engine->mechanism_agents);
return status;
CFReleaseSafe(properties);
return status;
}
OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t environment, AuthorizationFlags flags)
@ -1312,11 +1268,12 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
__block OSStatus status = errAuthorizationSuccess;
__block bool save_password = false;
__block bool password_only = false;
CFIndex rights_count = auth_rights_get_count(rights);
CFIndex rights_count = 0;
ccaudit_t ccaudit = NULL;
require(rights != NULL, done);
rights_count = auth_rights_get_count(rights);
ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthorize);
if (auth_rights_get_count(rights) > 0) {
ccaudit_log(ccaudit, "begin evaluation", NULL, 0);
@ -1404,7 +1361,6 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
engine_acquire_sheet_data(engine);
_extract_password_from_la(engine);
engine->preauthorizing = true;
}
engine->dismissed = false;
@ -1421,8 +1377,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
os_log_debug(AUTHD_LOG, "engine %lld: checking if rule %{public}s contains password-only item", engine->engine_index, key);
rule_t rule = _find_rule(engine, dbconn, key);
if (rule && _preevaluate_rule(engine, rule)) {
if (rule && _preevaluate_rule(engine, rule, NULL)) {
password_only = true;
CFReleaseSafe(rule);
return false;
@ -1459,9 +1414,10 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
}
os_log_debug(AUTHD_LOG, "engine %lld: using rule %{public}s", engine->engine_index, rule_name);
_set_right_hints(engine->hints, key); // set authorization right name for authorizationhost as well
// only need the hints & mechanisms if we are going to show ui
if (engine->flags & kAuthorizationFlagInteractionAllowed || engine->flags & kAuthorizationFlagSheet) {
_set_right_hints(engine->hints, key);
os_log_debug(AUTHD_LOG, "setting hints for UI authorization");
_set_localization_hints(dbconn, engine->hints, rule);
if (!engine->authenticateRule) {
engine->authenticateRule = rule_create_with_string("authenticate", dbconn);
@ -1544,10 +1500,6 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
os_log_debug(AUTHD_LOG, "engine %lld: authorize result: %d", engine->engine_index, (int)status);
if (engine->flags & kAuthorizationFlagSheet) {
engine->preauthorizing = false;
}
if ((engine->flags & kAuthorizationFlagExtendRights) && !(engine->flags & kAuthorizationFlagDestroyRights)) {
_cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
credential_t cred = (credential_t)value;

View File

@ -17,7 +17,7 @@ AUTH_NONNULL1 AUTH_NONNULL2
OSStatus engine_authorize(engine_t, auth_rights_t rights, auth_items_t environment, AuthorizationFlags);
AUTH_NONNULL1 AUTH_NONNULL2
OSStatus engine_preauthorize(engine_t engine, auth_items_t credentials);
OSStatus engine_get_right_properties(engine_t engine, const char *rightName, CFDictionaryRef *output);
AUTH_NONNULL_ALL
OSStatus engine_verify_modification(engine_t, rule_t, bool remove, bool force_modify);

View File

@ -14,7 +14,7 @@
#include <xpc/xpc.h>
#include <xpc/private.h>
#include <dispatch/dispatch.h>
#include <assert.h>
#include <security_utilities/simulatecrash_assert.h>
#include <sandbox.h>
#if DEBUG
@ -109,9 +109,18 @@ security_auth_peer_event_handler(xpc_connection_t connection, xpc_object_t event
}
status = errAuthorizationSuccess;
break;
case AUTHORIZATION_PREAUTHORIZE_CREDENTIALS:
status = authorization_preauthorize_credentials(conn,event,reply);
case AUTHORIZATION_COPY_RIGHT_PROPERTIES:
status = authorization_copy_right_properties(conn,event,reply);
break;
case AUTHORIZATION_COPY_PRELOGIN_USERDB:
status = authorization_copy_prelogin_userdb(conn,event,reply);
break;
case AUTHORIZATION_COPY_PRELOGIN_PREFS:
status = authorization_copy_prelogin_pref_value(conn, event, reply);
break;
case AUTHORIZATION_PRELOGIN_SC_OVERRIDE:
status = authorization_prelogin_smartcardonly_override(conn, event, reply);
break;
#if DEBUG
case AUTHORIZATION_DEV:
server_dev();

View File

@ -8,10 +8,13 @@
#include "authtoken.h"
#include "authutilities.h"
#include "ccaudit.h"
#include <libproc.h>
#include <Security/SecCode.h>
#include <Security/SecRequirement.h>
#include <security_utilities/simulatecrash_assert.h>
AUTHD_DEFINE_LOG
struct _process_s {
@ -139,6 +142,12 @@ process_create(const audit_info_s * auditInfo, session_t session)
proc->dispatch_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
check(proc->dispatch_queue != NULL);
// to have at least some code URL just for case later methods fail
int retval = proc_pidpath(proc->auditInfo.pid, proc->code_url, sizeof(proc->code_url));
if ( retval <= 0 ) {
os_log_error(AUTHD_LOG, "process: PID %d pidpathfailed %d", proc->auditInfo.pid, retval);
}
CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDataRef auditToken = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)&auditInfo->opaqueToken, sizeof(auditInfo->opaqueToken), kCFAllocatorNull);
if (auditToken) {
@ -152,13 +161,22 @@ process_create(const audit_info_s * auditInfo, session_t session)
}
status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &codeRef);
CFReleaseSafe(codeDict);
if (status) {
os_log_error(AUTHD_LOG, "process: PID %d failed to create code ref %d", proc->auditInfo.pid, (int)status);
CFReleaseNull(proc);
goto done;
}
status = SecCodeCopyPath(codeRef, kSecCSDefaultFlags, &code_url);
if (status == errSecSuccess) {
CFURLGetFileSystemRepresentation(code_url, true, (UInt8*)proc->code_url, sizeof(proc->code_url));
} else {
os_log_error(AUTHD_LOG, "process: PID %d failed to get path %d", proc->auditInfo.pid, (int)status);
}
status = SecCodeCheckValidity(codeRef, kSecCSDefaultFlags, NULL);
require_noerr_action(status, done, os_log_error(AUTHD_LOG, "process: PID %d SecCodeCheckValidity failed with %d", proc->auditInfo.pid, (int)status));
status = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &code_info);
require_noerr_action(status, done, os_log_debug(AUTHD_LOG, "process: PID %d SecCodeCopySigningInformation failed with %d", proc->auditInfo.pid, (int)status));
@ -173,10 +191,6 @@ process_create(const audit_info_s * auditInfo, session_t session)
value = NULL;
}
if (SecCodeCopyPath(codeRef, kSecCSDefaultFlags, &code_url) == errSecSuccess) {
CFURLGetFileSystemRepresentation(code_url, true, (UInt8*)proc->code_url, sizeof(proc->code_url));
}
if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoIdentifier, &value)) {
if (CFGetTypeID(value) == CFStringGetTypeID()) {
proc->code_identifier = _copy_cf_string(value, NULL);

View File

@ -176,35 +176,10 @@ rule_create_default()
CFArrayAppendValue(rule->mechanisms, mech);
CFReleaseNull(mech);
mech = mechanism_create_with_string("PKINITMechanism:auth,privileged", NULL);
CFArrayAppendValue(rule->mechanisms, mech);
CFReleaseNull(mech);
done:
return rule;
}
rule_t
rule_create_preauthorization()
{
rule_t rule = _rule_create();
require(rule != NULL, done);
auth_items_set_int64(rule->data, RULE_TYPE, RT_RIGHT);
auth_items_set_string(rule->data, RULE_NAME, "(preauthorization)");
auth_items_set_int64(rule->data, RULE_CLASS, RC_USER);
auth_items_set_string(rule->data, RULE_GROUP, "admin");
auth_items_set_int64(rule->data, RULE_TRIES, 1);
auth_items_set_int64(rule->data, RULE_FLAGS, RuleFlagShared | RuleFlagAuthenticateUser | RuleFlagRequireAppleSigned);
mechanism_t mech = mechanism_create_with_string("builtin:authenticate,privileged", NULL);
CFArrayAppendValue(rule->mechanisms, mech);
CFReleaseNull(mech);
done:
return rule;
}
rule_t
rule_create_with_string(const char * str, authdb_connection_t dbconn)
{
@ -766,7 +741,7 @@ rule_sql_commit(rule_t rule, authdb_connection_t dbconn, CFAbsoluteTime modified
mechanism_sql_fetch(mech, dbconn);
}
}
if (!mechanism_exists(mech)) {
if (!mechanism_exists(mech) && !isInFVUnlock()) {
os_log_error(AUTHD_LOG, "Warning mechanism not found on disk %{public}s during import of %{public}s", mechanism_get_string(mech), rule_get_name(rule));
}
require_action(mechanism_get_id(mech) != 0, done, os_log_error(AUTHD_LOG, "rule: commit, invalid mechanism %{public}s:%{public}s for %{public}s", mechanism_get_plugin(mech), mechanism_get_param(mech), rule_get_name(rule)));
@ -1168,6 +1143,9 @@ rule_check_flags(rule_t rule, RuleFlags flags)
bool
rule_get_shared(rule_t rule)
{
if (isInFVUnlock()) {
return false;
}
return rule_check_flags(rule, RuleFlagShared);
}

Some files were not shown because too many files have changed in this diff Show More