title: How to verify (and require) self-signed certificate in iOS
body: <p>I'd like to create an SSL connection to my server using self-signed certificates that are shipped with the code in iOS. That way I don't have to worry about more sophisticated man-in-the-middle attacks where someone has access to a high level "trusted" cert authority. I'm having issues doing so using what I believe to be Apple's standard way.</p>
  
  <p>Generating the certificate, via the procedure found <a href="http://svasey.org/projects/software-usage-notes/ssl_en.html" rel="noreferrer">here</a></p>
  
  <pre><code># Create root CA &amp; private key
  openssl req -newkey rsa:4096 -sha512 -days 9999 -x509 -nodes -out root.pem.cer
  # Create a certificate signing request
  openssl req -newkey rsa:4096 -sha512 -nodes -out ssl.csr -keyout ssl.key
  # Create an OpenSSL Configuration file from http://svasey.org/projects/software-usage-notes/ssl_en.html
  vim openssl.conf
  # Create the indexes
  touch certindex
  echo 000a &gt; certserial
  echo 000a &gt; crlnumber
  # Generate SSL certificate 
  openssl ca -batch -config openssl.conf -notext -in ssl.csr -out ssl.pem.cer
  # Create Certificate Revocation List
  openssl ca -config openssl.conf -gencrl -keyfile privkey.pem -cert root.pem.cer -out root.crl.pem
  openssl crl -inform PEM -in root.crl.pem -outform DER -out root.crl &amp;&amp; rm root.crl.pem
  </code></pre>
  
  <p>And the iOS code:</p>
  
  <pre><code>- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
    if ([protectionSpace authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
      // Load anchor cert.. also tried this with both certs and it doesn't seem to matter
      NSString *path = [[NSBundle mainBundle] pathForResource:@"root.der" ofType:@"crt"];
      NSData *data = [[NSData alloc] initWithContentsOfFile:path];
      SecCertificateRef anchorCert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)data);
      CFMutableArrayRef anchorCerts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &amp;kCFTypeArrayCallBacks);
      CFArrayAppendValue(anchorCerts, anchorCert);
  
      // Set anchor cert
      SecTrustRef trust = [protectionSpace serverTrust];
      SecTrustSetAnchorCertificates(trust, anchorCerts);
      SecTrustSetAnchorCertificatesOnly(trust, YES); // only use that certificate
      CFRelease(anchorCert);
      CFRelease(anchorCerts);
  
      // Validate cert
      SecTrustResultType secresult = kSecTrustResultInvalid;
      if (SecTrustEvaluate(trust, &amp;secresult) != errSecSuccess) {
        [challenge.sender cancelAuthenticationChallenge:challenge];
        return;
      }
  
      switch (secresult) {
        case kSecTrustResultInvalid:
        case kSecTrustResultDeny:
        case kSecTrustResultFatalTrustFailure:
        case kSecTrustResultOtherError:
        case kSecTrustResultRecoverableTrustFailure: { 
          // !!! It's always kSecTrustResultRecoverableTrustFailure, aka 5
          NSLog(@"Failing due to result: %lu", secresult);
          [challenge.sender cancelAuthenticationChallenge:challenge];
          return;
        }
  
        case kSecTrustResultUnspecified: // The OS trusts this certificate implicitly.
        case kSecTrustResultProceed: { // The user explicitly told the OS to trust it.
          NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
          [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
          return;
        }
        default: ;
          /* It's somebody else's key. Fall through. */
      }
      /* The server sent a key other than the trusted key. */
      [connection cancel];
  
      // Perform other cleanup here, as needed.
    } else {
      NSLog(@"In weird space... not handling authentication method: %@", [protectionSpace authenticationMethod]);
      [connection cancel];
    }
  }
  </code></pre>
  
  <p>I'm always getting kSecTrustResultRecoverableTrustFailure as the result. I don't think this is localhost issue as I've tried using Apple's code to change that too. What to do?</p>
  
  <p>Thanks!</p>