From f5bbf9d4803c648701acf0f67b97158e166136da Mon Sep 17 00:00:00 2001 From: Frederic Jacobs Date: Sat, 9 Aug 2014 02:39:09 +0200 Subject: [PATCH] Enhancements to certificate pinning //FREEBIE --- Signal.xcodeproj/project.pbxproj | 10 +++++----- Signal/src/network/PushManager.m | 2 +- .../network/http/CallServerRequestsManager.m | 7 +++++++ Signal/src/network/tcp/tls/Certificate.h | 4 +--- Signal/src/network/tcp/tls/Certificate.m | 14 +++++++++----- .../view controllers/RegisterViewController.m | 9 ++++++--- .../test/{ => Supporting Files}/whisperFake.cer | Bin Signal/test/audio/AudioRemoteIOTest.m | 5 +++-- Signal/test/network/tcp/tls/NetworkStreamTest.m | 16 ++++++++++++++++ 9 files changed, 48 insertions(+), 19 deletions(-) rename Signal/test/{ => Supporting Files}/whisperFake.cer (100%) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index c5f1c4051..906e30b11 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -381,7 +381,7 @@ B621B079198C69A100D36C3D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B621B017198C69A100D36C3D /* Localizable.strings */; }; B67ADDC41989FF8700E1A773 /* CallServerRequestsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B67ADDC31989FF8700E1A773 /* CallServerRequestsManager.m */; }; B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B67EBF5C19194AC60084CCFD /* Settings.bundle */; }; - B69B6305199573970072E805 /* whisperFake.cer in Resources */ = {isa = PBXBuildFile; fileRef = B69B6304199573970072E805 /* whisperFake.cer */; }; + B6850E5A1995A4710068E715 /* whisperFake.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6850E591995A4710068E715 /* whisperFake.cer */; }; B69CD25119773E79005CE69A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B69CD25019773E79005CE69A /* XCTest.framework */; }; B6B1013C196D213F007E3930 /* SGNKeychainUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B1013B196D213F007E3930 /* SGNKeychainUtil.m */; }; B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B9ECFB198B31BA00C620D3 /* PushManager.m */; }; @@ -1116,7 +1116,7 @@ B67ADDC21989FF8700E1A773 /* CallServerRequestsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallServerRequestsManager.h; sourceTree = ""; }; B67ADDC31989FF8700E1A773 /* CallServerRequestsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallServerRequestsManager.m; sourceTree = ""; }; B67EBF5C19194AC60084CCFD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = SettingsBundle/Settings.bundle; sourceTree = SOURCE_ROOT; }; - B69B6304199573970072E805 /* whisperFake.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = whisperFake.cer; sourceTree = ""; }; + B6850E591995A4710068E715 /* whisperFake.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = whisperFake.cer; sourceTree = ""; }; B69CD25019773E79005CE69A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; B6B1013A196D213F007E3930 /* SGNKeychainUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGNKeychainUtil.h; sourceTree = ""; }; B6B1013B196D213F007E3930 /* SGNKeychainUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGNKeychainUtil.m; sourceTree = ""; }; @@ -2232,7 +2232,6 @@ A15706EA17F0CD6D007C2BD6 /* test */ = { isa = PBXGroup; children = ( - B69B6304199573970072E805 /* whisperFake.cer */, 76919BF51805D169008C664A /* contact */, A15706EB17F0CD6D007C2BD6 /* async */, A15706F217F0CD6D007C2BD6 /* audio */, @@ -2397,6 +2396,7 @@ A157073917F0CD6D007C2BD6 /* Supporting Files */ = { isa = PBXGroup; children = ( + B6850E591995A4710068E715 /* whisperFake.cer */, A157073A17F0CD6D007C2BD6 /* SignalTests-Info.plist */, ); path = "Supporting Files"; @@ -3260,7 +3260,6 @@ E14874F418A06930002CC4F3 /* volume_low@2x.png in Resources */, E14874F518A06930002CC4F3 /* whisper_notification_icon.png in Resources */, E14874F618A06930002CC4F3 /* whisper_notification_icon@2x.png in Resources */, - E1370BF618A068A600826894 /* whisperReal.cer in Resources */, E1370BEA18A0689000826894 /* AppIcon29x29.jpg in Resources */, E1370BEB18A0689000826894 /* AppIcon29x29.png in Resources */, E1370BEC18A0689000826894 /* AppIcon29x29@2x.png in Resources */, @@ -3286,6 +3285,7 @@ E148751318A06AFD002CC4F3 /* HelveticaNeueLTStd-Th.otf in Resources */, E148751418A06AFD002CC4F3 /* HelveticaNeueLTStd-Lt.otf in Resources */, E148751518A06AFD002CC4F3 /* HelveticaNeueLTStd-Md.otf in Resources */, + E1370BF618A068A600826894 /* whisperReal.cer in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3309,7 +3309,7 @@ 76EB067918170B34006006FC /* InCallViewController.xib in Resources */, 76EB068318170B34006006FC /* SettingsViewController.xib in Resources */, 76EB068118170B34006006FC /* RegisterViewController.xib in Resources */, - B69B6305199573970072E805 /* whisperFake.cer in Resources */, + B6850E5A1995A4710068E715 /* whisperFake.cer in Resources */, B97CBFB218861023008E0DE9 /* CountryCodeTableViewCell.xib in Resources */, B9A578B5183D610300C17105 /* FavouriteTableViewCell.xib in Resources */, B9B89C58185A2B7000A24465 /* LeftSideMenuCell.xib in Resources */, diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index a741d6444..ecca05b78 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -119,7 +119,7 @@ } } } failure:^(NSURLSessionDataTask *task, NSError *error) { - [self registerForPushWithToken:token]; + [self registerFailureWithToken:token]; }]; } diff --git a/Signal/src/network/http/CallServerRequestsManager.m b/Signal/src/network/http/CallServerRequestsManager.m index 181c45401..e738ecd40 100644 --- a/Signal/src/network/http/CallServerRequestsManager.m +++ b/Signal/src/network/http/CallServerRequestsManager.m @@ -34,6 +34,13 @@ MacrosSingletonImplemention NSURLSessionConfiguration *sessionConf = [NSURLSessionConfiguration ephemeralSessionConfiguration]; self.operationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:endPointURL sessionConfiguration:sessionConf]; [self.operationManager setSecurityPolicy:[AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]]; + + NSString *certPath = [[NSBundle mainBundle] pathForResource:@"whisperReal" ofType:@"cer"]; + NSData *certData = [NSData dataWithContentsOfFile:certPath]; + + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); + + self.operationManager.securityPolicy.pinnedCertificates = @[(__bridge_transfer NSData *)SecCertificateCopyData(cert)]; self.operationManager.securityPolicy.allowInvalidCertificates = YES; // We use a custom certificate, not signed by a CA. self.operationManager.responseSerializer = [AFJSONResponseSerializer serializer]; } diff --git a/Signal/src/network/tcp/tls/Certificate.h b/Signal/src/network/tcp/tls/Certificate.h index 01f773d95..9353464a1 100644 --- a/Signal/src/network/tcp/tls/Certificate.h +++ b/Signal/src/network/tcp/tls/Certificate.h @@ -5,9 +5,7 @@ * Certificate is responsible for loading, exposing, and managing a SecCertificateRef. * */ -@interface Certificate : NSObject { -@private SecCertificateRef secCertificateRef; -} +@interface Certificate : NSObject +(Certificate*) certificateFromTrust:(SecTrustRef)trust atIndex:(CFIndex)index; diff --git a/Signal/src/network/tcp/tls/Certificate.m b/Signal/src/network/tcp/tls/Certificate.m index 9e781b60a..b45acc986 100644 --- a/Signal/src/network/tcp/tls/Certificate.m +++ b/Signal/src/network/tcp/tls/Certificate.m @@ -1,6 +1,10 @@ #import "Certificate.h" #import "Util.h" +@interface Certificate () +@property SecCertificateRef secCertificateRef; +@end + @implementation Certificate +(Certificate*) certificateFromTrust:(SecTrustRef)trust @@ -13,7 +17,7 @@ CFRetain(cert); Certificate* instance = [Certificate new]; - instance->secCertificateRef = cert; + instance.secCertificateRef = cert; return instance; } @@ -30,12 +34,12 @@ checkOperation(cert != nil); Certificate* instance = [Certificate new]; - instance->secCertificateRef = cert; + instance.secCertificateRef = cert; return instance; } -(void) dealloc { - CFRelease(secCertificateRef); + CFRelease(self.secCertificateRef); } -(void) setAsAnchorForTrust:(SecTrustRef)trust { @@ -44,7 +48,7 @@ CFMutableArrayRef anchorCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); checkOperation(anchorCerts != NULL); - CFArrayAppendValue(anchorCerts, secCertificateRef); + CFArrayAppendValue(anchorCerts, self.secCertificateRef); OSStatus setAnchorResult = SecTrustSetAnchorCertificates(trust, anchorCerts); CFRelease(anchorCerts); @@ -54,7 +58,7 @@ } -(NSString *)description { - return (__bridge_transfer NSString*)SecCertificateCopySubjectSummary(secCertificateRef); + return (__bridge_transfer NSString*)SecCertificateCopySubjectSummary(self.secCertificateRef); } @end diff --git a/Signal/src/view controllers/RegisterViewController.m b/Signal/src/view controllers/RegisterViewController.m index ace6c66ec..105325168 100644 --- a/Signal/src/view controllers/RegisterViewController.m +++ b/Signal/src/view controllers/RegisterViewController.m @@ -133,7 +133,6 @@ return [futurePhoneRegistrationStarted then:^(id _) { [self showViewNumber:CHALLENGE_VIEW_NUMBER]; - [Environment setRegistered:YES]; [self.challengeNumberLabel setText:[phoneNumber description]]; [_registerCancelButton removeFromSuperview]; [self startVoiceVerificationCountdownTimer]; @@ -196,14 +195,17 @@ }]; [futureDone thenDo:^(id result) { + [futureChallengeAcceptedSource trySetResult:@YES]; + }]; + + [futureChallengeAcceptedSource thenDo:^(id value) { [[PushManager sharedManager] askForPushRegistrationWithSuccess:^{ [Environment setRegistered:YES]; - [[[Environment getCurrent] phoneDirectoryManager] forceUpdate]; [registered trySetResult:@YES]; [self dismissView]; - [futureChallengeAcceptedSource trySetResult:result]; _challengeButton.enabled = YES; [_challengeActivityIndicator stopAnimating]; + [[[Environment getCurrent] phoneDirectoryManager] forceUpdate]; } failure:^{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:REGISTER_ERROR_ALERT_VIEW_TITLE message:REGISTER_ERROR_ALERT_VIEW_BODY delegate:nil cancelButtonTitle:REGISTER_ERROR_ALERT_VIEW_DISMISS otherButtonTitles:nil, nil]; [alertView show]; @@ -211,6 +213,7 @@ [_challengeActivityIndicator stopAnimating]; }]; }]; + } - (void)showViewNumber:(NSInteger)viewNumber { diff --git a/Signal/test/whisperFake.cer b/Signal/test/Supporting Files/whisperFake.cer similarity index 100% rename from Signal/test/whisperFake.cer rename to Signal/test/Supporting Files/whisperFake.cer diff --git a/Signal/test/audio/AudioRemoteIOTest.m b/Signal/test/audio/AudioRemoteIOTest.m index 59b99124b..a9986fd12 100644 --- a/Signal/test/audio/AudioRemoteIOTest.m +++ b/Signal/test/audio/AudioRemoteIOTest.m @@ -10,7 +10,8 @@ @implementation AudioRemoteIOTest --(void) testPlaysAndRecordsAudio { +// Disabled because won't work on Travis +-(void)___testPlaysAndRecordsAudio { __block RemoteIOAudio* a = nil; __block double t = 0; @@ -39,7 +40,7 @@ a = [RemoteIOAudio remoteIOInterfaceStartedWithDelegate:[AnonymousAudioCallbackHandler anonymousAudioInterfaceDelegateWithRecordingCallback:countCalls andPlaybackOccurredCallback:generateWhooOOOoooOOOOooOOOOoooSineWave] untilCancelled:[life getToken]]; - + // churn the run loop, to allow the audio to play and be recorded // YOU SHOULD HEAR A WOOOoooOOOOoooOOO TONE WHILE THIS IS HAPPENING (with the frequency going up and down) testChurnAndConditionMustStayTrue(true, 10); diff --git a/Signal/test/network/tcp/tls/NetworkStreamTest.m b/Signal/test/network/tcp/tls/NetworkStreamTest.m index b6f0543ec..ce2dc7d6a 100644 --- a/Signal/test/network/tcp/tls/NetworkStreamTest.m +++ b/Signal/test/network/tcp/tls/NetworkStreamTest.m @@ -19,6 +19,10 @@ @end +@interface Certificate () +@property SecCertificateRef secCertificateRef; +@end + @implementation NetworkStreamTest - (void)setUp{ @@ -93,9 +97,20 @@ [s terminate]; } + -(void) testAuthenticationFail_WrongCert { [Environment setCurrent:testEnv]; + NSString *certPath = [[[NSBundle bundleForClass:[NetworkStream class]] resourcePath] stringByAppendingPathComponent:@"whisperFake.cer"]; + NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath]; + checkOperation(certData != nil); + + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); + checkOperation(cert != nil); + + Certificate* instance = [Certificate new]; + instance.secCertificateRef = cert; + SecureEndPoint* e = [SecureEndPoint secureEndPointForHost:[HostNameEndPoint hostNameEndPointWithHostName:TEST_SERVER_HOST andPort:TEST_SERVER_PORT] identifiedByCertificate:[Certificate certificateFromResourcePath:TEST_SERVER_INCORRECT_CERT_PATH ofType:TEST_SERVER_INCORRECT_CERT_TYPE]]; @@ -116,6 +131,7 @@ [s terminate]; } + -(void) testAuthenticationFail_WrongHostName { [Environment setCurrent:testEnv];