Using: Alamofire 5, self-signed certificate.
The certificate is stored in application resources
AlamofireExtension(Bundle.main).certificates - returns it.
Session:
private let session: Session = {
let manager = ServerTrustManager(evaluators: ["com.my.host.here": PinnedCertificatesTrustEvaluator(certificates: AlamofireExtension(Bundle.main).certificates, acceptSelfSignedCertificates: true, performDefaultValidation: false, validateHost: false)])
let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 60
config.timeoutIntervalForResource = 60
config.httpMaximumConnectionsPerHost = 2
return Session(configuration: config, serverTrustManager: manager)
}()
.plist configuration:
Purpose is to use a self-signed certificate to validate the server without disabling validation and allowing insecure connections.
Note com.my.host.here is not my real hostname, I changed it for privacy reasons.
And here the result:
Task <715E277D-6BAA-4926-91AA-1060903D2924>.<1> HTTP load failed, 0/0 bytes (error code: -1200 [3:-9802])
my_app[12152:5481718] Task <715E277D-6BAA-4926-91AA-1060903D2924>.<1> finished with error [-1200] Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
"<cert(0x160039a00) s: com.my.host.here i: com.my.host.here>"
), NSErrorClientCertificateStateKey=0, NSErrorFailingURLKey=https://com.my.host.here:8043/some_end_point_here, NSErrorFailingURLStringKey=https://com.my.host.here:8043/some_end_point_here, NSUnderlyingError=0x281354870 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x282f35320>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"<cert(0x160039a00) s: com.my.host.here i: com.my.host.here>"
)}}, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <715E277D-6BAA-4926-91AA-1060903D2924>.<1>"
), _kCFStreamErrorCodeKey=-9802, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <715E277D-6BAA-4926-91AA-1060903D2924>.<1>, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x282f35320>, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made.}
Questions is: What is the problem? Is it a problem with the certificate, or with the server side settings? and maybe something else?
You need to change NSExceptionAllowsInsecureHTTPLoads to YES.
NSExceptionAllowsInsecureHTTPLoads
Set the value for this key to YES to allow insecure HTTP loads for the given domain, or to be able
to loosen the server trust evaluation requirements for HTTPS
connections to the domain, as described in Performing Manual Server
Trust Authentication.
Related
We have similar servers on two types of hardware devices, which we need to connect to using iOS application. Currently we are using Alamofire 4.9.1 for all the API requests.
Previously we supported only http endpoints on our servers, but recently we have moved to https on latest version of the devices.The app needs to support both.
The issue that we are facing is, when we connect to a Device X(which supports https), and then try to connect to Device Y(which only support http), we are getting this error
[Error] GET 'http://172.30.1.1/file.xml' [27.7252 s]:
Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo={NSUnderlyingError=0x281f2fde0 {Error Domain=kCFErrorDomainCFNetwork Code=-1004 "(null)" UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLStringKey=https://172.30.1.1/file.xml, NSErrorFailingURLKey=https://172.30.1.1/file.xml, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the server.}
Connecting to device Y(http) directly without first connecting to Device X(https) works fine, and after the error if we kill the app we are able to connect to Device Y(http). This happens even though we are using different SessionManagers in Alamofire.
Is this because we are using the same ip address? If we check the error NSErrorFailingURLStringKey, it is still https although the url we are calling is http.
I am pasting the relevant code here
private var manager: Alamofire.SessionManager = {
let configuration = URLSessionConfiguration.default
let manager = Alamofire.SessionManager(configuration: configuration)
manager.retrier = RetryHandler()
return manager
}()
private var manager2: Alamofire.SessionManager = {
var serverTrustPolicies: [String: ServerTrustPolicy] = [
"172.30.1.1": .disableEvaluation
]
let config = URLSessionConfiguration.ephemeral
//Adding TrustManager to Allow All Certificates
let manager = Alamofire.SessionManager(configuration: config, serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
manager.adapter = RequestInterceptor()
manager.retrier = RequestInterceptor()
return manager
}()
Things we have already tried :
Use different UrlSessionConfiguration
Set config.urlCache = nil
I have developed an app in Xcode10 with Swift (app name: "TerminalsPOC"). I am making an https request to my organization’s internal web api (let's call the url "https://example.com:50001/RESTAdapter/toolbox/getMyData") using Alamofire. I have a class with a class-level variable to reference a session manager:
// Swift code
let serverTrustPolicies: [String: ServerTrustPolicy] = [
“example.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(in: Bundle(for: type(of: self))),
validateCertificateChain: false,
validateHost: true
)
]
sessionManager = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
sessionManager.request(url, method: .get) ...
I have imported the necessary .cer certificate into the app’s bundle. I have left the default ATS settings, but have added an NSExceptionDomain. The relevant info.plist section looks like
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<false/>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
This works so long as the NSExceptionAllowsInsecureHTTPLoads setting is set to true. If I set it to false, the request fails with the message: An SSL error has occurred and a secure connection to the server cannot be made. [-1200]
2018-12-07 11:55:42.122423-0700 TerminalsPOC[27191:371810] ATS failed
system trust 2018-12-07 11:55:42.122530-0700
TerminalsPOC[27191:371810] System Trust failed for [2:0x600001fad740]
2018-12-07 11:55:42.122637-0700 TerminalsPOC[27191:371810] TIC SSL
Trust Error [2:0x600001fad740]: 3:0
2018-12-07 11:55:42.125928-0700
TerminalsPOC[27191:371810] NSURLSession/NSURLConnection HTTP load
failed (kCFStreamErrorDomainSSL, -9802)
2018-12-07 11:55:42.126109-0700 TerminalsPOC[27191:371810] Task
<54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1> HTTP load failed (error
code: -1200 [3:-9802])
2018-12-07 11:55:42.126872-0700
TerminalsPOC[27191:371812] Task
<54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1> finished with error - code:
-1200
2018-12-07 11:55:42.140600-0700 TerminalsPOC[27191:371810] Task <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1> load failed with error
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred
and a secure connection to the server cannot be made."
UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to
the server anyway?, _kCFStreamErrorDomainKey=3,
NSErrorPeerCertificateChainKey=(
"",
"" ), NSErrorClientCertificateStateKey=0,
NSErrorFailingURLKey=https://example.com:50001/RESTAdapter/toolbox/getMyData,
NSErrorFailingURLStringKey=https://example.com:50001/RESTAdapter/toolbox/getMyData,
NSUnderlyingError=0x6000024e89f0 {Error Domain=kCFErrorDomainCFNetwork
Code=-1200 "(null)"
UserInfo={_kCFStreamPropertySSLClientCertificateState=0,
kCFStreamPropertySSLPeerTrust=,
_kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"",
"" )}}, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1>" ), _kCFStreamErrorCodeKey=-9802, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1>,
NSURLErrorFailingURLPeerTrustErrorKey=,
NSLocalizedDescription=An SSL error has occurred and a secure
connection to the server cannot be made.} [-1200]
I tried running “nscurl --ats-diagnostics https://example.com:50001/RESTAdapter/toolbox/getMyData”, and the response included the following:
Default ATS Secure Connection
--- ATS Default Connection Result : PASS
========
Allowing Arbitrary Loads
--- Allow All Loads Result : PASS
========= Configuring TLS exceptions for example.com
--- TLSv1.3 2018-12-07 10:59:17.492 nscurl[24303:331847] NSURLSession/NSURLConnection HTTP load failed
(kCFStreamErrorDomainSSL, -9800) Result : FAIL
--- TLSv1.2 Result : PASS
--- TLSv1.1 Result : PASS
--- TLSv1.0 Result : PASS
============ Configuring PFS exceptions for example.com
--- Disabling Perfect Forward Secrecy Result : PASS
========== Configuring PFS exceptions and allowing insecure HTTP for example.com
--- Disabling Perfect Forward Secrecy and Allowing Insecure HTTP Result : PASS
This all looks OK to me. I must be missing something.
So my questions are:
1. Why does setting the NSExceptionAllowsInsecureHTTPLoads to true cause the call to work, given that it is an https request (with no redirect)? I thought this setting only affects http calls, and should not affect https calls.
2. How can I get this web request to work without setting NSExceptionAllowsInsecureHTTPLoads (which seems to be a hack/work-around, doesn’t it)?
The problem in this case was that the app was running on a simulator on which the required certificate had not been installed.
Once the correct (root) certificate had been installed and trusted, the pinned certificate check passed, and it was then possible to set the NSExceptionAllowsInsecureHTTPLoads info.plist setting back to "NO".
I wish the error message had been more explicit. :-/
I am trying to develop a app on my local machine with the local version of my api, but I am keep getting this error when I run alamofire get request.
[BoringSSL] Function nw_protocol_boringssl_input_finished: line 1436 Peer disconnected during the middle of a handshake. Sending errSSLFatalAlert(-9802) alert
2018-08-13 10:47:23.056793-0500 Edev[6851:453243] TIC TCP Conn Failed [1:0x60c000178480]: 3:-9802 Err(-9802)
2018-08-13 10:47:23.057251-0500 Edev[6851:453243] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
2018-08-13 10:47:23.057432-0500 Edev[6851:453243] Task <97194E8E-7E15-42EC-B8BA-534AC4E313A2>.<1> HTTP load failed (error code: -1200 [3:-9802])
2018-08-13 10:47:23.057686-0500 Edev[6851:453245] Task <97194E8E-7E15-42EC-B8BA-534AC4E313A2>.<1> finished with error - code: -1200
FAILURE: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorCodeKey=-9802, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x60400044f570 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://edev.test/edev, NSErrorFailingURLStringKey=https://edev.test/edev, _kCFStreamErrorDomainKey=3}
[BoringSSL] Function nw_protocol_boringssl_input_finished: line 1436 Peer disconnected during the middle of a handshake. Sending errSSLFatalAlert(-9802) alert
2018-08-13 10:47:23.056793-0500 Edev[6851:453243] TIC TCP Conn Failed [1:0x60c000178480]: 3:-9802 Err(-9802)
2018-08-13 10:47:23.057251-0500 Edev[6851:453243] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
2018-08-13 10:47:23.057432-0500 Edev[6851:453243] Task <97194E8E-7E15-42EC-B8BA-534AC4E313A2>.<1> HTTP load failed (error code: -1200 [3:-9802])
2018-08-13 10:47:23.057686-0500 Edev[6851:453245] Task <97194E8E-7E15-42EC-B8BA-534AC4E313A2>.<1> finished with error - code: -1200
FAILURE: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorCodeKey=-9802, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x60400044f570 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://edev.test/edev, NSErrorFailingURLStringKey=https://edev.test/edev, _kCFStreamErrorDomainKey=3}
This is the alamofire I am using to fetch the data
Alamofire.request("https://edev.test/edev").responseJSON { response in
print(response)
print("Request: \(String(describing: response.request))") // original url request
print("Response: \(String(describing: response.response))") // http url response
print("Result: \(response.result)") // response serialization result
if let json = response.result.value {
print("JSON: \(json)") // serialized json response
}
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)") // original server data as UTF8 string
}
}
I have have put a domain exception if my plist file that should make this run successfully based on what I have found online, but it still is not working.
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>edev.test</key>
<dict/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
does the server have an SSL certificate? if not change URL to Alamofire.request("http://edev.test/edev").responseJSON { response in
I have an issue when connect to Realm Object Server on my device but it works on simulator.
it's return errors :
Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server."
UserInfo={NSUnderlyingError=0x170255450 {Error
Domain=kCFErrorDomainCFNetwork Code=-1004 "(null)" UserInfo=
{_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}},
NSErrorFailingURLStringKey=http://127.0.0.1:9080/auth,
NSErrorFailingURLKey=http://127.0.0.1:9080/auth, _kCFStreamErrorDomainKey=1,
_kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the
server.}): file
/Users/tungvu/Desktop/Swift3Xcode8/RealmTask/RealmTask/ViewController.swift,
line 57
Here's my connect to Realm Object Server function:
SyncUser.logIn(with: .usernamePassword(username: username, password: password, register: false), server: URL(string : "http://127.0.0.1:9080")!) { (user, error) in
guard let user = user else {
fatalError(String(describing: error))
}
DispatchQueue.main.async {
// Open Realm
let configuration = Realm.Configuration(
syncConfiguration: SyncConfiguration(user: user, realmURL: URL(string: "realm://127.0.0.1:9080/~/realmtasks")!)
)
From the looks of it, you're using the localhost IP address 127.0.0.1. While this will work with apps running on the same device as the Realm Object Server instance (ie the iOS Simulator), you'll need the actual IP address of the machine on the local network in order to connect from a separate device like an iPhone.
The easiest way to find the network IP address is to hold down Alt, and then click on the Wi-Fi icon in the macOS status bar:
If you replace 127.0.0.1 with your Mac's network IP address, other devices should then be able to connect to it. This should work for the iOS Simulator as well, so there shouldn't be a need to change it until your machine's IP address changes.
When running the method:
CFReadStreamSetProperty(theReadStream, kCFStreamPropertySSLSettings (CFDictionaryRef)tlsPacket->tlsSettings);
To secure the connection of a CFReadStream, my iphone client returns the error:
Error Domain=kCFStreamErrorDomainSSL Code=-9824 "Operation could not be completed. (kCFStreamErrorDomainSSL error -9824.)"
and the server sends the error:
ERROR [STDERR] javax.net.ssl.SSLHandshakeException: no cipher suites in common
Is there any way to allow CFReadStream to use additional ciphers during the handshake process?
For anyone else who runs into this problem:
It turns out that the problem was on the server side. If you run into this issue yourself I would urge you to check that the handshake on the server side is working properly.