From 16c8a1a76eab0d353edbaf92cc05b8112899656d Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 14 Jan 2019 17:04:31 -0700 Subject: [PATCH] replace SocketRocket with Starscream --- Podfile | 9 +- Podfile.lock | 26 +-- Pods | 2 +- Signal.xcodeproj/project.pbxproj | 8 +- SignalServiceKit.podspec | 2 +- .../src/Network/SSKWebSocket.swift | 176 ++++++++++++++++++ .../src/Network/WebSockets/OWSWebSocket.m | 79 +++----- .../src/Security/OWSHTTPSecurityPolicy.h | 9 +- .../src/Security/OWSHTTPSecurityPolicy.m | 40 ++-- .../src/Security/OWSWebsocketSecurityPolicy.h | 9 - .../src/Security/OWSWebsocketSecurityPolicy.m | 29 --- 11 files changed, 256 insertions(+), 133 deletions(-) create mode 100644 SignalServiceKit/src/Network/SSKWebSocket.swift delete mode 100644 SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.h delete mode 100644 SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.m diff --git a/Podfile b/Podfile index fee7e98bc..fffcade5a 100644 --- a/Podfile +++ b/Podfile @@ -38,12 +38,6 @@ def shared_pods pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master' # pod 'Mantle', path: '../Mantle' - # SocketRocket has some critical crash fixes on Github, but have published an official release to cocoapods in ages, so - # we were following master - # Forked and have an open PR with our changes, but they have not been merged. - # pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git', inhibit_warnings: true - pod 'SocketRocket', :git => 'https://github.com/signalapp/SocketRocket.git', branch: 'mkirk/handle-sec-err', inhibit_warnings: true - # Forked for compatibily with the ShareExtension, changes have an open PR, but have not been merged. pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release' # pod 'YapDatabase/SQLCipher', path: '../YapDatabase' @@ -52,6 +46,9 @@ def shared_pods pod 'GRKOpenSSLFramework', git: 'https://github.com/signalapp/GRKOpenSSLFramework' #pod 'GRKOpenSSLFramework', path: '../GRKOpenSSLFramework' + pod 'Starscream', git: 'git@github.com:signalapp/Starscream.git', branch: 'signal-release' + # pod 'Starscream', path: '../Starscream' + ### # third party pods #### diff --git a/Podfile.lock b/Podfile.lock index 2ace31f7f..90692ff0e 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -94,7 +94,7 @@ PODS: - SAMKeychain - SignalCoreKit - SignalMetadataKit - - SocketRocket + - Starscream - SwiftProtobuf - YapDatabase/SQLCipher - SignalServiceKit/Tests (0.9.0): @@ -110,16 +110,16 @@ PODS: - SAMKeychain - SignalCoreKit - SignalMetadataKit - - SocketRocket + - Starscream - SwiftProtobuf - YapDatabase/SQLCipher - - SocketRocket (0.5.1) - SQLCipher (4.0.1): - SQLCipher/standard (= 4.0.1) - SQLCipher/common (4.0.1) - SQLCipher/standard (4.0.1): - SQLCipher/common - SSZipArchive (2.1.4) + - Starscream (3.0.6) - SwiftProtobuf (1.2.0) - YapDatabase/SQLCipher (3.1.1): - YapDatabase/SQLCipher/Core (= 3.1.1) @@ -205,9 +205,9 @@ DEPENDENCIES: - SignalMetadataKit/Tests (from `https://github.com/signalapp/SignalMetadataKit`) - SignalServiceKit (from `.`) - SignalServiceKit/Tests (from `.`) - - SocketRocket (from `https://github.com/signalapp/SocketRocket.git`, branch `mkirk/handle-sec-err`) - SQLCipher (>= 4.0.1) - SSZipArchive + - "Starscream (from `git@github.com:signalapp/Starscream.git`, branch `signal-release`)" - YapDatabase/SQLCipher (from `https://github.com/signalapp/YapDatabase.git`, branch `signal-release`) - YYImage @@ -244,9 +244,9 @@ EXTERNAL SOURCES: :git: https://github.com/signalapp/SignalMetadataKit SignalServiceKit: :path: "." - SocketRocket: - :branch: mkirk/handle-sec-err - :git: https://github.com/signalapp/SocketRocket.git + Starscream: + :branch: signal-release + :git: "git@github.com:signalapp/Starscream.git" YapDatabase: :branch: signal-release :git: https://github.com/signalapp/YapDatabase.git @@ -273,9 +273,9 @@ CHECKOUT OPTIONS: SignalMetadataKit: :commit: 56f28fc3a6e35d548d034ef7d0009f233ca0aa62 :git: https://github.com/signalapp/SignalMetadataKit - SocketRocket: - :commit: 9f9563a83cd8960503074aa8de72206f83fb7a69 - :git: https://github.com/signalapp/SocketRocket.git + Starscream: + :commit: edfb5964c5375ca55b3b0c517e1b5b7d0ac4519a + :git: "git@github.com:signalapp/Starscream.git" YapDatabase: :commit: 8e2b69110efd9499a5b553fda0165d2cea4e818d :git: https://github.com/signalapp/YapDatabase.git @@ -295,14 +295,14 @@ SPEC CHECKSUMS: SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SignalCoreKit: c2d8132cdedb95d35eb2f8ae7eac0957695d0a8b SignalMetadataKit: 6fa5e9a53c7f104568662521a2f3874672ff7a02 - SignalServiceKit: 80d774c32b22567682f63c36bf9da265d82083bb - SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e + SignalServiceKit: c637b66e485538dda76836a1ec560dc556035430 SQLCipher: 4636a257060f6f1b4e143a143028b61a2b462d0d SSZipArchive: 41455d4b8d2b6ab93990820b50dc697c2554a322 + Starscream: ef3ece99d765eeccb67de105bfa143f929026cf5 SwiftProtobuf: 91a9856079044ef4ec762b2344c763cd9e5a73c1 YapDatabase: b418a4baa6906e8028748938f9159807fd039af4 YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54 -PODFILE CHECKSUM: 7ccd091c65f353c7fcc3021a13b557a576d48509 +PODFILE CHECKSUM: 7856bf087f931a4089ebd9a08ed1dfe8389b8afc COCOAPODS: 1.5.3 diff --git a/Pods b/Pods index 527dca96c..c65309265 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 527dca96c23f0ac15664e9762987ff017cabdf90 +Subproject commit c653092655ec0c592d7e733e1bd5eee342849ae0 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9bf6c177a..1826603bf 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -3145,7 +3145,7 @@ "${BUILT_PRODUCTS_DIR}/SignalCoreKit/SignalCoreKit.framework", "${BUILT_PRODUCTS_DIR}/SignalMetadataKit/SignalMetadataKit.framework", "${BUILT_PRODUCTS_DIR}/SignalServiceKit/SignalServiceKit.framework", - "${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework", + "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", "${BUILT_PRODUCTS_DIR}/YapDatabase/YapDatabase.framework", @@ -3169,7 +3169,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalCoreKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalMetadataKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalServiceKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YapDatabase.framework", @@ -3220,7 +3220,7 @@ "${BUILT_PRODUCTS_DIR}/SignalCoreKit/SignalCoreKit.framework", "${BUILT_PRODUCTS_DIR}/SignalMetadataKit/SignalMetadataKit.framework", "${BUILT_PRODUCTS_DIR}/SignalServiceKit/SignalServiceKit.framework", - "${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework", + "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", "${BUILT_PRODUCTS_DIR}/YapDatabase/YapDatabase.framework", @@ -3243,7 +3243,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalCoreKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalMetadataKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalServiceKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YapDatabase.framework", diff --git a/SignalServiceKit.podspec b/SignalServiceKit.podspec index 8c01def24..ae42758ae 100644 --- a/SignalServiceKit.podspec +++ b/SignalServiceKit.podspec @@ -44,7 +44,7 @@ An Objective-C library for communicating with the Signal messaging service. s.dependency 'AxolotlKit' s.dependency 'Mantle' s.dependency 'YapDatabase/SQLCipher' - s.dependency 'SocketRocket' + s.dependency 'Starscream' s.dependency 'libPhoneNumber-iOS' s.dependency 'GRKOpenSSLFramework' s.dependency 'SAMKeychain' diff --git a/SignalServiceKit/src/Network/SSKWebSocket.swift b/SignalServiceKit/src/Network/SSKWebSocket.swift new file mode 100644 index 000000000..88c9d1c03 --- /dev/null +++ b/SignalServiceKit/src/Network/SSKWebSocket.swift @@ -0,0 +1,176 @@ +// +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. +// + +import Foundation +import Starscream + +@objc +public enum SSKWebSocketState: UInt { + case open, connecting, disconnected +} + +@objc +public class SSKWebSocketError: NSObject, CustomNSError { + + init(underlyingError: Starscream.WSError) { + self.underlyingError = underlyingError + } + + // MARK: - CustomNSError + + @objc + public static let errorDomain = "SignalServiceKit.SSKWebSocketError" + + public var errorUserInfo: [String: Any] { + return [ + type(of: self).kStatusCodeKey: underlyingError.code, + NSUnderlyingErrorKey: (underlyingError as NSError) + ] + } + + // MARK: - + + @objc + static let kStatusCodeKey = "SSKWebSocketErrorStatusCode" + + let underlyingError: Starscream.WSError +} + +@objc +public protocol SSKWebSocket { + + @objc + var delegate: SSKWebSocketDelegate? { get set } + + @objc + var state: SSKWebSocketState { get } + + @objc + func connect() + + @objc + func disconnect() + + @objc(writeData:error:) + func write(data: Data) throws + + @objc + func writePing() throws +} + +@objc +public protocol SSKWebSocketDelegate: class { + func websocketDidConnect(socket: SSKWebSocket) + + func websocketDidDisconnect(socket: SSKWebSocket, error: Error?) + + func websocketDidReceiveData(socket: SSKWebSocket, data: Data) + + @objc optional func websocketDidReceiveMessage(socket: SSKWebSocket, text: String) +} + +@objc +public class SSKWebSocketManager: NSObject { + + @objc + public class func buildSocket(request: URLRequest) -> SSKWebSocket { + return SSKWebSocketImpl(request: request) + } +} + +class SSKWebSocketImpl: SSKWebSocket { + + private let socket: Starscream.WebSocket + + init(request: URLRequest) { + let socket = WebSocket(request: request) + + socket.disableSSLCertValidation = true + socket.socketSecurityLevel = StreamSocketSecurityLevel.tlSv1_2 + let security = SSLSecurity(certs: [TextSecureCertificate()], usePublicKeys: false) + security.validateEntireChain = false + socket.security = security + + // TODO cipher suite selection + // socket.enabledSSLCipherSuites = [TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256] + + self.socket = socket + + socket.delegate = self + } + + // MARK: - SSKWebSocket + + weak var delegate: SSKWebSocketDelegate? + + var hasEverConnected = false + var state: SSKWebSocketState { + if socket.isConnected { + return .open + } + + if hasEverConnected { + return .disconnected + } + + return .connecting + } + + func connect() { + socket.connect() + } + + func disconnect() { + socket.disconnect() + } + + func write(data: Data) throws { + socket.write(data: data) + } + + func writePing() throws { + socket.write(ping: Data()) + } +} + +extension SSKWebSocketImpl: WebSocketDelegate { + func websocketDidConnect(socket: WebSocketClient) { + hasEverConnected = true + delegate?.websocketDidConnect(socket: self) + } + + func websocketDidDisconnect(socket: WebSocketClient, error: Error?) { + let websocketError: Error? + switch error { + case let wsError as WSError: + websocketError = SSKWebSocketError(underlyingError: wsError) + default: + assert(error == nil, "unexpected error type: \(String(describing: error))") + websocketError = error + } + + delegate?.websocketDidDisconnect(socket: self, error: websocketError) + } + + func websocketDidReceiveMessage(socket: WebSocketClient, text: String) { + if let websocketDidReceiveMessage = self.delegate?.websocketDidReceiveMessage { + websocketDidReceiveMessage(self, text) + } + } + + func websocketDidReceiveData(socket: WebSocketClient, data: Data) { + delegate?.websocketDidReceiveData(socket: self, data: data) + } +} + +private func TextSecureCertificate() -> SSLCert { + let data = OWSHTTPSecurityPolicy.dataFromCertificateFile(forService: "textsecure") + return SSLCert(data: data) +} + +private extension StreamSocketSecurityLevel { + static var tlSv1_2: StreamSocketSecurityLevel { + return StreamSocketSecurityLevel(rawValue: "kCFStreamSocketSecurityLevelTLSv1_2") + } +} diff --git a/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.m b/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.m index 334a98455..17d6b7c5a 100644 --- a/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.m +++ b/SignalServiceKit/src/Network/WebSockets/OWSWebSocket.m @@ -15,7 +15,6 @@ #import "OWSMessageReceiver.h" #import "OWSPrimaryStorage.h" #import "OWSSignalService.h" -#import "OWSWebsocketSecurityPolicy.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" #import "TSConstants.h" @@ -24,7 +23,6 @@ #import #import #import -#import NS_ASSUME_NONNULL_BEGIN @@ -144,13 +142,13 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O #pragma mark - // OWSWebSocket's properties should only be accessed from the main thread. -@interface OWSWebSocket () +@interface OWSWebSocket () // This class has a few "tiers" of state. // // The first tier is the actual websocket and the timers used // to keep it alive and connected. -@property (nonatomic, nullable) SRWebSocket *websocket; +@property (nonatomic, nullable) id websocket; @property (nonatomic, nullable) NSTimer *heartbeatTimer; @property (nonatomic, nullable) NSTimer *reconnectTimer; @@ -257,11 +255,6 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O return SSKEnvironment.shared.notificationsManager; } -- (OWSWebsocketSecurityPolicy *)websocketSecurityPolicy -{ - return OWSWebsocketSecurityPolicy.sharedPolicy; -} - - (id)udManager { return SSKEnvironment.shared.udManager; } @@ -310,11 +303,11 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O // Try to reuse the existing socket (if any) if it is in a valid state. if (self.websocket) { - switch ([self.websocket readyState]) { - case SR_OPEN: + switch (self.websocket.state) { + case SSKWebSocketStateOpen: self.state = OWSWebSocketStateOpen; return; - case SR_CONNECTING: + case SSKWebSocketStateConnecting: OWSLogVerbose(@"WebSocket is already connecting"); self.state = OWSWebSocketStateConnecting; return; @@ -355,8 +348,7 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O // and class state to reflect changes in app state. // // We learn about changes to socket state through websocket -// delegate methods like [webSocketDidOpen:], [didFailWithError:...] -// and [didCloseWithCode:...]. These delegate methods are sometimes +// delegate methods. These delegate methods are sometimes // invoked _after_ web socket state changes, so we sometimes learn // about changes to socket state in [ensureWebsocket]. Put another way, // it's not safe to assume we'll learn of changes to websocket state @@ -425,18 +417,17 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O NSURL *webSocketConnectURL = [NSURL URLWithString:webSocketConnect]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:webSocketConnectURL]; - SRWebSocket *socket = - [[SRWebSocket alloc] initWithURLRequest:request securityPolicy:self.websocketSecurityPolicy]; + id socket = [SSKWebSocketManager buildSocketWithRequest:request]; socket.delegate = self; [self setWebsocket:socket]; - // [SRWebSocket open] could hypothetically call a delegate method (e.g. if + // `connect` could hypothetically call a delegate method (e.g. if // the socket failed immediately for some reason), so we update the state // _before_ calling it, not after. _state = state; self.canMakeRequests = state == OWSWebSocketStateOpen; - [socket open]; + [socket connect]; [self failAllPendingSocketMessagesIfNecessary]; return; } @@ -463,7 +454,7 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O OWSAssertIsOnMainThread(); self.websocket.delegate = nil; - [self.websocket close]; + [self.websocket disconnect]; self.websocket = nil; [self.heartbeatTimer invalidate]; self.heartbeatTimer = nil; @@ -554,7 +545,7 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O return; } - BOOL wasScheduled = [self.websocket sendDataNoCopy:messageData error:&error]; + BOOL wasScheduled = [self.websocket writeData:messageData error:&error]; if (!wasScheduled || error) { OWSFailDebug(@"could not send socket request: %@", error); [socketMessage didFailBeforeSending]; @@ -676,13 +667,13 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O } } -#pragma mark - Delegate methods +#pragma mark - SSKWebSocketDelegate -- (void)webSocketDidOpen:(SRWebSocket *)webSocket +- (void)websocketDidConnectWithSocket:(id)websocket { OWSAssertIsOnMainThread(); - OWSAssertDebug(webSocket); - if (webSocket != self.websocket) { + OWSAssertDebug(websocket); + if (websocket != self.websocket) { // Ignore events from obsolete web sockets. return; } @@ -695,19 +686,18 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O [self.outageDetection reportConnectionSuccess]; } -- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error +- (void)websocketDidDisconnectWithSocket:(id)websocket error:(nullable NSError *)error { OWSAssertIsOnMainThread(); - OWSAssertDebug(webSocket); - if (webSocket != self.websocket) { + OWSAssertDebug(websocket); + if (websocket != self.websocket) { // Ignore events from obsolete web sockets. return; } OWSLogError(@"Websocket did fail with error: %@", error); - - if ([error.domain isEqualToString:SRWebSocketErrorDomain] && error.code == 2132) { - NSNumber *_Nullable statusCode = error.userInfo[SRHTTPResponseErrorKey]; + if ([error.domain isEqualToString:SSKWebSocketError.errorDomain]) { + NSNumber *_Nullable statusCode = error.userInfo[SSKWebSocketError.kStatusCodeKey]; if (statusCode.unsignedIntegerValue == 403) { if (self.tsAccountManager.isRegisteredAndReady) { [self.tsAccountManager setIsDeregistered:YES]; @@ -720,12 +710,12 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O [self handleSocketFailure]; } -- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(NSData *)data +- (void)websocketDidReceiveDataWithSocket:(id)websocket data:(NSData *)data { OWSAssertIsOnMainThread(); - OWSAssertDebug(webSocket); + OWSAssertDebug(websocket); - if (webSocket != self.websocket) { + if (websocket != self.websocket) { // Ignore events from obsolete web sockets. return; } @@ -749,6 +739,8 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O } } +#pragma mark - + - (dispatch_queue_t)serialQueue { static dispatch_queue_t _serialQueue; @@ -853,7 +845,7 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O return; } - [self.websocket sendDataNoCopy:messageData error:&error]; + [self.websocket writeData:messageData error:&error]; if (error) { OWSLogWarn(@"Error while trying to write on websocket %@", error); [self handleSocketFailure]; @@ -887,30 +879,13 @@ NSString *const kNSNotification_OWSWebSocketStateDidChange = @"kNSNotification_O [self.outageDetection reportConnectionFailure]; } -- (void)webSocket:(SRWebSocket *)webSocket - didCloseWithCode:(NSInteger)code - reason:(nullable NSString *)reason - wasClean:(BOOL)wasClean -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(webSocket); - if (webSocket != self.websocket) { - // Ignore events from obsolete web sockets. - return; - } - - OWSLogWarn(@"Websocket did close with code: %ld", (long)code); - - [self handleSocketFailure]; -} - - (void)webSocketHeartBeat { OWSAssertIsOnMainThread(); if ([self shouldSocketBeOpen]) { NSError *error; - [self.websocket sendPing:nil error:&error]; + [self.websocket writePingAndReturnError:&error]; if (error) { OWSLogWarn(@"Error in websocket heartbeat: %@", error.localizedDescription); [self handleSocketFailure]; diff --git a/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.h b/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.h index 10057838a..2980c6112 100644 --- a/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.h +++ b/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.h @@ -1,12 +1,17 @@ // -// Created by Fred on 01/09/15. -// Copyright © 2015 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import +NS_ASSUME_NONNULL_BEGIN + +extern NSData *SSKTextSecureServiceCertificateData(void); + @interface OWSHTTPSecurityPolicy : AFSecurityPolicy + (instancetype)sharedPolicy; @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.m b/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.m index 40a518705..3a866e0a4 100644 --- a/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.m +++ b/SignalServiceKit/src/Security/OWSHTTPSecurityPolicy.m @@ -1,10 +1,12 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import "OWSHTTPSecurityPolicy.h" #import +NS_ASSUME_NONNULL_BEGIN + @implementation OWSHTTPSecurityPolicy + (instancetype)sharedPolicy { @@ -21,24 +23,15 @@ if (self) { self.pinnedCertificates = [NSSet setWithArray:@[ - [self certificateDataForService:@"textsecure"], + [self.class certificateDataForService:@"textsecure"] ]]; } return self; } -- (NSArray *)certs { - return @[ (__bridge id)[self certificateForService:@"textsecure"] ]; -} - -- (NSData *)certificateDataForService:(NSString *)service { - SecCertificateRef certRef = [self certificateForService:service]; - return (__bridge_transfer NSData *)SecCertificateCopyData(certRef); -} - -- (SecCertificateRef)certificateForService:(NSString *)service { - ++ (NSData *)dataFromCertificateFileForService:(NSString *)service +{ NSBundle *bundle = [NSBundle bundleForClass:self.class]; NSString *path = [bundle pathForResource:service ofType:@"cer"]; @@ -46,12 +39,25 @@ OWSFail(@"Missing signing certificate for service %@", service); } - NSData *certificateData = [NSData dataWithContentsOfFile:path]; + NSData *data = [NSData dataWithContentsOfFile:path]; + OWSAssert(data.length > 0); + + return data; +} + ++ (NSData *)certificateDataForService:(NSString *)service { + SecCertificateRef certRef = [self certificateForService:service]; + return (__bridge_transfer NSData *)SecCertificateCopyData(certRef); +} + ++ (SecCertificateRef)certificateForService:(NSString *)service +{ + NSData *certificateData = [self dataFromCertificateFileForService:service]; return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certificateData)); } - -- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain { +- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(nullable NSString *)domain +{ NSMutableArray *policies = [NSMutableArray array]; [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; @@ -90,3 +96,5 @@ _out: } @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.h b/SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.h deleted file mode 100644 index a259620a4..000000000 --- a/SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.h +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2016 Open Whisper Systems. All rights reserved. - -#import - -@interface OWSWebsocketSecurityPolicy : SRSecurityPolicy - -+ (instancetype)sharedPolicy; - -@end diff --git a/SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.m b/SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.m deleted file mode 100644 index 20fdce6d3..000000000 --- a/SignalServiceKit/src/Security/OWSWebsocketSecurityPolicy.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSWebsocketSecurityPolicy.h" -#import "OWSHTTPSecurityPolicy.h" -#import - -@implementation OWSWebsocketSecurityPolicy - -+ (instancetype)sharedPolicy { - static OWSWebsocketSecurityPolicy *websocketSecurityPolicy = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - // We use our own CA - websocketSecurityPolicy = [[self alloc] initWithCertificateChainValidationEnabled:NO]; -#pragma clang diagnostic pop - }); - return websocketSecurityPolicy; -} - -- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain { - // Delegate server trust to our existing HTTP policy. - return [[OWSHTTPSecurityPolicy sharedPolicy] evaluateServerTrust:serverTrust forDomain:domain]; -} - -@end