NSURLDownload and handling HTTPS certificates

  • I've seen this question asked before in the archives, but no one had
    an answer...

    I've got an NSURLDownload object (which is actually a WebDownload
    object). When NSURLDownload is sent to an HTTPS server that has a bad
    certificate, it fails the download with the appropriate error.
    However, I want to change this so that it asks the user what to do in
    this case (using SFCertificateTrustPanel).

    Besides writing my own HTTPS-handling NSURLProtocol, how do I do
    this? I don't see any delegate methods anywhere that handle
    certificates...

    Nick Zitzmann
    <http://www.chronosnet.com/>
  • hack: override a private method / categorize it.
    ..... I had the same issue but as I dont remember the name, search
    the archives of this list or macnetworkprog.

    Regards,
    Dominik

    On May 17, 2007, at 1:58 AM, Nick Zitzmann wrote:

    > I've seen this question asked before in the archives, but no one
    > had an answer...
    >
    > I've got an NSURLDownload object (which is actually a WebDownload
    > object). When NSURLDownload is sent to an HTTPS server that has a
    > bad certificate, it fails the download with the appropriate error.
    > However, I want to change this so that it asks the user what to do
    > in this case (using SFCertificateTrustPanel).
    >
    > Besides writing my own HTTPS-handling NSURLProtocol, how do I do
    > this? I don't see any delegate methods anywhere that handle
    > certificates...
    >
    > Nick Zitzmann
    > <http://www.chronosnet.com/
    >
  • On May 17, 2007, at 3:24 AM, Dominik Pich wrote:

    > hack: override a private method / categorize it.
    > ..... I had the same issue but as I dont remember the name, search
    > the archives of this list or macnetworkprog.

    I figured it out, and did something similar to this (which should
    also work with NSURLConnection in case anyone's wondering), with
    "theDownload" being the name of a retained NSURLDownload/WebDownload
    ivar:

    @interface NSURLRequest (SomePrivateAPIs)
    + (BOOL)allowsAnyHTTPSCertificateForHost:(id)fp8;
    + (void)setAllowsAnyHTTPSCertificate:(BOOL)fp8 forHost:(id)fp12;
    @end

    - (void)download:(NSURLDownload *)download didFailWithError:(NSError
    *)error
    {
    if ([[error domain] isEqualToString:NSURLErrorDomain] && [error
    code] <= NSURLErrorServerCertificateHasBadDate && [error code] >=
    NSURLErrorServerCertificateNotYetValid)    // handle certificate failures
    {
      NSURL *failingURL = [[error userInfo]
    objectForKey:@"NSErrorFailingURLKey"];
      NSArray *badCerts = [[error userInfo]
    objectForKey:@"NSErrorPeerCertificateChainKey"];
      SecPolicySearchRef policySearch;

      if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL,
    NULL, &policySearch) == noErr)
      {
      SecPolicyRef policy;

      while (SecPolicySearchCopyNext(policySearch, &policy) == noErr) //
    this should only go through once
      {
        SecTrustRef trust;

        if (SecTrustCreateWithCertificates((CFArrayRef)badCerts, policy,
    &trust) == noErr)
        {
        SFCertificateTrustPanel *panel = [[SFCertificateTrustPanel
    alloc] init];
        int result;
        NSString *host = [failingURL host];

        [panel setDefaultButtonTitle:@"Continue"];
        [panel setAlternateButtonTitle:@"Cancel"];

        if ([panel respondsToSelector:@selector
    (setInformativeText:)])    // this method is in Tiger but is undocumented
          [panel performSelector:@selector(setInformativeText:)
    withObject:@"Some informative text here..."];
        [panel setShowsHelp:YES];

        result = [panel runModalForTrust:trust message:@"Insert your own
    title here..."];

        [panel release];
        [theDownload autorelease];
        CFRelease(trust);
        CFRelease(policy);
        CFRelease(policySearch);
        if (result == NSOKButton)
        {
          [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:
    [failingURL host]];    // unfortunately we have to use a private API here
          theDownload = [[WebDownload alloc] initWithRequest:
    [NSURLRequest requestWithURL:failingURL] delegate:self];    // once
    we've set the certificate to be ignored, then start the download again
        }
        else
        {
          // The user clicked on Cancel...
        }
        return;
        }
      }
      }
    }
    else
    {
      // Handle other download errors here.
    }
    }

    Nick Zitzmann
    <http://www.chronosnet.com/>
previous month may 2007 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today