iOS mobile app certificate authority - ios

I apologize in advance if i made a duplicate of this question. I'm working on a mobile app that communicates with an API on a .local domain. I'm stuck at trying to establish a secure connection (using Alamofire). I Tried to write a custom ServerTrustPolicy just as Alamofire wiki suggests, and include my certificate chain, but it always fails. The only way to get the app to connect is by configuring App Transport Security in .plist file and adding the domain as exception. Does anyone have experiance with using certificates trough alamofire with .local domains? Would really appreciate any advice. Thank you in advance.
This is my Alamofire.Manger:
static let sharedInstance: Manager = {
var apiObject = ApiBaseService()
//let domainName = apiObject.getDomain()
let pathToCert = NSBundle.mainBundle().pathForResource("certca", ofType: "der")
let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
let value = GlobalConstants.APICallErrorLocations.actionsGetActions
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.ex01.local": serverTrustPolicy
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
configuration.timeoutIntervalForRequest = NSTimeInterval(12.0)
return Manager(configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
}()
Am I doing something wrong?
Kristian
EDIT:
The thing was TLS version was v1.0 which i discovered with this command:
openssl s_client -connect test.ex01.local:5000
After updating TLS version and including certificate chain in ServerTrustPolicy object, everything works.
Hope this will help someone in the future.

If your certificate chain is not valid and is self-signed (assuming this is the case), then you MUST disable ATS for that host, or you'll never be able to use the Alamofire cert pinning logic. ATS will never even give Alamofire a chance to evaluate the cert chain.
The reason for this behavior is that ATS first evaluates the connection challenge before giving the NSURLSessionDelegate a chance to evaluate the challenge. If ATS evaluates the properties of the challenge and determines it should not trust the connection, it stops there and the request will not succeed. It doesn't call the NSURLSessionDelegate to give you a second chance to override it.
However, when you disable ATS, the first ATS checks no longer happen, and the challenge is sent to the NSURLSessionDelegate for evaluation which is where Alamofire kicks in.

AppTransportSecurity is used to list connections that you want that are not HTTPS. iOS blocks non HTTPS connections that are not in this list!

Related

alamofire SSL errors on self-signed local certificates

I have a HTTP REST server with a self-signed certificate. I want to talk to this server from an iOS Swift app, using alamofire. The current code that I have is:
```
let Almgr : Alamofire.SessionManager = {
// Create the server trust policies
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"localhost": .disableEvaluation
]
// Create custom manager
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
let man = Alamofire.SessionManager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
return man
}()
Almgr.request(url, method: .post, parameters: params).responseJSON {
response in
if response.result.isSuccess {
print("Success")
} else {
print("Failure")
}
}
With the above code snippet, I am always getting an error when I try to make the http call Almgr.request. The error message is:
2017-12-30 18:24:20.114486+0530 myApp[58036:2721102] ATS failed system trust
2017-12-30 18:24:20.114625+0530 myApp[58036:2721102] System Trust failed for [1:0x600000178a80]
2017-12-30 18:24:20.114814+0530 myApp[58036:2721102] TIC SSL Trust Error [1:0x600000178a80]: 3:0
2017-12-30 18:24:20.115142+0530 myApp[58036:2721102] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
2017-12-30 18:24:20.115274+0530 myApp[58036:2721102] Task <4E3D9E88-B9CE-48C4-850C-5A3E7C9A6A72>.<1> HTTP load failed (error code: -1200 [3:-9802])
2017-12-30 18:24:20.115469+0530 myApp[58036:2721231] Task <4E3D9E88-B9CE-48C4-850C-5A3E7C9A6A72>.<1> finished with error - code: -1200
Any idea how to get this fixed ? I do not want any checks to be done if the url is localhost on port 8000. I have even tried with adding port to the serverTrustPolicies definition but that does not make any difference and I still get error. Any help ?
Update: My problem I believe is related to https://developer.apple.com/library/content/qa/qa1948/_index.html but not found the way to fix yet.
1.
Your approach of modifying server trust policies should work when providing the port. Also see this post. Maybe you are testing your app with the simulator and trying to connect to a web server on the same machine? This can cause all kinds of connection problems (or why are you trying to connect to localhost anyway?).
2.
You should never set NSAllowsLocalNetworking or similar parameters. It breaks SSL and you never know what may happen, even in the local network. If absolutely necessary, you should just make exceptions for single hosts and ports as stated above.
3.
You should never use self signed certificates because this also breaks SSL. It is very easy to obtain a valid certificate using Let's Encrypt. Though, in some cases it is just not possible to obtain a valid certificate. You should then create your own certificate authority and export the CA root certificate to your device. This way, you also make an exception for only one specific host.
Please note that security is crucial in all applications. Please only make exceptions if you exactly know what you are doing.
I have figured out the solution. We need to edit the Info.plist file and add the following section:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
to let iOS allow local networking without https errors.
I was facing same problems. What I figured out and what works:
let almgr:Alamofire.SessionManager = {
//getcertificates is my own method where i create certificate with data from my .cer file
let certificates = getCertificates()
let trustPolicy = ServerTrustPolicy.pinCertificates(certificates: certificates, validateCertificateChain: true, validateHost: true)
// Here was the problem. I had to modify that dict: (localhost with port and with .disableEvaluation)
let serverTrustPolicies = ["liper:8000":trustPolicy, "liper":.disableEvaluation]
let serverTrustPolicyManager = ServerTrustPolicyManager(policies: serverTrustPolicies)
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
let man = Alamofire.SessionManager(configuration: URLSessionConfiguration.default, serverTrustPolicyManager: serverTrustPolicyManager)
return man
}()

How can i add authentication header in asnetworkimagenode url request?

I'm using AsyncDisplaykit in my swift application and ASNetworkImageNode as my imageview in collectionNode. I can load any external url with great performance but for my application I need to communicate with our api which requires authentication header to be sent on each GET request. How can i add authentication header in asnetworkimagenode url request or write an extension or any other workaround to achieve this?
I searched the library files and found that there is a setSharedImageManagerWith(_:URLSessionConfiguration?) in PINRemoteImageManager. One can add additional header in session configuration. So in swift 3 the code can be added in appdelegate didFinishLaunchingWithOptions as:
let config = URLSessionConfiguration.ephemeral
config.httpAdditionalHeaders = [
"clientid": "yourAdditionalHeader",
"clientkey": "yourAdditionalHeader"
] as [AnyHashable:Any]
ASPINRemoteImageDownloader.setSharedImageManagerWith(config)
Now setting the url in AsNetworkImageNode will send the url request with additional headers added to the request. This has solved my issue.
The doc of PINRemoteImageManager reads
"Sets the shared instance of PINRemoteImageManager to an instance with the supplied configuration. If configuration is nil, [NSURLSessionConfiguration ephemeralSessionConfiguration] is used. You specify a custom configuration if you need to configure timeout values, cookie policies, additional HTTP headers, etc. This method should not be used if the shared instance has already been created."
So the similar code can be used to configure timeout values, cookie policy and of course additional http headers. Hope this will help someone.

AFNetworking checking server certificate domain

I have a static function which I use to retrieve a configuration file through AFNetworking library, as follows:
static func getConfiguration(success: NetworkServiceSuccessBlock, failure: NetworkServiceFailureBlock) -> AFHTTPSessionManager? {
let sessionManager = AFHTTPSessionManager(sessionConfiguration: NSURLSessionConfiguration.defaultSessionConfiguration())
sessionManager.requestSerializer.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
sessionManager.GET(getConfigurationUrl()!, parameters: nil, progress: nil, success: success, failure: failure)
return sessionManager
}
I need to check the server SSL certificate domain to be the proper one, something like challenge.protectionSpace.host for NSURLSession, and I need the check to determine whether the GET request will fail or not.
EDIT: I don't want to perform SSL Pinning with certificates stored in the app bundle, it is enough for me to verify the server certificate domain is correct.
Can someone point me in the right direction to perform this?

Websocket : Starscream "masked and rsv data is not currently supported"

I am developing an iOS app which required to connect with web socket server.
I can successfully connect to server but when I send request on it, it drop off the connection.
I am using Starscream library for web socket.
As per server support team:
it does not support protocol compression, but in the headers below they're requesting "permessage-deflate" from us. We'll accept uncompressed messages just fine (it's just a flag on the packet) but due to the extension they asked for, messages we send out will be compressed with that flag set.
I send request as following using Swift
let dict = ["Parameter1":"value1","Parameter2":"value2"]
do {
let data = try NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions(rawValue: 0))
var jsonString: String = String(data: data, encoding: UInt())!
self.socket.writeString(jsonString);
} catch {
print(error)
}
It disconnect with server and print following message.
"websocket is disconnected: Optional("masked and rsv data is not currently supported")"
What the server support team meant is that the request from your WebSocket client application contained an HTTP header like below.
Sec-WebSocket-Extensions: permessage-deflate
So, if your application has a line like below, remove it.
socket.headers["Sec-WebSocket-Extensions"] = "permessage-deflate"
This error might also be thrown if the server doesn't accept the incoming connection (regardless of the reasons), or if the server crashed.
Basically, when this message shows up, the best action would be to check what is going on the server as you might be wasting time trying improve client code (it happened to me :)
For those facing this issue when trying to connect to the backend WebSocket, make sure the front end and the backend version of the socket.io are compatible. Running the following command fixed the issue for me.
pod update
Updated the both to the latest and solved the issue.
this will fix your issue I believe. just add "wamp" in the header like this.
*
var request = URLRequest(url: URL(string: URL)!)
request.setValue(["wamp"].joined(separator: ","), forHTTPHeaderField: "Sec-WebSocket-Protocol")
socket = WebSocket(request: request)
socket.delegate = self
socket.connect()

Alamofire not executing correctly in Swift

I have an Alamofire request that is suppose to download a file, but it will not execute the code it self. Here is the Alamofire Code:
var testNumbers: Int = 0
var testString: String = "Hi"
Alamofire.download(.GET, "http://www.sayweee.com/admin_groupbuy/export_deal_orders/71w4o?format=csv") { temporaryURL, response in
let fileManager = NSFileManager.defaultManager()
let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
print("1")
testNumbers = 1
print(directoryURL.URLByAppendingPathComponent(pathComponent!))
print("blah")
testString = "blah"
print("2")
testNumbers = 2
return directoryURL.URLByAppendingPathComponent(pathComponent!)
}
print(testNumbers)
print(testString)
Executing this code will print this in the console:
0
Hi
I am pretty sure this means that the code within the {} are not getting executed. I've read another on this subject, and learned that Alamofire is "asynchronous", as they said in this post. I've tried to get rid of everything in viewDidLoad() method and viewDidAppear() method, and made sure I didn't have any endless loops. Even after that, the results are the same. Any ideas or suggestion on why this is happening to me? I tried to look here and on Google, but I only found one post related to this topic, the one linked above.
First of all, I put your code to run in Demo Alamofire found running results and what you said is the same, as shown in the figure below:
0
Hi
2015-12-30 14:31:29.873 iOS Example[3966:142688] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
According to the prompt you will see that the problem:
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
The solution is as follows(In the project file "info.plist" ):
In project's "info.plist" file to add a "NSAppTransportSecurity" dictionary, an element is added in the dictionary.Key for "NSAllowsArbitraryLoads", the value is: YES, make it back to the HTTP protocol for the time being.
The problem solution links:
Transport security has blocked a cleartext HTTP
The final results are as follows:
0
Hi
1
file:///Users/yangshebing/Library/Developer/CoreSimulator/Devices/151CB429-29B3-46D0-AFF5-37D5B8D9E4FC/data/Containers/Data/Application/756A32D1-64C5-48CF-B652-D3009D80780D/Documents/71w4o.html
blah
2
Specific problems you can go to query the apple official documentation, query iOS9 ATS adaptation problem.
The hope can help you!

Resources