From 48fe40c569c7b29e864e980e4e1e4f2faf7a42bd Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 30 Sep 2020 16:13:54 -0300 Subject: [PATCH] [REGRESSION] SSL Pinning stopped working after #2449 (#2510) --- patches/react-native+0.63.1.patch | 9 +- patches/react-native-webview+10.3.2.patch | 119 ++++++++++++++++++++ patches/rn-fetch-blob+0.12.0.patch | 129 ++++++++++++++++++++++ 3 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 patches/react-native-webview+10.3.2.patch create mode 100644 patches/rn-fetch-blob+0.12.0.patch diff --git a/patches/react-native+0.63.1.patch b/patches/react-native+0.63.1.patch index 32295e89..6d3ce0c3 100644 --- a/patches/react-native+0.63.1.patch +++ b/patches/react-native+0.63.1.patch @@ -51,10 +51,10 @@ index af4becd..55bc2c8 100644 } diff --git a/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm b/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm -index 274f381..fa74a27 100644 +index 274f381..c7749ef 100644 --- a/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm +++ b/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm -@@ -8,11 +8,12 @@ +@@ -8,11 +8,13 @@ #import #import @@ -62,13 +62,14 @@ index 274f381..fa74a27 100644 +#import #import #import ++#import #import "RCTNetworkPlugins.h" +#import "SecureStorage.h" @interface RCTHTTPRequestHandler () -@@ -58,6 +59,101 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request +@@ -58,6 +60,103 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request return [schemes containsObject:request.URL.scheme.lowercaseString]; } @@ -119,6 +120,8 @@ index 274f381..fa74a27 100644 + NSMutableArray *certificates = [[NSMutableArray alloc] init]; + [certificates addObject:CFBridgingRelease(certificate)]; + ++ [SDWebImageDownloader sharedDownloader].config.urlCredential = [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone]; ++ + return [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone]; + } + diff --git a/patches/react-native-webview+10.3.2.patch b/patches/react-native-webview+10.3.2.patch new file mode 100644 index 00000000..a47d8fbb --- /dev/null +++ b/patches/react-native-webview+10.3.2.patch @@ -0,0 +1,119 @@ +diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m +index 02b4238..04bad05 100644 +--- a/node_modules/react-native-webview/apple/RNCWebView.m ++++ b/node_modules/react-native-webview/apple/RNCWebView.m +@@ -17,6 +17,9 @@ + + #import "objc/runtime.h" + ++#import "SecureStorage.h" ++#import ++ + static NSTimer *keyboardTimer; + static NSString *const HistoryShimName = @"ReactNativeHistoryShim"; + static NSString *const MessageHandlerName = @"ReactNativeWebView"; +@@ -737,6 +740,68 @@ + (void)setCustomCertificatesForHost:(nullable NSDictionary*)certificates { + customCertificatesForHost = certificates; + } + ++-(NSURLCredential *)getUrlCredential:(NSURLAuthenticationChallenge *)challenge path:(NSString *)path password:(NSString *)password ++{ ++ NSString *authMethod = [[challenge protectionSpace] authenticationMethod]; ++ SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; ++ ++ if ([authMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || path == nil || password == nil) { ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ } else if (path && password) { ++ NSMutableArray *policies = [NSMutableArray array]; ++ [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)]; ++ SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); ++ ++ SecTrustResultType result; ++ SecTrustEvaluate(serverTrust, &result); ++ ++ if (![[NSFileManager defaultManager] fileExistsAtPath:path]) ++ { ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ } ++ ++ NSData *p12data = [NSData dataWithContentsOfFile:path]; ++ NSDictionary* options = @{ (id)kSecImportExportPassphrase:password }; ++ CFArrayRef rawItems = NULL; ++ OSStatus status = SecPKCS12Import((__bridge CFDataRef)p12data, ++ (__bridge CFDictionaryRef)options, ++ &rawItems); ++ ++ if (status != noErr) { ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ } ++ ++ NSArray* items = (NSArray*)CFBridgingRelease(rawItems); ++ NSDictionary* firstItem = nil; ++ if ((status == errSecSuccess) && ([items count]>0)) { ++ firstItem = items[0]; ++ } ++ ++ SecIdentityRef identity = (SecIdentityRef)CFBridgingRetain(firstItem[(id)kSecImportItemIdentity]); ++ SecCertificateRef certificate = NULL; ++ if (identity) { ++ SecIdentityCopyCertificate(identity, &certificate); ++ if (certificate) { CFRelease(certificate); } ++ } ++ ++ NSMutableArray *certificates = [[NSMutableArray alloc] init]; ++ [certificates addObject:CFBridgingRelease(certificate)]; ++ ++ return [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone]; ++ } ++ ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++} ++ ++- (NSString *)stringToHex:(NSString *)string ++{ ++ char *utf8 = (char *)[string UTF8String]; ++ NSMutableString *hex = [NSMutableString string]; ++ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF]; ++ ++ return [[NSString stringWithFormat:@"%@", hex] lowercaseString]; ++} ++ + - (void) webView:(WKWebView *)webView + didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler +@@ -746,7 +811,34 @@ - (void) webView:(WKWebView *)webView + host = webView.URL.host; + } + if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) { +- completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential); ++ NSString *host = challenge.protectionSpace.host; ++ ++ // Read the clientSSL info from MMKV ++ __block NSDictionary *clientSSL; ++ SecureStorage *secureStorage = [[SecureStorage alloc] init]; ++ ++ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31 ++ [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"] callback:^(NSArray *response) { ++ // Error happened ++ if ([response objectAtIndex:0] != [NSNull null]) { ++ return; ++ } ++ NSString *key = [response objectAtIndex:1]; ++ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding]; ++ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess]; ++ ++ clientSSL = [mmkv getObjectOfClass:[NSDictionary class] forKey:host]; ++ }]; ++ ++ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ ++ if (clientSSL != (id)[NSNull null]) { ++ NSString *path = [clientSSL objectForKey:@"path"]; ++ NSString *password = [clientSSL objectForKey:@"password"]; ++ credential = [self getUrlCredential:challenge path:path password:password]; ++ } ++ ++ completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + return; + } + if ([[challenge protectionSpace] serverTrust] != nil && customCertificatesForHost != nil && host != nil) { diff --git a/patches/rn-fetch-blob+0.12.0.patch b/patches/rn-fetch-blob+0.12.0.patch new file mode 100644 index 00000000..b28e8ae8 --- /dev/null +++ b/patches/rn-fetch-blob+0.12.0.patch @@ -0,0 +1,129 @@ +diff --git a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m +index cdbe6b1..bee6228 100644 +--- a/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m ++++ b/node_modules/rn-fetch-blob/ios/RNFetchBlobRequest.m +@@ -15,6 +15,9 @@ + #import "IOS7Polyfill.h" + #import + ++#import "SecureStorage.h" ++#import ++ + + typedef NS_ENUM(NSUInteger, ResponseFormat) { + UTF8, +@@ -450,16 +453,109 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen + } + } + ++-(NSURLCredential *)getUrlCredential:(NSURLAuthenticationChallenge *)challenge path:(NSString *)path password:(NSString *)password ++{ ++ NSString *authMethod = [[challenge protectionSpace] authenticationMethod]; ++ SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; ++ ++ if ([authMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || path == nil || password == nil) { ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ } else if (path && password) { ++ NSMutableArray *policies = [NSMutableArray array]; ++ [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)]; ++ SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); ++ ++ SecTrustResultType result; ++ SecTrustEvaluate(serverTrust, &result); ++ ++ if (![[NSFileManager defaultManager] fileExistsAtPath:path]) ++ { ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ } ++ ++ NSData *p12data = [NSData dataWithContentsOfFile:path]; ++ NSDictionary* options = @{ (id)kSecImportExportPassphrase:password }; ++ CFArrayRef rawItems = NULL; ++ OSStatus status = SecPKCS12Import((__bridge CFDataRef)p12data, ++ (__bridge CFDictionaryRef)options, ++ &rawItems); ++ ++ if (status != noErr) { ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ } ++ ++ NSArray* items = (NSArray*)CFBridgingRelease(rawItems); ++ NSDictionary* firstItem = nil; ++ if ((status == errSecSuccess) && ([items count]>0)) { ++ firstItem = items[0]; ++ } ++ ++ SecIdentityRef identity = (SecIdentityRef)CFBridgingRetain(firstItem[(id)kSecImportItemIdentity]); ++ SecCertificateRef certificate = NULL; ++ if (identity) { ++ SecIdentityCopyCertificate(identity, &certificate); ++ if (certificate) { CFRelease(certificate); } ++ } ++ ++ NSMutableArray *certificates = [[NSMutableArray alloc] init]; ++ [certificates addObject:CFBridgingRelease(certificate)]; ++ ++ return [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone]; ++ } + +-- (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler ++ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++} ++ ++- (NSString *)stringToHex:(NSString *)string + { +- if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) { +- completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); +- } else { +- completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); ++ char *utf8 = (char *)[string UTF8String]; ++ NSMutableString *hex = [NSMutableString string]; ++ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF]; ++ ++ return [[NSString stringWithFormat:@"%@", hex] lowercaseString]; ++} ++ ++-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler ++{ ++ NSString *host = challenge.protectionSpace.host; ++ ++ // Read the clientSSL info from MMKV ++ __block NSDictionary *clientSSL; ++ SecureStorage *secureStorage = [[SecureStorage alloc] init]; ++ ++ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31 ++ [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"] callback:^(NSArray *response) { ++ // Error happened ++ if ([response objectAtIndex:0] != [NSNull null]) { ++ return; + } ++ NSString *key = [response objectAtIndex:1]; ++ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding]; ++ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess]; ++ ++ clientSSL = [mmkv getObjectOfClass:[NSDictionary class] forKey:host]; ++ }]; ++ ++ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ ++ if (clientSSL != (id)[NSNull null]) { ++ NSString *path = [clientSSL objectForKey:@"path"]; ++ NSString *password = [clientSSL objectForKey:@"password"]; ++ credential = [self getUrlCredential:challenge path:path password:password]; ++ } ++ ++ completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + } + ++// - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler ++// { ++// if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) { ++// completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); ++// } else { ++// completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); ++// } ++// } ++ + + - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session + {