From 3aad26155d79a927a4e3aaab951bb44fece6d372 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Fri, 21 Nov 2014 20:23:12 -0800 Subject: [PATCH 1/2] Empty files for NFCMirrorEvidenceSource --- ControlPlane.xcodeproj/project.pbxproj | 6 ++++++ Source/NFCMirrorEvidenceSource.h | 13 +++++++++++++ Source/NFCMirrorEvidenceSource.m | 13 +++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 Source/NFCMirrorEvidenceSource.h create mode 100644 Source/NFCMirrorEvidenceSource.m diff --git a/ControlPlane.xcodeproj/project.pbxproj b/ControlPlane.xcodeproj/project.pbxproj index 7fc6a8b0e..9301c58bf 100644 --- a/ControlPlane.xcodeproj/project.pbxproj +++ b/ControlPlane.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6D6857041A2046FD00803A34 /* NFCMirrorEvidenceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D6857031A2046FD00803A34 /* NFCMirrorEvidenceSource.m */; }; 732A58DF1484300A0011019C /* ShellScriptEvidenceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 732A58DE1484300A0011019C /* ShellScriptEvidenceSource.m */; }; 739492E2146B8018003C94DE /* DisplaySleepTimeAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 739492E1146B8018003C94DE /* DisplaySleepTimeAction.m */; }; 73A5092F14849405007D22B5 /* ShellScriptRule.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73A5092714849405007D22B5 /* ShellScriptRule.xib */; }; @@ -307,6 +308,8 @@ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* ControlPlane_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ControlPlane_Prefix.pch; path = Source/ControlPlane_Prefix.pch; sourceTree = ""; }; + 6D6857021A2046FD00803A34 /* NFCMirrorEvidenceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NFCMirrorEvidenceSource.h; path = Source/NFCMirrorEvidenceSource.h; sourceTree = ""; }; + 6D6857031A2046FD00803A34 /* NFCMirrorEvidenceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NFCMirrorEvidenceSource.m; path = Source/NFCMirrorEvidenceSource.m; sourceTree = ""; }; 732A58DD1484300A0011019C /* ShellScriptEvidenceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ShellScriptEvidenceSource.h; path = Source/ShellScriptEvidenceSource.h; sourceTree = ""; }; 732A58DE1484300A0011019C /* ShellScriptEvidenceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShellScriptEvidenceSource.m; path = Source/ShellScriptEvidenceSource.m; sourceTree = ""; }; 732A58E91484311C0011019C /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "pt-PT"; path = "pt-PT.lproj/CoreLocationRule.xib"; sourceTree = ""; }; @@ -1011,6 +1014,8 @@ 8DE428FA0C5084D00073499A /* TimeOfDayEvidenceSource.m */, 8D35A34C0BBBA0CB006ACBB0 /* USBEvidenceSource.h */, 8D35A34D0BBBA0CB006ACBB0 /* USBEvidenceSource.m */, + 6D6857021A2046FD00803A34 /* NFCMirrorEvidenceSource.h */, + 6D6857031A2046FD00803A34 /* NFCMirrorEvidenceSource.m */, ); name = "Concrete Evidence Sources"; sourceTree = ""; @@ -1493,6 +1498,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6D6857041A2046FD00803A34 /* NFCMirrorEvidenceSource.m in Sources */, DAF2257E15ABD8CD003A8030 /* DisplayBrightnessAction.m in Sources */, DAE893EE1454FFFB005FA13C /* ToggleFirewallAction.m in Sources */, DAF36ECA143E7C5700350991 /* CoreLocationSource.m in Sources */, diff --git a/Source/NFCMirrorEvidenceSource.h b/Source/NFCMirrorEvidenceSource.h new file mode 100644 index 000000000..e3952f7f0 --- /dev/null +++ b/Source/NFCMirrorEvidenceSource.h @@ -0,0 +1,13 @@ +// +// NFCMirrorEvidenceSource.h +// ControlPlane +// +// Created by Eric Betts on 11/21/14. +// +// + +#import + +@interface NFCMirrorEvidenceSource : NSObject + +@end diff --git a/Source/NFCMirrorEvidenceSource.m b/Source/NFCMirrorEvidenceSource.m new file mode 100644 index 000000000..88159e627 --- /dev/null +++ b/Source/NFCMirrorEvidenceSource.m @@ -0,0 +1,13 @@ +// +// NFCMirrorEvidenceSource.m +// ControlPlane +// +// Created by Eric Betts on 11/21/14. +// +// + +#import "NFCMirrorEvidenceSource.h" + +@implementation NFCMirrorEvidenceSource + +@end From 99f2c92db862472ef7b9ee1c5ec731dbca3b12fd Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Fri, 21 Nov 2014 22:27:14 -0800 Subject: [PATCH 2/2] Add NFC reader called "Mirror" as evidence source A consumer grade NFC reader from a defunct French company, Violet, who also made the Nabaztag and Karotz, early attempts at Internet of Things appliances. --- Source/CPController.m | 1 + Source/EvidenceSource.m | 3 + Source/NFCMirrorEvidenceSource.h | 37 ++++- Source/NFCMirrorEvidenceSource.m | 248 +++++++++++++++++++++++++++++++ 4 files changed, 287 insertions(+), 2 deletions(-) diff --git a/Source/CPController.m b/Source/CPController.m index 27f6a0283..6297e30d4 100644 --- a/Source/CPController.m +++ b/Source/CPController.m @@ -174,6 +174,7 @@ + (void)initialize { [appDefaults setValue:@"" forKey:@"DefaultContext"]; [appDefaults setValue:[NSNumber numberWithBool:YES] forKey:@"EnablePersistentContext"]; [appDefaults setValue:@"" forKey:@"PersistentContext"]; + [appDefaults setValue:[NSNumber numberWithBool:NO] forKey:@"EnableNFCMirrorEvidenceSource"]; // Advanced [appDefaults setValue:[NSNumber numberWithBool:NO] forKey:@"ShowAdvancedPreferences"]; diff --git a/Source/EvidenceSource.m b/Source/EvidenceSource.m index f2c0bf1c5..37a865d81 100644 --- a/Source/EvidenceSource.m +++ b/Source/EvidenceSource.m @@ -412,6 +412,7 @@ - (NSArray *)getEvidenceSourcePlugins; #import "RunningApplicationEvidenceSource.h" #import "TimeOfDayEvidenceSource.h" #import "USBEvidenceSource.h" +#import "NFCMirrorEvidenceSource.h" #import "CoreWLANEvidenceSource.h" #import "ShellScriptEvidenceSource.h" #import "SleepEvidenceSource.h" @@ -445,6 +446,7 @@ - (id)init { [FireWireEvidenceSource class], [MonitorEvidenceSource class], [USBEvidenceSource class], + [NFCMirrorEvidenceSource class], [AudioOutputEvidenceSource class], //[HostAvailabilityEvidenceSource class], [BluetoothEvidenceSource class], @@ -496,6 +498,7 @@ - (id)init { NSLocalizedString(@"Sleep/Wake", @"Evidence source"); NSLocalizedString(@"TimeOfDay", @"Evidence source"); NSLocalizedString(@"USB", @"Evidence source"); + NSLocalizedString(@"NFC Mirror", @"Evidence source"); NSLocalizedString(@"WiFi using CoreWLAN", @"Evidence source"); } diff --git a/Source/NFCMirrorEvidenceSource.h b/Source/NFCMirrorEvidenceSource.h index e3952f7f0..14e823fd8 100644 --- a/Source/NFCMirrorEvidenceSource.h +++ b/Source/NFCMirrorEvidenceSource.h @@ -6,8 +6,41 @@ // // -#import +#import "GenericEvidenceSource.h" +#import +#import +#import + +#define UPSIDE_DOWN 5 +#define RIGHTSIDE_UP 4 +#define TAG_EVENT 2 +#define MIRROR_REPORT_LENGTH 64 +#define TAG_ON 1 +#define TAG_OFF 2 + +@interface NFCMirrorEvidenceSource : GenericEvidenceSource { + NSLock *lock; + + NSMutableArray *tags; +} + + @property IOHIDDeviceRef mirror; + +- (id)init; +- (void)dealloc; + +- (void)start; +- (void)stop; + +- (void)doUpdate; +- (void)clearCollectedData; + +- (NSString *)name; +- (BOOL)doesRuleMatch:(NSDictionary *)rule; +- (NSString *)getSuggestionLeadText:(NSString *)type; +- (NSArray *)getSuggestions; + +- (NSArray *)getTags; -@interface NFCMirrorEvidenceSource : NSObject @end diff --git a/Source/NFCMirrorEvidenceSource.m b/Source/NFCMirrorEvidenceSource.m index 88159e627..a63b978b3 100644 --- a/Source/NFCMirrorEvidenceSource.m +++ b/Source/NFCMirrorEvidenceSource.m @@ -10,4 +10,252 @@ @implementation NFCMirrorEvidenceSource +- (id)init { + if (!(self = [super init])) + return nil; + + lock = [[NSLock alloc] init]; + tags = [[NSMutableArray alloc] init]; + + return self; +} + +- (void)dealloc { + [lock release]; + [tags release]; + + [super dealloc]; +} + +#pragma mark C callbacks + +void MyInputCallback(void *inContext, IOReturn result, void *sender, + IOHIDReportType type, uint32_t reportID, uint8_t *report, + CFIndex reportLength) { + // process device response buffer (report) here + NFCMirrorEvidenceSource *self = (__bridge NFCMirrorEvidenceSource *)inContext; + NSString *tagID = @""; + int interface = report[0]; + int method = report[1]; + // int correlationID = report[2] * 255 + report[3]; + int dataLength = report[4]; + uint8_t *data = report + 5; + if (reportLength == 0 || report[1] == 0) { + return; + } else if (reportLength == MIRROR_REPORT_LENGTH) { + if (interface == TAG_EVENT) { + tagID = [self bytesToString:data andLength:dataLength]; + [self handleTag:tagID forState:method]; + } + } +} + +static void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, + void *inSender, + IOHIDDeviceRef inIOHIDDeviceRef) { + @autoreleasepool { + NFCMirrorEvidenceSource *self = + (__bridge NFCMirrorEvidenceSource *)inContext; + self.mirror = inIOHIDDeviceRef; + long reportSize = 0; + uint8_t *report; + (void)IOHIDDevice_GetLongProperty( + inIOHIDDeviceRef, CFSTR(kIOHIDMaxInputReportSizeKey), &reportSize); + if (reportSize) { + report = calloc(1, reportSize); + if (report) { + IOHIDDeviceRegisterInputReportCallback( + inIOHIDDeviceRef, report, reportSize, MyInputCallback, inContext); + NSLog(@"%s", __PRETTY_FUNCTION__); + //Default to choreo off so I can use at work + //[self setChoreography:NO]; + } + } + } +} + +static void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, + void *inSender, + IOHIDDeviceRef inIOHIDDeviceRef) { + @autoreleasepool { + NFCMirrorEvidenceSource *self = + (__bridge NFCMirrorEvidenceSource *)inContext; + self.mirror = nil; + NSLog(@"%s", __PRETTY_FUNCTION__); + } +} + +- (NSString *)description { + return NSLocalizedString(@"Create rules based on presence of NFC tag.", @""); +} + +- (NSString *)name { + return @"NFCMirror"; +} + +- (NSString *)getSuggestionLeadText:(NSString *)type { + return NSLocalizedString(@"The presence of", @"In rule-adding dialog"); +} + + +- (NSArray *)getSuggestions +{ + NSMutableArray *arr = [NSMutableArray array]; + + [lock lock]; + NSEnumerator *en = [tags objectEnumerator]; + NSString *aTag; + while ((aTag = [en nextObject])) { + [arr addObject:@{@"type": @"NFCMirror", @"parameter": aTag, @"description": aTag}]; + } + [lock unlock]; + + return arr; +} + +- (NSString *)friendlyName { + return NSLocalizedString(@"NFC Tag", @""); +} + +- (BOOL)doesRuleMatch:(NSDictionary *)rule +{ + BOOL match = NO; + NSString *inputTag = rule[@"parameter"]; + [lock lock]; + match = [tags containsObject:inputTag]; + [lock unlock]; + return match; +} + +- (void)start { + if (running) { + return; + } + + const long vendorId = 0x1da8; + const long productId = 0x1301; + NSDictionary *dict = @{ + @kIOHIDProductIDKey: @(productId), + @kIOHIDVendorIDKey: @(vendorId) + }; + IOHIDManagerRef managerRef = + IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + IOHIDManagerScheduleWithRunLoop(managerRef, CFRunLoopGetCurrent(), + kCFRunLoopDefaultMode); + IOHIDManagerOpen(managerRef, 0L); + IOHIDManagerSetDeviceMatching(managerRef, (__bridge CFDictionaryRef)dict); + IOHIDManagerRegisterDeviceMatchingCallback( + managerRef, Handle_DeviceMatchingCallback, (__bridge void *)(self)); + IOHIDManagerRegisterDeviceRemovalCallback( + managerRef, Handle_DeviceRemovalCallback, (__bridge void *)(self)); + + running = YES; +} + +- (void)stop { + if (!running) { + return; + } + [self setDataCollected:NO]; + // remove callbacks? + + running = NO; +} + +- (NSArray *)getTags { + NSArray *arr; + + [lock lock]; + arr = [NSArray arrayWithArray:tags]; + [lock unlock]; + + return arr; +} + +- (void)doUpdate +{ +#ifdef DEBUG_MODE + NSLog(@"%@ >> found %ld tags", [self class], (long) [tags count]); +#endif +} + +- (void)clearCollectedData +{ + [lock lock]; + [tags removeAllObjects]; + [self setDataCollected:NO]; + [lock unlock]; +} + ++ (BOOL)isEvidenceSourceApplicableToSystem { + return YES; //Figure out how to check currently connected USB devices +} + +- (void)handleTag:(NSString *)tagID forState:(int)state { + NSLog(@"\t\t\t\t%s %@ %i", __PRETTY_FUNCTION__, tagID, state); + [self setDataCollected:YES]; + if (state == TAG_ON) { + [lock lock]; + [tags addObject:tagID]; + [lock unlock]; + } else if (state == TAG_OFF) { + [lock lock]; + [tags removeObject:tagID]; + [lock unlock]; + } +} + +- (NSString *)bytesToString:(uint8_t *)bytes andLength:(CFIndex)length { + NSMutableString *result = + [NSMutableString stringWithCapacity:2 * length + length - 1]; + for (int i = 0; i < length; i++) { + [result appendFormat:@"%02X", bytes[i]]; + } + return [result lowercaseString]; // Result is auto-released +} + +- (void)setChoreography:(NSNotification *)notification { + NSDictionary *userInfo = notification.userInfo; + NSNumber *state = userInfo[@"state"]; + size_t bufferSize = 64; + long reportSize = 0; + uint8_t *outputBuffer = malloc(bufferSize); + memset(outputBuffer, 0, bufferSize); + // Interface + outputBuffer[0] = 0x03; + // CID + outputBuffer[2] = 0; + outputBuffer[3] = 0; + // length + outputBuffer[4] = 0; + + if ([state boolValue]) { + NSLog(@"Choreography on"); + // Method + outputBuffer[1] = 0x03; + } else { + NSLog(@"Choreography off"); + // Method + outputBuffer[1] = 0x01; + } + IOHIDDeviceSetReport(self.mirror, kIOHIDReportTypeOutput, reportSize, + outputBuffer, bufferSize); + free(outputBuffer); +} + +static Boolean IOHIDDevice_GetLongProperty(IOHIDDeviceRef inDeviceRef, + CFStringRef inKey, long *outValue) { + Boolean result = FALSE; + CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inDeviceRef, inKey); + if (tCFTypeRef) { + // if this is a number + if (CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef)) { + // get its value + result = CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, + outValue); + } + } + return result; +} + @end