Permalink
Browse files

allow user to ignore SSL errors for certain domains (allows browsing …

…to sites with self-signed certs; can test against https://torstatus.blutmagie.de/ )

fixes #8
  • Loading branch information...
1 parent 7267ff9 commit a8778e09004df36a984d86d6a837c4bc737e5bf6 @mtigas committed May 12, 2012
@@ -128,26 +128,42 @@ - (void)start
_HTTPStream = (__bridge_transfer NSInputStream *)CFReadStreamCreateForHTTPRequest(NULL, [self HTTPRequest]);
+ AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
+
+ // Ignore SSL errors for domains if user has explicitly said to "continue anyway"
+ // (for self-signed certs)
// Ignore SSL errors for .onion addresses because they will not have been
// signed by known authorities. (They will be self-signed or signed by alternative roots
- // similar to CACert.)
- // TODO: actually implement a popup with cert signature info (like a desktop browser would)
- // which would provide a more secure way of manually whitelisting exceptions (and
- // disallowing SSL certificates that are non-matching, unknown, or etc)
+ // similar to CACert or they are actually the cert for the non-.onion version of that domain.)
NSURL *URL = [_HTTPStream propertyForKey:(NSString *)kCFStreamPropertyHTTPFinalURL];
- if (([URL.absoluteString rangeOfString:@"https://"].location == 0) && ([URL.host rangeOfString:@".onion"].location != NSNotFound)) {
- #ifdef DEBUG
- NSLog(@"loading https://*.onion/ URL, ignoring SSL certificate status (%@)", URL.absoluteString);
- #endif
- CFMutableDictionaryRef sslOption = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFDictionarySetValue(sslOption, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
- CFReadStreamSetProperty((__bridge CFReadStreamRef)_HTTPStream, kCFStreamPropertySSLSettings, sslOption);
+ if ([URL.absoluteString rangeOfString:@"https://"].location == 0) {
+ Boolean ignoreSSLErrors = NO;
+ if ([URL.host rangeOfString:@".onion"].location != NSNotFound) {
+ #ifdef DEBUG
+ NSLog(@"loading https://*.onion/ URL, ignoring SSL certificate status (%@)", URL.absoluteString);
+ #endif
+ ignoreSSLErrors = YES;
+ } else {
+ for (NSString *whitelistHost in appDelegate.sslWhitelistedDomains) {
+ if ([whitelistHost isEqualToString:URL.host]) {
+ #ifdef DEBUG
+ NSLog(@"%@ in SSL host whitelist ignoring SSL certificate status", URL.host);
+ #endif
+ ignoreSSLErrors = YES;
+ break;
+ }
+ }
+ }
+ if (ignoreSSLErrors) {
+ CFMutableDictionaryRef sslOption = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(sslOption, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
+ CFReadStreamSetProperty((__bridge CFReadStreamRef)_HTTPStream, kCFStreamPropertySSLSettings, sslOption);
+ }
}
// Use tor proxy server
NSString *hostKey = (NSString *)kCFStreamPropertySOCKSProxyHost;
NSString *portKey = (NSString *)kCFStreamPropertySOCKSProxyPort;
- AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSUInteger proxyPortNumber = appDelegate.torSocksPort;
NSMutableDictionary *proxyToUse = [NSMutableDictionary
@@ -40,6 +40,8 @@
@property (nonatomic) NSUInteger torSocksPort;
@property (nonatomic) NSUInteger torControlPort;
+@property (nonatomic) NSMutableArray *sslWhitelistedDomains; // for self-signed
+
- (void)reachabilityChanged;
- (void)activateTorCheckLoop;
@@ -25,7 +25,8 @@ @implementation AppDelegate
spoofUserAgent,
dntHeader,
torControlPort = _torControlPort,
- torSocksPort = _torSocksPort;
+ torSocksPort = _torSocksPort,
+ sslWhitelistedDomains;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
@@ -38,6 +39,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
_torControlPort = (arc4random() % (57343-49153)) + 49153;
_torSocksPort = (arc4random() % (65534-57344)) + 57344;
+ sslWhitelistedDomains = [[NSMutableArray alloc] init];
+
// listen to changes in connection state
// (tor has auto detection when external IP changes, but if we went
// offline, tor might not handle coming back gracefully -- we will SIGHUP
@@ -8,7 +8,7 @@
#import <UIKit/UIKit.h>
-@interface WebViewController : UIViewController <UIWebViewDelegate, UITextFieldDelegate, UIActionSheetDelegate> {
+@interface WebViewController : UIViewController <UIWebViewDelegate, UITextFieldDelegate, UIActionSheetDelegate, UIAlertViewDelegate> {
}
@property (strong, nonatomic) UIWebView *myWebView;
@@ -326,31 +326,68 @@ - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
}
- (void)informError:(NSError *)error {
- if ([error.domain isEqualToString:(NSString *)kCFErrorDomainCFNetwork]) {
+ if ([error.domain isEqualToString:@"NSOSStatusErrorDomain"] &&
+ (error.code == -9807 || error.code == -9812)) {
+ // Invalid certificate chain; valid cert chain, untrusted root
+
+ UIAlertView* alertView = [[UIAlertView alloc]
+ initWithTitle:@"SSL Error"
+ message:@"Certificate chain is invalid. Either the site's SSL certificate is self-signed or the certificate was signed by an untrusted authority."
+ delegate:nil
+ cancelButtonTitle:@"Cancel"
+ otherButtonTitles:@"Continue",nil];
+ alertView.delegate = self;
+ [alertView show];
+
+ } else if ([error.domain isEqualToString:(NSString *)kCFErrorDomainCFNetwork] ||
+ [error.domain isEqualToString:@"NSOSStatusErrorDomain"]) {
NSString* errorDescription;
if (error.code == kCFSOCKS5ErrorBadState) {
errorDescription = @"Could not connect to the server. Either the domain name is incorrect, the server is inaccessible, or the Tor circuit was broken.";
} else if (error.code == kCFHostErrorHostNotFound) {
errorDescription = @"The server could not be found";
} else {
- errorDescription = [NSString stringWithFormat:@"An unknown error occurred: %@",
+ errorDescription = [NSString stringWithFormat:@"An error occurred: %@",
error.localizedDescription];
}
- UIAlertView* alertView = [[UIAlertView alloc]
- initWithTitle:@"Cannot Open Page"
- message:errorDescription delegate:nil
- cancelButtonTitle:@"OK"
+ UIAlertView* alertView = [[UIAlertView alloc]
+ initWithTitle:@"Cannot Open Page"
+ message:errorDescription delegate:nil
+ cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
}
#ifdef DEBUG
else {
NSLog(@"[WebViewController] uncaught error: %@", [error localizedDescription]);
+ NSLog(@"\t -> %@", error.domain);
}
#endif
}
+- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
+ if (buttonIndex == 1) {
+ // "Continue anyway" for SSL cert error
+ AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
+
+ // Assumung URL in address bar is the one that caused this error.
+ NSURL *url = [NSURL URLWithString:_currentURL];
+ NSString *hostname = url.host;
+ [appDelegate.sslWhitelistedDomains addObject:hostname];
+
+ UIAlertView* alertView = [[UIAlertView alloc]
+ initWithTitle:@"Whitelisted Domain"
+ message:[NSString stringWithFormat:@"SSL certificate errors for '%@' will be ignored for the rest of this session.", hostname] delegate:nil
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil];
+ [alertView show];
+
+ // Reload (now that we have added host to whitelist)
+ [self loadURL:url];
+ }
+}
+
# pragma mark -

0 comments on commit a8778e0

Please sign in to comment.