0
votes

I'm using NSULConnection to send data to a webservice over SSL. The server is signed with a wildcard certificate (*.mydomain.com). The certificate is using RES SHA256 and TLS 1.2 and is signed by a CA. I'm trying to send my data using the following code:

NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
[req setTimeoutInterval:60];
[req setHTTPMethod:@"POST"];
// ... Set content type and add data to body ... //

[req setURL:@"https://subdomain.mydomain.com/service/"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSLog(@"Starting Upload");
NSURLSessionDataTask *task = [session dataTaskWithRequest:req
                                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
    // .. Handle Completion .. //
}];

[task resume];

When I run the above code I get the following output.

CFNetwork SSLHandshake failed (-9801) 
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9801)

So, I tried adding the exceptions explained in this post: CFNetwork SSLHandshake failed iOS 9

But had no luck in getting the error to resolve itself. I then switched to using http instead of https, while leaving in the configuration changes explained above and it did work. However, that is far from an ideal solution. The http is fine for testing, but this app will be handling data where SSL is required. How can I get the SSL working?

Edit

Here are the results of running nscurl --ats-diagnostics on the https version of my service url

================================================================================

Default ATS Secure Connection
---
ATS Default Connection
Result : PASS
---

================================================================================

Allowing Arbitrary Loads

---
Allow All Loads
Result : PASS
---

================================================================================

Configuring TLS exceptions for ****

---
TLSv1.2
Result : PASS
---

---
TLSv1.1
Result : PASS
---

---
TLSv1.0
Result : PASS
---

================================================================================

Configuring PFS exceptions for ****

---
Disabling Perfect Forward Secrecy
Result : PASS
---

================================================================================

Configuring PFS exceptions and allowing insecure HTTP for ****

---
Disabling Perfect Forward Secrecy and Allowing Insecure HTTP
Result : PASS
---

================================================================================

Configuring TLS exceptions with PFS disabled for ****

---
TLSv1.2 with PFS disabled
Result : PASS
---

---
TLSv1.1 with PFS disabled
Result : PASS
---

---
TLSv1.0 with PFS disabled
Result : PASS
---

================================================================================

Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for ****

---
TLSv1.2 with PFS disabled and insecure HTTP allowed
Result : PASS
---

---
TLSv1.1 with PFS disabled and insecure HTTP allowed
Result : PASS
---

---
TLSv1.0 with PFS disabled and insecure HTTP allowed
Result : PASS
---

================================================================================ 

Edit 2

Here are the exceptions I added:

<dict>
    <key>mydomain.com</key>
    <dict>
        <key>NSIncludesSubdomains</key>
        <true/>
        <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
        <true/>
        <key>NSTemporaryExceptionMinimumTLSVersion</key>
        <string>1.0</string>
        <key>NSTemporaryExceptionRequiresForwardSecrecy</key>
        <false/>
    </dict>
</dict>

Result of curl -v

*   CAfile: /opt/local/share/curl/curl-ca-bundle.crt
  CApath: none
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA384
* Server certificate:
*    subject: C=XXX; ST=XXX; L=XXX; O=XXX; CN=*.mydomain.com
*    start date: 2015-08-17 00:00:00 GMT
*    expire date: 2018-11-14 12:00:00 GMT
*    subjectAltName: subdomain.mydomain.com matched
*    issuer: C=US; O=DigiCert Inc; CN=DigiCert SHA2 Secure Server CA
*    SSL certificate verify ok.

Result of openssl s_client -connect

CONNECTED(00000003)
depth=1 C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=XXX/ST=XXX/L=XXX/O=XXX/CN=*.mydomain.com
   i:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
 1 s:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
.
.
.
-----END CERTIFICATE-----
subject=/C=XXX/ST=XXX/L=XXX/O=XXX/CN=*.mydomain.com
issuer=/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
---
No client certificate CA names sent
---
SSL handshake has read 3033 bytes and written 490 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-SHA384
    Session-ID: XXX
    Session-ID-ctx: 
    Master-Key: XXX
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1454971371
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---
2
@rmaddy I have looked through several of those already. And a lot of times it comes down to either not using TLS 1.2, using a self-signed cert or simply trying to use http. I'm not trying to do any of those things. I have all the security requirements the ATS claims to want, yet it is still blocking me for some unknown reason.Chris Stillwell
Can you give the output of curl -v insert_url_here and openssl s_client -connect insert_domain_here:443?jcaron
Have you checked whether the target URL returns a redirect?jcaron
@jcaron it doesn't not redirect.Chris Stillwell

2 Answers

0
votes
Verify return code: 20 (unable to get local issuer certificate)

It looks like the DigiCert Root CA is not properly loaded on your local machine. Open the KeyChain Access App, and check if it is either in the Login or System Roots section.

0
votes

This answer saved my day! Turns out that ATS requires that server must support ciphers listed in cipher suite here. I can confirm that suggested fix works.