Swift 3 How to validate server certificate using SSL Pinning and AlamoFire? - ios

I'm writing an app in swift 3 that needs to talk to my server. I have the full certificate chain in der and crt format which I am the CA for(Not to be confused with self signed). How do I use this in my app to validate my server? Below is my rest call and response
Rest Call:
var request = URLRequest(url: URL(string: "https://myserver/login")!)
request.addValue("Content-Type", forHTTPHeaderField: "application/json")
request.httpMethod = "GET"
let session = URLSession.shared
session.dataTask(with: request) {data, response, err in
print("=========================DATA===============================")
if data != nil {
print(data!)
}
print("=========================RESPONSE===============================")
if response != nil {
print(response!)
}
print("=========================ERR===============================")
if err != nil {
print(err!)
}
}.resume()
Output:
=========================DATA===============================
=========================RESPONSE===============================
=========================ERR===============================
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x60800011f020>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=(
"<cert(0x7fae4803d200) s: myserver i: MySubCA>",
"<cert(0x7fae48047000) s: MySubCA i: MyRootCA>",
"<cert(0x7fae48044600) s: MyRootCA i: MyRootCA>"
), NSUnderlyingError=0x60800005a040 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x60800011f020>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"<cert(0x7fae4803d200) s: myserver i: MySubCA>",
"<cert(0x7fae48047000) s: MySubCA i: MyRootCA>",
"<cert(0x7fae48044600) s: MyRootCA i: MyRootCA>"
)}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://myserver/login, NSErrorFailingURLStringKey=https://myserver/login, NSErrorClientCertificateStateKey=0}

I solved it pretty simply leveraging an online blog, AlamoFire and openssl.
I used AlamoFire for the networking on iOS.
I used an article about SSL pinning on iOS to get on the right direction.
I used openssl to convert my cert to der format.
Der conversion through openssl.
openssl x509 -in cert.crt -out cert.der -outform DER
You will need to add the der formatted cert to your app bundle.
Swift 3 implementation
// Your hostname and endpoint
let hostname = "YOUR_HOST_NAME"
let endpoint = "YOUR_ENDPOINT"
let cert = "YOUR_CERT" // e.g. for cert.der, this should just be "cert"
// Set up certificates
let pathToCert = Bundle.main.path(forResource: cert, ofType: "der")
let localCertificate = NSData(contentsOfFile: pathToCert!)
let certificates = [SecCertificateCreateWithData(nil, localCertificate!)!]
// Configure the trust policy manager
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: certificates,
validateCertificateChain: true,
validateHost: true
)
let serverTrustPolicies = [hostname: serverTrustPolicy]
let serverTrustPolicyManager = ServerTrustPolicyManager(policies: serverTrustPolicies)
// Configure session manager with trust policy
afManager = SessionManager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: serverTrustPolicyManager
)
afManager.request(endpoint, method: .get).responseJSON { response in
debugPrint("All Response Info: \(response)")
}

Related

HTTPS requests implemented with Certificate pinning in Swift using AlamoFire fails

We are trying to implement ssl in our iOS application to connect to Rest webservices running in Tomcat Webserver.
Facing following issue when clientAuth is set to true in tomcat configuration :
2018-05-08 09:28:08.442409+0530 [925:337357] XPC connection interrupted
2018-05-08 09:29:26.481465+0530 [925:336959] [Common] _BSMachError: port 9d6f; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
2018-05-08 09:29:26.485693+0530 [925:336959] [Common] _BSMachError: port 9d6f; (os/kern) invalid name (0xf) "Unable to deallocate send right"
2018-05-08 09:29:44.930812+0530 [925:337804] [] nw_coretls_read_one_record tls_handshake_process: [-9825]
2018-05-08 09:29:44.970760+0530 [925:337766] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9825)
2018-05-08 09:29:44.989 [Debug] [main] [HttpUtils.swift:351] handleResponse(response:completionHandler:) > Value: FAILURE;
2018-05-08 09:29:44.999 [Error] [main] [HttpUtils.swift:363] checkRestResponseErrorAndGetUserUnderstandableError(error:completionHandler:) > Error Domain=NSURLErrorDomain Code=-1205 "The server “example.com” did not accept the certificate." UserInfo={NSLocalizedDescription=The server “example.com” did not accept the certificate., _kCFStreamErrorDomainKey=3, NSUnderlyingError=0x16e35930 {Error Domain=kCFErrorDomainCFNetwork Code=-1205 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=1, _kCFNetworkCFStreamSSLErrorOriginalValue=-9825, _kCFStreamErrorCodeKey=-9825, _kCFStreamErrorDomainKey=3, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x16e2ab90>, kCFStreamPropertySSLPeerCertificates=(
"<cert(0x17337200) s: example.com i: Go Daddy Secure Certificate Authority - G2>",
"<cert(0x172e0c00) s: Go Daddy Secure Certificate Authority - G2 i: Go Daddy Root Certificate Authority - G2>",
"<cert(0x172abe00) s: Go Daddy Root Certificate Authority - G2 i: Go Daddy Root Certificate Authority - G2>"
)}}, _kCFStreamErrorCodeKey=-9825, NSErrorFailingURLStringKey=https://example.com:8443/myserver/rest/myresource/servicepath, NSErrorPeerCertificateChainKey=(
"<cert(0x17337200) s: example.com i: Go Daddy Secure Certificate Authority - G2>",
"<cert(0x172e0c00) s: Go Daddy Secure Certificate Authority - G2 i: Go Daddy Root Certificate Authority - G2>",
"<cert(0x172abe00) s: Go Daddy Root Certificate Authority - G2 i: Go Daddy Root Certificate Authority - G2>"
), NSErrorClientCertificateStateKey=1, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x16e2ab90>, NSErrorFailingURLKey=https://example.com:8443/myserver/rest/myresource/servicepath}
Here is a code snippet that shows how we create AlamoFire Session manager:
import Foundation
import Alamofire
class HttpUtils {
static let utils = HttpUtils()
var alamoFireSSLManager : SessionManager?
public static func getJSONRequestWithBody(url: String, targetViewController: UIViewController?, params : Dictionary<String, String>,
handler: #escaping RiderRideRestClient.responseJSONCompletionHandler){
let isNetworkAvailable = Reachability.isConnectedToNetwork()
if isNetworkAvailable {
utils.createAlamoFireManager()
utils.alamoFireSSLManager!
.request(url, method: .get, parameters: params, encoding: URLEncoding.methodDependent, headers: nil)
.responseJSON(completionHandler: {
(response) in
handleResponse(response: response, completionHandler: handler)
})
}
else {
handler(nil, Errors.NetworkConnectionNotAvailableError)
}
}
func createAlamoFireManager() {
if (HttpUtils.utils.alamoFireSSLManager == nil) {
let mydomainCertificates = getCertificates(filename: "mydomaincertificate", type: "cer")
let mydomainTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: mydomainCertificates,
validateCertificateChain: true,
validateHost: true)
let sub2DomainCertificates = getCertificates(filename: "sub2domaincertificate", type: "cer")
let sub2DomainTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: sub2DomainCertificates,
validateCertificateChain: true,
validateHost: true)
var serverTrustPolicies = [String : ServerTrustPolicy] ()
serverTrustPolicies[example.com] = mydomainTrustPolicy
serverTrustPolicies[sub2.example.com] = sub2DomainTrustPolicy
serverTrustPolicies[sub3.example.com] = ServerTrustPolicy.disableEvaluation
HttpUtils.utils.alamoFireSSLManager = SessionManager(configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
}
}
func getCertificates(filename : String, type : String) -> [SecCertificate] {
let url = Bundle.main.url(forResource: filename, withExtension: type)!
let localCertificate = try! Data(contentsOf: url) as CFData
guard let certificate = SecCertificateCreateWithData(nil, localCertificate)
else { return [] }
return [certificate]
}
}
I tried by adding following to "App Transport Security Settings" of info.plist :
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>sub2.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
Then I got following error :
2018-05-08 12:36:26.761020+0530[82215:62448515] CredStore - copyIdentPrefs - Error copying Identity cred. Error=-25300, query={
class = idnt;
labl = "https://example.com:8443/";
"r_Ref" = 1;
}
2018-05-08 12:36:26.834384+0530[82215:62448514] [BoringSSL] Function boringssl_session_handshake_error_print: line 3108 boringssl ctx 0x105767600: 4505905920:error:10000412:SSL routines:OPENSSL_internal:SSLV3_ALERT_BAD_CERTIFICATE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl/boringssl-109.20.5/ssl/tls_record.c:547:SSL alert number 42
2018-05-08 12:36:26.838433+0530[82215:62448514] TIC TCP Conn Failed [1:0x1c017b900]: 3:-9802 Err(-9802)
2018-05-08 12:36:27.044962+0530[82215:62447873] CredStore - copyIdentPrefs - Error copying Identity cred. Error=-25300, query={
class = idnt;
labl = "https://example.com:8443/";
"r_Ref" = 1;
}
2018-05-08 12:36:27.112478+0530[82215:62448515] TIC TCP Conn Failed [2:0x1c417e240]: 3:-9802 Err(-9802)
2018-05-08 12:36:27.179865+0530[82215:62448515] TIC TCP Conn Failed [3:0x1c417dac0]: 3:-9800 Err(-9800)
2018-05-08 12:36:27.180800+0530[82215:62448515] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9800)
2018-05-08 12:36:27.180898+0530[82215:62448515] Task .<1> HTTP load failed (error code: -1200 [3:-9800])
2018-05-08 12:36:27.182153+0530[82215:62448514] Task .<1> finished with error - code: -1200
2018-05-08 12:36:27.204 [Error] [main] Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorCodeKey=-9800, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x1c025d2b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9800, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9800}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://example.com:8443/myserver/rest/myresource/servicepath, NSErrorFailingURLStringKey=https://example.com:8443/myserver/rest/myresource/servicepath, _kCFStreamErrorDomainKey=3}
I generated the certificate using following command and made sure this certificate is applied to my target in Xcode:
openssl s_client -connect example.com:8443 -servername example.com < /dev/null | openssl x509 -outform DER > mydomaincertificate.cer
I have checked several SO posts to understand what's wrong, but none of the answers given in other posts worked. What am I doing wrong?
Apparently, client certificates are not supported by AlamoFire! Hence this error when clientAuth is set to true in tomcat configuration.

How to connect using Socket-IO-Swift on a self-signed certificate?

I use the framework Socket.IO-cleint-swift. Below is the code for creating and connecting:
let socket = SocketIOClient.init(socketURL: URL(string: "https://ts4.steelsea.net:8080")!, config: [.log(true), .forcePolling(true),.secure(true),.selfSigned(true)])
socket.on("connect") {data, ack in
print("socket connected")
}
socket.on("currentAmount") {data, ack in
if let cur = data[0] as? Double {
socket.emitWithAck("canUpdate", cur).timingOut(after: 0) {data in
socket.emit("update", ["amount": cur + 2.50])
}
ack.with("Got your currentAmount", "dude")
}
}
socket.connect()
Below is an error:
ERROR SocketIOClient: The certificate for this server is invalid. You
might be connecting to a server that is pretending to be
“ts4.steelsea.net” which could put your confidential information at
risk.
I can not figure out how to confirm this certificate to me.
This is connected with insecure connection with the server. And that is why Socket.IO is sending you error.
If you would like to silent this error you can try to drop secure(true) and selfSigned(true) configs.

Pinning PublicKey with AlamoFire

I've been trying to perform a public key pinning for my application.
And I did the following steps:
1) First I used openssl to extract the server cert in der format
openssl s_client -showcerts -connect my.server.com:443 < /dev/null | openssl x509 -outform DER > serverCert.der
2) Loaded publicKey from cert:
func getPubKey() -> SecKey? {
let certificateData = NSData(contentsOfURL:NSBundle.mainBundle().URLForResource("serverCert", withExtension: "der")!)
let certificate = SecCertificateCreateWithData(nil, certificateData!)
var trust: SecTrustRef?
let policy = SecPolicyCreateBasicX509()
let status = SecTrustCreateWithCertificates(certificate!, policy, &trust)
var key: SecKey?
if status == errSecSuccess {
key = SecTrustCopyPublicKey(trust!)!;
print("NetworkImplementation :: getPubKey :: success")
}
return key
}
3) added my serverTrustPolicy to Alamofire’s Manager:
let key: SecKey? = self.getPubKey()
self.serverTrustPolicy = ServerTrustPolicy.PinPublicKeys(publicKeys: [key!],
validateCertificateChain: true,
validateHost: true)
self.serverTrustPolicies = [
"*.my.server.com": self.serverTrustPolicy!
]
self.afManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
serverTrustPolicyManager: ServerTrustPolicyManager(policies: self.serverTrustPolicies))
print("NetworkImplementation :: init :: success")
4) When I want to perform a request I do this:
self.afManager
.request(almethod, url, parameters: alparams, encoding: encoding, headers: alheaders)
.validate()
.response { //... }
Then I tried to check if it was not trusting a self signed certificate, to do that I used Charles and the iOS Simulator.
After installing Charles, added my server domain to the SSL Proxy configuration on port 443 and clicked Help -> SSL Proxying -> Install on simulators.
I was able to see the request and response content of my application inside the Charles UI and the request connection status was not an error.
What am I missing?

Self-signed certificate iOS

I am trying to configure my iOS app to accept self-signed certificates.
I am trying to fetch the data on a button click. Below is the code that I am using currently:
private var manager : SessionManager?
func setManager(url: String) {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
url: .disableEvaluation
]
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
manager = Alamofire.SessionManager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}
#IBAction func nonCertifiedClick(_ sender: UIButton) {
outputText.text = ""
setManager(url: "sand.xxx.int:16443")
manager?.request("https://sand.xxx.int:16443/version").response { response in
debugPrint("R: \(response)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)")
self.outputText.text = utf8Text
}
}
}
My Info.plist file has the below configuration:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
But when the request is executed, I get the following response:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
"R: DefaultDataResponse(request: Optional(https://sand.xxx.int:16443/version), response: nil, data: Optional(0 bytes),
error: Optional(Error Domain=NSURLErrorDomain Code=-1202 \"The certificate for this server is invalid. You might be connecting to a server that is pretending to be “sand.xxx.int” which could put your confidential information at risk.\"
UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x600000105730>,
NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?,
_kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813,
NSErrorPeerCertificateChainKey=(\n \"<cert(0x7fcf8b81e800) s: sand i: sand>\"\n),
NSUnderlyingError=0x60000005f440 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 \"(null)\" UserInfo={_kCFStreamPropertySSLClientCertificateState=0,
kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x600000105730>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9813,
_kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813,
kCFStreamPropertySSLPeerCertificates=(\n \"<cert(0x7fcf8b81e800) s: sand i: sand>\"\n)}},
NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “sand.xxx.int” which could put your confidential information at risk.,
NSErrorFailingURLKey=https://sand.xxx.int:16443/version,
NSErrorFailingURLStringKey=https://sand.xxx.int:16443/version, NSErrorClientCertificateStateKey=0}),
_metrics: Optional((Task Interval) <_NSConcreteDateInterval: 0x600000224e40> (Start Date) 2016-11-02 14:13:57 +0000 + (Duration) 0.381569 seconds = (End Date) 2016-11-02 14:13:58 +0000\n(Redirect Count) 0\n(Transaction Metrics) (Request) <NSURLRequest: 0x600000200120> { URL: https://sand.xxx.int:16443/version }\n(Response) (null)\n(Fetch Start) 2016-11-02 14:13:57 +0000\n(Domain Lookup Start) (null)\n(Domain Lookup End) (null)\n(Connect Start) (null)\n(Secure Connection Start) (null)\n(Secure Connection End) (null)\n(Connect End) (null)\n(Request Start) 2016-11-02 14:13:57 +0000\n(Request End) 2016-11-02 14:13:57 +0000\n(Response Start) 2016-11-02 14:13:57 +0000\n(Response End) (null)\n(Protocol Name) (null)\n(Proxy Connection) NO\n(Reused Connection) YES\n(Fetch Type) Unknown\n\n))"
Data:
I am testing this on Xcode 8.1 with Swift3 and Alamofire4.
What am I misisng here to make it work right?
Update (Answer)
If incase someone encounters the same issue, the problem was the server's SSL certificate. The certificate needs to be signed with at least SHA256 algorithm but mine was signed with SHA1.
I faced the same problem. But using your question, i found the solution. Tnx..
Here is my solution. it works with swift 3
create a class SecurityCertificateManager
import Foundation
import Alamofire
class SecurityCertificateManager {
static let sharedInstance = SecurityCertificateManager()
let defaultManager: Alamofire.SessionManager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"272.73.41.156": .disableEvaluation
]
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
return Alamofire.SessionManager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
}
call it like this in viewDIdLoad
let baseUrl ="https://272.73.41.156/cas/tickets?"+"username="+userEmail.text!+"&password="+userPassword.text!
print("Base url : \(baseUrl)")
let params2 = ["nostring": "nodata", "nostring": "nodata",]
SecurityCertificateManager.sharedInstance.defaultManager.request(baseUrl, method: .post, parameters: params2, encoding: JSONEncoding.default, headers: ["Content-Type":"application/x-www-form-urlencoded"]).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print("response : \(response.result.value)")
}
break
case .failure(_):
print("Failure : \(response.result.error)")
break
}
}
It Works in Swift3

Alamofire with a self-signed certificate / ServerTrustPolicy

I want to use Alamofire to communicate with my server over a https connection with a self signed certificate. My environment runs on localhost. I've tried to connect, but the response all the time looks like this:
Success: false
Response String: nil
I've done it with the following code:
import Foundation
import UIKit
import Alamofire
class MessageView: UITableViewController {
let defaultManager: Alamofire.Manager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"localhost": .DisableEvaluation
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
return Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
override func viewDidLoad() {
super.viewDidLoad()
defaultManager
.request(.GET, "https://localhost:3443/message")
.responseJSON { _, _, result in
print("Success: \(result.isSuccess)")
print("Response String: \(result.value)")
}
}
}
I've created the server side certificates with this line of bash:
openssl req -x509 -nodes -days 999 -newkey rsa:2048 -keyout server.key -out server.crt
I don't know what am I doing wrong. Help would be great.
### Update ###
Here is the cURL request. In my opinion, there is no problem, or am I wrong?
curl -X GET https://localhost:3443/message -k -v
* Trying ::1...
* Connected to localhost (::1) port 3443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
* Server certificate: teawithfruit
> GET /message HTTP/1.1
> Host: localhost:3443
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 1073
< Date: Tue, 15 Sep 2015 06:20:45 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
[{"_id":"55f3ed2d81a334558241e2f4","email":"abc#def.com","password":"abc","name":"teawithfruit","language":"en","__v":0,"timestamp":1442049325159,"messages":[{"_id":"55f40553e568236589772c61","user":"55f3ed2d81a334558241e2f4","language":"en","message":"hello world","__v":0,"timestamp":1442055507301,"id":"55f40553e568236589772c61"},{"_id":"55f48b2b02e7b059b54e99f6","user":"55f3ed2d81a334558241e2f4","language":"en","message":"hello world","__v":0,"timestamp":1442089771312,"id":"55f48b2b02e7b059b54e99f6"}],"id":"55f3ed2d81a334558241e2f4"}]
### Update 2 ###
Sorry for the late answer.
Here are the two debugPrints:
Request debugPrint:
$ curl -i \
-H "Accept-Language: en-US;q=1.0" \
-H "Accept-Encoding: gzip;q=1.0,compress;q=0.5" \
-H "User-Agent: Message/com.teawithfruit.Message (1; OS Version 9.0 (Build 13A340))" \
"https://localhost:3443/message"
Result debugPrint:
FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://localhost:3443/message, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://localhost:3443/message}
### Update 3 ###
Here is the complete error with maybe an ATS problem?
nil
$ curl -i \
-H "Accept-Language: en-US;q=1.0" \
-H "Accept-Encoding: gzip;q=1.0,compress;q=0.5" \
-H "User-Agent: Message/com.teawithfruit.Message (1; OS Version 9.0 (Build 13A340))" \
"https://localhost:3443/message"
2015-10-17 15:10:48.346 Message[25531:1001269] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
FAILURE: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7fdc3044b740>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=<CFArray 0x7fdc2a7ca300 [0x10f7037b0]>{type = immutable, count = 1, values = (
0 : <cert(0x7fdc31d31670) s: teawithfruit i: teawithfruit>
)}, NSUnderlyingError=0x7fdc30064bd0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fdc3044b740>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7fdc2a7ca300 [0x10f7037b0]>{type = immutable, count = 1, values = (
0 : <cert(0x7fdc31d31670) s: teawithfruit i: teawithfruit>
)}}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://localhost:3443/message, NSErrorFailingURLStringKey=https://localhost:3443/message, NSErrorClientCertificateStateKey=0}
Success: false
Response String: nil
You need to add the port domain when you create your ServerTrustPolicy dictionary.
let defaultManager: Alamofire.Manager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"localhost:3443": .DisableEvaluation
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
return Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
For swift 4:
private static var Manager : Alamofire.SessionManager = {
// Create the server trust policies
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"your domain goes here": .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
}()
Then you call it like this:
Manager.upload(body.data(using: .utf8)!, to: url, method: .post, headers: headers)
Credits to Cnoon
My approach for self-signed https. The ServerTrustPolicyManager is an open class, and it's serverTrustPolicy function is open too. So it can be override.
In my case, the server list will grow in future. If I hard-code the https list, I will need to maintain the list when adding new https server. So, I decide to override the ServerTrustPolicyManager class in order to meet my needs.
// For Swift 3 and Alamofire 4.0
open class MyServerTrustPolicyManager: ServerTrustPolicyManager {
// Override this function in order to trust any self-signed https
open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
return ServerTrustPolicy.disableEvaluation
}
}
Then,
let trustPolicies = MyServerTrustPolicyManager(policies: [:])
let manager = Alamofire.SessionManager(configuration: sessionConfig, delegate: SessionDelegate(), serverTrustPolicyManager: trustPolicies)
So I know some time has passed, but I had exactly the same problem. And I found a solution with above answers. I had to add 2 things to trustPolicies:
let defaultManager: Alamofire.Manager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
// Here host with port (trustPolicy is my var where I pin my certificates)
"localhost:3443": trustPolicy
//Here without port
"localhost": .disableEvaluation
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
return Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
Also in Info.plist had to add:
<key>AppTransportSecurity</key>
<dict>
<key>AllowsArbitraryLoads</key>
<true/>
</dict>

Resources