diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 52564a344..31773b5e8 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -222,6 +222,7 @@ 34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */; }; 34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */; }; 34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */; }; + 34E8A8D12085238A00B272B1 /* ProtoParsingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */; }; 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; }; 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; }; 4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; }; @@ -860,6 +861,7 @@ 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIDiskUsage.m; sourceTree = ""; }; 34E3EF0E1EFC2684007F6822 /* DebugUIPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIPage.h; sourceTree = ""; }; 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIPage.m; sourceTree = ""; }; + 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoParsingTest.m; sourceTree = ""; }; 34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = ""; }; 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBezierPathView.m; sourceTree = ""; }; 34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = views/OWSAnyTouchGestureRecognizer.h; sourceTree = ""; }; @@ -2191,10 +2193,11 @@ 34DB0BEB2011548A007B313F /* OWSDatabaseConverterTest.h */, 34DB0BEC2011548B007B313F /* OWSDatabaseConverterTest.m */, 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */, + 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */, 45360B8F1F9527DA00FA666C /* SearcherTest.swift */, + 452D1AF02081059C00A67F7F /* StringAdditionsTest.swift */, B660F6B31C29868000687D6E /* UtilTest.h */, B660F6B41C29868000687D6E /* UtilTest.m */, - 452D1AF02081059C00A67F7F /* StringAdditionsTest.swift */, ); path = util; sourceTree = ""; @@ -3360,6 +3363,7 @@ B660F6BB1C29868000687D6E /* OWSContactsManagerTest.m in Sources */, B660F6D21C29868000687D6E /* PushManagerTest.m in Sources */, 455AC69E1F4F8B0300134004 /* ImageCacheTest.swift in Sources */, + 34E8A8D12085238A00B272B1 /* ProtoParsingTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Signal/src/util/OWSBackupImportJob.m b/Signal/src/util/OWSBackupImportJob.m index 752d2bd8a..7a4cae790 100644 --- a/Signal/src/util/OWSBackupImportJob.m +++ b/Signal/src/util/OWSBackupImportJob.m @@ -391,8 +391,13 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe aborted = YES; return completion(NO); } - OWSSignaliOSProtosBackupSnapshot *_Nullable entities = - [OWSSignaliOSProtosBackupSnapshot parseFromData:uncompressedData]; + OWSSignaliOSProtosBackupSnapshot *_Nullable entities; + @try { + entities = [OWSSignaliOSProtosBackupSnapshot parseFromData:uncompressedData]; + } @catch (NSException *exception) { + OWSProdLogAndFail(@"%@ Could not parse proto: %@", self.logTag, exception.debugDescription); + // TODO: Add analytics. + } if (!entities || entities.entity.count < 1) { DDLogError(@"%@ missing entities.", self.logTag); // Database-related errors are unrecoverable. diff --git a/Signal/test/util/ProtoParsingTest.m b/Signal/test/util/ProtoParsingTest.m new file mode 100644 index 000000000..cae8f9a56 --- /dev/null +++ b/Signal/test/util/ProtoParsingTest.m @@ -0,0 +1,41 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +#import "OWSSignalServiceProtos.pb.h" +#import + +@interface ProtoParsingTest : XCTestCase + +@end + +#pragma mark - + +@implementation ProtoParsingTest + +- (void)testProtoParsing_nil +{ + OWSSignalServiceProtosEnvelope *_Nullable envelope = [OWSSignalServiceProtosEnvelope parseFromData:nil]; + XCTAssertNotNil(envelope); +} + +- (void)testProtoParsing_empty +{ + NSData *data = [NSData new]; + OWSSignalServiceProtosEnvelope *_Nullable envelope = [OWSSignalServiceProtosEnvelope parseFromData:data]; + XCTAssertNotNil(envelope); +} + +- (void)testProtoParsing_wrong1 +{ + @try { + NSData *data = [@"test" dataUsingEncoding:NSUTF8StringEncoding]; + [OWSSignalServiceProtosEnvelope parseFromData:data]; + XCTFail(@"Missing expected exception"); + } @catch (NSException *exception) { + // Exception is expected. + NSLog(@"Caught expected exception: %@", [exception class]); + } +} + +@end diff --git a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m index 34450d880..790e612b3 100644 --- a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -62,7 +62,12 @@ NS_ASSUME_NONNULL_BEGIN - (OWSSignalServiceProtosEnvelope *)envelope { if (!_envelope) { - _envelope = [OWSSignalServiceProtosEnvelope parseFromData:self.envelopeData]; + @try { + _envelope = [OWSSignalServiceProtosEnvelope parseFromData:self.envelopeData]; + } @catch (NSException *exception) { + OWSProdLogAndFail(@"%@ Could not parse proto: %@", self.logTag, exception.debugDescription); + // TODO: Add analytics. + } } return _envelope; } diff --git a/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m b/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m index 772cb5ca6..fc41a9ec8 100644 --- a/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m +++ b/SignalServiceKit/src/Messages/OWSBatchMessageProcessor.m @@ -375,9 +375,14 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo NSMutableArray *processedJobs = [NSMutableArray new]; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { for (OWSMessageContentJob *job in jobs) { - [self.messagesManager processEnvelope:job.envelopeProto - plaintextData:job.plaintextData - transaction:transaction]; + @try { + [self.messagesManager processEnvelope:job.envelopeProto + plaintextData:job.plaintextData + transaction:transaction]; + } @catch (NSException *exception) { + OWSProdLogAndFail(@"%@ Received an invalid envelope: %@", self.logTag, exception.debugDescription); + // TODO: Add analytics. + } [processedJobs addObject:job]; if (self.isAppInBackground) { diff --git a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m index 6fddcc18d..220b36983 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m @@ -106,16 +106,17 @@ NS_ASSUME_NONNULL_BEGIN failureBlockParameter(); }); }; - DDLogInfo(@"%@ decrypting envelope: %@", self.logTag, [self descriptionForEnvelope:envelope]); - - OWSAssert(envelope.source.length > 0); - if ([self isEnvelopeBlocked:envelope]) { - DDLogInfo(@"%@ ignoring blocked envelope: %@", self.logTag, envelope.source); - failureBlock(); - return; - } @try { + DDLogInfo(@"%@ decrypting envelope: %@", self.logTag, [self descriptionForEnvelope:envelope]); + + OWSAssert(envelope.source.length > 0); + if ([self isEnvelopeBlocked:envelope]) { + DDLogInfo(@"%@ ignoring blocked envelope: %@", self.logTag, envelope.source); + failureBlock(); + return; + } + switch (envelope.type) { case OWSSignalServiceProtosEnvelopeTypeCiphertext: { [self decryptSecureMessage:envelope @@ -167,7 +168,7 @@ NS_ASSUME_NONNULL_BEGIN break; } } @catch (NSException *exception) { - DDLogError(@"Received an incorrectly formatted protocol buffer: %@", exception.debugDescription); + OWSProdLogAndFail(@"%@ Received an invalid envelope: %@", self.logTag, exception.debugDescription); OWSProdFail([OWSAnalyticsEvents messageManagerErrorInvalidProtocolMessage]); } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 999eacbe2..1c64c563b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -200,7 +200,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(!plaintextData); [self handleDeliveryReceipt:envelope transaction:transaction]; break; - // Other messages are just dismissed for now. + // Other messages are just dismissed for now. case OWSSignalServiceProtosEnvelopeTypeKeyExchange: DDLogWarn(@"Received Key Exchange Message, not supported"); break; diff --git a/SignalServiceKit/src/Messages/OWSMessageReceiver.m b/SignalServiceKit/src/Messages/OWSMessageReceiver.m index 68a36f1bd..0af8b6baa 100644 --- a/SignalServiceKit/src/Messages/OWSMessageReceiver.m +++ b/SignalServiceKit/src/Messages/OWSMessageReceiver.m @@ -316,7 +316,18 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin AssertOnDispatchQueue(self.serialQueue); OWSAssert(job); - OWSSignalServiceProtosEnvelope *envelope = job.envelopeProto; + OWSSignalServiceProtosEnvelope *_Nullable envelope = nil; + @try { + envelope = job.envelopeProto; + } @catch (NSException *exception) { + OWSProdLogAndFail(@"%@ Could not parse proto: %@", self.logTag, exception.debugDescription); + // TODO: Add analytics. + dispatch_async(self.serialQueue, ^{ + completion(NO); + }); + return; + } + [self.messageDecrypter decryptEnvelope:envelope successBlock:^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) { OWSAssert(transaction); diff --git a/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m b/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m index dd9e09db4..8074e8e24 100644 --- a/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m +++ b/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m @@ -385,21 +385,26 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_ __block OWSBackgroundTask *backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *decryptedPayload = [Cryptography decryptAppleMessagePayload:message.body + withSignalingKey:TSAccountManager.signalingKey]; - NSData *decryptedPayload = - [Cryptography decryptAppleMessagePayload:message.body withSignalingKey:TSAccountManager.signalingKey]; + if (!decryptedPayload) { + DDLogWarn(@"%@ Failed to decrypt incoming payload or bad HMAC", self.logTag); + [self sendWebSocketMessageAcknowledgement:message]; + backgroundTask = nil; + return; + } - if (!decryptedPayload) { - DDLogWarn(@"%@ Failed to decrypt incoming payload or bad HMAC", self.logTag); - [self sendWebSocketMessageAcknowledgement:message]; - backgroundTask = nil; - return; + OWSSignalServiceProtosEnvelope *envelope = + [OWSSignalServiceProtosEnvelope parseFromData:decryptedPayload]; + + [self.messageReceiver handleReceivedEnvelope:envelope]; + } @catch (NSException *exception) { + OWSProdLogAndFail(@"%@ Received an invalid envelope: %@", self.logTag, exception.debugDescription); + // TODO: Add analytics. } - OWSSignalServiceProtosEnvelope *envelope = [OWSSignalServiceProtosEnvelope parseFromData:decryptedPayload]; - - [self.messageReceiver handleReceivedEnvelope:envelope]; - dispatch_async(dispatch_get_main_queue(), ^{ [self sendWebSocketMessageAcknowledgement:message]; backgroundTask = nil;