Skip to content

Commit

Permalink
Merge pull request #68 from nemesis/ssl_pinning
Browse files Browse the repository at this point in the history
Added SSL pinning
  • Loading branch information
nemesis authored Aug 2, 2016
2 parents 5b48f3c + 1e3294b commit 68d289f
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 16 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ DerivedData

# CocoaPods
#
Pods/
Pods/

# OS X
#
.DS_Store
31 changes: 16 additions & 15 deletions Classes/API/SERequestHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@

#import "SERequestHandler.h"
#import "SEError.h"
#import "SERequestHandlerURLSessionDelegate.h"

static NSString* const kRequestMethodPOST = @"POST";
static NSString* const kRequestMethodGET = @"GET";
static NSString* const kRequestMethodDELETE = @"DELETE";
static NSString* const kRequestMethodPUT = @"PUT";

static NSString* const kErrorClassKey = @"error_class";
static NSString* const kMessageKey = @"message";
static NSString* const kRequestKey = @"request";
static NSString* const kParametersKey = @"parameters";
static NSString* const kErrorClassKey = @"error_class";
static NSString* const kErrorMessageKey = @"error_message";
static NSString* const kErrorRequestKey = @"request";
static NSString* const kParametersKey = @"parameters";

static NSString* const kEmptyURLErrorClass = @"SEEmptyURLError";
static NSString* const kEmptyURLErrorMessage = @"Cannot send a request to an empty URL.";
Expand Down Expand Up @@ -67,7 +68,7 @@ + (void)initialize
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
_requestHandlerURLSession = [NSURLSession sessionWithConfiguration:sessionConfig];
_requestHandlerURLSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:[SERequestHandlerURLSessionDelegate sharedInstance] delegateQueue:nil];
});
}

Expand Down Expand Up @@ -125,8 +126,8 @@ - (void)sendRequest:(SERequestMethod)method
if (url.length == 0) {
if (failure) {
failure(@{ kErrorClassKey : kEmptyURLErrorClass,
kMessageKey : kEmptyURLErrorMessage,
kRequestKey : @{
kErrorMessageKey : kEmptyURLErrorMessage,
kErrorRequestKey : @{
kParametersKey : parameters ? parameters : [NSNull null]
}
});
Expand All @@ -148,8 +149,8 @@ - (void)sendRequest:(SERequestMethod)method
if (![self handleParameters:parameters assignmentInRequest:request]) {
if (failure) {
failure(@{ kErrorClassKey : kBadRequestParametersErrorClass,
kMessageKey : kBadRequestParametersErrorMessage,
kRequestKey : @{
kErrorMessageKey : kBadRequestParametersErrorMessage,
kErrorRequestKey : @{
kParametersKey : parameters
}
});
Expand All @@ -162,8 +163,8 @@ - (void)sendRequest:(SERequestMethod)method
dispatch_async(dispatch_get_main_queue(), ^{
if (responseError) {
self.failureBlock(@{ kErrorClassKey : responseError.domain,
kMessageKey : responseError.localizedDescription,
kRequestKey : request
kErrorMessageKey : responseError.localizedDescription,
kErrorRequestKey : request
});
return;
}
Expand All @@ -173,8 +174,8 @@ - (void)sendRequest:(SERequestMethod)method
NSDictionary* data = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
self.failureBlock(@{ kErrorClassKey : error.domain,
kMessageKey : error.localizedDescription,
kRequestKey : request });
kErrorMessageKey : error.localizedDescription,
kErrorRequestKey : request });
} else {
if ((responseStatusCode >= 200 && responseStatusCode < 300)) {
self.successBlock(data);
Expand Down Expand Up @@ -217,8 +218,8 @@ - (BOOL)handleParameters:(NSDictionary*)parameters assignmentInRequest:(NSMutabl
if (error) {
if (self.failureBlock) {
self.failureBlock(@{ kErrorClassKey : error.domain,
kMessageKey : error.localizedDescription,
kRequestKey : parameters });
kErrorMessageKey : error.localizedDescription,
kErrorRequestKey : parameters });
}
return NO;
}
Expand Down
15 changes: 15 additions & 0 deletions Classes/API/SERequestHandlerURLSessionDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// SERequestHandlerURLSessionDelegate.h
// Salt Edge API Demo
//
// Created by Constantin Lungu on 6/9/16.
// Copyright © 2016 Salt Edge. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface SERequestHandlerURLSessionDelegate : NSObject <NSURLSessionDelegate>

+ (instancetype)sharedInstance;

@end
48 changes: 48 additions & 0 deletions Classes/API/SERequestHandlerURLSessionDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// SERequestHandlerURLSessionDelegate.m
// Salt Edge API Demo
//
// Created by Constantin Lungu on 6/9/16.
// Copyright © 2016 Salt Edge. All rights reserved.
//

#import "SERequestHandlerURLSessionDelegate.h"

@implementation SERequestHandlerURLSessionDelegate

#pragma mark - Public API

+ (instancetype)sharedInstance
{
static SERequestHandlerURLSessionDelegate* _sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
NSString* cerPath = [[NSBundle mainBundle] pathForResource:@"saltedge.com" ofType:@"cer"];
NSAssert(cerPath != nil, @"The saltedge.com SSL certificate could not be located in the app bundle.");
});
return _sharedInstance;
}

#pragma mark - NSURLSessionDelegate

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
NSData* remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
NSString* cerPath = [[NSBundle mainBundle] pathForResource:@"saltedge.com" ofType:@"cer"];
NSData* localCertificateData = [NSData dataWithContentsOfFile:cerPath];

if ([remoteCertificateData isEqualToData:localCertificateData]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
NSLog(@"*** SSL Pinning FAILED *** Request to %@://%@ cancelled.", challenge.protectionSpace.protocol, challenge.protectionSpace.host);
}
}

@end
Binary file added Classes/Supporting Files/saltedge.com.cer
Binary file not shown.
18 changes: 18 additions & 0 deletions Salt Edge API Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
0AAB6D7019827D9B009DCDD5 /* SELoginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AAB6D6F19827D9B009DCDD5 /* SELoginTests.m */; };
0AAB6D7219827E45009DCDD5 /* SEAccountTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AAB6D7119827E45009DCDD5 /* SEAccountTests.m */; };
0AAB6D7419827ECE009DCDD5 /* SETransactionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AAB6D7319827ECE009DCDD5 /* SETransactionTests.m */; };
0AAF30481D0954AA0097B0EA /* SERequestHandlerURLSessionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AAF30471D0954A90097B0EA /* SERequestHandlerURLSessionDelegate.m */; };
0AAF304E1D097DC20097B0EA /* saltedge.com.cer in Resources */ = {isa = PBXBuildFile; fileRef = 0AAF304D1D097DC20097B0EA /* saltedge.com.cer */; };
0AB068DA1A010E7E00596A3B /* SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AB068D91A010E7E00596A3B /* SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m */; };
0AD2C2E019E7EEF1003D2FD0 /* SEError.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AD2C2DF19E7EEF1003D2FD0 /* SEError.m */; };
0AE487131A02AC8B00F5CEBF /* NSURL+SECallbacksAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AE4870F1A02AC8B00F5CEBF /* NSURL+SECallbacksAdditions.m */; };
Expand Down Expand Up @@ -157,6 +159,9 @@
0AAB6D6F19827D9B009DCDD5 /* SELoginTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SELoginTests.m; sourceTree = "<group>"; };
0AAB6D7119827E45009DCDD5 /* SEAccountTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEAccountTests.m; sourceTree = "<group>"; };
0AAB6D7319827ECE009DCDD5 /* SETransactionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SETransactionTests.m; sourceTree = "<group>"; };
0AAF30461D0954A90097B0EA /* SERequestHandlerURLSessionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SERequestHandlerURLSessionDelegate.h; sourceTree = "<group>"; };
0AAF30471D0954A90097B0EA /* SERequestHandlerURLSessionDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SERequestHandlerURLSessionDelegate.m; sourceTree = "<group>"; };
0AAF304D1D097DC20097B0EA /* saltedge.com.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = saltedge.com.cer; sourceTree = "<group>"; };
0AB068D81A010E7E00596A3B /* SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h"; sourceTree = "<group>"; };
0AB068D91A010E7E00596A3B /* SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m"; sourceTree = "<group>"; };
0AB068DB1A01106C00596A3B /* SEAPIRequestManager_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SEAPIRequestManager_private.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -213,6 +218,7 @@
0A3F86E219A1F05E00B7E5E2 /* Categories */,
0A3F86E519A1F05E00B7E5E2 /* Models */,
0AE4870C1A02AC8B00F5CEBF /* SEWebView */,
0AAF304C1D097DC20097B0EA /* Supporting Files */,
0A3F86FB19A1F05E00B7E5E2 /* Utils */,
);
path = Classes;
Expand All @@ -223,6 +229,8 @@
children = (
5897167B19E6ACB3001E2AA9 /* SERequestHandler.h */,
5897167C19E6ACB3001E2AA9 /* SERequestHandler.m */,
0AAF30461D0954A90097B0EA /* SERequestHandlerURLSessionDelegate.h */,
0AAF30471D0954A90097B0EA /* SERequestHandlerURLSessionDelegate.m */,
0A3F86DF19A1F05E00B7E5E2 /* SEAPIRequestManager.h */,
0A3F86E019A1F05E00B7E5E2 /* SEAPIRequestManager.m */,
0AB068DB1A01106C00596A3B /* SEAPIRequestManager_private.h */,
Expand Down Expand Up @@ -445,6 +453,14 @@
path = Protocols;
sourceTree = "<group>";
};
0AAF304C1D097DC20097B0EA /* Supporting Files */ = {
isa = PBXGroup;
children = (
0AAF304D1D097DC20097B0EA /* saltedge.com.cer */,
);
path = "Supporting Files";
sourceTree = "<group>";
};
0AE4870C1A02AC8B00F5CEBF /* SEWebView */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -566,6 +582,7 @@
0AAB6D6319827AEA009DCDD5 /* Main.storyboard in Resources */,
0AAB6CFD19827AAA009DCDD5 /* Images.xcassets in Resources */,
0A939EA019DA9F0E005BD28C /* TransactionTableViewCell.xib in Resources */,
0AAF304E1D097DC20097B0EA /* saltedge.com.cer in Resources */,
0AAB6CEF19827AAA009DCDD5 /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -637,6 +654,7 @@
0AAB6D6619827AFB009DCDD5 /* AppDelegate.m in Sources */,
0A6568A419F91E20004A1EB1 /* OptionSelectButton.m in Sources */,
0AE487131A02AC8B00F5CEBF /* NSURL+SECallbacksAdditions.m in Sources */,
0AAF30481D0954AA0097B0EA /* SERequestHandlerURLSessionDelegate.m in Sources */,
0A1BEB7619EBD0E5000C0D64 /* PickerTVC.m in Sources */,
0A3F870019A1F05E00B7E5E2 /* NSString+SEModelsSerializingAdditions.m in Sources */,
0A939E9F19DA9F0E005BD28C /* TransactionTableViewCell.m in Sources */,
Expand Down

0 comments on commit 68d289f

Please sign in to comment.