tags:

views:

10909

answers:

6

I have the following simple code to connect to a SSL webpage

NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[ NSURLConnection sendSynchronousRequest: urlRequest returningResponse: nil error: &error ];

Except it gives an error if the cert is a self signed one Error Domain=NSURLErrorDomain Code=-1202 UserInfo=0xd29930 "untrusted server certificate". Is there a way to set it to accept connections anyway (just like in a browser you can press accept) or a way to bypass it?

+1  A: 

NSURLRequest has a private method called setAllowsAnyHTTPSCertificate:forHost:, which will do exactly what you'd like. You could define the allowsAnyHTTPSCertificateForHost: method on NSURLRequest via a category, and set it to return YES for the host that you'd like to override.

Nathan de Vries
Usual caveats about undocumented APIs apply... but good to know that it's possible.
Stephen Darlington
Yeah, absolutely. I've added another answer which doesn't involve the use of private APIs.
Nathan de Vries
Does that work when you use "NSURLConnection sendSynchronousRequest:"?
Tim Büthe
+7  A: 

If you're unwilling (or unable) to use private APIs, there's an open source (BSD license) library called ASIHTTPRequest that provides a wrapper around the lower-level CFNetwork APIs. They recently introduced the ability to allow HTTPS connections using self-signed or untrusted certificates with the -setValidatesSecureCertificate: API. If you don't want to pull in the whole library, you could use the source as a reference for implementing the same functionality yourself.

Nathan de Vries
This saved me, thanks! I tried the accepted answer, but had to change my request from synchronious to async just to accept some cert. After hours trying to get this work, I threw it all in the trash and used ASIHTTPRequest and it works charming. Beside the mentioned option, it seems to have a lot useful features.
Tim Büthe
A: 

Nathan de Vries, Can you please explain me in more detail about NRURLRequest and setAllowsAnyHTTPSCertificate:forHost:?

Satyam
+30  A: 

There is a supported API for accomplishing this! Add something like this to your NSURLConnection delegate:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
  return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
  if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    if ([trustedHosts containsObject:challenge.protectionSpace.host])
      [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];

  [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

Note that connection:didReceiveAuthenticationChallenge: can send its message to challenge.sender (much) later, after presenting a dialog box to the user if necessary, etc.

Gordon Henriksen
Thanks a lot, it works perfectly. Just remove the the two ifs and keep only the useCendential part in the didReceiveAuthentificationChallenge callback if you want to accept any https site.
yonel
This is awesome! However, it only works on iPhone and 10.6. Is there a similar work-around for 10.5?
Dave DeLong
Any thoughts on how to send a authenticated credential (created with "credentialWithUser") along with this "credentialForTrust" credential? Specifically...http://stackoverflow.com/questions/2949640/nsurlconnection-nsurlrequest-untrusted-cert-and-user-authentication
Staros
Thanks a lot! This worked out great :)
abelito
what is a trustedHosts, where n how is the object defined
Ameya
+4  A: 

I can't take any credit for this, but this one I found worked really well for my needs. "shouldAllowSelfSignedCert" is my BOOL variable. Just add to your NSURLConnection delegate and you should be rockin for a quick bypass on a per connection basis.

    - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space {
     if([[space authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
          if(shouldAllowSelfSignedCert) {
               return YES; // Self-signed cert will be accepted
          } else {
               return NO;  // Self-signed cert will be rejected
          }
          // Note: it doesn't seem to matter what you return for a proper SSL cert
          //       only self-signed certs
     }
     // If no other authentication is required, return NO for everything else
     // Otherwise maybe YES for NSURLAuthenticationMethodDefault and etc.
     return NO;
}
Ryna
+2  A: 

The category workaround posted by Nathan de Vries will pass the AppStore private API checks, and is useful in cases where you do not have control of the NSUrlConnection object. One example is NSXMLParser which will open the URL you supply, but does not expose the NSURLRequest or NSURLConnection.

In iOS 4 the workaround still seems to work, but only on the device, the Simulator does not invoke the allowsAnyHTTPSCertificateForHost: method anymore.

Alex Suzuki