Certificate pinning in Alamofire not working - ios

I've added a .der certificate to my project, which is recognised by ServerTrustPolicy.certificatesInBundle(). I'm now creating a Manager which is then used to make API calls:
private class func manager() -> Alamofire.Manager {
let certificates = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"api.oursite.com": certificates
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let manager = Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
return manager
}
Before this, it was just using Alamofire.request(..., and those requests were working perfectly fine, but now it's giving me an error on every call:
Error Domain=NSURLErrorDomain Code=-999 "cancelled"
Am I setting up the manager incorrectly? Perhaps my certificate was created incorrectly, and that's causing this to not work?

Be sure that your manager not deallocated in short time after request. Make it as stored property in custom Manager class for example.

Related

Swift AlamoFire 5 won't execute Request

My problem is, when I execute the request it will happen nothing.
What I made:
I made an Api with .net core Api on a another PC and now I want to make a IOS App, that has access to the Api. (The API works I tested it with swagger and Insomnia) On the IOS app I made a put request with AlamoFire. And when I execute the request it's happening nothing. I watched the Network with Wireshark and there comes Nothing too.
When I Debug, it will step through the request Methode, but it goes nothing out to the API. And there are no errors.
// buttonClick will call this Methode
func requst() {
// testing parameters
let params: Parameters = [
"nfcId": 1,
"date" : "2021-04-12T09:47:12.053Z"
]
//
session.request("http://MyAPI/api/Guard/AddGuard", method: .put, parameters: params, headers: nil).validate(statusCode: 200 ..< 299)
}
I made an own Session wehere I pinned a certificate
private let certificates = [
"https://MyAPI:5001":
PinnedCertificatesTrustEvaluator(certificates: [Certificates.certificate], acceptSelfSignedCertificates: false, performDefaultValidation: true, validateHost: true)
]
private let session: Session
init(allHostsMustBeEvaluated: Bool) {
let serverTrustPolicy = ServerTrustManager(allHostsMustBeEvaluated: allHostsMustBeEvaluated, evaluators: certificates)
let config = URLSessionConfiguration.af.default
session = Session(configuration: config, serverTrustManager: serverTrustPolicy)
}
You haven't attached a response handler or called resume(), so no, the request isn't going to do anything. Adding something like responseDecodable will start the request automatically.

How to trust an endpoint iOS swift

I'm calling an endpoint that has a self-signed ssl certificate i have tried adding this in my info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
But i am still not able to access the endpoint i keep getting this
NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “endpoint” which could put your confidential information at risk.
You need to create a session manager and tell it to disable evaluation of the ssl in that server.
Something like this
static var manager: Alamofire.SessionManager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"https://example.com": .disableEvaluation
]
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
let manager = Alamofire.SessionManager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
return manager
}()
An then, instead of calling request in Alamofire, like this
Alamofire.request("https://example.com", method: .get…
you call it in your manager
manager.request("https://example.com"…

How to use ssl certificate with Swift Alamofire?

I am upgrading my iOS apps with HTTPS web services.
I have upgrade my web server with SSL certificate. But don't know what to do from iOS code side?
Do I need to pass any certificate along with the web request?
I am using Alamofire for making web request.
Thanks
Simple googling would have given you so many results.
For example, https://infinum.co/the-capsized-eight/how-to-make-your-ios-apps-more-secure-with-ssl-pinning
func configureAlamoFireSSLPinning {
let pathToCert = NSBundle.mainBundle().pathForResource(githubCert, ofType: "cer")
let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!
self.serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: [SecCertificateCreateWithData(nil, localCertificate)!],
validateCertificateChain: true,
validateHost: true
)
self.serverTrustPolicies = [
"your-api.com": self.serverTrustPolicy!
]
self.afManager = Manager(
configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
serverTrustPolicyManager: ServerTrustPolicyManager(policies: self.serverTrustPolicies)
)
}
func alamoFireRequestHandler {
self.afManager.request(.GET, self.urlTextField.text!)
.response { request, response, data, error in
// response management code
}
}

Alamofire 4 FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled"

Hi I am try to use Alamofire for my project but the error come out.
Here is my requesting code
//Google testing
Alamofire.request("http://google.com").responseString{
response in
debugPrint(response)
}.session.invalidateAndCancel()
Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled"
UserInfo={NSErrorFailingURLKey=http://google.com/,
NSLocalizedDescription=cancelled,
NSErrorFailingURLStringKey=http://google.com/}
//Own server testing
Alamofire.request("https://10.68.24.127:4533").responseString{
response in
debugPrint(response)
}.session.invalidateAndCancel()
same result
class NetworkManager {
var manager: SessionManager?
init() {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"https://10.68.24.127:4533" : .disableEvaluation
]
let configuration = URLSessionConfiguration.default
manager = Alamofire.SessionManager(
configuration: configuration,
serverTrustPolicyManager :ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}
}
I set the NSAllowsArbitraryLoads to true and NSExceptionDomains.
Where is the problem?
There could be a lot of reason to why your requests "cancelled".
If you are facing that a request cancels immediately you can refer to this issue in Alamofire repository issues
jshier commented on Oct 10, 2016
An unexpected error -999 almost always means your SessionManager was
deallocated, cancelling any ongoing requests. I suggest you create a
singleton value for your custom SessionManager, or perhaps just
reevaluate if you really need one.
if you create a singleton value for your object it remains in memory and prevent from deallocate
and another thing that i avoid is to name your variables diffrent, a sessionManager is in Alamofire and your variable is also called sessionManager.
Alamofire 4.7 , Swift 4
import Alamofire
class Networking {
public static let sharedManager: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest=20
let manager = Alamofire.SessionManager(configuration: configuration, delegate: SessionManager.default.delegate)
return manager
}()
}
Alamofire 5.4.4 , Siwft 5.2
import Alamofire
class Networking {
static let APIManager: Session = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 20
let delegate = Session.default.delegate
let manager = Session.init(configuration: configuration,
delegate: delegate,
startRequestsImmediately: true,
cachedResponseHandler: nil)
return manager
}()
}
Check this documentation from Alamofire app-transport-security
try to add the following in your .plist file
<key>NSAppTransportSecurity</key><dict>
<key>NSExceptionDomains</key>
<dict>
<key>url.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
Most likely you should be checking if there is an implementation of authentication challenge delegate method and check if its calling NSURLSessionAuthChallengeCancelAuthenticationChallenge.
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler

certificatesInBundle doesn't append self signed certificates

Using the convenience method ServerTrustPolicy.certificatesInBundle() doesn't appear to work correctly in my case
// MARK: - Bundle Location
/**
Returns all certificates within the given bundle with a `.cer` file extension.
- parameter bundle: The bundle to search for all `.cer` files.
- returns: All certificates within the given bundle.
*/
public static func certificatesInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecCertificate] {
var certificates: [SecCertificate] = []
let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in
bundle.pathsForResourcesOfType(fileExtension, inDirectory: nil)
}.flatten())
for path in paths {
if let
certificateData = NSData(contentsOfFile: path), // <-- we get the data of the certificate in bundle
certificate = SecCertificateCreateWithData(nil, certificateData) // <-- The problem is here, the certificate is not set neither errors.
{
certificates.append(certificate) // <-- this doesn't run
}
}
return certificates
}
Probably has to do something with the format of the self-signed certificate. I used exactly the #tip 5 from this blog post. Five Tips for Using Self Signed SSL Certificates with iOS
The question is what is the limitations of the SecCertificateCreateWithData method and which certificate formats are acceptable? Even better where can I read more about this particular issue.
my code appears to be correct it's nothing special, probably one of the most used snippets :P
let defaultManager:Alamofire.Manager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"localhost": .PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
]
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
return Alamofire.Manager(
configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
}()
The most likely reason that SecCertificateCreateWithData would return nil, is that the file is in PEM not DER format.
As per the documentation, data should contain
A DER (Distinguished Encoding Rules) representation of an X.509
certificate
If your data begins with "-----BEGIN...", then it is the wrong format. PEM can be converted to DER (and vice versa) with OpenSSL - here is a handy reference https://www.sslshopper.com/article-most-common-openssl-commands.html.
Also, in case of a self-signed certificate (judging by "localhost"), the validateCertificateChain property should be false. Otherwise the request will fail with a "cancelled" NSError.
Additionally, starting from iOS9, App Transport Security settings should be set to allow arbitrary loads (in Info.plist). That is the only setting that will permit self-signed certificates to be evaluated by your app. Without it, the Alamofire trust policy mechanism will not get a chance to kick in.
I had a similar problem. Alamofire couldn't find my certificate, the ServerTrustPolicy.certificatesInBundle() method did not return anything.
The problem was that when dragging my certificate into my Xcode project I didn't select "Add to targets: MyProjectName".
Make sure that you downloaded the certificate in der format and added correctly to your project.
after that define a static SessionManager as mentioned below
public static let sharedManager: SessionManager = {
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"subdomain.domain.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: false,
validateHost: true
),
"insecure.expired-apis.com": .disableEvaluation
]
let manager = Alamofire.SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
return manager
}()
then you can call the above sharedManager:
YourHttpClassName.sharedManager.request(url, method: .get, headers: headers).response { response in
print("Request: \(response.request)")
print("Response: \(response.response)")
print("Error: \(response.error)")
debugPrint(response)
}
it should work fine with your self-signed certificate.

Resources