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)
---
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.
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.
Related
I am trying to login to docker repository using https proxy
i am getting error of
proxyconnect tcp: tls: first record does not look like a TLS handshake
when inspecting the proxy
openssl s_client -connect
CONNECTED(00000003)
139776809346960:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:794:
no peer certificate available
No client certificate CA names sent
SSL handshake has read 7 bytes and written 289 bytes
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1646054120
Timeout : 300 (sec)
Verify return code: 0 (ok)
what can cause the issue?
I have to scrape a website without disabling SSL. I tried by using Nokogiri gem
require 'httparty'
require 'nokogiri'
require 'open-uri'
page = open("https://mywebsiteurl.com",{ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE})
doc = Nokogiri::HTML(page)
puts doc
This code works by disabling SSL. but I want it to work without disabling SSL.
when I tried without disabling SSL I got this error
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)
when I do curl https://mywebsiteurl.com I got this result.
* Hostname was NOT found in DNS cache
* Trying xxx.xxx.xxx.xxx...
* Connected to wxxxxxxxxx.com (xxx.xxx.xxx.xxx) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: certificate has expired
* Closing connection 0
curl: (60) SSL certificate problem: certificate has expired
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
I have a simple backend for my iOS application. It used to work perfectly but recently SSL connection started to fail only on iOS.
The strange part is that it started fail on Friday at some point and then started work again. Now I can't use my backend on iOS.
All certificate checks I did shows that everything is ok and TLS 1.2 is working. But iOS (and only iOS, macOS is fine) says that SSL cert is invalid.
Tried to renew certificate - didn't help. Certificate is not self-signed (it is from letsencrypt.org)
This is a test link:
https://api.dartoapp.com:9001/station/test1
SSL Lab report:
https://www.ssllabs.com/ssltest/analyze.html?d=api.dartoapp.com
NSURLRequest error:
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x1d430dec0>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=(
"<cert(0x1400cec00) s: api.dartoapp.com i: Let's Encrypt Authority X3>"
), NSUnderlyingError=0x1d084bc40 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x1d430dec0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"<cert(0x1400cec00) s: api.dartoapp.com i: Let's Encrypt Authority X3>"
)}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://api.dartoapp.com:9001/station/test1, NSErrorFailingURLStringKey=https://api.dartoapp.com:9001/station/test1, NSErrorClientCertificateStateKey=0}
curl output:
~ ⟩ curl -kvI https://api.dartoapp.com:9001/station/test1
* Trying 54.154.203.139...
* TCP_NODELAY set
* Connected to api.dartoapp.com (54.154.203.139) port 9001 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=api.dartoapp.com
* start date: Mar 11 18:18:58 2018 GMT
* expire date: Jun 9 18:18:58 2018 GMT
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7ffeac806c00)
> HEAD /station/test1 HTTP/2
> Host: api.dartoapp.com:9001
> User-Agent: curl/7.54.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200
HTTP/2 200
< content-type: application/json; charset=utf-8
content-type: application/json; charset=utf-8
< content-length: 471
content-length: 471
< date: Sun, 11 Mar 2018 19:38:24 GMT
date: Sun, 11 Mar 2018 19:38:24 GMT
Ok, so the issue was that my server wan't sending intermediate cert. If was OK before but recent LetsEncrypt changes made it mandatory.
I have a following single line code in rails:
Curl::Easy.new("https://www.uts.edu.au/" ).perform
Running this is giving following error:
Curl::Err::SSLCACertificateError: Peer certificate cannot be authenticated with given CA certificates
Can anyone please suggest how to fix it ?
For further help:
curl -v https://www.uts.edu.au/
* Adding handle: conn: 0x16a3a40
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x16a3a40) send_pipe: 1, recv_pipe: 0
* About to connect() to www.uts.edu.au port 443 (#0)
* Trying 54.79.20.73...
* Connected to www.uts.edu.au (54.79.20.73) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
For some reason, Curl is failing to use trusted CAs. By any chance, are you running this inside a Docker Container without CAs?
Please provide the output of curl -v https://www.uts.edu.au/
Update:
It seems there is a problem with the Chain of Certificates for the host you are making requests.
The certificate might lack necessary meta-data or its certificate
authority might be malfunctioning
https://whatsmychaincert.com/generate?host=www.uts.edu.au
On Ubuntu trusty-64 with rvm and ruby 2.0.0-p353 using curb 0.8.5 I try to make post request.
When I perform it in command line using curl it makes request and returns ok, but when I do the same request in ruby, it fails with error reading X.509 key or certificate file message. In both cases I use just the same certificate.
vagrant#cabinet:~/app$ curl -k --cert certs/ds_admin.pem --cert-type PEM https://pim.somewhere.ru:5543/authentication/user/login/? --data "{\"login\":\"+71111111150\",\"password\":\"qwerty123\"}" -v
* Hostname was NOT found in DNS cache 151.209.250.186
* Trying 151.209.250.186...
* Connected to pim.somewhere.ru (151.209.250.186) port 5543 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* 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 AES128-SHA
* Server certificate:
* subject: C=RU; O=BE; OU=test env; CN=*.somewhere.ru
* start date: 2013-02-27 15:09:21 GMT
* expire date: 2015-11-24 15:09:21 GMT
* issuer: C=RU; O=BE; OU=test env; CN=*.somewhere.ru
* SSL certificate verify result: self signed certificate (18), continuing anyway.
> POST /authentication/user/login/? HTTP/1.1
> User-Agent: curl/7.35.0
> Host: pim.somewhere.ru:5543
> Accept: */*
> Content-Length: 47
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 47 out of 47 bytes
* SSLv3, TLS handshake, Hello request (0):
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS handshake, CERT verify (15):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
< HTTP/1.1 200 OK
< Content-Length: 325
< Content-Type: application/json; charset=utf-8
* Server Microsoft-HTTPAPI/2.0 is not blacklisted
< Server: Microsoft-HTTPAPI/2.0
< Date: Wed, 30 Jul 2014 06:15:58 GMT
<
* Connection #0 to host pim.somewhere.ru left intact
{"Token":"re7hCmYB4hCjJRphLS4dK58nNAkIvHZYVbY9ie94vICPbJadauLclDjPKFLz9lGCz6jjex3GFTL7NmxBofOP70bx6Abin+UrXZj\/N5PEFi3jYR9LIaIxgz5AXYoLxr1kismBZgjvQYCIndhr8lwNpw==|2014-07-30T08:15:58","User":{"FirstName":"First","LastName":"Last","Login":"+71111111150","UserId":"UAS100004","UserNativeId":"1-156LVK","UserSysName":"siebel"}}
In Rails console by using curb
From: /home/vagrant/app/app/models/uas/query.rb # line 49 Uas::Query.client:
44: def self.client(url)
45: url = "#{Rails.configuration.uas_url}/#{url}"
46:
47: Curl::Easy.new(url) do |curl|
48: curl.use_ssl = 1
=> 49: binding.pry
50: curl.cert = Rails.configuration.uas_sertificate
51: curl.ssl_verify_peer = false
52: curl.ssl_verify_host = false
53: curl.verbose = true
54: end
55: end
[1] pry(Uas::Query)> c
Request post user/login/?
{:login=>"+71111111150", :password=>"qwerty123"}
* Hostname was NOT found in DNS cache
* Trying 151.209.250.186...
* Connected to pim.somewhere.ru (151.209.250.186) port 5543 (#0)
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* error reading X.509 key or certificate file
* Closing connection 0
Curl::Err::SSLConnectError: Curl::Err::SSLConnectError
I checked Rails.configuration.uas_sertificate - it's the certificate and could be read by File.read(Rails.configuration.uas_sertificate)
How can I fix it?
In my vagrant box I got installed two libcurl packages:
libcurl4-openssl-dev
libcurl4-gnutls-dev
from which the second one was used for compiling curb gem native extension. I guess it was used due to it was installed after the libcurl4-openssl-dev package.
After I removed libcurl4-gnutls-dev from packages installation list and rebuilt vagrant box, curb had accepted the certificate.